/**************************************************/
/* projet_config : routines de trace du cartouche */
/**************************************************/

#include "fctsys.h"
#include "gr_basic.h"

#include "common.h"

#define CONFIG_VERSION 1

#define FORCE_LOCAL_CONFIG TRUE


/*********************************************************************/
static bool ReCreatePrjConfig( const wxString& local_config_filename,
                               const wxString& GroupName,
                               bool            ForceUseLocalConfig )
/*********************************************************************/

/* Cree ou recree la configuration locale de kicad (filename.pro)
 * initialise:
 *     g_Prj_Config
 *     g_Prj_Config_LocalFilename
 *     g_Prj_Default_Config_FullFilename
 * return:
 *     TRUE si config locale
 *     FALSE si default config
 */
{
    // free old config
    if( g_Prj_Config )
        delete g_Prj_Config;
    g_Prj_Config = NULL;

    // Init local Config filename
    if( local_config_filename.IsEmpty() )
        g_Prj_Config_LocalFilename = wxT( "kicad" );
    else
        g_Prj_Config_LocalFilename = local_config_filename;

    ChangeFileNameExt( g_Prj_Config_LocalFilename, g_Prj_Config_Filename_ext );

    // Init local config filename
    if( ForceUseLocalConfig || wxFileExists( g_Prj_Config_LocalFilename ) )
    {
        g_Prj_Default_Config_FullFilename.Empty();
        g_Prj_Config = new wxFileConfig( wxEmptyString,
                                         wxEmptyString,
                                         g_Prj_Config_LocalFilename,
                                         wxEmptyString,
                                         wxCONFIG_USE_RELATIVE_PATH );

        g_Prj_Config->DontCreateOnDemand();

        if( ForceUseLocalConfig )
            return TRUE;

        // Test de la bonne version du fichier (ou groupe) de configuration
        int version = -1, def_version = 0;
        g_Prj_Config->SetPath( GroupName );
        version = g_Prj_Config->Read( wxT( "version" ), def_version );
        g_Prj_Config->SetPath( UNIX_STRING_DIR_SEP );
        if( version > 0 )
            return TRUE;
        else
            delete g_Prj_Config;    // Version incorrecte
    }


    // Fichier local non trouve ou invalide
    g_Prj_Config_LocalFilename.Empty();
    g_Prj_Default_Config_FullFilename =
        ReturnKicadDatasPath() +
        wxT( "template/kicad" ) +
        g_Prj_Config_Filename_ext;

    // Recreate new config
    g_Prj_Config = new wxFileConfig( wxEmptyString,
                                     wxEmptyString,
                                     wxEmptyString,
                                     g_Prj_Default_Config_FullFilename,
                                     wxCONFIG_USE_RELATIVE_PATH );

    g_Prj_Config->DontCreateOnDemand();

    return FALSE;
}


/***************************************************************************************/
void WinEDA_App::WriteProjectConfig( const wxString&  local_config_filename,
                                     const wxString&  GroupName,
                                     PARAM_CFG_BASE** List )
/***************************************************************************************/
/* enregistrement de la config "projet"*/
{
    const PARAM_CFG_BASE* pt_cfg;
    wxString msg;

    ReCreatePrjConfig( local_config_filename, GroupName,
                       FORCE_LOCAL_CONFIG );

    /* Write date ( surtout pour eviter bug de wxFileConfig
     * qui se trompe de rubrique si declaration [xx] en premiere ligne
     * (en fait si groupe vide) */
    g_Prj_Config->SetPath( UNIX_STRING_DIR_SEP );
    msg = DateAndTime();

    g_Prj_Config->Write( wxT( "update" ), msg );
    msg = GetAppName();

    g_Prj_Config->Write( wxT( "last_client" ), msg );

    /* ecriture de la configuration */
    g_Prj_Config->DeleteGroup( GroupName );   // Erase all datas
    g_Prj_Config->Flush();

    g_Prj_Config->SetPath( GroupName );
    g_Prj_Config->Write( wxT( "version" ), CONFIG_VERSION );
    g_Prj_Config->SetPath( UNIX_STRING_DIR_SEP );

    for( ; *List != NULL; List++ )
    {
        pt_cfg = *List;
        if( pt_cfg->m_Group )
            g_Prj_Config->SetPath( pt_cfg->m_Group );
        else
            g_Prj_Config->SetPath( GroupName );

        switch( pt_cfg->m_Type )
        {
        case PARAM_INT:
            #undef PTCFG
            #define PTCFG ( (PARAM_CFG_INT*) pt_cfg )
            if( PTCFG->m_Pt_param == NULL )
                break;

            if( pt_cfg->m_Setup )
                m_EDA_Config->Write( pt_cfg->m_Ident, *PTCFG->m_Pt_param );
            else
                g_Prj_Config->Write( pt_cfg->m_Ident, *PTCFG->m_Pt_param );
            break;

        case PARAM_SETCOLOR:
            #undef PTCFG
            #define PTCFG ( (PARAM_CFG_SETCOLOR*) pt_cfg )
            if( PTCFG->m_Pt_param == NULL )
                break;

            if( pt_cfg->m_Setup )
                m_EDA_Config->Write( pt_cfg->m_Ident, *PTCFG->m_Pt_param );
            else
                g_Prj_Config->Write( pt_cfg->m_Ident, *PTCFG->m_Pt_param );
            break;

        case PARAM_DOUBLE:
            #undef PTCFG
            #define PTCFG ( (PARAM_CFG_DOUBLE*) pt_cfg )
            if( PTCFG->m_Pt_param == NULL )
                break;

            if( pt_cfg->m_Setup )
                m_EDA_Config->Write( pt_cfg->m_Ident, *PTCFG->m_Pt_param );
            else
                g_Prj_Config->Write( pt_cfg->m_Ident, *PTCFG->m_Pt_param );
            break;

        case PARAM_BOOL:
            #undef PTCFG
            #define PTCFG ( (PARAM_CFG_BOOL*) pt_cfg )
            if( PTCFG->m_Pt_param == NULL )
                break;

            if( pt_cfg->m_Setup )
                m_EDA_Config->Write( pt_cfg->m_Ident, (int) *PTCFG->m_Pt_param );
            else
                g_Prj_Config->Write( pt_cfg->m_Ident, (int) *PTCFG->m_Pt_param );
            break;

        case PARAM_WXSTRING:
            #undef PTCFG
            #define PTCFG ( (PARAM_CFG_WXSTRING*) pt_cfg )
            if( PTCFG->m_Pt_param == NULL )
                break;

            if( pt_cfg->m_Setup )
                m_EDA_Config->Write( pt_cfg->m_Ident, *PTCFG->m_Pt_param );
            else
                g_Prj_Config->Write( pt_cfg->m_Ident, *PTCFG->m_Pt_param );
            break;

        case PARAM_LIBNAME_LIST:
        {
            #undef PTCFG
            #define PTCFG ( (PARAM_CFG_LIBNAME_LIST*) pt_cfg )
            if( PTCFG->m_Pt_param == NULL )
                break;

            wxArrayString* libname_list = PTCFG->m_Pt_param;
            if( libname_list == NULL )
                break;

            unsigned indexlib = 0;
            wxString cle_config;
            for( ; indexlib < libname_list->GetCount(); indexlib++ )
            {
                cle_config = pt_cfg->m_Ident;

                // We use indexlib+1 because first lib name is LibName1
                cle_config << (indexlib + 1);
                g_Prj_Config->Write( cle_config,
                                     libname_list->Item( indexlib ) );
            }

            break;
        }

        case PARAM_COMMAND_ERASE:       // Erase all datas
            if( pt_cfg->m_Ident )
            {
                m_EDA_Config->DeleteGroup( pt_cfg->m_Ident );
                g_Prj_Config->DeleteGroup( pt_cfg->m_Ident );
            }
            break;
        }
    }

    g_Prj_Config->SetPath( UNIX_STRING_DIR_SEP );
    delete g_Prj_Config;
    g_Prj_Config = NULL;
}


/***************************************************************************************/
bool WinEDA_App::ReadProjectConfig( const wxString&  local_config_filename,
                                    const wxString&  GroupName,
                                    PARAM_CFG_BASE** List,
                                    bool             Load_Only_if_New )
/***************************************************************************************/

/* Lecture de la config "projet"
 *** si Load_Only_if_New == TRUE, elle n'est lue que si elle
 *** est differente de la config actuelle (dates differentes)
 *
 * return:
 *     TRUE si lue.
 * Met a jour en plus:
 *     wxGetApp().m_CurrentOptionFileDateAndTime
 *     wxGetApp().m_CurrentOptionFile
 */
{
    const PARAM_CFG_BASE* pt_cfg;
    wxString timestamp;

    if( List == NULL )
        return FALSE;

    ReCreatePrjConfig( local_config_filename, GroupName, FALSE );

    g_Prj_Config->SetPath( UNIX_STRING_DIR_SEP );
    timestamp = g_Prj_Config->Read( wxT( "update" ) );
    if( Load_Only_if_New && ( !timestamp.IsEmpty() )
       && (timestamp == wxGetApp().m_CurrentOptionFileDateAndTime) )
    {
        return FALSE;
    }

    wxGetApp().m_CurrentOptionFileDateAndTime = timestamp;

    if( !g_Prj_Default_Config_FullFilename.IsEmpty() )
        wxGetApp().m_CurrentOptionFile = g_Prj_Default_Config_FullFilename;
    else
    {
        if( wxPathOnly( g_Prj_Config_LocalFilename ).IsEmpty() )
            wxGetApp().m_CurrentOptionFile =
                wxGetCwd() + STRING_DIR_SEP + g_Prj_Config_LocalFilename;
        else
            wxGetApp().m_CurrentOptionFile = g_Prj_Config_LocalFilename;
    }

    for( ; *List != NULL; List++ )
    {
        pt_cfg = *List;
        if( pt_cfg->m_Group )
            g_Prj_Config->SetPath( pt_cfg->m_Group );
        else
            g_Prj_Config->SetPath( GroupName );

        switch( pt_cfg->m_Type )
        {
        case PARAM_INT:
        {
            #undef PTCFG
            #define PTCFG ( (PARAM_CFG_INT*) pt_cfg )
            int itmp;
            if( pt_cfg->m_Setup )
                itmp = m_EDA_Config->Read( pt_cfg->m_Ident, PTCFG->m_Default );
            else
                itmp = g_Prj_Config->Read( pt_cfg->m_Ident, PTCFG->m_Default );

            if( (itmp < PTCFG->m_Min) || (itmp > PTCFG->m_Max) )
                itmp = PTCFG->m_Default;

            *PTCFG->m_Pt_param = itmp;
            break;
        }

        case PARAM_SETCOLOR:
        {
            #undef PTCFG
            #define PTCFG ( (PARAM_CFG_SETCOLOR*) pt_cfg )
            int itmp;
            if( pt_cfg->m_Setup )
                itmp = m_EDA_Config->Read( pt_cfg->m_Ident, PTCFG->m_Default );
            else
                itmp = g_Prj_Config->Read( pt_cfg->m_Ident, PTCFG->m_Default );

            if( (itmp < 0) || (itmp > MAX_COLOR) )
                itmp = PTCFG->m_Default;

            *PTCFG->m_Pt_param = itmp;
            break;
        }

        case PARAM_DOUBLE:
        {
            #undef PTCFG
            #define PTCFG ( (PARAM_CFG_DOUBLE*) pt_cfg )
            double ftmp = 0;
            wxString msg;
            if( pt_cfg->m_Setup )
                msg = m_EDA_Config->Read( pt_cfg->m_Ident, wxT( "" ) );
            else
                msg = g_Prj_Config->Read( pt_cfg->m_Ident, wxT( "" ) );

            if( msg.IsEmpty() )
                ftmp = PTCFG->m_Default;
            else
            {
                msg.ToDouble( &ftmp );
                if( (ftmp < PTCFG->m_Min) || (ftmp > PTCFG->m_Max) )
                    ftmp = PTCFG->m_Default;
            }
            *PTCFG->m_Pt_param = ftmp;
            break;
        }

        case PARAM_BOOL:
        {
            #undef PTCFG
            #define PTCFG ( (PARAM_CFG_BOOL*) pt_cfg )
            int itmp;
            if( pt_cfg->m_Setup )
                itmp = m_EDA_Config->Read( pt_cfg->m_Ident, PTCFG->m_Default );
            else
                itmp = g_Prj_Config->Read( pt_cfg->m_Ident, PTCFG->m_Default );

            *PTCFG->m_Pt_param = itmp ? TRUE : FALSE;
            break;
        }

        case PARAM_WXSTRING:
        {
            #undef PTCFG
            #define PTCFG ( (PARAM_CFG_WXSTRING*) pt_cfg )
            if( PTCFG->m_Pt_param == NULL )
                break;

            if( pt_cfg->m_Setup )
                *PTCFG->m_Pt_param = m_EDA_Config->Read( pt_cfg->m_Ident );
            else
                *PTCFG->m_Pt_param = g_Prj_Config->Read( pt_cfg->m_Ident );
            break;
        }

        case PARAM_LIBNAME_LIST:
        {
            #undef PTCFG
            #define PTCFG ( (PARAM_CFG_LIBNAME_LIST*) pt_cfg )
            int indexlib = 1;       // We start indexlib to 1 because first lib name is LibName1
            wxString libname, id_lib;
            wxArrayString* libname_list = PTCFG->m_Pt_param;
            while( 1 )
            {
                id_lib  = pt_cfg->m_Ident; id_lib << indexlib; indexlib++;
                libname = g_Prj_Config->Read( id_lib, wxT( "" ) );
                if( libname.IsEmpty() )
                    break;
                libname_list->Add( libname );
            }

            break;
        }

        case PARAM_COMMAND_ERASE:
            break;
        }
    }

    delete g_Prj_Config;
    g_Prj_Config = NULL;

    return TRUE;
}


/**************************************************************/
/* Constructeurs des descripteurs de structs de configuration */
/**************************************************************/

PARAM_CFG_BASE::PARAM_CFG_BASE( const wxChar* ident, const paramcfg_id type,
                                const wxChar* group )
{
    m_Ident = ident;
    m_Type  = type;
    m_Group = group;
    m_Setup = FALSE;
}


PARAM_CFG_INT::PARAM_CFG_INT( const wxChar* ident, int* ptparam,
                              int default_val, int min, int max,
                              const wxChar* group ) :
    PARAM_CFG_BASE( ident, PARAM_INT, group )
{
    m_Pt_param = ptparam;
    m_Default  = default_val;
    m_Min = min;
    m_Max = max;
}


PARAM_CFG_INT::PARAM_CFG_INT( bool Insetup, const wxChar* ident, int* ptparam,
                              int default_val, int min, int max,
                              const wxChar* group ) :
    PARAM_CFG_BASE( ident, PARAM_INT, group )
{
    m_Pt_param = ptparam;
    m_Default  = default_val;
    m_Min   = min;
    m_Max   = max;
    m_Setup = Insetup;
}


PARAM_CFG_SETCOLOR::PARAM_CFG_SETCOLOR( const wxChar* ident, int* ptparam,
                                        int default_val,
                                        const wxChar* group ) :
    PARAM_CFG_BASE( ident, PARAM_SETCOLOR, group )
{
    m_Pt_param = ptparam;
    m_Default  = default_val;
}


PARAM_CFG_SETCOLOR::PARAM_CFG_SETCOLOR( bool          Insetup,
                                        const wxChar* ident,
                                        int*          ptparam,
                                        int           default_val,
                                        const wxChar* group ) :
    PARAM_CFG_BASE( ident, PARAM_SETCOLOR, group )
{
    m_Pt_param = ptparam;
    m_Default  = default_val;
    m_Setup    = Insetup;
}


PARAM_CFG_DOUBLE::PARAM_CFG_DOUBLE( const wxChar* ident, double* ptparam,
                                    double default_val, double min, double max,
                                    const wxChar* group ) :
    PARAM_CFG_BASE( ident, PARAM_DOUBLE, group )
{
    m_Pt_param = ptparam;
    m_Default  = default_val;
    m_Min = min;
    m_Max = max;
}


PARAM_CFG_DOUBLE::PARAM_CFG_DOUBLE( bool          Insetup,
                                    const wxChar* ident,
                                    double*       ptparam,
                                    double        default_val,
                                    double        min,
                                    double        max,
                                    const wxChar* group ) :
    PARAM_CFG_BASE( ident, PARAM_DOUBLE, group )
{
    m_Pt_param = ptparam;
    m_Default  = default_val;
    m_Min   = min;
    m_Max   = max;
    m_Setup = Insetup;
}


PARAM_CFG_BOOL::PARAM_CFG_BOOL( const wxChar* ident, bool* ptparam,
                                int default_val, const wxChar* group ) :
    PARAM_CFG_BASE( ident, PARAM_BOOL, group )
{
    m_Pt_param = ptparam;
    m_Default  = default_val ? TRUE : FALSE;
}


PARAM_CFG_BOOL::PARAM_CFG_BOOL( bool          Insetup,
                                const wxChar* ident,
                                bool*         ptparam,
                                int           default_val,
                                const wxChar* group ) :
    PARAM_CFG_BASE( ident, PARAM_BOOL, group )
{
    m_Pt_param = ptparam;
    m_Default  = default_val ? TRUE : FALSE;
    m_Setup    = Insetup;
}


PARAM_CFG_WXSTRING::PARAM_CFG_WXSTRING( const wxChar* ident,
                                        wxString*     ptparam,
                                        const wxChar* group ) :
    PARAM_CFG_BASE( ident, PARAM_WXSTRING, group )
{
    m_Pt_param = ptparam;
}


PARAM_CFG_WXSTRING::PARAM_CFG_WXSTRING( bool Insetup, const wxChar* ident,
                                        wxString* ptparam,
                                        const wxChar* group ) :
    PARAM_CFG_BASE( ident, PARAM_WXSTRING, group )
{
    m_Pt_param = ptparam;
    m_Setup    = Insetup;
}


PARAM_CFG_LIBNAME_LIST::PARAM_CFG_LIBNAME_LIST( const wxChar*  ident,
                                                wxArrayString* ptparam,
                                                const wxChar*  group ) :
    PARAM_CFG_BASE( ident, PARAM_LIBNAME_LIST, group )
{
    m_Pt_param = ptparam;
}