Subversion Repositories svn1-original

Rev

Rev 344 | Blame | Compare with Previous | Last modification | View Log | RSS feed

#include "qmconfig.h"
#include "mainwindow.h"
#include <QFileDialog>
#include <QObject>
#include <QMessageBox>
#include <QFileInfo>
#include <QFile>
#include <QCoreApplication>
#include <QSettings>

//#define DISPLAY_STRUCTURES

// Global Data
QmConfig    config;

// Application Config
//  Only use this to store user setting
//  Thinks like : 
//      Last path for loaded file
//      Last entered uploaded leg
//      Swim Start: Leg Set up Delta and base

QSettings   *appSettings = NULL;


/*
**  Local definitions
*/
char        datfile[20];                         /* Name of the data file */
char        filebase[20];                        /* Event file name base */
char        filepath[300];

/*----------------------------------------------------------------------------
** FUNCTION           : QmConfig 
**
** DESCRIPTION        : Constructor
**
**
** INPUTS             :
**
----------------------------------------------------------------------------*/

QmConfig::QmConfig(void)
{
    /*
    ** Init appSettings - once !
    */
    //qDebug("Create a QmConfig");
    if (!appSettings)
    {
        appSettings = new QSettings(getAddendemFile("mara.ini", true), QSettings::IniFormat); 
    }
}

/*----------------------------------------------------------------------------
** FUNCTION           : ~QmConfig
**
** DESCRIPTION        : Destructor
**
**
----------------------------------------------------------------------------*/

QmConfig::~QmConfig()
{
    /*
    ** This will force the items to be flushed
    */
    if (appSettings)
    {
        delete(appSettings);
        appSettings = NULL;
    }
}

void QmConfig::load(const QString &cnfFile)
{
#ifdef DISPLAY_STRUCTURES
    display_structures();
#endif
    fileName = cnfFile;

    if ( !fileName.endsWith(".cnf",Qt::CaseInsensitive))
    {
        fileName.append(".cnf");
    }
    if (cnfFile.isEmpty())
    {
        fileName = QFileDialog::getOpenFileName(0, "Select Config File",
                                                         filepath,
                                                         "Data (*.cnf);;All (*.*)",
                                                         0,
                                                         0
                                                         );
    }

    //  No file selected
    //  Just exit
    if (fileName.isEmpty())
    {
        qDebug("No Config file selected");
        exit(1);
    }

    //
    //  Setup file names
    //
    QFileInfo info (fileName);
    strncpy(filebase, qPrintable(info.baseName()), 8);
    strcpy( datfile, filebase );
    strcat( datfile, ".dat" );

    strncpy(filepath, qPrintable(info.absolutePath()), sizeof(filepath)-3);
    strcat(filepath, "/");
    qDebug("FilePath:%s", filepath );

    if ( !open_read_config() )
    {
        if (QMessageBox::Cancel == QMessageBox::question ( 0,
                                                       "Config Load Error",
                                                       "Cannot load or read configuration file.\n"
                                                       "If you continue a new configuration will be created\n"
                                                       "If you cancel then the application will terminate.",
                                                       QMessageBox::Ok | QMessageBox::Cancel
                                                       ) )
        {
            qDebug("Cancel to bad config");
            exit(2);
        }
    }
}


bool QmConfig::open_read_config( void )
{
    bool result;
    // Open the file
    QFile configFile;
    configFile.setFileName(fileName);
    if ( ! configFile.open(QIODevice::ReadOnly) )
    {
        MainWindow::showMessage("Cannot open config File");
        return (false );
    }

    result = read_config(configFile);
    configFile.close();

    if ( result )
    {
        /*
        **  Post read calculations and fixups
        */
        if( datafilename[0] )
        {
            strcpy( datfile, datafilename );
            strcat( datfile, ".dat" );
        }
        nonequestrian_class = lookup_class( nonequestrian_class_abr );

        class_ne_winners_by_class = false;
        for( int i = 0; i < MAX_CLASS; i++ )
        {
           if(class_ne_winners[i])
           {
               class_ne_winners_by_class = true;
               break;
           }
        }


    }
    return result;
}

/*========================================================================
 *
 *  Read in the configuration file
 *
 *  Purpose:
 *      This function is called to read in the configuration file
 *      NOTE: Must be maintained with the Writer function
 *
 *  Parameters:
 *      fcon        File number of the config file
 *
 *  Returns:
 *      FALSE if an error is encountered
 *
 *========================================================================*/

bool QmConfig::read_config( QFile &configFile  )
{
    int         len;                            /* Length of data read */
    int         fsize;                          /* Length of desired data */

    /*
     * Event name
     */
//qDebug( "Reading: Event Name" );
    fsize = sizeof( event_name );
    len = configFile.read( event_name, fsize );
    if( len != fsize )
        return ( FALSE );

    /*
     * Leg names
     */
//qDebug( "Reading: Leg Names" );
    fsize = sizeof( leg_name );
    len = configFile.read( (char *)leg_name, fsize );
    if( len != fsize )
        return ( FALSE );

    /*
     * Team definitions
     */
//qDebug( "Reading: Team Defs" );
    fsize = sizeof( t_def  );
    len = configFile.read( (char *)t_def, fsize );
    if( len != fsize )
        return ( FALSE );

    /*
     * Number of legs
     */
//qDebug( "Reading: Leg Nums" );
    fsize = sizeof( num_legs  );
    len = configFile.read( (char *)&num_legs, fsize );
    if( len != fsize)
        return ( FALSE );

    /*
     * Number of team splits
     */
//qDebug( "Reading: Team Splits" );
    fsize = sizeof( num_teams  );
    len = configFile.read( (char *)&num_teams, fsize );
    if( len != fsize )
        return ( FALSE );

    min_team = t_def[0].start;
    max_team = t_def[num_teams - 1].end;

    /*
     * Class information
     */
//qDebug( "Reading: Class Data" );
    fsize = sizeof( team_class  );
    len = configFile.read( (char *)team_class, fsize );
    if( len != fsize )
        return ( FALSE );
    fsize = sizeof( num_class  );
    len = configFile.read( (char *)&num_class, fsize);
    if( len != fsize )
        return ( FALSE );

    /*
     * Country list
     */
//qDebug( "Reading: Country Data, Name" );
    fsize = sizeof( country_name  );
    len = configFile.read( (char *)country_name, fsize );
    if( len != fsize )
        return ( FALSE );

//qDebug( "Reading: Country Data, Number" );
    fsize = sizeof( num_countries  );
    len = configFile.read( (char *)&num_countries, fsize );
    if( len != fsize )
        return ( FALSE );

    /*
     * Addendum file
     */
//qDebug( "Reading: Addendum File" );
    fsize = sizeof( addendum );
    len = configFile.read( addendum, fsize );
    if( len != fsize )
        return ( configFile.atEnd() );

    /*
     * Name of the data file
     */

//qDebug( "Reading: Name of data file" );
    fsize = sizeof( datafilename );
    len = configFile.read( datafilename, fsize );
    if( len != fsize )
        return ( configFile.atEnd() );

    /*
     **  Non-equestrian configuration information
     */
//qDebug( "Reading: NonEquest" );
    fsize = sizeof( nonequestrian_class_abr );
    len = configFile.read( nonequestrian_class_abr, fsize );
    if( len != fsize )
        return ( configFile.atEnd() );

//qDebug( "Reading: NonEquest-2" );
    fsize = sizeof( equestrian_leg );
    len = configFile.read( (char *)&equestrian_leg, fsize );
    if( len != fsize )
        return ( FALSE );

    /*
    **  .txt file output control. Lines per page and perf-skipping
    */
//qDebug( "Reading: Output Control" );
    fsize = sizeof( lines_per_page );
    len = configFile.read( (char *)&lines_per_page, fsize );
    if( len != fsize )
        return ( configFile.atEnd() );

//qDebug( "Reading: Output Control-2" );
    fsize = sizeof( perf_skip );
    len = configFile.read( (char *)&perf_skip, fsize );
    if( len != fsize )
        return ( FALSE );

//qDebug( "Reading: Winners Info" );
    fsize = sizeof( class_winners );
    len = configFile.read( (char *)&class_winners, fsize );
    if( len != fsize )
        return ( FALSE );

//qDebug( "Reading: Hall of Fame Info" );
    fsize = sizeof( hall_fame );
    len = configFile.read( (char *)&hall_fame, fsize );
    if( len != fsize )
        return ( FALSE );

//qDebug( "Reading: Hall of Fame Numbers" );
    fsize = sizeof( num_fame );
    len = configFile.read( (char *)&num_fame, fsize );
    if( len != fsize )
        return ( configFile.atEnd() );

//qDebug( "Reading: NE Winners Info" );
    fsize = sizeof( class_ne_winners );
    len = configFile.read( (char *)&class_ne_winners, fsize );
    if( len != fsize )
         return ( configFile.atEnd() );

//qDebug( "Reading: Web Import Url" );
    fsize = sizeof( webUrl );
    len = configFile.read( (char *)&webUrl, fsize );
    if( len != fsize )
        return ( configFile.atEnd() );

//qDebug( "Reading: Awards Text File" );
    fsize = sizeof( awardsfilename );
    len = configFile.read( (char *)&awardsfilename, fsize );
    if( len != fsize )
        return ( configFile.atEnd() );

    return ( TRUE );
}

/*----------------------------------------------------------------------------
** FUNCTION           : getAddendemFile
**
** DESCRIPTION        : Returns the full path the the addemdum file
**                      The function will look for the file in a number of
**                      locations
**
**
** INPUTS             : name    - Name of the addenum file
**                      create  - True. Allow file to be created
**
** RETURNS            : NULL    - No addendum name, or file not found
**                                If create' is true then the preferred
**                                location will be returned.
**
----------------------------------------------------------------------------*/


const QString QmConfig::getAddendemFile(const QString &name, bool create )
{
    if (name.isEmpty())
        return NULL;

    QFile file;
    QString addendumFileName;
    addendumFileName = filepath;
    addendumFileName.append(name);
    QString addendumFileNamePreferred(addendumFileName);
    file.setFileName(addendumFileName);
    //qDebug("Try:%s", qPrintable(addendumFileName));
    if ( !file.exists())
    {
        addendumFileName = QCoreApplication::applicationDirPath ();
        addendumFileName.append("/");
        addendumFileName.append(name);
        file.setFileName(addendumFileName);
        //qDebug("Try:%s", qPrintable(addendumFileName));
        if ( !file.exists())
        {
             addendumFileName = QDir::currentPath ();
             addendumFileName.append("/");
             addendumFileName.append(name);
             file.setFileName(addendumFileName);
             //qDebug("Try:%s", qPrintable(addendumFileName));
             if ( !file.exists())
             {
                 //qDebug("Addeddum File not found");
                 if (create)
                 {
                     addendumFileName = addendumFileNamePreferred;
                 }
                 else
                 {
                     return NULL;
                 }
             }
        }
    }
    return addendumFileName;
}

/*========================================================================
 *
 *  Write out the configuration file
 *
 *  Purpose:
 *      This function is called to write the configuration file
 *      NOTE: Must be maintained with the Reader function
 *
 *  Parameters:
 *      None
 *
 *  Returns:
 *      FALSE   : Error encountered
 *
 *========================================================================*/

bool QmConfig::write_config( void )
{
    if (fileName.isEmpty())
    {
        qDebug("No Config file selected");
        return(false);
    }
    /*
     **  Open as a binary file
     */
    QFile file;
    file.setFileName(fileName);
    if ( ! file.open(QIODevice::WriteOnly | QIODevice::Truncate) )
    {
        qDebug("File error: %s", qPrintable(file.errorString()));
        MainWindow::showMessage("Cannot write config file");
        return (false);
    }

     /*
     **  Write out multiple structures
     **     Event name
     **     Leg names
     **     Team definitions
     **     Number of legs
     **     Number fo team splits
     **     Class information
     **     Number of defined classes
     **     Country list
     **     Number of defined countries
     **     Legend addendum file name
     **     Data file name
     */

    file.write( (const char *) event_name, sizeof( event_name ) );
    file.write( (const char *) leg_name, sizeof( leg_name ) );
    file.write( (const char *) t_def, sizeof( t_def ) );
    file.write( (const char *) &num_legs, sizeof( num_legs ) );
    file.write( (const char *) &num_teams, sizeof( num_teams ) );
    file.write( (const char *) team_class, sizeof( team_class ) );
    file.write( (const char *) &num_class, sizeof( num_class ) );
    file.write( (const char *) country_name, sizeof( country_name ) );
    file.write( (const char *) &num_countries, sizeof( num_countries ) );
    file.write( (const char *) addendum, sizeof( addendum ) );
    file.write( (const char *) datafilename, sizeof( datafilename ) );
    file.write( (const char *) nonequestrian_class_abr, sizeof( nonequestrian_class_abr ) );
    file.write( (const char *) &equestrian_leg, sizeof( equestrian_leg ) );
    file.write( (const char *) &lines_per_page, sizeof( lines_per_page ) );
    file.write( (const char *) &perf_skip, sizeof( perf_skip ) );
    file.write( (const char *) &class_winners, sizeof( class_winners ) );
    file.write( (const char *) &hall_fame, sizeof( hall_fame ) );
    file.write( (const char *) &num_fame, sizeof( num_fame ) );
    file.write( (const char *) &class_ne_winners, sizeof( class_ne_winners ) );
    file.write( (const char *) &webUrl, sizeof( webUrl ) );
    file.write( (const char *) &awardsfilename, sizeof( awardsfilename ) );

    file.close();
    return ( TRUE );
}

/*========================================================================
 *
 *  Qsort callback: Sort by team
 *
 *  Purpose:
 *      Function used by the team definition sort operation
 *      It will compare two entries of the team def structure and return an
 *      integer for gt eq lt conditions.
 *      Note : If the start is 0 the team entry does exist and is placed at the
 *      end of the sorted list.
 *
 *  Parameters:
 *      a           comparision entry
 *      b           comparision entry
 *
 *  Returns:
 *      gt, eq, lt as required
 *
 *========================================================================*/

int f_comp_int( const void *aa, const void *bb )
{
    const ty_t_def *a = (ty_t_def *)aa;
    const ty_t_def *b = (ty_t_def *)bb;

    if( a->start == 0 )
        return ( 1 );
    else if( b->start == 0 )
        return ( -1 );
    else
        return ( a->start - b->start );
}

/*========================================================================
 *
 *  Compact a string
 *
 *  Purpose:
 *      This function is called remove leading and trailing spaces from
 *      a string. Treats other non-printing characters as leading
 *      spaces. This solves a problem when importing data from a
 *      Microsoft CSV file with empty fields.
 *
 *  Parameters:
 *      str     Address of the string to compact
 *
 *  Returns:
 *      Nothing
 *
 *========================================================================*/

void compact( char *str )
{
    char       *ptr;

    ptr = str;
    while( *str && ( isspace( *str ) || !isprint( *str ) ) )
        str++;
    strcpy( ptr, str );
}

/*========================================================================
 *
 *  Validate a team number
 *
 *  Purpose:
 *      This function is called to validate a team number
 *
 *  Parameters:
 *      x       Number to validate
 *
 *  Returns:
 *      TRUE    : Valid
 *      FALSE   : Not valid
 *
 *========================================================================*/

bool valid_field( int x )
{
    int         i;

    for( i = 0; i < config.num_teams; i++ )
    {
        if( x <= config.t_def[i].end && x >= config.t_def[i].start )
            return ( TRUE );
        if( x < config.t_def[i].start )
            break;                               /* Because the list is sorted */
    }
    return ( FALSE );
}

/*========================================================================
 *
 *  Get a class descriptor from existing text
 *
 *  Purpose:
 *      This function is called to Get a class descriptor
 *
 *  Parameters:
 *      text    - User text to examine
 *      config  - configuration dtaa to use
 *
 *  Returns:
 *      An integer which is the index into the  config.team_class array
 *      The integer is in the range 1 .. num_class
 *      A value fo zero indicates the text was not found.
 *
 *========================================================================*/

int QmConfig::lookup_class( const char *text )
{
    int         i;

//    if( config_ptr == NULL )
//        config_ptr = &config;

    /*
     * Attempt to locate the entered class in the list of defined classes
     */

    for( i = 0; i < num_class; i++ )
    {
        if( toupper(text[0]) == toupper(team_class[i].abr[0]) &&
            toupper(text[1]) == toupper(team_class[i].abr[1]) )
            return ( ++i );
    }
    return ( 0 );
}

#ifdef DISPLAY_STRUCTURES
/*============================================================================
**
**  Display structure information
**
**  Purpose:    Display internal structure information
**
**  Parameters: Nothing
**
**  Returns:    Nothing directly
**
**===========================================================================*/

/*
**  esize - A macro to return the size of a structure element
**  element - print element information
*/
#define esize( st, el) ( sizeof(((st *)0)->el))
#define element( st, el) \
    printf( "Offset of %-15s :%4d, Size:%d", #el, offsetof( st, el), esize(st, el) );
#define element2( st, el) \
    printf( "Size of %-15s :%4d", #el, esize(st, el) );

void display_structures(void)
{
    printf( "Structure: leg_type" );
    element( leg_type, start    );
    element( leg_type, end      );
    element( leg_type, elapsed  );
    element( leg_type, l_place  );
    element( leg_type, le_place );
    element( leg_type, lc_place );
    element( leg_type, lec_place);
    element( leg_type, manual   );
    printf( "Sizeof %-18s :%4d", "leg_type", sizeof(leg_type) );


    printf( "" );
    printf( "Structure: team_type" );
    element( team_type, numb   );
    element( team_type, name   );
    element( team_type, leg    );
    element( team_type, members);
    element( team_type, teamclass  );
    element( team_type, country);
    element( team_type, flags  );
    printf( "Sizeof %-18s :%4d", "team_type", sizeof(team_type) );

#if 1
    printf( "" );
    printf( "Structure: MARA_CFG" );
    element2( QmConfig, event_name      );
    element2( QmConfig, leg_name        );
    element2( QmConfig, t_def           );
    element2( QmConfig, num_legs        );
    element2( QmConfig, num_teams       );
    element2( QmConfig, max_team        );
    element2( QmConfig, min_team        );
    element2( QmConfig, team_class      );
    element2( QmConfig, num_class       );
    element2( QmConfig, country_name    );
    element2( QmConfig, num_countries   );
    element2( QmConfig, addendum        );
    element2( QmConfig, datafilename    );
    printf( "Sizeof %-18s :%4d", "QmConfig", sizeof(QmConfig) );
#endif
}
#endif