/**
 * @file 
 * File containing gameIOManager module
 */

#include "gameIOManager.h"

/* Start function definition of gameIOManager module */
char **readfile( char namefile[],
                 bool *schema_ok,
                 unsigned int *mapCurrentRow,
                 unsigned int *mapCurrentCol,
                 unsigned int mapMaxRow,
                 unsigned int mapMaxCol,                  
                 bool differentColLen
               )
{
    D1(printf("\nGAMEIOMANAGER.readfile() - START\n"));
    D2(printf("\nMax dimensions (rows,cols)=(%u,%u)\n",
                                         mapMaxRow,mapMaxCol  ));
    D2(printf("\nDIFFerent columns CONTROL is turn %s\n",
                                    differentColLen?"ON":"OFF" ));
                                    
    char **contentFile = allocResetVariable(mapMaxRow,mapMaxCol);
    
    // set current position to first row,col
    *mapCurrentRow = 0;
    *mapCurrentCol = 0;   
    
    /* First reading of the file, to set the number of rows and the row with 
    maximum length*/
    FILE *file2read = NULL;
    char fileChar;
    int checkchar;
    unsigned int checkCol = 0;

    if ( (file2read=fopen(namefile,"r")) == NULL)
    { 
         D1(printf("Impossible to open the file %s\n",namefile));
	     *schema_ok = false;
         return contentFile; 
    }

    do
    {   // there's always a character, otherwise it doesn't enter in this cicle
        checkchar = fscanf(file2read,"%c",&fileChar);
        if(checkchar == EOF )
            fileChar = EOF;
        
        if((fileChar == COMMENT) || (fileChar == EOF) || (fileChar == ENDLINE))
            skipCharacters( &fileChar, &checkchar, file2read );
        else      // else reading and saving the rest of the row
        {
            if( *mapCurrentRow >= mapMaxRow ){     // max number of ROW control
                D1(printf("\nFile have more rows then maximum allowed (%u)\n",
                                                                 mapMaxRow  ));
                D1(printf("\nGAMEIOMANAGER.readfile() - Error & END\n"));
                *schema_ok = false;
                return contentFile;
            }      
            // Set first character already read
            contentFile[ *mapCurrentRow ] [ 0 ] = fileChar;
            *mapCurrentCol = 1;             // Reset columns to second
                            
            if ( ! readCharacters( mapCurrentCol, mapMaxCol, mapCurrentRow,
                                   mapMaxRow, contentFile, file2read        ) )
            {
                *schema_ok = false;
                D1(printf("\nGAMEIOMANAGER.readfile() - Error & END\n"));
                return contentFile;
            }        
                        
            // Test if all the columns have the same length
            if( differentColLen )
            {
                if ( ! checkDifferentColLen( mapCurrentRow, mapCurrentCol,
                                             &checkCol                       ) )
                {
                    *schema_ok = false;
                    D1(printf("\nGAMEIOMANAGER.readfile() - Error & END\n"));
                    return contentFile;
                } 
            }   
            *mapCurrentRow = *mapCurrentRow + 1;
        }
    }
    while( fileChar != EOF );  // until there are characters
    
    // Close the file
    fclose(file2read);
    *schema_ok = true;
    
    D1(printf("\nGAMEIOMANAGER.readfile() - END\n"));
    return contentFile;
}


char **allocResetVariable( unsigned int mapMaxRow,
                           unsigned int mapMaxCol
                        )
{
    D1(printf("\nGAMEIOMANAGER.allocResetVariable() - START\n"));

    // Alloc and reset the array of strings in which file's data will be saved
    char **contentFile = (char **) malloc( sizeof(char *) * mapMaxRow );
    unsigned int i = 0, j = 0;
    for( i=0; i<mapMaxRow; i++)
    {
           assert( i < mapMaxRow );
           contentFile[i] = (char *) malloc( sizeof(char) * mapMaxCol );

           for(j=0; j<mapMaxCol; j++){
               assert( j < mapMaxCol );
               contentFile[i][j] = NULLCHAR;
           }
    }

    D1(printf("\nGAMEIOMANAGER.allocResetVariable() - END\n"));

    return contentFile;
}


void skipCharacters( char *fileChar,
                     int *checkchar,
                     FILE *file2read
                    )
{
    D1(printf("\nGAMEIOMANAGER.skipCharacters() - START\n"));

    while( ( *fileChar != EOF ) && ( *fileChar != ENDLINE ) )
        {
            *checkchar = fscanf(file2read,"%c",fileChar);
            if(*checkchar == EOF )
                *fileChar = EOF;
        }

    D1(printf("\nGAMEIOMANAGER.skipCharacters() - END\n"));
}


bool readCharacters(unsigned int *mapCurrentCol,
                    unsigned int mapMaxCol,
                    const unsigned int *mapCurrentRow,
                    unsigned int mapMaxRow,
                    char **contentFile,
                    FILE *file2read
                    )
{
    D1(printf("\nGAMEIOMANAGER.readCharacters() - START\n"));
    bool stopRead = false;
    char fileChar;
    int checkchar;

    while( !stopRead )
    {
        assert( !stopRead );
        checkchar = fscanf(file2read,"%c",&fileChar);
        if(checkchar == EOF )
            fileChar = EOF;
        
        // if row is not end
        if( ( fileChar != ENDLINE ) && ( fileChar != EOF ) )
        {
            // max number of COL control
            if( *mapCurrentCol >= mapMaxCol )
            {
                D1(printf("\nGAMEIOMANAGER.readCharacters() - END\n"));
                D1(printf("\nFile have more columns then maximum allowed (%u)\n",
                                                            mapMaxCol  ));
                return false;
            }
            // save the character at it's position    
            else
            {
                contentFile[ *mapCurrentRow ] [ *mapCurrentCol ] = fileChar;
                *mapCurrentCol = *mapCurrentCol + 1;
            }
        }        
        else
            stopRead = true;
    }

    D1(printf("\nGAMEIOMANAGER.readCharacters() - END\n"));
    return true;
}


bool checkDifferentColLen(  const unsigned int *mapCurrentRow,
                            const unsigned int *mapCurrentCol,
                            unsigned int *checkCol
                           )
{
    D1(printf("\nGAMEIOMANAGER.checkDifferentColLen() - START\n"));  

    if(*mapCurrentRow == 0) // set check parameter only first time
        *checkCol = *mapCurrentCol;
    else                    // if not the first row
    if( *checkCol != *mapCurrentCol )
    {
        D1(printf("\nDifferent columns number in schema (at row %u)\n",
                                                (*mapCurrentRow+1)));
        return false;
    }

    D1(printf("\nGAMEIOMANAGER.checkDifferentColLen() - END\n"));
    return true;
}


bool readSetGameRecord( unsigned int *readrows )
{

    D1(printf("\nGAMEIOMANAGER.readSetGameRecord() - START\n")); 
	
    /*Read from record file the number of saved records and the value list*/
    unsigned int numrow=0, numcol=0;
    const unsigned short int RECORD_ROW_NUMBER = 3;
    const unsigned short int ADDITIONAL_CHAR_NUMBER = 1;
    char **filecontent = NULL;
    bool record_ok = false;
    char *filenamecpy = 
            (char *) malloc( sizeof(char) * ( ADDITIONAL_CHAR_NUMBER 
                                              + strlen(RECORD_FILE_NAME) ) );
                                      
    strcpy( filenamecpy , RECORD_FILE_NAME );
    filecontent = readfile( filenamecpy, 
                            &record_ok,
                            &numrow,
                            &numcol,
                            (MAX_RECORD_SHOW * RECORD_ROW_NUMBER),
                            MAX_RECORDNAME_LEN,
                            false 
                          );
    
    free( filenamecpy );

    // if RECORD_FILE_NAME file is corrupted    
    if( ! record_ok )
    {
        D1(printf("\nRecord file is corrupted!\n"));
        D1(printf("\nGAMEIOMANAGER.readSetGameRecord() - Error & END\n"));
        return false;
    }
    
    // else RECORD_FILE_NAME file is ok
    D2(printf("\nReading file %s return %u record lines.\n",
                RECORD_FILE_NAME, numrow                  ));
    
    bool foundErrors = false;
    foundErrors = setGameRecordStructValue(filecontent, numrow, numcol);
    
    if (foundErrors)
    {
        D1(printf("\nGAMEIOMANAGER.readSetGameRecord() - Error & END\n"));
        return false;
    }
    
    *readrows = (numrow/RECORD_ROW_NUMBER);

    D1(printf("\nGAMEIOMANAGER.readSetGameRecord() - END\n")); 
	return true;
}


bool setGameRecordStructValue( char **filecontent,
                               unsigned int numrow, 
                               unsigned int numcol 
                             )
{
    D1(printf("\nGAMEIOMANAGER.setGameRecordStructValue() - START\n"));
    
    unsigned int structind = 0, i = 0, j = 0;
    for(i=0; i<numrow; i++)
    {
        // Check and set name(s)
        for(j=0; j<strlen(filecontent[i]); j++)
            if( ! isallowedchar(LOWERCASE+UPPERCASE+DIGITS, filecontent[i][j]))
            {
                D1(printf("\nName's character %u^ at row %u not allowed.\n"
                                                ,j        ,i              ));
                D1(printf(
                        "\nGAMEIOMANAGER.setGameRecordStructValue() - END\n"));
                return true;
            }

        strcpy( gameRecord[ structind ].name , filecontent[i] );
        
        // Next row
        i++;
        
        // Check and set points
        for(j=0; j<strlen(filecontent[i]); j++)
            if( ! isallowedchar( DIGITS , filecontent[i][j] ) )
            {
                D1(printf(
                      "\nPoints' character %u^ at row %u not allowed.\n",j,i));
                D1(printf(
                      "\nGAMEIOMANAGER.setGameRecordStructValue() - END\n"));
                return true;
            }
        
        double check = atoi( filecontent[i] );
        if( check > UINT_MAX ){
            D1(printf(
                    "\nPoints value (%.0lf) exceed max allowed (%u).\n",
                                        check,                UINT_MAX    ));
            D1(printf("\nGAMEIOMANAGER.setGameRecordStructValue() - END\n"));
            return true;
        }
        
        gameRecord[ structind ].points = (unsigned int) check;
        
        // Next row
        i++;
        
        // Check and set level
        for(j=0; j<strlen(filecontent[i]); j++)
            if( ! isallowedchar( DIGITS , filecontent[i][j] ) )
            {
                D1(printf(
                    "\nLevel's character %u^ at row %u not allowed.\n",j,i
                            ));
                D1(printf(
                        "\nGAMEIOMANAGER.setGameRecordStructValue() - END\n"));
                return true;
            }
        
        check = atoi( filecontent[i] );
        if( check > NEW_GAME_ROUND ){
            D1(printf(
                    "\nLevel value (%.0lf) exceed max allowed (%u).\n",
                                        check,             NEW_GAME_ROUND ));
            D1(printf("\nGAMEIOMANAGER.setGameRecordStructValue() - END\n"));
            return true;
        }
        
        gameRecord[ structind ].level = (unsigned int) check;
        
        //Next struct
        structind++;    
    }

    D1(printf("\nGAMEIOMANAGER.setGameRecordStructValue() - END\n"));
    return false;
}

void save_record( const char *name,
                  unsigned int totalpoints,
                  unsigned int currentlevel
                )
{
	
    D1(printf("\nGAMEIOMANAGERS.save_record() - START\n"));	
	
	unsigned int numrec = 0;
	bool readstat = false;
	
	readstat = readSetGameRecord( &numrec );
	
	if( ! readstat ){
        assert( !readstat );
	    remove( RECORD_FILE_NAME );
	    numrec = 0;
	}
	
	unsigned int pos = 0;
	
	/*If there are other record in file*/
	if( numrec > 0 ){
        assert( numrec > 0 );
		/* Find the position where put the new record
		   in order to mantein it ordered */
		while( pos < numrec ){
            assert( pos < numrec );

			if(gameRecord[pos].points <= totalpoints)
				break;
			else
				pos++;
		}
	}

	if ( numrec < MAX_RECORD_SHOW )
	    numrec++;
	
	D2(printf("\nInsert position: %u\n",pos));

	FILE * recordf = fopen ( RECORD_FILE_NAME , "w" );
    
    if( recordf == NULL ){
        D1(printf("\nError in file %s when opening for writing!\n",
                                   RECORD_FILE_NAME                 ));
        return;
    }

    D2(printf("\nWriting on %s number of record %u\n",
                    RECORD_FILE_NAME,         numrec    ));
    
	unsigned int i=0;
	unsigned int i_gameRecord=0; 
	while( i<numrec )
	{
	    assert( recordf != NULL );
	    
		if( pos == i )
		{
			fprintf( recordf, "%s\n", name );
			fprintf( recordf, "%u\n", totalpoints );
			fprintf( recordf, "%u\n", currentlevel );
			i_gameRecord--;
		}
		else
		{
    		fprintf( recordf, "%s\n", gameRecord[i_gameRecord].name );
    		fprintf( recordf, "%u\n", gameRecord[i_gameRecord].points );
    		fprintf( recordf, "%u\n", gameRecord[i_gameRecord].level );
    		
    		D3(printf("\nName: %s  points: %u  level: %u\n", 
    		         gameRecord[i_gameRecord].name,
                     gameRecord[i_gameRecord].points,
                     gameRecord[i_gameRecord].level             ));
		}
		
		i++;
		i_gameRecord++;

	}

    assert( recordf != NULL );
	fclose(recordf);
	
    D1(printf("\nGAMEIOMANAGER.save_record() - END\n"));	
	
}

/* Works only in debug mode.*/
void printschema()
{
  D1(

         unsigned int i = 0;
         unsigned int j = 0;

         printf("\nSCHEMA:\n");
         for(i=0;i<schemaData.numRow;i++)
         {
            printf("\n");
            for(j=0;j<schemaData.numCol;j++)
                printf("%c",schemaData.gameMap[i][j]);
         }
         printf("\n\n");

    );
}


/* End function definition of gameIOManager module */
