/***************************************************************************
 *
 * Project:  OpenCPN
 *
 ***************************************************************************
 *   Copyright (C) 2018 by David S. Register                               *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,  USA.         *
 **************************************************************************/

#ifdef __MINGW32__
#undef IPV6STRICT    // mingw FTBS fix:  missing struct ip_mreq
#include <windows.h>
#endif

#include <wx/tokenzr.h>

#include "config.h"
#include "ConfigMgr.h"

#include <wx/filename.h>
#include <wx/fileconf.h>
#include <wx/statline.h>


#include "dychart.h"

#include <stdlib.h>
//#include <math.h>
#include <time.h>
#include <locale>
#include <list>

#include <wx/listimpl.cpp>
#include <wx/progdlg.h>

#include "chart1.h"
#include "navutil.h"
#include "chcanv.h"
#include "georef.h"
#include "cutil.h"
#include "styles.h"
#include "routeman.h"
#include "s52utils.h"
#include "chartbase.h"
#include "ocpndc.h"
#include "geodesic.h"
#include "datastream.h"
#include "multiplexer.h"
#include "ais.h"
#include "Route.h"
#include "Select.h"
#include "FontMgr.h"
#include "Layer.h"
#include "NavObjectCollection.h"
#include "NMEALogWindow.h"
#include "AIS_Decoder.h"
#include "OCPNPlatform.h"
#include "Track.h"
#include "chartdb.h"
#include "CanvasConfig.h"

#include "s52plib.h"
#include "cm93.h"

#ifdef ocpnUSE_GL
#include "glChartCanvas.h"
#endif

// Global statics
//    Statics

extern OCPNPlatform     *g_Platform;
extern MyFrame          *gFrame;

extern int              g_restore_stackindex;
extern int              g_restore_dbindex;
extern LayerList        *pLayerList;
extern MyConfig         *pConfig;
extern double           initial_scale_ppm, initial_rotation;
extern int              g_nbrightness;
extern bool             g_bShowTrue, g_bShowMag;
extern double           g_UserVar;
extern bool             g_bShowStatusBar;
extern bool             g_bUIexpert;
extern bool             g_bFullscreen;
extern int              g_nDepthUnitDisplay;



extern wxString         g_SENCPrefix;
extern wxString         g_UserPresLibData;

extern wxString         *pInit_Chart_Dir;
extern wxString         gWorldMapLocation;

extern bool             s_bSetSystemTime;
extern bool             g_bDisplayGrid;         //Flag indicating if grid is to be displayed
extern bool             g_bPlayShipsBells;
extern int              g_iSoundDeviceIndex;
extern bool             g_bFullscreenToolbar;
extern bool             g_bShowLayers;
extern bool             g_bTransparentToolbar;
extern bool             g_bPermanentMOBIcon;

extern bool             g_bShowDepthUnits;
extern bool             g_bAutoAnchorMark;
extern bool             g_bskew_comp;
extern bool             g_bopengl;
extern bool             g_bSoftwareGL;
extern bool             g_bShowFPS;
extern bool             g_bsmoothpanzoom;

extern bool             g_bShowOutlines;
extern bool             g_bShowActiveRouteHighway;
extern bool             g_bShowRouteTotal;
extern int              g_nNMEADebug;
extern int              g_nAWDefault;
extern int              g_nAWMax;
extern int              g_nTrackPrecision;

extern int              g_iSDMMFormat;
extern int              g_iDistanceFormat;
extern int              g_iSpeedFormat;

extern int              g_nframewin_x;
extern int              g_nframewin_y;
extern int              g_nframewin_posx;
extern int              g_nframewin_posy;
extern bool             g_bframemax;
extern int              g_route_prop_x, g_route_prop_y;
extern int              g_route_prop_sx, g_route_prop_sy;

extern double           g_PlanSpeed;
extern wxString         g_VisibleLayers;
extern wxString         g_InvisibleLayers;


// LIVE ETA OPTION
extern bool             g_bShowLiveETA;
extern double           g_defaultBoatSpeed;

//    AIS Global configuration
extern bool             g_bCPAMax;
extern double           g_CPAMax_NM;
extern bool             g_bCPAWarn;
extern double           g_CPAWarn_NM;
extern bool             g_bTCPA_Max;
extern double           g_TCPA_Max;
extern bool             g_bMarkLost;
extern double           g_MarkLost_Mins;
extern bool             g_bRemoveLost;
extern double           g_RemoveLost_Mins;
extern bool             g_bShowCOG;
extern double           g_ShowCOG_Mins;
extern bool             g_bAISShowTracks;
extern bool             g_bTrackCarryOver;
extern bool             g_bTrackDaily;
extern int              g_track_rotate_time;
extern int              g_track_rotate_time_type;
extern double           g_AISShowTracks_Mins;
extern double           g_AISShowTracks_Limit;
extern bool             g_bHideMoored;
extern double           g_ShowMoored_Kts;
extern bool             g_bAllowShowScaled;
extern bool             g_bShowScaled;
extern int              g_ShowScaled_Num;
extern bool             g_bAIS_CPA_Alert;
extern bool             g_bAIS_CPA_Alert_Audio;
extern int              g_ais_alert_dialog_x, g_ais_alert_dialog_y;
extern int              g_ais_alert_dialog_sx, g_ais_alert_dialog_sy;
extern int              g_ais_query_dialog_x, g_ais_query_dialog_y;
extern wxString         g_sAIS_Alert_Sound_File;
extern bool             g_bAIS_CPA_Alert_Suppress_Moored;
extern bool             g_bAIS_ACK_Timeout;
extern double           g_AckTimeout_Mins;
extern wxString         g_AisTargetList_perspective;
extern int              g_AisTargetList_range;
extern int              g_AisTargetList_sortColumn;
extern bool             g_bAisTargetList_sortReverse;
extern wxString         g_AisTargetList_column_spec;
extern wxString         g_AisTargetList_column_order;
extern bool             g_bShowAreaNotices;
extern bool             g_bDrawAISSize;
extern bool             g_bDrawAISRealtime;
extern double           g_AIS_RealtPred_Kts;
extern bool             g_bShowAISName;
extern int              g_Show_Target_Name_Scale;
extern bool             g_bWplIsAprsPosition;
extern bool             g_benableAISNameCache;
extern int              g_ScaledNumWeightSOG;
extern int              g_ScaledNumWeightCPA;
extern int              g_ScaledNumWeightTCPA;
extern int              g_ScaledNumWeightRange;
extern int              g_ScaledNumWeightSizeOfT;
extern int              g_ScaledSizeMinimal;

extern int              g_S57_dialog_sx, g_S57_dialog_sy;

extern int              g_iNavAidRadarRingsNumberVisible;
extern float            g_fNavAidRadarRingsStep;
extern int              g_pNavAidRadarRingsStepUnits;
extern int              g_iWaypointRangeRingsNumber;
extern float            g_fWaypointRangeRingsStep;
extern int              g_iWaypointRangeRingsStepUnits;
extern wxColour         g_colourWaypointRangeRingsColour;
extern bool             g_bWayPointPreventDragging;
extern bool             g_bConfirmObjectDelete;
extern wxColour         g_colourOwnshipRangeRingsColour;

extern bool             g_bEnableZoomToCursor;
extern wxString         g_toolbarConfig;
extern double           g_TrackIntervalSeconds;
extern double           g_TrackDeltaDistance;
extern int              gps_watchdog_timeout_ticks;


extern bool             g_bGDAL_Debug;
extern bool             g_bDebugCM93;
extern bool             g_bDebugS57;

extern double           g_ownship_predictor_minutes;
extern double           g_ownship_HDTpredictor_miles;

extern bool             g_own_ship_sog_cog_calc;
extern int              g_own_ship_sog_cog_calc_damp_sec;

extern s52plib          *ps52plib;

extern int              g_cm93_zoom_factor;
extern bool             g_b_legacy_input_filter_behaviour;
extern bool             g_bShowDetailSlider;
extern int              g_detailslider_dialog_x, g_detailslider_dialog_y;


extern int              g_OwnShipIconType;
extern double           g_n_ownship_length_meters;
extern double           g_n_ownship_beam_meters;
extern double           g_n_gps_antenna_offset_y;
extern double           g_n_gps_antenna_offset_x;
extern int              g_n_ownship_min_mm;
extern double           g_n_arrival_circle_radius;

extern bool             g_bPreserveScaleOnX;
extern bool             g_bsimplifiedScalebar;

extern bool             g_bUseGLL;

extern wxString         g_locale;
extern wxString         g_localeOverride;


extern bool             g_bCourseUp;
extern bool             g_bLookAhead;
extern int              g_COGAvgSec;
extern bool             g_bMagneticAPB;
extern bool             g_bShowChartBar;

extern int              g_MemFootMB;

extern int              g_nCOMPortCheck;


extern wxString         g_AW1GUID;
extern wxString         g_AW2GUID;
extern int              g_BSBImgDebug;

extern wxString        g_config_version_string;
extern wxString        g_config_version_string;


extern bool             g_bAISRolloverShowClass;
extern bool             g_bAISRolloverShowCOG;
extern bool             g_bAISRolloverShowCPA;

extern bool             g_bDebugGPSD;

extern bool             g_bfilter_cogsog;
extern int              g_COGFilterSec;

extern int              g_navobjbackups;

extern bool             g_bQuiltEnable;
extern bool             g_bFullScreenQuilt;
extern bool             g_bQuiltStart;

extern int              g_SkewCompUpdatePeriod;

extern int              g_maintoolbar_x;
extern int              g_maintoolbar_y;
extern long             g_maintoolbar_orient;


extern int              g_lastClientRectx;
extern int              g_lastClientRecty;
extern int              g_lastClientRectw;
extern int              g_lastClientRecth;

extern bool             g_bHighliteTracks;
extern int              g_cog_predictor_width;
extern int              g_ais_cog_predictor_width;

extern int              g_route_line_width;
extern int              g_track_line_width;
extern wxColour         g_colourTrackLineColour;
extern wxString         g_default_wp_icon;

extern ChartGroupArray  *g_pGroupArray;

extern bool             g_bDebugOGL;
extern wxString         g_GPS_Ident;
extern bool             g_bGarminHostUpload;
extern wxString         g_uploadConnection;

extern wxArrayString    TideCurrentDataSet;
extern wxString         g_TCData_Dir;

extern bool             g_btouch;
extern bool             g_bresponsive;

extern bool             g_bGLexpert;

extern int              g_SENC_LOD_pixels;
extern ArrayOfMMSIProperties   g_MMSI_Props_Array;

extern int              g_chart_zoom_modifier;
extern int              g_chart_zoom_modifier_vector;

extern int              g_NMEAAPBPrecision;

extern wxString         g_TalkerIdText;
extern int              g_maxWPNameLength;

extern bool             g_bAdvanceRouteWaypointOnArrivalOnly;
extern double           g_display_size_mm;
extern double           g_config_display_size_mm;
extern bool             g_config_display_size_manual;

extern bool             g_benable_rotate;
extern bool             g_bEmailCrashReport;

extern int              g_default_font_size;

extern bool             g_bAutoHideToolbar;
extern int              g_nAutoHideToolbar;
extern int              g_GUIScaleFactor;
extern int              g_ChartScaleFactor;
extern int              g_ShipScaleFactor;

extern bool             g_bInlandEcdis;
extern int              g_iENCToolbarPosX;
extern int              g_iENCToolbarPosY;

extern bool             g_bSpaceDropMark;


extern bool             g_benableUDPNullHeader;
extern bool             g_bShowMenuBar;
extern bool             g_bShowCompassWin;

extern wxString         g_uiStyle;
extern bool             g_useMUI;
extern wxString         g_gpx_path;


extern bool             g_bDarkDecorations;
extern unsigned int     g_canvasConfig;

#ifdef ocpnUSE_GL
extern ocpnGLOptions g_GLOptions;
#endif

#if !defined(NAN)
static const long long lNaN = 0xfff8000000000000;
#define NAN (*(double*)&lNaN)
#endif



ConfigMgr * ConfigMgr::instance = NULL;

//--------------------------------------------------------------------------
//
//      Utility functions
//
//--------------------------------------------------------------------------
int GetRandomNumber(int range_min, int range_max)
{
    long u = (long)wxRound(((double)rand() / ((double)(RAND_MAX) + 1) * (range_max - range_min)) + range_min);
    return (int)u;
}

//Helper conditional file name dir slash
void appendOSDirSlash(wxString* pString);


class OCPNConfigObject
{
public:
    OCPNConfigObject();
    ~OCPNConfigObject();

    OCPNConfigObject( int canvas_config );
    
    void Init();
    wxPanel *GetSettingsPanel();
    
    int m_canvasConfig;
    wxString m_GUID;
    wxString templateFileName;
    wxString m_title;
    wxString m_description;
    
    
};

OCPNConfigObject::OCPNConfigObject()
{
    Init();
}

OCPNConfigObject::OCPNConfigObject( int canvas_config )
{
    Init();
    m_canvasConfig = canvas_config;
}

OCPNConfigObject::~OCPNConfigObject()
{
}

void OCPNConfigObject::Init()
{
    m_canvasConfig = 0;
}

#include <wx/listimpl.cpp>
WX_DEFINE_LIST(ConfigObjectList);

//--------------------------------------------------------------------
//   Private ( XML encoded ) catalog of available configurations
//--------------------------------------------------------------------

class OCPNConfigCatalog : public pugi::xml_document
{
public:
    OCPNConfigCatalog();
    ~OCPNConfigCatalog();
    
    bool AddConfig( OCPNConfigObject *config, unsigned int flags );
    bool RemoveConfig( wxString GUID);
    
    
    void SetRootConfigNode(void);
    bool IsOpenCPN();
    bool SaveFile( const wxString filename );
    bool LoadFile( const wxString filename );
    
    pugi::xml_node      m_config_root;
};

OCPNConfigCatalog::OCPNConfigCatalog()
: pugi::xml_document()
{
}

OCPNConfigCatalog::~OCPNConfigCatalog()
{
}

void OCPNConfigCatalog::SetRootConfigNode(void)
{
    if(!strlen(m_config_root.name())) {
        m_config_root = append_child("configs");
        m_config_root.append_attribute ( "version" ) = "1.0";
        m_config_root.append_attribute ( "creator" ) = "OpenCPN";
        m_config_root.append_attribute( "xmlns:xsi" ) = "http://www.w3.org/2001/XMLSchema-instance";
        m_config_root.append_attribute( "xmlns" ) = "http://www.topografix.com/GPX/1/1";
        m_config_root.append_attribute( "xmlns:gpxx" ) =  "http://www.garmin.com/xmlschemas/GpxExtensions/v3";
        m_config_root.append_attribute( "xsi:schemaLocation" ) = "http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd";
        m_config_root.append_attribute( "xmlns:opencpn" ) = "http://www.opencpn.org";
    }
}

bool OCPNConfigCatalog::IsOpenCPN()
{
    for (pugi::xml_attribute attr = root().first_child().first_attribute(); attr; attr = attr.next_attribute())
        if( !strcmp(attr.name(), "creator") && !strcmp(attr.value(), "OpenCPN") )
            return true;
    return false;
}

bool OCPNConfigCatalog::SaveFile( const wxString filename )
{
    save_file(filename.fn_str(), "  ");
    return true;
}

bool OCPNConfigCatalog::LoadFile( const wxString filename )
{
    load_file( filename.fn_str() );
    m_config_root =  this->child("configs");
    return true;
}

bool OCPNConfigCatalog::AddConfig( OCPNConfigObject *config, unsigned int flags )
{
    pugi::xml_node node = m_config_root.append_child("config");
    
    node.append_attribute("GUID") = config->m_GUID.mb_str();

    //  Handle non-ASCII characters as UTF8
    wxCharBuffer abuf = config->m_title.ToUTF8();
    if( abuf.data() )                            
        node.append_attribute("title") = abuf.data();
    else 
        node.append_attribute("title") = _T("Substitute Title");

    abuf = config->m_description.ToUTF8();
    if( abuf.data() )                            
        node.append_attribute("description") = abuf.data();
    else 
        node.append_attribute("description") = _T("Substitute Description");
    
    node.append_attribute("templateFile") = config->templateFileName.mb_str();

    
    return true;
}
    
bool OCPNConfigCatalog::RemoveConfig( wxString GUID)
{
    for (pugi::xml_node child = m_config_root.first_child(); child; )
    {
        pugi::xml_node next = child.next_sibling();
        const char* guid = child.attribute("GUID").value();
        
        if(!strcmp(guid, GUID.mb_str())){
            child.parent().remove_child(child);
            return true;
        }
        
        child = next;
    }
    
    return false;
}

    


//--------------------------------------------------------------------
//   ConfigPanel implementation
//--------------------------------------------------------------------
    
ConfigPanel::ConfigPanel(OCPNConfigObject *config, wxWindow *parent, wxWindowID id, const wxPoint &pos, const wxSize &size)
:wxPanel(parent, id, pos, size, wxSIMPLE_BORDER)

{
    m_config = config;
    wxBoxSizer* mainSizer = new wxBoxSizer(wxVERTICAL);
    SetSizer(mainSizer);
    
    mainSizer->Add(new wxStaticText(this, wxID_ANY, _("Title")));
    mainSizer->Add(new wxStaticText(this, wxID_ANY, config->m_title));
    
    mainSizer->Add(new wxStaticLine(this, wxID_ANY), 0, wxEXPAND | wxALL, 1);
    
    mainSizer->Add(new wxStaticText(this, wxID_ANY, _("Description")));
    mainSizer->Add(new wxStaticText(this, wxID_ANY, config->m_description));
    
    SetMinSize(wxSize(-1, 6 * GetCharHeight()) );
    
    wxColour colour;
    GetGlobalColor(_T("COMP1"), &colour);
    SetBackgroundColour(colour);
    //Connect(wxEVT_LEFT_DOWN, wxMouseEventHandler(ConfigPanel::OnConfigPanelMouseSelected), NULL, this);
    
}

ConfigPanel::~ConfigPanel()
{
}

void ConfigPanel::OnConfigPanelMouseSelected( wxMouseEvent &event)
{
//     SetBackgroundColour(*wxRED);
//     event.Skip();
}

wxString ConfigPanel::GetConfigGUID()
{
    return m_config->m_GUID;
}


//--------------------------------------------------------------------
//   ConfigMgr implementation
//   Singleton Pattern
//--------------------------------------------------------------------
    

ConfigMgr & ConfigMgr::Get()
{
    if (!instance)
        instance = new ConfigMgr;
    return *instance;
}

void ConfigMgr::Shutdown()
{
    if (instance)
    {
        delete instance;
        instance = NULL;
    }
}

ConfigMgr::ConfigMgr()
{
    Init();
    
    // Load any existing configs from the catalog
    LoadCatalog();
    
}

ConfigMgr::~ConfigMgr()
{
    delete configList;
}

void ConfigMgr::Init()
{
    m_configDir = g_Platform->GetPrivateDataDir();
    appendOSDirSlash(&m_configDir);
    m_configDir.append(_T("Configs"));
    appendOSDirSlash(&m_configDir);
    if(!wxFileName::DirExists( m_configDir )){
        wxFileName::Mkdir( m_configDir );
    }
    
    m_configCatalogName = g_Platform->GetPrivateDataDir();
    appendOSDirSlash(&m_configCatalogName);
    m_configCatalogName.append(_T("Configs"));
    appendOSDirSlash(&m_configCatalogName);
    m_configCatalogName.append(_T("configs.xml"));

    //Create the catalog, if necessary
    if(!wxFileExists(m_configCatalogName)){
        
        wxLogMessage( _T("Creating new Configs catalog: ") + m_configCatalogName );
        
        OCPNConfigCatalog *cat = new OCPNConfigCatalog();
        cat->SetRootConfigNode();
        cat->SaveFile( m_configCatalogName);
        delete cat;
    }
    
    m_configCatalog = new OCPNConfigCatalog();
    
    configList = new ConfigObjectList;

    //  Add the default "Recovery" template
     wxString t_title = _("Recovery Template");
     wxString t_desc = _("Apply this template to return to a known safe configuration");
     CreateNamedConfig( t_title, t_desc, _T("11111111-1111-1111-1111-111111111111"));
    
}

bool ConfigMgr::LoadCatalog()
{
    wxLogMessage( _T("Loading Configs catalog: ") + m_configCatalogName );
    m_configCatalog->LoadFile( m_configCatalogName );
    
    // Parse the config catalog
    pugi::xml_node objects = m_configCatalog->child("configs");

    //pugi::xml_node node = m_config_root.append_child("config");
    
    //node.append_attribute("GUID") = config->m_GUID.mb_str();
    //node.append_attribute("title") = config->m_title.mb_str();
    //node.append_attribute("description") = config->m_description.mb_str();
    //node.append_attribute("templateFile") = config->templateFileName.mb_str();
    
    for (pugi::xml_node object = objects.first_child(); object; object = object.next_sibling())
    {
        if( !strcmp(object.name(), "config") ) {
            
            //Check the GUID for duplicates
            wxString testGUID = wxString::FromUTF8(object.attribute( "GUID" ).as_string());
            
            bool bFound = false;
            for ( ConfigObjectList::Node *node = configList->GetFirst(); node; node = node->GetNext() )
            {
                OCPNConfigObject *look = node->GetData();
                if(look->m_GUID == testGUID){
                    bFound = true;
                    break;
                }
            }

            if(!bFound){
                OCPNConfigObject *newConfig = new OCPNConfigObject;
            
                newConfig->m_GUID = wxString::FromUTF8(object.attribute( "GUID" ).as_string());
                newConfig->m_title = wxString::FromUTF8(object.attribute( "title" ).as_string());
                newConfig->m_description = wxString::FromUTF8(object.attribute( "description" ).as_string());
                newConfig->templateFileName = wxString::FromUTF8(object.attribute( "templateFile" ).as_string());

                // Add to the class list of configs
                configList->Append(newConfig);
            }
        }
    }
    
    return true;
    
}

bool ConfigMgr::SaveCatalog()
{
    m_configCatalog->SaveFile( m_configCatalogName);
    
    return true;
}

wxString ConfigMgr::CreateNamedConfig( const wxString &title, const wxString &description, wxString UUID )
{
    wxString GUID;
    
    // Must have title
    if( title.IsEmpty())
        return GUID;
    
    OCPNConfigObject *pConfig = new OCPNConfigObject;
    
    //If no UUID is passed, then create a new GUID for this config
    if(UUID.IsEmpty())
        GUID = GetUUID();
    else
        GUID = UUID;
    
    pConfig->m_GUID = GUID;
    pConfig->m_title = title;
    pConfig->m_description = description;
    
    if(UUID.IsEmpty()){
        // create template file name
        pConfig->templateFileName = _T("OCPNTemplate-") + GUID + _T(".conf");
    
        //  Save the template contents
        wxString templateFullFileName = GetConfigDir() + pConfig->templateFileName;
        if(!SaveTemplate( templateFullFileName )){
            wxLogMessage(_T("Unable to save template titled: ") + title + _T(" as file: ") + templateFullFileName);
            delete pConfig;
            return _T("");
        }
    }
    
    // Add this config to the catalog
    if(!m_configCatalog->AddConfig( pConfig, 0 )){
        wxLogMessage(_T("Unable to add config to catalog...Title: ") + title);
        delete pConfig;
        return _T("");
    }
    
    // Add to the class list of configs
    configList->Append(pConfig);
    
    if(UUID.IsEmpty())
        SaveCatalog();
    
    return GUID;
}

bool ConfigMgr::DeleteConfig(wxString GUID)
{
    OCPNConfigObject *cfg = GetConfig( GUID );
    if(!cfg)
        return false;
    
    // Find and delete the template file
    wxString templateFullFileName = GetConfigDir() + cfg->templateFileName;
    if(wxFileExists(templateFullFileName))
        wxRemoveFile(templateFullFileName);
    
    // Remove the config from the catalog
    bool rv = m_configCatalog->RemoveConfig(GUID);
    
    if(rv)
        SaveCatalog();
    
    //  Remove the config from the member list
    bool bDel = configList->DeleteObject(cfg);
    if(bDel)
        delete cfg;
        
    return rv;
}



wxPanel *ConfigMgr::GetConfigPanel( wxWindow *parent, wxString GUID )
{
    wxPanel *retPanel = NULL;
    
    // Find the GUID-matching config in the member list
    OCPNConfigObject *config = GetConfig( GUID );
    
    //  Found it?
    if(config){
        retPanel = new ConfigPanel( config, parent );
    }
        
    return retPanel;
}

OCPNConfigObject *ConfigMgr::GetConfig( wxString GUID )
{
    // Find the GUID-matching config in the member list
    for ( ConfigObjectList::Node *node = configList->GetFirst(); node; node = node->GetNext() )
    {
        OCPNConfigObject *look = node->GetData();
        if(look->m_GUID == GUID){
            return look;
            break;
        }
    }
    
    return NULL;
}

wxString ConfigMgr::GetTemplateTitle( wxString GUID)
{
    for ( ConfigObjectList::Node *node = configList->GetFirst(); node; node = node->GetNext() )
    {
        OCPNConfigObject *look = node->GetData();
        if(look->m_GUID == GUID){
            return look->m_title;
            break;
        }
    }
    
    return wxEmptyString;
}
    

wxArrayString ConfigMgr::GetConfigGUIDArray()
{
    wxArrayString ret_val;
    
    for ( ConfigObjectList::Node *node = configList->GetFirst(); node; node = node->GetNext() )
    {
        OCPNConfigObject *look = node->GetData();
        ret_val.Add(look->m_GUID);
    }
    
    return ret_val;
}

bool ConfigMgr::ApplyConfigGUID( wxString GUID)
{
     
    // Find the GUID-matching config in the member list
    OCPNConfigObject *config = GetConfig( GUID );
    
    //  Found it?
    if(config){
        wxString thisConfig = GetConfigDir() + config->templateFileName;

        // Special case for Recovery template
        if(GUID.StartsWith(_T("11111111"))){
            thisConfig = *GetpSharedDataLocation() + _T("configs/OCPNTemplate-Recovery.conf");
        }

        MyConfig fconf( thisConfig );
        
        //  Load the template contents, without resetting defaults
        fconf.LoadMyConfigRaw( true );
        
        //  Load Canvas configs, applying only the "templateable" items
        fconf.LoadCanvasConfigs( true );
        
        if( ps52plib && ps52plib->m_bOK ) 
            fconf.LoadS57Config();

        return true;
    }
    
    return false;
}


// RFC4122 version 4 compliant random UUIDs generator.
wxString ConfigMgr::GetUUID(void)
{
    wxString str;
    struct {
        int time_low;
        int time_mid;
        int time_hi_and_version;
        int clock_seq_hi_and_rsv;
        int clock_seq_low;
        int node_hi;
        int node_low;
    } uuid;
    
    uuid.time_low = GetRandomNumber(0, 2147483647);//FIXME: the max should be set to something like MAXINT32, but it doesn't compile un gcc...
    uuid.time_mid = GetRandomNumber(0, 65535);
    uuid.time_hi_and_version = GetRandomNumber(0, 65535);
    uuid.clock_seq_hi_and_rsv = GetRandomNumber(0, 255);
    uuid.clock_seq_low = GetRandomNumber(0, 255);
    uuid.node_hi = GetRandomNumber(0, 65535);
    uuid.node_low = GetRandomNumber(0, 2147483647);
    
    /* Set the two most significant bits (bits 6 and 7) of the
     * clock_seq_hi_and_rsv to zero and one, respectively. */
    uuid.clock_seq_hi_and_rsv = (uuid.clock_seq_hi_and_rsv & 0x3F) | 0x80;
    
    /* Set the four most significant bits (bits 12 through 15) of the
     * time_hi_and_version field to 4 */
    uuid.time_hi_and_version = (uuid.time_hi_and_version & 0x0fff) | 0x4000;
    
    str.Printf(_T("%08x-%04x-%04x-%02x%02x-%04x%08x"),
                  uuid.time_low,
                  uuid.time_mid,
                  uuid.time_hi_and_version,
                  uuid.clock_seq_hi_and_rsv,
                  uuid.clock_seq_low,
                  uuid.node_hi,
                  uuid.node_low);
    
    return str;
}


bool ConfigMgr::SaveTemplate( wxString fileName)
{
    //  Assuming the file exists, and is empty....
    
    //  Create a private wxFileConfig object
    MyConfig *conf = new MyConfig( fileName );
    
    //  Write out all the elements of a config template....
    
    //  Temporarily suppress logging of trivial non-fatal wxLogSysError() messages provoked by Android security...
    #ifdef __OCPN__ANDROID__    
    wxLogNull logNo;
    #endif    
    
    //    Global options and settings
    conf->SetPath( _T ( "/Settings" ) );
    
    conf->Write( _T ( "InlandEcdis" ), g_bInlandEcdis );
    conf->Write( _T ( "DarkDecorations"), g_bDarkDecorations );
    conf->Write( _T ( "UIexpert" ), g_bUIexpert );
    conf->Write( _T ( "SpaceDropMark" ), g_bSpaceDropMark );
    
    conf->Write( _T ( "ShowStatusBar" ), g_bShowStatusBar );
    #ifndef __WXOSX__
    conf->Write( _T ( "ShowMenuBar" ), g_bShowMenuBar );
    #endif
    conf->Write( _T ( "DefaultFontSize" ), g_default_font_size );
    
    conf->Write( _T ( "Fullscreen" ), g_bFullscreen );
    conf->Write( _T ( "ShowCompassWindow" ), g_bShowCompassWin );
    conf->Write( _T ( "SetSystemTime" ), s_bSetSystemTime );
    conf->Write( _T ( "ShowGrid" ), g_bDisplayGrid );
    conf->Write( _T ( "PlayShipsBells" ), g_bPlayShipsBells );
    conf->Write( _T ( "SoundDeviceIndex" ), g_iSoundDeviceIndex );
    conf->Write( _T ( "FullscreenToolbar" ), g_bFullscreenToolbar );
    //conf->Write( _T ( "TransparentToolbar" ), g_bTransparentToolbar );
    conf->Write( _T ( "PermanentMOBIcon" ), g_bPermanentMOBIcon );
    conf->Write( _T ( "ShowLayers" ), g_bShowLayers );
    conf->Write( _T ( "AutoAnchorDrop" ), g_bAutoAnchorMark );
    conf->Write( _T ( "ShowChartOutlines" ), g_bShowOutlines );
    conf->Write( _T ( "ShowActiveRouteTotal" ), g_bShowRouteTotal );
    conf->Write( _T ( "ShowActiveRouteHighway" ), g_bShowActiveRouteHighway );
    conf->Write( _T ( "SDMMFormat" ), g_iSDMMFormat );
    conf->Write( _T ( "ShowChartBar" ), g_bShowChartBar );
    
    conf->Write( _T ( "GUIScaleFactor" ), g_GUIScaleFactor );
    conf->Write( _T ( "ChartObjectScaleFactor" ), g_ChartScaleFactor );
    conf->Write( _T ( "ShipScaleFactor" ), g_ShipScaleFactor );
    
    conf->Write( _T ( "ShowTrue" ), g_bShowTrue );
    conf->Write( _T ( "ShowMag" ), g_bShowMag );
    conf->Write( _T ( "UserMagVariation" ), wxString::Format( _T("%.2f"), g_UserVar ) );
    
    conf->Write( _T ( "CM93DetailFactor" ), g_cm93_zoom_factor );
    conf->Write( _T ( "CM93DetailZoomPosX" ), g_detailslider_dialog_x );
    conf->Write( _T ( "CM93DetailZoomPosY" ), g_detailslider_dialog_y );
    conf->Write( _T ( "ShowCM93DetailSlider" ), g_bShowDetailSlider );
    
    conf->Write( _T ( "SkewToNorthUp" ), g_bskew_comp );
    
    conf->Write( _T ( "ZoomDetailFactor" ), g_chart_zoom_modifier );
    conf->Write( _T ( "ZoomDetailFactorVector" ), g_chart_zoom_modifier_vector );
    
    conf->Write( _T ( "SmoothPanZoom" ), g_bsmoothpanzoom );
    
    conf->Write( _T ( "CourseUpMode" ), g_bCourseUp );
    if (!g_bInlandEcdis )
        conf->Write( _T ( "LookAheadMode" ), g_bLookAhead );
    conf->Write( _T ( "COGUPAvgSeconds" ), g_COGAvgSec );
    conf->Write( _T ( "UseMagAPB" ), g_bMagneticAPB );
    
    conf->Write( _T ( "OwnshipCOGPredictorMinutes" ), g_ownship_predictor_minutes );
    conf->Write( _T ( "OwnshipCOGPredictorWidth" ), g_cog_predictor_width );
    conf->Write( _T ( "OwnshipHDTPredictorMiles" ), g_ownship_HDTpredictor_miles );
    conf->Write( _T ( "OwnShipIconType" ), g_OwnShipIconType );
    conf->Write( _T ( "OwnShipLength" ), g_n_ownship_length_meters );
    conf->Write( _T ( "OwnShipWidth" ), g_n_ownship_beam_meters );
    conf->Write( _T ( "OwnShipGPSOffsetX" ), g_n_gps_antenna_offset_x );
    conf->Write( _T ( "OwnShipGPSOffsetY" ), g_n_gps_antenna_offset_y );
    conf->Write( _T ( "OwnShipMinSize" ), g_n_ownship_min_mm );
    conf->Write( _T ( "OwnShipSogCogCalc" ), g_own_ship_sog_cog_calc );
    conf->Write( _T ( "OwnShipSogCogCalcDampSec"), g_own_ship_sog_cog_calc_damp_sec );
    
    conf->Write( _T ( "RouteArrivalCircleRadius" ), wxString::Format( _T("%.3f"), g_n_arrival_circle_radius ));
    conf->Write( _T ( "ChartQuilting" ), g_bQuiltEnable );
    
    conf->Write( _T ( "StartWithTrackActive" ), g_bTrackCarryOver );
    conf->Write( _T ( "AutomaticDailyTracks" ), g_bTrackDaily );
    conf->Write( _T ( "TrackRotateAt" ), g_track_rotate_time );
    conf->Write( _T ( "TrackRotateTimeType" ), g_track_rotate_time_type );
    conf->Write( _T ( "HighlightTracks" ), g_bHighliteTracks );
    
    conf->Write( _T ( "InitialStackIndex" ), g_restore_stackindex );
    conf->Write( _T ( "InitialdBIndex" ), g_restore_dbindex );
    
    conf->Write( _T ( "AnchorWatch1GUID" ), g_AW1GUID );
    conf->Write( _T ( "AnchorWatch2GUID" ), g_AW2GUID );
    
    conf->Write( _T ( "ToolbarX" ), g_maintoolbar_x );
    conf->Write( _T ( "ToolbarY" ), g_maintoolbar_y );
    conf->Write( _T ( "ToolbarOrient" ), g_maintoolbar_orient );
    
    conf->Write( _T ( "iENCToolbarX" ), g_iENCToolbarPosX );
    conf->Write( _T ( "iENCToolbarY" ), g_iENCToolbarPosY );
    
    if ( !g_bInlandEcdis ){  
        conf->Write( _T ( "GlobalToolbarConfig" ), g_toolbarConfig );
        conf->Write( _T ( "DistanceFormat" ), g_iDistanceFormat );
        conf->Write( _T ( "SpeedFormat" ), g_iSpeedFormat );
        conf->Write( _T ( "ShowDepthUnits" ), g_bShowDepthUnits );
    }

    conf->Write( _T ( "MobileTouch" ), g_btouch );
    conf->Write( _T ( "ResponsiveGraphics" ), g_bresponsive );
    
    conf->Write( _T ( "AutoHideToolbar" ), g_bAutoHideToolbar );
    conf->Write( _T ( "AutoHideToolbarSecs" ), g_nAutoHideToolbar );
    
    conf->Write( _T ( "DisplaySizeMM" ), g_config_display_size_mm );
    conf->Write( _T ( "DisplaySizeManual" ), g_config_display_size_manual );
    
    conf->Write( _T ( "PlanSpeed" ), wxString::Format( _T("%.2f"), g_PlanSpeed ));

#if 0    
    wxString vis, invis;
    LayerList::iterator it;
    int index = 0;
    for( it = ( *pLayerList ).begin(); it != ( *pLayerList ).end(); ++it, ++index ) {
        Layer *lay = (Layer *) ( *it );
        if( lay->IsVisibleOnChart() ) vis += ( lay->m_LayerName ) + _T(";");
        else
            invis += ( lay->m_LayerName ) + _T(";");
    }
    conf->Write( _T ( "VisibleLayers" ), vis );
    conf->Write( _T ( "InvisibleLayers" ), invis );
#endif

    conf->Write( _T ( "Locale" ), g_locale );
    conf->Write( _T ( "LocaleOverride" ), g_localeOverride );
    
    // LIVE ETA OPTION
    conf->Write( _T( "LiveETA" ), g_bShowLiveETA);
    conf->Write( _T( "DefaultBoatSpeed" ), g_defaultBoatSpeed);
    
    //    S57 Object Filter Settings
    conf->SetPath( _T ( "/Settings/ObjectFilter" ) );
    
    if( ps52plib ) {
        for( unsigned int iPtr = 0; iPtr < ps52plib->pOBJLArray->GetCount(); iPtr++ ) {
            OBJLElement *pOLE = (OBJLElement *) ( ps52plib->pOBJLArray->Item( iPtr ) );
            
            wxString st1( _T ( "viz" ) );
            char name[7];
            strncpy( name, pOLE->OBJLName, 6 );
            name[6] = 0;
            st1.Append( wxString( name, wxConvUTF8 ) );
            conf->Write( st1, pOLE->nViz );
        }
    }
    
    //    Global State
    
    conf->SetPath( _T ( "/Settings/GlobalState" ) );
    
    //    Various Options
    if ( !g_bInlandEcdis )
        conf->Write( _T ( "nColorScheme" ), (int) gFrame->GetColorScheme() );
    
    
    //    AIS
    conf->SetPath( _T ( "/Settings/AIS" ) );
    
    conf->Write( _T ( "bNoCPAMax" ), g_bCPAMax );
    conf->Write( _T ( "NoCPAMaxNMi" ), g_CPAMax_NM );
    conf->Write( _T ( "bCPAWarn" ), g_bCPAWarn );
    conf->Write( _T ( "CPAWarnNMi" ), g_CPAWarn_NM );
    conf->Write( _T ( "bTCPAMax" ), g_bTCPA_Max );
    conf->Write( _T ( "TCPAMaxMinutes" ), g_TCPA_Max );
    conf->Write( _T ( "bMarkLostTargets" ), g_bMarkLost );
    conf->Write( _T ( "MarkLost_Minutes" ), g_MarkLost_Mins );
    conf->Write( _T ( "bRemoveLostTargets" ), g_bRemoveLost );
    conf->Write( _T ( "RemoveLost_Minutes" ), g_RemoveLost_Mins );
    conf->Write( _T ( "bShowCOGArrows" ), g_bShowCOG );
    conf->Write( _T ( "CogArrowMinutes" ), g_ShowCOG_Mins );
    conf->Write( _T ( "bShowTargetTracks" ), g_bAISShowTracks );
    conf->Write( _T ( "TargetTracksMinutes" ), g_AISShowTracks_Mins );
    
    conf->Write( _T ( "bHideMooredTargets" ), g_bHideMoored );
    conf->Write( _T ( "MooredTargetMaxSpeedKnots" ), g_ShowMoored_Kts );
    
    conf->Write( _T ( "bAISAlertDialog" ), g_bAIS_CPA_Alert );
    conf->Write( _T ( "bAISAlertAudio" ), g_bAIS_CPA_Alert_Audio );
    conf->Write( _T ( "AISAlertAudioFile" ), g_sAIS_Alert_Sound_File );
    conf->Write( _T ( "bAISAlertSuppressMoored" ), g_bAIS_CPA_Alert_Suppress_Moored );
    conf->Write( _T ( "bShowAreaNotices" ), g_bShowAreaNotices );
    conf->Write( _T ( "bDrawAISSize" ), g_bDrawAISSize );
    conf->Write( _T ( "bDrawAISRealtime" ), g_bDrawAISRealtime );
    conf->Write( _T ( "AISRealtimeMinSpeedKnots" ), g_AIS_RealtPred_Kts );
    conf->Write( _T ( "bShowAISName" ), g_bShowAISName );
    conf->Write( _T ( "ShowAISTargetNameScale" ), g_Show_Target_Name_Scale );
    conf->Write( _T ( "bWplIsAprsPositionReport" ), g_bWplIsAprsPosition );
    conf->Write( _T ( "AISCOGPredictorWidth" ), g_ais_cog_predictor_width );
    conf->Write( _T ( "bShowScaledTargets" ), g_bAllowShowScaled );
    conf->Write( _T ( "AISScaledNumber" ), g_ShowScaled_Num );    
    conf->Write( _T ( "AISScaledNumberWeightSOG" ), g_ScaledNumWeightSOG );
    conf->Write( _T ( "AISScaledNumberWeightCPA" ), g_ScaledNumWeightCPA );
    conf->Write( _T ( "AISScaledNumberWeightTCPA" ), g_ScaledNumWeightTCPA );
    conf->Write( _T ( "AISScaledNumberWeightRange" ), g_ScaledNumWeightRange );
    conf->Write( _T ( "AISScaledNumberWeightSizeOfTarget" ), g_ScaledNumWeightSizeOfT ); 
    conf->Write( _T ( "AISScaledSizeMinimal" ), g_ScaledSizeMinimal );
    conf->Write( _T ( "AISShowScaled"), g_bShowScaled);
    
    conf->Write( _T ( "AlertDialogSizeX" ), g_ais_alert_dialog_sx );
    conf->Write( _T ( "AlertDialogSizeY" ), g_ais_alert_dialog_sy );
    conf->Write( _T ( "AlertDialogPosX" ), g_ais_alert_dialog_x );
    conf->Write( _T ( "AlertDialogPosY" ), g_ais_alert_dialog_y );
    conf->Write( _T ( "QueryDialogPosX" ), g_ais_query_dialog_x );
    conf->Write( _T ( "QueryDialogPosY" ), g_ais_query_dialog_y );
    conf->Write( _T ( "AISTargetListPerspective" ), g_AisTargetList_perspective );
    conf->Write( _T ( "AISTargetListRange" ), g_AisTargetList_range );
    conf->Write( _T ( "AISTargetListSortColumn" ), g_AisTargetList_sortColumn );
    conf->Write( _T ( "bAISTargetListSortReverse" ), g_bAisTargetList_sortReverse );
    conf->Write( _T ( "AISTargetListColumnSpec" ), g_AisTargetList_column_spec );
    conf->Write( _T ( "AISTargetListColumnOrder" ), g_AisTargetList_column_order);
    conf->Write( _T ( "S57QueryDialogSizeX" ), g_S57_dialog_sx );
    conf->Write( _T ( "S57QueryDialogSizeY" ), g_S57_dialog_sy );
    conf->Write( _T ( "bAISRolloverShowClass" ), g_bAISRolloverShowClass );
    conf->Write( _T ( "bAISRolloverShowCOG" ), g_bAISRolloverShowCOG );
    conf->Write( _T ( "bAISRolloverShowCPA" ), g_bAISRolloverShowCPA );
    conf->Write( _T ( "bAISAlertAckTimeout" ), g_bAIS_ACK_Timeout );
    conf->Write( _T ( "AlertAckTimeoutMinutes" ), g_AckTimeout_Mins );
    
    conf->SetPath( _T ( "/Settings/GlobalState" ) );
    if( ps52plib ) {
        conf->Write( _T ( "bShowS57Text" ), ps52plib->GetShowS57Text() );
        conf->Write( _T ( "bShowS57ImportantTextOnly" ), ps52plib->GetShowS57ImportantTextOnly() );
        if ( !g_bInlandEcdis )
            conf->Write( _T ( "nDisplayCategory" ), (long) ps52plib->GetDisplayCategory() );
        conf->Write( _T ( "nSymbolStyle" ), (int) ps52plib->m_nSymbolStyle );
        conf->Write( _T ( "nBoundaryStyle" ), (int) ps52plib->m_nBoundaryStyle );
        
        conf->Write( _T ( "bShowSoundg" ), ps52plib->m_bShowSoundg );
        conf->Write( _T ( "bShowMeta" ), ps52plib->m_bShowMeta );
        conf->Write( _T ( "bUseSCAMIN" ), ps52plib->m_bUseSCAMIN );
        conf->Write( _T ( "bShowAtonText" ), ps52plib->m_bShowAtonText );
        conf->Write( _T ( "bShowLightDescription" ), ps52plib->m_bShowLdisText );
        conf->Write( _T ( "bExtendLightSectors" ), ps52plib->m_bExtendLightSectors );
        conf->Write( _T ( "bDeClutterText" ), ps52plib->m_bDeClutterText );
        conf->Write( _T ( "bShowNationalText" ), ps52plib->m_bShowNationalTexts );
        
        conf->Write( _T ( "S52_MAR_SAFETY_CONTOUR" ), S52_getMarinerParam( S52_MAR_SAFETY_CONTOUR ) );
        conf->Write( _T ( "S52_MAR_SHALLOW_CONTOUR" ), S52_getMarinerParam( S52_MAR_SHALLOW_CONTOUR ) );
        conf->Write( _T ( "S52_MAR_DEEP_CONTOUR" ), S52_getMarinerParam( S52_MAR_DEEP_CONTOUR ) );
        conf->Write( _T ( "S52_MAR_TWO_SHADES" ), S52_getMarinerParam( S52_MAR_TWO_SHADES ) );
        conf->Write( _T ( "S52_DEPTH_UNIT_SHOW" ), ps52plib->m_nDepthUnitDisplay );
    }
    
    conf->SetPath( _T ( "/Settings/Others" ) );
    
    // Radar rings
    conf->Write( _T ( "ShowRadarRings" ), (bool)(g_iNavAidRadarRingsNumberVisible > 0) );  //3.0.0 config support
    conf->Write( _T ( "RadarRingsNumberVisible" ), g_iNavAidRadarRingsNumberVisible );
    conf->Write( _T ( "RadarRingsStep" ), g_fNavAidRadarRingsStep );
    conf->Write( _T ( "RadarRingsStepUnits" ), g_pNavAidRadarRingsStepUnits );
    conf->Write( _T ( "RadarRingsColour" ), g_colourOwnshipRangeRingsColour.GetAsString( wxC2S_HTML_SYNTAX ) );
    
    // Waypoint Radar rings
    conf->Write( _T ( "WaypointRangeRingsNumber" ), g_iWaypointRangeRingsNumber );
    conf->Write( _T ( "WaypointRangeRingsStep" ), g_fWaypointRangeRingsStep );
    conf->Write( _T ( "WaypointRangeRingsStepUnits" ), g_iWaypointRangeRingsStepUnits );
    conf->Write( _T ( "WaypointRangeRingsColour" ), g_colourWaypointRangeRingsColour.GetAsString( wxC2S_HTML_SYNTAX ) );
    
    conf->Write( _T ( "ConfirmObjectDeletion" ), g_bConfirmObjectDelete );
    
    // Waypoint dragging with mouse
    conf->Write( _T ( "WaypointPreventDragging" ), g_bWayPointPreventDragging );
    
    conf->Write( _T ( "EnableZoomToCursor" ), g_bEnableZoomToCursor );
    
    conf->Write( _T ( "TrackIntervalSeconds" ), g_TrackIntervalSeconds );
    conf->Write( _T ( "TrackDeltaDistance" ), g_TrackDeltaDistance );
    conf->Write( _T ( "TrackPrecision" ), g_nTrackPrecision );
    
    conf->Write( _T ( "RouteLineWidth" ), g_route_line_width );
    conf->Write( _T ( "TrackLineWidth" ), g_track_line_width );
    conf->Write( _T ( "TrackLineColour" ), g_colourTrackLineColour.GetAsString( wxC2S_HTML_SYNTAX ) );
    conf->Write( _T ( "DefaultWPIcon" ), g_default_wp_icon );

    //    Fonts
    
    //  Store the persistent Auxiliary Font descriptor Keys
    conf->SetPath( _T ( "/Settings/AuxFontKeys" ) );
    
    wxArrayString keyArray = FontMgr::Get().GetAuxKeyArray();
    for(unsigned int i=0 ; i <  keyArray.GetCount() ; i++){
        wxString key;
        key.Printf(_T("Key%i"), i);
        wxString keyval = keyArray[i];
        conf->Write( key, keyval );
    }
    
    wxString font_path;
    #ifdef __WXX11__
    font_path = ( _T ( "/Settings/X11Fonts" ) );
    #endif
    
    #ifdef __WXGTK__
    font_path = ( _T ( "/Settings/GTKFonts" ) );
    #endif
    
    #ifdef __WXMSW__
    font_path = ( _T ( "/Settings/MSWFonts" ) );
    #endif
    
    #ifdef __WXMAC__
    font_path = ( _T ( "/Settings/MacFonts" ) );
    #endif
    
    #ifdef __WXQT__
    font_path = ( _T ( "/Settings/QTFonts" ) );
    #endif
    
    conf->DeleteGroup(font_path);
    
    conf->SetPath( font_path );
    
    int nFonts = FontMgr::Get().GetNumFonts();
    
    for( int i = 0; i < nFonts; i++ ) {
        wxString cfstring(FontMgr::Get().GetConfigString(i));
        wxString valstring = FontMgr::Get().GetFullConfigDesc( i );
        conf->Write( cfstring, valstring );
    }
    
    //  Save the per-canvas config options
    conf->SaveCanvasConfigs( );
    
    conf->Flush();
    
    delete conf;
    
    return true;
}


bool ConfigMgr::CheckTemplateGUID( wxString GUID )
{
    bool rv = false;
    
    OCPNConfigObject *config = GetConfig( GUID );
    if(config){
        rv = CheckTemplate( GetConfigDir() + config->templateFileName );
    }
    
    return rv;
}


#define CHECK_INT(s, t)         read_int = *t; \
                                if(!conf->Read( s , &read_int)) wxLogMessage(s); \
                                if( (int)*t  != read_int) return false;

#define CHECK_STR(s, t)         val = t;  \
                                conf->Read( s , &val); \
                                if( !t.IsSameAs( val )) return false;

#define CHECK_STRP(s, t)        conf->Read( s , &val); \
                                if( !t->IsSameAs( val )) return false;
                                
#define CHECK_FLT(s, t, eps)    conf->Read(s, &val);  \
                                val.ToDouble( &dval ); \
                                if(fabs(dval - *t) > eps) return false;
                                
bool ConfigMgr::CheckTemplate( wxString fileName) 
{
    bool rv = true;
 
    
    int read_int;
    wxString val;
    double dval;

    MyConfig *conf = new MyConfig( fileName );
    
//    Global options and settings
    conf->SetPath( _T ( "/Settings" ) );    
    
    
    
    CHECK_INT( _T ( "UIexpert" ), &g_bUIexpert );
    
    ///CHECK_STR( _T ( "UIStyle" ), g_uiStyle  );

     
    CHECK_INT( _T ( "InlandEcdis" ), &g_bInlandEcdis );
    
    CHECK_INT( _T ("DarkDecorations" ), &g_bDarkDecorations );

    CHECK_INT( _T( "SpaceDropMark" ), &g_bSpaceDropMark );

    ///CHECK_INT( _T ( "UseModernUI5" ), &g_useMUI );

#if 0    
    CHECK_INT( _T ( "DebugGDAL" ), &g_bGDAL_Debug );
    CHECK_INT( _T ( "DebugNMEA" ), &g_nNMEADebug );
    CHECK_INT( _T ( "DebugOpenGL" ), &g_bDebugOGL );
    ///CHECK_INT( _T ( "AnchorWatchDefault" ), &g_nAWDefault );
    ///CHECK_INT( _T ( "AnchorWatchMax" ), &g_nAWMax );
    ///CHECK_INT( _T ( "GPSDogTimeout" ), &gps_watchdog_timeout_ticks );
    CHECK_INT( _T ( "DebugCM93" ), &g_bDebugCM93 );
    CHECK_INT( _T ( "DebugS57" ), &g_bDebugS57 );         // Show LUP and Feature info in object query
    CHECK_INT( _T ( "DebugBSBImg" ), &g_BSBImgDebug );
    CHECK_INT( _T ( "DebugGPSD" ), &g_bDebugGPSD );
#endif

    CHECK_INT( _T ( "DefaultFontSize"), &g_default_font_size );
    
//    Read( _T ( "GPSIdent" ), &g_GPS_Ident );
    CHECK_INT( _T ( "UseGarminHostUpload" ),  &g_bGarminHostUpload );

    CHECK_INT( _T ( "UseNMEA_GLL" ), &g_bUseGLL );

    CHECK_INT( _T ( "AutoHideToolbar" ), &g_bAutoHideToolbar );
    CHECK_INT( _T ( "AutoHideToolbarSecs" ), &g_nAutoHideToolbar );
    
    CHECK_INT( _T ( "UseSimplifiedScalebar" ), &g_bsimplifiedScalebar );
    
    CHECK_INT( _T ( "DisplaySizeMM" ), &g_display_size_mm );
    CHECK_INT( _T ( "DisplaySizeManual" ), &g_config_display_size_manual );
    
    CHECK_INT( _T ( "GUIScaleFactor" ), &g_GUIScaleFactor );
    
    CHECK_INT( _T ( "ChartObjectScaleFactor" ), &g_ChartScaleFactor );
    CHECK_INT( _T ( "ShipScaleFactor" ), &g_ShipScaleFactor );
    
    CHECK_INT( _T ( "FilterNMEA_Avg" ), &g_bfilter_cogsog );
    CHECK_INT( _T ( "FilterNMEA_Sec" ), &g_COGFilterSec );

    CHECK_INT( _T ( "ShowTrue" ), &g_bShowTrue );
    CHECK_INT( _T ( "ShowMag" ), &g_bShowMag );

    CHECK_FLT( _T ( "UserMagVariation" ), &g_UserVar, 0.1) 

    CHECK_INT( _T ( "UseMagAPB" ), &g_bMagneticAPB );

    CHECK_INT( _T ( "ScreenBrightness" ), &g_nbrightness );

    CHECK_INT( _T ( "MemFootprintTargetMB" ), &g_MemFootMB );

    CHECK_INT( _T ( "WindowsComPortMax" ), &g_nCOMPortCheck );

    CHECK_INT( _T ( "ChartQuilting" ), &g_bQuiltEnable );
    CHECK_INT( _T ( "ChartQuiltingInitial" ), &g_bQuiltStart );

    CHECK_INT( _T ( "CourseUpMode" ), &g_bCourseUp );
    CHECK_INT( _T ( "COGUPAvgSeconds" ), &g_COGAvgSec );
    //CHECK_INT( _T ( "LookAheadMode" ), &g_bLookAhead );
    //CHECK_INT( _T ( "SkewToNorthUp" ), &g_bskew_comp );
    CHECK_INT( _T ( "OpenGL" ), &g_bopengl );
    CHECK_INT( _T ( "SoftwareGL" ), &g_bSoftwareGL );
    
    CHECK_INT( _T ( "ShowFPS" ), &g_bShowFPS );
    
    CHECK_INT( _T( "NMEAAPBPrecision" ), &g_NMEAAPBPrecision );
    
    CHECK_STR( _T( "TalkerIdText" ), g_TalkerIdText );
    CHECK_INT( _T( "MaxWaypointNameLength" ), &g_maxWPNameLength );

    /* opengl options */
#ifdef ocpnUSE_GL
    CHECK_INT( _T ( "OpenGLExpert" ), &g_bGLexpert );
    CHECK_INT( _T ( "UseAcceleratedPanning" ), &g_GLOptions.m_bUseAcceleratedPanning );
    CHECK_INT( _T ( "GPUTextureCompression" ), &g_GLOptions.m_bTextureCompression);
    CHECK_INT( _T ( "GPUTextureCompressionCaching" ), &g_GLOptions.m_bTextureCompressionCaching);
    CHECK_INT( _T ( "PolygonSmoothing" ), &g_GLOptions.m_GLPolygonSmoothing);
    CHECK_INT( _T ( "LineSmoothing" ), &g_GLOptions.m_GLLineSmoothing);
    CHECK_INT( _T ( "GPUTextureDimension" ), &g_GLOptions.m_iTextureDimension );
    CHECK_INT( _T ( "GPUTextureMemSize" ), &g_GLOptions.m_iTextureMemorySize );

#endif
    CHECK_INT( _T ( "SmoothPanZoom" ), &g_bsmoothpanzoom );

    CHECK_INT( _T ( "ToolbarX"), &g_maintoolbar_x );
    CHECK_INT( _T ( "ToolbarY" ), &g_maintoolbar_y );
    CHECK_INT( _T ( "ToolbarOrient" ), &g_maintoolbar_orient );
    CHECK_STR( _T ( "GlobalToolbarConfig" ), g_toolbarConfig );

    CHECK_INT( _T ( "iENCToolbarX"), &g_iENCToolbarPosX );
    CHECK_INT( _T ( "iENCToolbarY"), &g_iENCToolbarPosY );
    
    CHECK_STR( _T ( "AnchorWatch1GUID" ), g_AW1GUID );
    CHECK_STR( _T ( "AnchorWatch2GUID" ), g_AW2GUID );

    CHECK_INT( _T ( "MobileTouch" ), &g_btouch );
    CHECK_INT( _T ( "ResponsiveGraphics" ), &g_bresponsive );

    CHECK_INT( _T ( "ZoomDetailFactor" ), &g_chart_zoom_modifier );
    CHECK_INT( _T ( "ZoomDetailFactorVector" ), &g_chart_zoom_modifier_vector );
    
    CHECK_INT( _T ( "CM93DetailFactor" ), &g_cm93_zoom_factor );
    CHECK_INT( _T ( "CM93DetailZoomPosX" ), &g_detailslider_dialog_x );
    CHECK_INT( _T ( "CM93DetailZoomPosY" ), &g_detailslider_dialog_y );
    CHECK_INT( _T ( "ShowCM93DetailSlider" ), &g_bShowDetailSlider );

    CHECK_INT( _T ( "SENC_LOD_Pixels" ), &g_SENC_LOD_pixels );

    CHECK_INT( _T ( "SkewCompUpdatePeriod" ), &g_SkewCompUpdatePeriod );

    CHECK_INT( _T ( "ShowStatusBar" ), &g_bShowStatusBar );
#ifndef __WXOSX__
    CHECK_INT( _T ( "ShowMenuBar" ), &g_bShowMenuBar );
#endif
    CHECK_INT( _T ( "Fullscreen" ), &g_bFullscreen );
    CHECK_INT( _T ( "ShowCompassWindow" ), &g_bShowCompassWin );
    CHECK_INT( _T ( "PlayShipsBells" ), &g_bPlayShipsBells );
    CHECK_INT( _T ( "SoundDeviceIndex" ), &g_iSoundDeviceIndex );
    CHECK_INT( _T ( "FullscreenToolbar" ), &g_bFullscreenToolbar );
    //CHECK_INT( _T ( "TransparentToolbar" ), &g_bTransparentToolbar );
    CHECK_INT( _T ( "PermanentMOBIcon" ), &g_bPermanentMOBIcon );
    CHECK_INT( _T ( "ShowLayers" ), &g_bShowLayers );
    CHECK_INT( _T ( "ShowDepthUnits" ), &g_bShowDepthUnits );
    CHECK_INT( _T ( "AutoAnchorDrop" ), &g_bAutoAnchorMark );
    CHECK_INT( _T ( "ShowActiveRouteHighway" ), &g_bShowActiveRouteHighway );
    CHECK_INT( _T ( "ShowActiveRouteTotal" ), &g_bShowRouteTotal );
    CHECK_STR( _T ( "MostRecentGPSUploadConnection" ), g_uploadConnection);
    CHECK_INT( _T ( "ShowChartBar" ), &g_bShowChartBar );
    CHECK_INT( _T ( "SDMMFormat" ), &g_iSDMMFormat ); //0 = "Degrees, Decimal minutes"), 1 = "Decimal degrees", 2 = "Degrees,Minutes, Seconds"
      
    CHECK_INT( _T ( "DistanceFormat" ), &g_iDistanceFormat ); //0 = "Nautical miles"), 1 = "Statute miles", 2 = "Kilometers", 3 = "Meters"
    CHECK_INT( _T ( "SpeedFormat" ), &g_iSpeedFormat ); //0 = "kts"), 1 = "mph", 2 = "km/h", 3 = "m/s"

    // LIVE ETA OPTION
    CHECK_INT( _T ( "LiveETA" ), &g_bShowLiveETA );
    CHECK_INT( _T ( "DefaultBoatSpeed" ), &g_defaultBoatSpeed );
    
    CHECK_INT( _T ( "OwnshipCOGPredictorMinutes" ), &g_ownship_predictor_minutes );
    CHECK_INT( _T ( "OwnshipCOGPredictorWidth" ), &g_cog_predictor_width );
    CHECK_INT( _T ( "OwnshipHDTPredictorMiles" ), &g_ownship_HDTpredictor_miles );

    CHECK_INT( _T ( "OwnShipIconType" ), &g_OwnShipIconType );
    CHECK_FLT( _T ( "OwnShipLength" ), &g_n_ownship_length_meters, 0.1 );
    CHECK_FLT( _T ( "OwnShipWidth" ), &g_n_ownship_beam_meters, 0.1 );
    CHECK_FLT( _T ( "OwnShipGPSOffsetX" ), &g_n_gps_antenna_offset_x, 0.1 );
    CHECK_FLT( _T ( "OwnShipGPSOffsetY" ), &g_n_gps_antenna_offset_y, 0.1 );
    CHECK_INT( _T ( "OwnShipMinSize" ), &g_n_ownship_min_mm );
    CHECK_INT( _T ( "OwnShipSogCogCalc" ), &g_own_ship_sog_cog_calc );
    CHECK_INT( _T ( "OwnShipSogCogCalcDampSec"), &g_own_ship_sog_cog_calc_damp_sec );

    CHECK_FLT( _T ( "RouteArrivalCircleRadius" ), &g_n_arrival_circle_radius, .01 );

    CHECK_INT( _T ( "FullScreenQuilt" ), &g_bFullScreenQuilt );

    CHECK_INT( _T ( "StartWithTrackActive" ), &g_bTrackCarryOver );
    CHECK_INT( _T ( "AutomaticDailyTracks" ), &g_bTrackDaily );
    CHECK_INT( _T ( "TrackRotateAt" ), &g_track_rotate_time );
    CHECK_INT( _T ( "TrackRotateTimeType" ), &g_track_rotate_time_type );
    CHECK_INT( _T ( "HighlightTracks" ), &g_bHighliteTracks );

    CHECK_FLT( _T ( "PlanSpeed" ), &g_PlanSpeed, 0.1)
    
    ///CHECK_STR( _T ( "VisibleLayers" ), g_VisibleLayers );
    ///CHECK_STR( _T ( "InvisibleLayers" ), g_InvisibleLayers );

    CHECK_INT( _T ( "PreserveScaleOnX" ), &g_bPreserveScaleOnX );

    CHECK_STR( _T ( "Locale" ), g_locale );
    CHECK_STR( _T ( "LocaleOverride" ), g_localeOverride );
    
    //We allow 0-99 backups ov navobj.xml
    CHECK_INT( _T ( "KeepNavobjBackups" ), &g_navobjbackups );
    
//     NMEALogWindow::Get().SetSize(Read(_T("NMEALogWindowSizeX"), 600L), Read(_T("NMEALogWindowSizeY"), 400L));
//     NMEALogWindow::Get().SetPos(Read(_T("NMEALogWindowPosX"), 10L), Read(_T("NMEALogWindowPosY"), 10L));
//     NMEALogWindow::Get().CheckPos(display_width, display_height);

    // Boolean to cater for legacy Input COM Port filer behaviour, i.e. show msg filtered but put msg on bus.
    CHECK_INT( _T ( "LegacyInputCOMPortFilterBehaviour" ), &g_b_legacy_input_filter_behaviour );
    
    CHECK_INT( _T( "AdvanceRouteWaypointOnArrivalOnly" ), &g_bAdvanceRouteWaypointOnArrivalOnly);

    CHECK_INT( _T ( "EnableRotateKeys" ),  &g_benable_rotate );
    CHECK_INT( _T ( "EmailCrashReport" ),  &g_bEmailCrashReport );
    
    CHECK_INT( _T ( "EnableAISNameCache" ),  &g_benableAISNameCache );
    
    CHECK_INT( _T ( "EnableUDPNullHeader" ),  &g_benableUDPNullHeader );
    
    conf->SetPath( _T ( "/Settings/GlobalState" ) );

    CHECK_INT( _T ( "FrameWinX" ), &g_nframewin_x );
    CHECK_INT( _T ( "FrameWinY" ), &g_nframewin_y );
    CHECK_INT( _T ( "FrameWinPosX" ), &g_nframewin_posx );
    CHECK_INT( _T ( "FrameWinPosY" ), &g_nframewin_posy );
    CHECK_INT( _T ( "FrameMax" ), &g_bframemax );

    CHECK_INT( _T ( "ClientPosX" ), &g_lastClientRectx );
    CHECK_INT( _T ( "ClientPosY" ), &g_lastClientRecty );
    CHECK_INT( _T ( "ClientSzX" ), &g_lastClientRectw );
    CHECK_INT( _T ( "ClientSzY" ), &g_lastClientRecth );
    
    CHECK_INT( _T( "RoutePropSizeX" ), &g_route_prop_sx );
    CHECK_INT( _T( "RoutePropSizeY" ), &g_route_prop_sy );
    CHECK_INT( _T( "RoutePropPosX" ), &g_route_prop_x );
    CHECK_INT( _T( "RoutePropPosY" ), &g_route_prop_y );
    
    CHECK_INT( _T ( "S52_DEPTH_UNIT_SHOW" ), &g_nDepthUnitDisplay );   // default is metres

    //    AIS
    conf->SetPath( _T ( "/Settings/AIS" ) );
    CHECK_INT( _T ( "bNoCPAMax" ), &g_bCPAMax );
    CHECK_FLT( _T ( "NoCPAMaxNMi" ), &g_CPAMax_NM, .01 )
    CHECK_INT( _T ( "bCPAWarn" ), &g_bCPAWarn );
    CHECK_FLT( _T ( "CPAWarnNMi" ), &g_CPAWarn_NM, .01 )
    CHECK_INT( _T ( "bTCPAMax" ), &g_bTCPA_Max );
    CHECK_FLT( _T ( "TCPAMaxMinutes" ), &g_TCPA_Max, 1  )
    CHECK_INT( _T ( "bMarkLostTargets" ), &g_bMarkLost );
    CHECK_FLT( _T ( "MarkLost_Minutes" ), &g_MarkLost_Mins, 1 )
    CHECK_INT( _T ( "bRemoveLostTargets" ), &g_bRemoveLost );
    CHECK_FLT( _T ( "RemoveLost_Minutes" ), &g_RemoveLost_Mins, 1 )
    CHECK_INT( _T ( "bShowCOGArrows" ), &g_bShowCOG );
    CHECK_FLT( _T ( "CogArrowMinutes" ), &g_ShowCOG_Mins, 1 );
    CHECK_INT( _T ( "bShowTargetTracks" ), &g_bAISShowTracks );
    CHECK_FLT( _T ( "TargetTracksMinutes" ), &g_AISShowTracks_Mins, 1 )
    CHECK_FLT( _T ( "TargetTracksLimit" ), &g_AISShowTracks_Limit, 300 )
    CHECK_INT( _T ( "bHideMooredTargets" ), &g_bHideMoored )
    CHECK_FLT( _T ( "MooredTargetMaxSpeedKnots" ), &g_ShowMoored_Kts, .1 )
    CHECK_INT( _T ( "bShowScaledTargets"), &g_bAllowShowScaled );
    CHECK_INT( _T ( "AISScaledNumber" ), &g_ShowScaled_Num );
    CHECK_INT( _T ( "AISScaledNumberWeightSOG" ), &g_ScaledNumWeightSOG );
    CHECK_INT( _T ( "AISScaledNumberWeightCPA" ), &g_ScaledNumWeightCPA );
    CHECK_INT( _T ( "AISScaledNumberWeightTCPA" ), &g_ScaledNumWeightTCPA );
    CHECK_INT( _T ( "AISScaledNumberWeightRange" ), &g_ScaledNumWeightRange );
    CHECK_INT( _T ( "AISScaledNumberWeightSizeOfTarget" ), &g_ScaledNumWeightSizeOfT );
    CHECK_INT( _T ( "AISScaledSizeMinimal" ), &g_ScaledSizeMinimal );
    CHECK_INT( _T(  "AISShowScaled"), &g_bShowScaled );
    CHECK_INT( _T ( "bShowAreaNotices" ), &g_bShowAreaNotices );
    CHECK_INT( _T ( "bDrawAISSize" ), &g_bDrawAISSize );
    CHECK_INT( _T ( "bDrawAISRealtime" ), &g_bDrawAISRealtime );
    CHECK_FLT( _T ( "AISRealtimeMinSpeedKnots" ), &g_AIS_RealtPred_Kts, .1 );
    CHECK_INT( _T ( "bShowAISName" ), &g_bShowAISName );
    CHECK_INT( _T ( "bAISAlertDialog" ), &g_bAIS_CPA_Alert );
    CHECK_INT( _T ( "ShowAISTargetNameScale" ), &g_Show_Target_Name_Scale );
    CHECK_INT( _T ( "bWplIsAprsPositionReport" ), &g_bWplIsAprsPosition );
    CHECK_INT( _T ( "AISCOGPredictorWidth" ), &g_ais_cog_predictor_width );
    CHECK_INT( _T ( "bAISAlertAudio" ), &g_bAIS_CPA_Alert_Audio );
    CHECK_STR( _T ( "AISAlertAudioFile" ), g_sAIS_Alert_Sound_File );
    CHECK_INT( _T ( "bAISAlertSuppressMoored" ), &g_bAIS_CPA_Alert_Suppress_Moored );
    CHECK_INT( _T ( "bAISAlertAckTimeout" ), &g_bAIS_ACK_Timeout );
    CHECK_FLT( _T ( "AlertAckTimeoutMinutes" ), &g_AckTimeout_Mins, 1 )
    CHECK_STR( _T ( "AISTargetListPerspective" ), g_AisTargetList_perspective );
    CHECK_INT( _T ( "AISTargetListRange" ), &g_AisTargetList_range );
    CHECK_INT( _T ( "AISTargetListSortColumn" ), &g_AisTargetList_sortColumn );
    CHECK_INT( _T ( "bAISTargetListSortReverse" ), &g_bAisTargetList_sortReverse );
    CHECK_STR( _T ( "AISTargetListColumnSpec" ), g_AisTargetList_column_spec );
    CHECK_STR( _T ("AISTargetListColumnOrder"), g_AisTargetList_column_order);
    CHECK_INT( _T ( "bAISRolloverShowClass" ), &g_bAISRolloverShowClass );
    CHECK_INT( _T ( "bAISRolloverShowCOG" ), &g_bAISRolloverShowCOG );
    CHECK_INT( _T ( "bAISRolloverShowCPA" ), &g_bAISRolloverShowCPA );
    
    CHECK_INT( _T ( "S57QueryDialogSizeX" ), &g_S57_dialog_sx );
    CHECK_INT( _T ( "S57QueryDialogSizeY" ), &g_S57_dialog_sy );
    CHECK_INT( _T ( "AlertDialogSizeX" ), &g_ais_alert_dialog_sx );
    CHECK_INT( _T ( "AlertDialogSizeY" ), &g_ais_alert_dialog_sy );
    CHECK_INT( _T ( "AlertDialogPosX" ), &g_ais_alert_dialog_x );
    CHECK_INT( _T ( "AlertDialogPosY" ), &g_ais_alert_dialog_y );
    CHECK_INT( _T ( "QueryDialogPosX" ), &g_ais_query_dialog_x );
    CHECK_INT( _T ( "QueryDialogPosY" ), &g_ais_query_dialog_y );
    
    
    conf->SetPath( _T ( "/Directories" ) );
    CHECK_STR( _T ( "PresentationLibraryData" ), g_UserPresLibData)
    ///CHECK_STRP( _T ( "InitChartDir" ), pInit_Chart_Dir)
    
    CHECK_STR( _T ( "SENCFileLocation" ), g_SENCPrefix)

    
    CHECK_STR( _T ( "GPXIODir" ), g_gpx_path );           // Get the Directory name
    CHECK_STR( _T ( "TCDataDir" ), g_TCData_Dir );           // Get the Directory name
    CHECK_STR( _T ( "BasemapDir"), gWorldMapLocation );

//    Fonts

#if 0
    //  Load the persistent Auxiliary Font descriptor Keys
    conf->SetPath ( _T ( "/Settings/AuxFontKeys" ) );
    
    wxString strk;
    long dummyk;
    wxString kval;
    bool bContk = conf->GetFirstEntry( strk, dummyk );
    bool bNewKey = false;
    while( bContk ) {
        Read( strk, &kval );
        bNewKey = FontMgr::Get().AddAuxKey(kval);
        if(!bNewKey) {
            DeleteEntry( strk );
            dummyk--;
        }
        bContk = GetNextEntry( strk, dummyk );
    }
#endif

#ifdef __WXX11__
    conf->SetPath ( _T ( "/Settings/X11Fonts" ) );
#endif

#ifdef __WXGTK__
    conf->SetPath ( _T ( "/Settings/GTKFonts" ) );
#endif

#ifdef __WXMSW__
    conf->SetPath( _T ( "/Settings/MSWFonts" ) );
#endif

#ifdef __WXMAC__
    conf->SetPath ( _T ( "/Settings/MacFonts" ) );
#endif

#ifdef __WXQT__
    conf->SetPath ( _T ( "/Settings/QTFonts" ) );
#endif

#if 0    
    if(conf->GetNumberOfEntries() != (unsigned int)FontMgr::Get().GetNumFonts() )
        return false;
    
    wxString str;
    long dummy;
    wxString pval;

    bool bCont = conf->GetFirstEntry( str, dummy );
    while( bCont ) {
        conf->Read( str, &pval );
        if(!FontMgr::Get().FindFontByConfigString(str))
            return false;

        bCont = conf->GetNextEntry( str, dummy );
    }


//  Tide/Current Data Sources
    conf->SetPath( _T ( "/TideCurrentDataSources" ) );
    if( conf->GetNumberOfEntries() != TideCurrentDataSet.GetCount())
        return false;
    
    if( conf->GetNumberOfEntries()){
        wxString str, val;
        long dummy;
        bool bCont = conf->GetFirstEntry( str, dummy );
        while( bCont ) {
            conf->Read( str, &val );              // Get a file name
            if( TideCurrentDataSet.Index(val) == wxNOT_FOUND)
                return false;
            bCont = conf->GetNextEntry( str, dummy );
        }
    }

#endif

#if 0
    //    Groups
    conf->SetPath( _T ( "/Groups" ) );
    unsigned int group_count;
    conf->Read( _T ( "GroupCount" ), (int *) &group_count, 0 );
    
    if(group_count != g_pGroupArray->GetCount())
        return false;
    
    // Walk the array of groups in the target template
    for( unsigned int i = 0; i < group_count; i++ ) {
        wxString s;
        s.Printf( _T("Group%d"), i + 1 );
        s.Prepend( _T ( "/Groups/" ) );
        conf->SetPath( s );
        
        wxString t;
        conf->Read( _T ( "GroupName" ), &t );
        
        // Look for this group name int the active array
        bool bfound = false;
        ChartGroup *pGroup;
        for(unsigned int j = 0 ; j < g_pGroupArray->GetCount() ; j++){
            pGroup = g_pGroupArray->Item(i);
            if(pGroup && (pGroup->m_group_name.IsSameAs(t))){
                bfound = true;
                break;
            }
        }
        
        if(!bfound)
            return false;
        //TODO
        // Here we could further check the contents of the found group.    
    }
        
    
#endif    
    
    
    
    conf->SetPath( _T ( "/Settings/Others" ) );

    // Radar rings
    CHECK_INT( _T ( "RadarRingsNumberVisible" ), &g_iNavAidRadarRingsNumberVisible )
    CHECK_INT( _T ( "RadarRingsStep" ), &g_fNavAidRadarRingsStep )

    CHECK_INT( _T ( "RadarRingsStepUnits" ), &g_pNavAidRadarRingsStepUnits );

//    wxString l_wxsOwnshipRangeRingsColour;
//    CHECK_STR( _T ( "RadarRingsColour" ), &l_wxsOwnshipRangeRingsColour );
//    if(l_wxsOwnshipRangeRingsColour.Length()) g_colourOwnshipRangeRingsColour.Set( l_wxsOwnshipRangeRingsColour );
    
    // Waypoint Radar rings
    CHECK_INT( _T ( "WaypointRangeRingsNumber" ), &g_iWaypointRangeRingsNumber )

    CHECK_FLT( _T ( "WaypointRangeRingsStep" ), &g_fWaypointRangeRingsStep, .1 )

    CHECK_INT( _T ( "WaypointRangeRingsStepUnits" ), &g_iWaypointRangeRingsStepUnits );
    
//    wxString l_wxsWaypointRangeRingsColour;
//    CHECK_STR( _T( "WaypointRangeRingsColour" ), &l_wxsWaypointRangeRingsColour );
//    g_colourWaypointRangeRingsColour.Set( l_wxsWaypointRangeRingsColour );


    CHECK_INT( _T ( "ConfirmObjectDeletion" ), &g_bConfirmObjectDelete );

    // Waypoint dragging with mouse
    CHECK_INT( _T ( "WaypointPreventDragging" ), &g_bWayPointPreventDragging );

    CHECK_INT( _T ( "EnableZoomToCursor" ), &g_bEnableZoomToCursor );

    CHECK_FLT( _T ( "TrackIntervalSeconds" ), &g_TrackIntervalSeconds, 1 )

    CHECK_FLT( _T ( "TrackDeltaDistance" ), &g_TrackDeltaDistance, .1 )

    CHECK_INT( _T ( "TrackPrecision" ), &g_nTrackPrecision );

    //CHECK_STR( _T ( "NavObjectFileName" ), m_sNavObjSetFile );

    CHECK_INT( _T ( "RouteLineWidth" ), &g_route_line_width );
    CHECK_INT( _T ( "TrackLineWidth" ), &g_track_line_width );
    
//     wxString l_wxsTrackLineColour;
//     CHECK_STR( _T( "TrackLineColour" ), l_wxsTrackLineColour )
//         g_colourTrackLineColour.Set( l_wxsTrackLineColour );

    CHECK_STR( _T ( "DefaultWPIcon" ), g_default_wp_icon )

    // S57 template items
    
    #define CHECK_BFN(s, t)         conf->Read( s , &read_int); \
                                    bval = t; \
                                    bval0 = read_int != 0; \
                                    if( bval != bval0 ) return false;

    #define CHECK_IFN(s, t)         conf->Read( s , &read_int); \
                                    if( read_int != t ) return false;

    #define CHECK_FFN(s, t)         conf->Read( s , &dval); \
                                    if( fabs(dval - t) > 0.1) return false;
                                    
    if( ps52plib ){
    
        int read_int;
        double dval;
        bool bval, bval0;
        
        conf->SetPath( _T ( "/Settings/GlobalState" ) );

        CHECK_BFN( _T ( "bShowS57Text" ), ps52plib->GetShowS57Text() );
       
        CHECK_BFN( _T ( "bShowS57ImportantTextOnly" ), ps52plib->GetShowS57ImportantTextOnly() );
        CHECK_BFN( _T ( "bShowLightDescription" ), ps52plib->m_bShowLdisText );
        CHECK_BFN( _T ( "bExtendLightSectors" ), ps52plib->m_bExtendLightSectors );
        CHECK_BFN( _T ( "bShowSoundg" ), ps52plib->m_bShowSoundg );
        CHECK_BFN( _T ( "bShowMeta" ), ps52plib->m_bShowMeta );
        CHECK_BFN( _T ( "bUseSCAMIN" ), ps52plib->m_bUseSCAMIN );
        CHECK_BFN( _T ( "bShowAtonText" ), ps52plib->m_bShowAtonText );
        CHECK_BFN( _T ( "bDeClutterText" ), ps52plib->m_bDeClutterText );
        CHECK_BFN( _T ( "bShowNationalText" ), ps52plib->m_bShowNationalTexts );
        CHECK_IFN( _T ( "nDisplayCategory" ), ps52plib->GetDisplayCategory() );
        CHECK_IFN( _T ( "nSymbolStyle" ), ps52plib->m_nSymbolStyle );
        CHECK_IFN( _T ( "nBoundaryStyle" ), ps52plib->m_nBoundaryStyle );
        CHECK_FFN( _T ( "S52_MAR_SAFETY_CONTOUR" ), S52_getMarinerParam( S52_MAR_SAFETY_CONTOUR ));
        CHECK_FFN( _T ( "S52_MAR_SHALLOW_CONTOUR" ), S52_getMarinerParam( S52_MAR_SHALLOW_CONTOUR ));
        CHECK_FFN( _T ( "S52_MAR_DEEP_CONTOUR" ), S52_getMarinerParam( S52_MAR_DEEP_CONTOUR ));
        CHECK_FFN( _T ( "S52_MAR_TWO_SHADES" ), S52_getMarinerParam( S52_MAR_TWO_SHADES ));
        CHECK_INT( _T ( "S52_DEPTH_UNIT_SHOW" ), &g_nDepthUnitDisplay );
        
        //    S57 Object Class Visibility
        
        OBJLElement *pOLE;
        
        conf->SetPath( _T ( "/Settings/ObjectFilter" ) );
        
        unsigned int iOBJMax = conf->GetNumberOfEntries();
        
        if(iOBJMax != ps52plib->pOBJLArray->GetCount() )
            return false;
           
        if( iOBJMax ) {
            
            wxString str, sObj;
            long val;
            long dummy;
            
            bool bCont = conf->GetFirstEntry( str, dummy );
            while( bCont ) {
                conf->Read( str, &val );              // Get an Object Viz
                
                // scan for the same key in the global list
                bool bfound = false;
                if( str.StartsWith( _T ( "viz" ), &sObj ) ) {
                    for( unsigned int iPtr = 0; iPtr < ps52plib->pOBJLArray->GetCount(); iPtr++ ) {
                        pOLE = (OBJLElement *) ( ps52plib->pOBJLArray->Item( iPtr ) );
                        if( !strncmp( pOLE->OBJLName, sObj.mb_str(), 6 ) ) {
                            bfound = true;
                            if(pOLE->nViz != val){
                                return false;
                            }
                        }
                    }
                    
                    if(!bfound)
                        return false;
                }
                bCont = conf->GetNextEntry( str, dummy );
            }
        }
    }
    
    conf->SetPath( _T ( "/MMSIProperties" ) );
    int iPMax = conf->GetNumberOfEntries();
    if( iPMax ) {
        wxString str, val;
        long dummy;
        
        bool bCont = conf->GetFirstEntry( str, dummy );
        while( bCont ) {
            conf->Read( str, &val );              // Get an entry

            bool bfound = false;
            for(unsigned int j=0 ; j < g_MMSI_Props_Array.GetCount() ; j++){
                MMSIProperties *pProps = g_MMSI_Props_Array.Item(j);
                if(pProps->Serialize().IsSameAs( val )){
                    bfound = true;
                    break;
                }
            }
            if(!bfound)
                return false;
                
            bCont = conf->GetNextEntry( str, dummy );
        }
    }

    return rv;
}

