/******************************************************************************
 *
 * Project:  OpenCPN
 * Purpose:  Chart Database Object
 * Author:   David Register
 *
 ***************************************************************************
 *   Copyright (C) 2010 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.             *
 ***************************************************************************
 *
 *
 *
 */

#ifndef __CHARTDB_H__
#define __CHARTDB_H__


#include <wx/xml/xml.h>

#include "chartbase.h"
#include "chartdbs.h"

#define     MAXSTACK          100



// ----------------------------------------------------------------------------
//    Constants, etc.
// ----------------------------------------------------------------------------

typedef struct  {
    float y;
    float x;
} MyFlPoint;


// ----------------------------------------------------------------------------
//    Fwd Declarations
// ----------------------------------------------------------------------------
class ChartBase;

// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------

class ChartStack
{
public:
      ChartStack() { nEntry = 0; CurrentStackEntry = 0; b_valid = false;}

      bool        b_valid;
      int         nEntry;
      int         CurrentStackEntry;
      int         GetCurrentEntrydbIndex(void);
      void        SetCurrentEntryFromdbIndex(int current_db_index);
      int         GetDBIndex(int stack_index);
      void        SetDBIndex(int stack_index, int db_index);
      bool        DoesStackContaindbIndex(int db_index);
      void        AddChart( int db_add );

private:
      int         DBIndex[MAXSTACK];


};

class CacheEntry
{
public:
      wxString    FullPath;
      void        *pChart;
      int         RecentTime;
      int         dbIndex;
      bool        b_in_use;
      int         n_lock;
};



// ----------------------------------------------------------------------------
// Chart Database
// ----------------------------------------------------------------------------

class ChartDB: public ChartDatabase
{
public:

      ChartDB();
      virtual ~ChartDB();


      bool LoadBinary(const wxString & filename, ArrayOfCDI& dir_array_check);
      bool SaveBinary(const wxString & filename) { return ChartDatabase::Write(filename); }

      int  BuildChartStack(ChartStack * cstk, float lat, float lon, int groupIndex);
      int  BuildChartStack(ChartStack * cstk, float lat, float lon, int db_add, int groupIndex );
      bool EqualStacks(ChartStack *, ChartStack *);
      bool CopyStack(ChartStack *pa, ChartStack *pb);
      wxString GetFullPath(ChartStack *ps, int stackindex);
      int  GetStackChartScale(ChartStack *ps, int stackindex, char *buf, int nbuf);
      int  GetCSPlyPoint(ChartStack *ps, int stackindex, int plyindex, float *lat, float *lon);
      ChartTypeEnum GetCSChartType(ChartStack *ps, int stackindex);
      ChartFamilyEnum GetCSChartFamily(ChartStack *ps, int stackindex);
      bool SearchForChartDir(const wxString &dir);
      ChartBase *OpenStackChartConditional(ChartStack *ps, int start_index, bool bLargest, ChartTypeEnum New_Type, ChartFamilyEnum New_Family_Fallback);

      wxArrayPtrVoid *GetChartCache(void) { return pChartCache; }
      std::vector<int> GetCSArray(ChartStack *ps);

      int GetStackEntry(ChartStack *ps, wxString fp);
      bool IsChartInCache(int dbindex);
      bool IsChartInCache(wxString path);
      bool IsChartInGroup(const int db_index, const int group);
      bool IsENCInGroup(const int group);
      bool IsNonMBTileInGroup(const int group);

      ChartBase *OpenChartFromStack(ChartStack *pStack, int StackEntry, ChartInitFlag iflag = FULL_INIT);
      ChartBase *OpenChartFromDB(int index, ChartInitFlag init_flag);
      ChartBase *OpenChartFromDBAndLock(int index, ChartInitFlag init_flag , bool lock = true);
      ChartBase *OpenChartFromDBAndLock(wxString chart_path, ChartInitFlag init_flag);
      ChartBase *OpenChartFromDB(wxString chart_path, ChartInitFlag init_flag);
      
      void ApplyColorSchemeToCachedCharts(ColorScheme cs);
      void PurgeCache();
      void PurgeCachePlugins();
      bool DeleteCacheChart(ChartBase *pChart);

      void LockCache(bool bl){m_b_locked = bl;}
      void LockCache(){m_b_locked = true;}
      void UnLockCache(){m_b_locked = false;}
      bool IsCacheLocked(){ return m_b_locked; }
      wxXmlDocument GetXMLDescription(int dbIndex, bool b_getGeom);

      bool LockCacheChart( int index );
      bool IsChartLocked( int index );
      
      void UnLockCacheChart( int index );
      void UnLockAllCacheCharts();
      
      void ClearCacheInUseFlags(void);
      void PurgeCacheUnusedCharts( double factor );

      bool IsBusy(){ return m_b_busy; }
      bool CheckExclusiveTileGroup( int canvasIndex );
      bool CheckAnyCanvasExclusiveTileGroup( );

protected:
      virtual ChartBase *GetChart(const wxChar *theFilePath, ChartClassDescriptor &chart_desc) const;

private:
      InitReturn CreateChartTableEntry(wxString full_name, ChartTableEntry *pEntry);

      int SearchDirAndAddSENC(wxString& dir, bool bshow_prog, bool bupdate);
      bool CreateS57SENCChartTableEntry(wxString full_name, ChartTableEntry *pEntry, Extent *pext);
      bool CheckPositionWithinChart(int index, float lat, float lon);
      ChartBase *OpenChartUsingCache(int dbindex, ChartInitFlag init_flag);
      CacheEntry *FindOldestDeleteCandidate( bool blog );
      void DeleteCacheEntry(int i, bool bDelTexture = false, const wxString &msg = wxEmptyString);
      void DeleteCacheEntry(CacheEntry *pce, bool bDelTexture = false, const wxString &msg = wxEmptyString);
      
      
      wxArrayPtrVoid    *pChartCache;
      int              m_ticks;

      bool              m_b_locked;
      bool              m_b_busy;

      wxCriticalSection m_critSect;
      wxMutex           m_cache_mutex;
      int               m_checkGroupIndex[2];
      bool              m_checkedTileOnly[2];
};


#endif

