/**
 *  Returns true if all relevant children of the widget managed by this
 *  instance are valid AND if #isOtherValid() returns true; otherwise returns
 *  false. Disabled children and children without validation
 *  are skipped and don't affect the result.
 *
 *  The method emits the #isValidRequested() signal before calling
 *  #isOtherValid(), thus giving someone an opportunity to affect its result by
 *  calling #setOtherValid() from the signal handler. Note that #isOtherValid()
 *  returns true by default, until #setOtherValid( false ) is called.
 *
 *  @note If #isOtherValid() returns true this method does a hierarchy scan, so
 *  it's a good idea to store the returned value in a local variable if needed
 *  more than once within a context of a single check.
 */
bool QIWidgetValidator::isValid() const
{
    // wgt is null, we assume we're valid
    if (!mWidget)
        return true;

    QIWidgetValidator *that = const_cast <QIWidgetValidator *> (this);
    emit that->isValidRequested (that);
    if (!isOtherValid())
        return false;

    QValidator::State state = QValidator::Acceptable;

    foreach (Watched watched, mWatched)
    {
        if (watched.widget->inherits ("QLineEdit"))
        {
            QLineEdit *le = ((QLineEdit *) watched.widget);
            Assert (le->validator());
            if (!le->validator() || !le->isEnabled())
                continue;
            QString text = le->text();
            int pos;
            state = le->validator()->validate (text, pos);
        }
        else if (watched.widget->inherits ("QComboBox"))
        {
            QComboBox *cb = ((QComboBox *) watched.widget);
            Assert (cb->validator());
            if (!cb->validator() || !cb->isEnabled())
                continue;
            QString text = cb->lineEdit()->text();
            int pos;
            state = cb->lineEdit()->validator()->validate (text, pos);
        }

        if (state != QValidator::Acceptable)
        {
            that->mLastInvalid = watched;
            that->mLastInvalid.state = state;
            return false;
        }
    }

    /* reset last invalid */
    that->mLastInvalid = Watched();
    return true;
}
int main( void ){

    int i; //Loop counter.
    int tempTokCtr = 0; //Count number of tokens.

    char buffer[ 10000 ]; //For reading in tokens.
    char temp[ 10000 ]; //Back-up buffer.

    //Prompt user for source program name.
    char sp[50]; //Name of input file.
    printf( "What is the file name for your source program?\n" );
    scanf( "%s", sp );

    //Open file input stream to main input (the program).
    FILE *fin = fopen( sp, "r" );

    //Open file output stream to intermediary output file.
    //In this file, unprocessed tokens will be stored for further processing.
    FILE *temp_fout = fopen( "temp_output.txt", "w" );

    //Procedure for creating intermediary output.
    /** BEGIN PROCEDURE **/
    while( fscanf( fin, "%s", buffer ) != EOF ){

        int len = (int) strlen( buffer ); //Length of read-in token.

        //For the length of the read-in token:
        for( i = 0; i < len; i++ ){

            //If we've reached the end of the buffer, and it's not a special symbol, print the token.
            //If invalid symbols are present, they're ignored and taken care of later.
            if( i == len-1 && !isSpecialSymbol( buffer[ i ] ) ){
                fprintf( temp_fout, "%s ", buffer );
                tempTokCtr++; //Increment the token counter.
            }

            //If the i-th element of the token is a special symbol.
            else if( isSpecialSymbol( buffer[ i ] ) ){

                //Brute force examine particular token cases: comment tokems, not equal, less-than-or-equal, ... , null, and odd.
                if( len > 1 ){
                    if( buffer[ i ] == '/' && buffer[ i+1 ] == '*' ){
                        strncpy( temp, buffer, i );
                        temp[ i ] = '\0';

                        fprintf( temp_fout, "%s ", temp );
                        tempTokCtr++;

                        fprintf( temp_fout, "/* " );
                        tempTokCtr++;

                        strncpy( buffer, &buffer[i]+2, len-1 );
                        buffer[ len - 1 ] = '\0';
                        len = (int) strlen( buffer );
                        i = -1;
                    }
                    else if( buffer[ i ] == '*' && buffer[ i+1 ] == '/' ){
                        strncpy( temp, buffer, i );
                        temp[ i ] = '\0';

                        fprintf( temp_fout, "%s ", temp );
                        tempTokCtr++;

                        fprintf( temp_fout, "*/ " );
                        tempTokCtr++;

                        strncpy( buffer, &buffer[i]+2, len-1 );
                        buffer[ len - 1 ] = '\0';
                        len = (int) strlen( buffer );
                        i = -1;
                    }
                    else if( buffer[ i ] == '!' && buffer[ i+1 ] == '=' ){
                        strncpy( temp, buffer, i );
                        temp[ i ] = '\0';

                        fprintf( temp_fout, "%s ", temp );
                        tempTokCtr++;

                        fprintf( temp_fout, "!= " );
                        tempTokCtr++;

                        strncpy( buffer, &buffer[i]+2, len-1 );
                        buffer[ len - 1 ] = '\0';
                        len = (int) strlen( buffer );
                        i = -1;
                    }
                    else if( buffer[ i ] == '<' && buffer[ i+1 ] == '=' ){
                        strncpy( temp, buffer, i );
                        temp[ i ] = '\0';

                        fprintf( temp_fout, "%s ", temp );
                        tempTokCtr++;

                        fprintf( temp_fout, "<= " );
                        tempTokCtr++;

                        strncpy( buffer, &buffer[i]+2, len-1 );
                        buffer[ len - 1 ] = '\0';
                        len = (int) strlen( buffer );
                        i = -1;
                    }
                    else if( buffer[ i ] == '>' && buffer[ i+1 ] == '=' ){
                        strncpy( temp, buffer, i );
                        temp[ i ] = '\0';

                        fprintf( temp_fout, "%s ", temp );
                        tempTokCtr++;

                        fprintf( temp_fout, ">= " );
                        tempTokCtr++;

                        strncpy( buffer, &buffer[i]+2, len-1 );
                        buffer[ len - 1 ] = '\0';
                        len = (int) strlen( buffer );
                        i = -1;
                    }
                    else if( buffer[ i ] == ':' && buffer[ i+1 ] == '=' ){
                        strncpy( temp, buffer, i );
                        temp[ i ] = '\0';

                        fprintf( temp_fout, "%s ", temp );
                        tempTokCtr++;

                        fprintf( temp_fout, ":= " );
                        tempTokCtr++;

                        strncpy( buffer, &buffer[i]+2, len-1 );
                        buffer[ len - 1 ] = '\0';
                        len = (int) strlen( buffer );
                        i = -1;
                    }
                    else if( len > 3 && buffer[ i ] == 'n' && buffer[ i+1 ] == 'u' && buffer[ i+2 ] == 'l' && buffer[ i+3 ] =='l' ){
                        strncpy( temp, buffer, i );
                        temp[ i ] = '\0';

                        fprintf( temp_fout, "%s ", temp );
                        tempTokCtr++;

                        fprintf( temp_fout, "null " );
                        tempTokCtr++;

                        strncpy( buffer, &buffer[i]+4, len-1 );
                        buffer[ len - 1 ] = '\0';
                        len = (int) strlen( buffer );
                        i = -1;
                    }
                    else if( len > 2 && buffer[ i ] == 'o' && buffer[ i+1 ] == 'd' && buffer[ i+2 ] == 'd' ){
                        strncpy( temp, buffer, i );
                        temp[ i ] = '\0';

                        fprintf( temp_fout, "%s ", temp );
                        tempTokCtr++;

                        fprintf( temp_fout, "odd " );
                        tempTokCtr++;

                        strncpy( buffer, &buffer[i]+3, len-1 );
                        buffer[ len - 1 ] = '\0';
                        len = (int) strlen( buffer );
                        i = -1;
                    }

                }

                //Special symbol token at the beginning.
                if( i == 0 ){
                    //Print symbol as individual token.
                    fprintf( temp_fout, "%c ", buffer[i] );
                    tempTokCtr++; //Increment token counter.

                    //Shift buffer, and update loop index.
                    //Similar procedure used for brute force token examination, and further token examination.
                    strncpy( buffer, &buffer[i]+1, len-1 );
                    buffer[ len - 1 ] = '\0';
                    len = (int) strlen( buffer );
                    i = -1;
                }

                //Valid symbol is splitting tokens within the buffer; split, print, and shift the tokens left of the valid symbol, including the symbol.
                if( i > 0 ){
                    strncpy( temp, buffer, i );
                    temp[ i ] = '\0';

                    fprintf( temp_fout, "%s ", temp );
                    tempTokCtr++;

                    fprintf( temp_fout, "%c ", buffer[i] );
                    tempTokCtr++;

                    strncpy( buffer, &buffer[i]+1, len-1 );
                    buffer[ len - 1 ] = '\0';
                    len = (int) strlen( buffer );
                    i = -1;
                }

            }

        }

    }
    /** END OF PROCEDURE **/

    //Resource management.
    fclose( temp_fout );
    fclose( fin );

    //Open file input stream to intermediary output created by the procedure above (unprocessed tokens).
    fin = fopen( "temp_output.txt", "r" );
    FILE *table = fopen( "lexeme_table.txt", "w" ); //Will hold the lexeme table.
    FILE *list = fopen( "lexeme_list.txt", "w" ); //Will hold the lexeme list.

    //Print header for lexeme table.
    fprintf( table, "Lexeme Table:\n%15s%15s\n", "lexeme", "token type");

    //Procedure to examine printed tokens.

    /** BEGIN PROCEDURE **/

    //Initialize.
    int isResWord = -1; //If currently examined token is a reserved word, != -1; otherwise, = -1.
    int len = 0; //Length of examined token.
    int isComment = 0; //If currently reading in a comment, = 1; otherwise, = 0.

    //For the length of tokens.
    while( fscanf( fin, "%s ", buffer ) != EOF ){

        //fscanf( fin, "%s", buffer ); //Read in token.
        len = (int) strlen( buffer ); //Get token string length.

        //Recognize beginning of comment block.
        if( !strcmp( buffer, "/*" ) ){
            isComment = 1;
        }

        //Recognize end of comment block.
        else if( isComment == 1 && !strcmp( buffer, "*/" ) ){
            isComment = 0;
        }

        //Only read in tokens while not examining a comment block.
        else if( !isComment ){

            //Error detection by token.
            if( detectError( buffer ) ){
                fclose( fin );
                fclose( table );
                fclose( list );
                exit( 0 );
            }

            //Is the current token a reserved word? Print to table and list appropriately.
            isResWord = isReservedWord( buffer );

            if( isResWord != -1 ){

                fprintf( table, "%15s%15d\n", buffer, isResWord );
                fprintf( list, "%d ", isResWord );

            }

            //Is the current token an identifier? Print to table and list appropriately.
            else if( isalpha( buffer[0] ) ){

                fprintf( table, "%15s%15d\n", buffer, 2 );
                fprintf( list, "2 %s ", buffer );

            }

            //Is the current token a number? Print to table and list appropriately.
            else if( isdigit( buffer[0] ) ){

                fprintf( table, "%15s%15d\n", buffer, 3 );
                fprintf( list, "3 %s ", buffer );

            }

            //Otherwise, our token is some other valid symbol (checked for errors above). Print appropriately.
            else{

                fprintf( table, "%15s%15d\n", buffer, isOtherValid( buffer ) );
                fprintf( list, "%d ", isOtherValid( buffer ) );

            }
        }


    }

    //Resource management.
    fclose( fin );
    fclose( table );
    fclose( list );

    /** END OF PROCEDURE **/

    //Procedure to copy and source program.
    /** BEGIN PROCEDURE **/

    fin = fopen( sp, "r" ); //File containing source program.
    FILE *source = fopen( "source_program.txt", "w" ); //File to copy source program to.
    char copy; //Used to copy file, character by character.

    //Copy character by character, until end of file.
    while( ( copy = fgetc( fin ) ) != EOF )
        fputc( copy, source );

    //Resource management.
    fclose( fin );
    fclose( source );
    remove( "temp_output.txt" ); //Delete intermediary output.

    /** END OF PROCEDURE **/

    return 0;

} //End of main.