/***********************************************************************
**
**   mapcontents.h
**
**   This file is part of KFLog2.
**
************************************************************************
**
**   Copyright (c):  2000 by Heiner Lamprecht, Florian Ehinger
**
**   This file is distributed under the terms of the General Public
**   Licence. See the file COPYING for more information.
**
**   $Id: mapcontents.h,v 1.27 2004/06/24 19:56:29 axel Exp $
**
***********************************************************************/

#ifndef MAPCONTENTS_H
#define MAPCONTENTS_H
#include "targets.h"

#include <qbitarray.h>
#include <qfile.h>
#include <qlist.h>
#include <qsortedlist.h>
#include <qobject.h>
#include <qstrlist.h>
#include <qguardedptr.h>
#include <qdatetime.h>
#include <qcstring.h>
#include <qmap.h>

#include "flighttask.h"
#include "mapelementlist.h"
#include "waitscreen.h"

class Airport;
class Airspace;
class Flight;
class GliderSite;
class Isohypse;
class LineElement;
class RadioPoint;
class SinglePoint;
class Distance;

/**
 * @short Entry in the isolist
 *
 * This class contains a @ref QRegion and a height. A list of entries
 * like this is created when the map is drawn, and is used to detect the
 * elevation at a given position, for instance under the mousecursor.
 *
 */
 
class isoListEntry {
  public:
    /**
     * Constructor.
     * @param region Region in coordinate system of the map-object, not in KFLog system
     * @param height the elevation of the isoline in meters
     */
    isoListEntry(QRegion* region=0, int height=0);
    /**
     * Destructor
     */
    virtual ~isoListEntry();
  
    bool operator == (const isoListEntry& x) {return x.height==height;}
    bool operator >= (const isoListEntry& x) {return x.height>=height;}
    bool operator <= (const isoListEntry& x) {return x.height<=height;}
    bool operator < (const isoListEntry& x) {return x.height<height;}
    bool operator > (const isoListEntry& x) {return x.height>height;}
    
    QRegion* region;
    int height;
};

/**
 * This class provides functions for accessing the contents of the map.
 * It takes control over loading all needed map-files.
 * The class contains several QLists holding the mapelements.
 *
 * @author Heiner Lamprecht, Florian Ehinger
 * @version $Id: mapcontents.h,v 1.27 2004/06/24 19:56:29 axel Exp $
 */
class MapContents : public QObject
{
  Q_OBJECT

  public:
    /**
     * Creates a new MapContents-object.
     */
    //MapContents(QObject*);
    MapContents(QObject*, WaitScreen * waitscreen);
    /**
     * Destructor, deletes all lists.
     */
    virtual ~MapContents();
    /**
     * @return the current length of the given list.
     *
     * @param  listIndex  the index of the list.
     */
    unsigned int getListLength(int listIndex) const;
    /**
     * Proofes, which mapsections are needed to draw the map and loads
     * the missing sections.
     */
    void proofeSection();
    /**
     * @return a pointer to the BaseMapElement of the given mapelement in
     *         the list.
     *
     * @param  listIndex  the index of the list containing the element
     * @param  index  the index of the element in the list
     */
    BaseMapElement* getElement(int listIndex, unsigned int index);
    /**
     * @return a pointer to the given airspace
     *
     * @param  index  the list-index of the airspace
     */
    Airspace* getAirspace(unsigned int index);
    /**
     * @returns a pointer to the given glidersite
     *
     * @param  index  the list-index of the glidersite
     */
    GliderSite* getGlidersite(unsigned int index);
    /**
     * @return a pointer to the given airport
     *
     * @param  index  the list-index of the airport
     */
    Airport* getAirport(unsigned int index);
    /**
     * @return a pointer to the SinglePoint of the given mapelement
     *
     * @param  listIndex  the index of the list containing the element
     * @param  index  the index of the element in the list
     */
    SinglePoint* getSinglePoint(int listIndex, unsigned int index);
    /**
     * Draws all elements of a list into the painter.
     *
     * @param  targetP  The painter to draw the elements into
     * @param  maskP  The maskpainter of targetP
     * @param  listID  The index of the list to be drawn
     */
    void drawList(QPainter* targetPainter, QPainter* maskPainter,
        unsigned int listID);
    /**
     * Draws all isohypses into the given painter
     *
     * @param  targetP  The painter to draw the elements into
     * @param  maskP  The maskpainter of targetP
     */
    void drawIsoList(QPainter* targetP, QPainter* maskP);
    /**
     * Prints the whole content of the map into the given painter.
     *
     * @param  targetP  The painter to draw the elements into
     *
     * @param  isText  Shows, if the text of some mapelements should
     *                 be printed.
     */
    void printContents(QPainter* targetP, bool isText);
    /**
     * Loads a new flight-file.
     *
     * @param  file  The path to the igc-file
     * @return "true", when the file has successfully been loaded
     */
//    bool loadFlight(QFile);
    /**
     * @return a pointer to the current flight
     */
    BaseFlightElement* getFlight();
    /**
     * @return a pointer to the current flight index
     */
//    int getFlightIndex() { return flightList.at(); };
    /**
     * @returns the flightList
     */
//    QList<BaseFlightElement>* getFlightList();
    /**
     * @returns the wpList
     */
	QList<wayPoint>* getWaypointList()  {  return &wpList;  };

    /**
     * Searches the first point of the current flight, which distance to the
     * mousecursor is less than 30 pixel. If no point is found, -1 is
     * returned.
     *
     * @see Flight::searchPoint
     *
     * @param  cPoint  The map-position of the mousecursor.
     * @param  searchPoint  A pointer to a flightpoint. Will be filled
     *                      with the flightpoint found.
     *
     * @return the index of the flightpoint or -1 if no point is found.
     */
    int searchFlightPoint(QPoint cPos, flightPoint& fP);
    /**
     * Converts the longitute or latitute into the internal format.
     *
     * @param  degree  The position to be converted. The string must
     *                 have the format:<BR>
     *                 <TT>[g]gg.mm'ss"X</TT> where <TT>g</TT>, <TT>m</TT>,
     *                 <TT>s</TT> are any digits from 0 to 9 and <TT>X</TT>
     *                 is one of N, S, E, W.
     */
    static int degreeToNum(QString degree);
  /** No descriptions */
  bool importFlightGearFile(QFile flightgearFile);
  /** Imports a file downloaded with Gardown in DOS  */
  bool importGardownFile(QFile gardownFile);
  /** Write property of FlightTask * currentTask. */
  virtual void setCurrentTask( FlightTask * _newVal);
  /** Read property of FlightTask * currentTask. */
  virtual const FlightTask * getCurrentTask();
  /** Returns true if the coordinates of the waypoint in the argument matches one of the waypoints in the list. */
  bool getIsInWaypointList(const wayPoint * wp);
  /** No descriptions */

  /** read a task file and append all tasks to flight list
switch to first task in file */
//  bool loadTask(QFile path);
    /**
		 * Get the contents of the next FlightPoint after number 'index'
	   */
//    int searchGetNextFlightPoint(int index, flightPoint & fP);
    /**
		 * Get the contents of the previous FlightPoint before number 'index'
	   */
//    int searchGetPrevFlightPoint(int index, flightPoint & fP);
		/**
		 * Get the contents of the next FlightPoint 'step' indexes after number 'index'
		 */
//  	int searchStepNextFlightPoint(int index, flightPoint & fP, int step);
  	/**
		 * Get the contents of the previous FlightPoint 'step' indexes before number 'index'
		 */
//  	int searchStepPrevFlightPoint(int index,  flightPoint & fP, int step);
    /**
     * The index of Mapelement-Lists.
     */
    enum MapContentsListID {NotSet = 0, AirportList, GliderList,
        AddSitesList, OutList, NavList, AirspaceList, ObstacleList, ReportList,
        CityList, VillageList, LandmarkList, HighwayList, HighwayEntryList,
	RoadList, RailList, StationList, HydroList, LakeList, TopoList, IsohypseList,
        WaypointList, DigitList, FlightList};

	/** Add a point to a rectangle, so the rectangle will be the bounding box
	  * of all points added to it. If the point allready lies within the borders
	  * of the QRect, the QRect is unchanged. If the point is outside the
	  * defined QRect, the QRox will be modified so the point lies inside the
	  * new QRect. If the QRect is empty, the QRect will be set to a rect of
	  * size (1,1) at the location of the point. */
	void MapContents::AddPointToRect(QRect& rect, const QPoint& point);

	/** Returns list of IsoHypse Regions */
	inline QSortedList<isoListEntry>* getIsohypseRegions(){return &regIsoLines;};
  	/** returns ground elevation in meters
	  * If the error argument is given, it will be set to the errormargin for the
	  * returned value. */
	int findElevation(const QPoint& coord, Distance * errorDist=0);
	/**
	 * Deletes all currently not-needed mapsections from memory
	 */
	void unloadMaps(unsigned int=0);
	/**
	 * Deletes all mapitems that are not in the sectionArray from the given list.
	 * Used by @ref unloadMaps to do the actual deleting.
	 */
	void unloadMapObjects(QList<LineElement> * list);
	void unloadMapObjects(QList<SinglePoint> * list);
	void unloadMapObjects(QList<RadioPoint> * list);
	void unloadMapObjects(QList< QList<Isohypse> > * list);

  public slots:
    /**
     * Close current flight
     */
//    void closeFlight();
    /** No descriptions */
//    void slotSetFlight(int id);
    /** No descriptions */
//    void slotSetFlight(BaseFlightElement *);
    /** create a new, empty flight group */
//    void slotNewFlightGroup();
    /** create a new, empty task */
//    void slotNewTask();
    /** No descriptions */
//    void slotEditFlightGroup();
    /** */
    void slotReloadMapData();

  signals:
    /**
     * emitted during maploading to display a message f.e. in the
     * splash-screen of the mainwindow.
     */
    void loadingMessage(const QString& message);
    /** signal that a new flight/task/flight group become active */
    void currentFlightChanged();
    /** signal that a new task has been created */
    void newTaskAdded(FlightTask *);
    /**
     * Emitted, when no mapfiles are found, or the when the map-directories
     * do not exists.
     */
    void errorOnMapLoading();

    /*
      *
      * Activates the graphical planning
      */
    void activatePlanning();

    /** Emitted if a new file is being loaded. */
    void loadingFile(const QString&);
    /** Emitted if an object has been loaded. */
    void progress(int);
    /** Emitted before loading maps */
    void majorAction(const QString&);
    /** Emitted after reload of map data */
    void mapDataReloaded();

  private:
    /**
     * Reads a binary map file containing airfields.
     *
     * @param  fileName  The path and name of the airfield-file.
     */
    bool __readAirfieldFile(const QString& pathName);

    /**
     * Reads a binary map file containing airspaces.
     *
     * @param  fileName  The path and name of the airspace-file.
     */
    bool __readAirspaceFile(const QString& pathName);

    /**
     * Reads a new binary map file.
     *
     * @param  fileSecID  The sectionID of the mapfile
     * @param  fileTypeID  The typeID of the mapfile ("G" for ground-data,
     *                     "M" for additional mapdata and "T" for
     *                     terraindata)
     *
     * @return "true", when the file has successfully been loaded
     */
    bool __readBinaryFile(const int fileSecID, const char fileTypeID);

    /**
     * Reads a new binary terrain-map file.
     *
     * @param  fileSecID  The sectionID of the mapfile
     * @param  fileTypeID  The typeID of the mapfile ("G" for ground-data,
     *                     "M" for additional mapdata and "T" for
     *                     terraindata)
     *
     * @return "true", when the file has successfully been loaded
     */
    bool __readTerrainFile(const int fileSecID, const int fileTypeID);

    /**
     * Reads a new ascii map file.
     *
     * NOTE: This function is obsolete and will be removed in further
     * releases!!!
     *
     * @param  fileName  The name of the mapfile
     *
     * @return "true", when the file has successfully been loaded
     */
    // bool __readAsciiFile(const char* fileName);

    /**
     * airportList contains all airports.
     */
//    QList<Airport> airportList;
    MapElementList airportList;

    /**
     * gliderList contains all glider-sites.
     */
//    QList<GliderSite> gliderList;
    MapElementList gliderList;

    /**
     * addSitesList contains all, ultra-light,
     * hang-glider-sites, free-ballon-sites, parachute-jumping-sites.
     */
    QList<SinglePoint> addSitesList;
//    MapElementList addSitesList;

    /**
     * outList contains all outlanding-fields.
     */
//    QList<SinglePoint> outList;
    MapElementList outList;

    /**
     * navList contains all radio navigation facilities.
     */
    QList<RadioPoint> navList;
//    MapElementList navList;

    /**
     * airspaceList contails all airspaces.
     */
    QList<Airspace> airspaceList;
//  there are different airspaces with same name ! Don't use MapElementList, it would sort them out.
//    MapElementList airspaceList;

    /**
     * obstacleList contains all obstacles and -groups, as well
     * as the spots and passes.
     */
    QList<SinglePoint> obstacleList;

    /**
     * reportList contains all reporting points.
     */
    QList<SinglePoint> reportList;

    /**
     * cityList contails all cities.
     */
    QList<LineElement> cityList;

    /**
     * villageList contains all villages.
     */
    QList<SinglePoint> villageList;

    /**
     * landmarkList contains all landmarks.
     */
    QList<SinglePoint> landmarkList;

    /**
     * highwayList contails all highways.
     */
    QList<LineElement> highwayList;

    /**
     * roadList contails all roads.
     */
    QList<LineElement> roadList;
    /**
     * railList contains all railways and aerial railways.
     */
    QList<LineElement> railList;
    /**
     * stationList contains all stations.
     */
//    QList<SinglePoint> stationList;
    /**
     * hydroList contains all shorelines, rivers, ...
     */
    QList<LineElement> hydroList;
    /**
     * hydroList contains all lakes, ...
     */
    QList<LineElement> lakeList;
    /**
     * topoList contains all topographical objects.
     */
    QList<LineElement> topoList;
    /**
     * isohypseList contains all isohypses.
     */
    QList< QList<Isohypse> > isoList;
    /** */
//    QList<BaseFlightElement> flightList;
    /*
	 * This list is reset every time the current WaypointCatalog is changed.
	 */
    QList<wayPoint> wpList;
    /**
     * List of all map-sections. Contains a "1" for all fully loaded section-files,
     * otherwise "0".
     */
    QBitArray sectionArray;
    /**
     * QMap of all partially loaded maptiles. These maptiles are marked as not loaded
     * in the sectionArray above. Partially loaded tiles (each tile currently consists of
     * a maximum of three files) can occur when Cumulus runs out of free memory. The
     * proofeSection routine uses this QMap to determine if it really needs to load a
     * specific file for that tile.
     */
    typedef QMap<int, char> TilePartMap;
    TilePartMap tilePartMap;
    /**
     * True if an unload call has allready been made this 'round' of mapdrawing.
     */
    bool unloadDone;
    /**
     * True if even after the unload, there is still not enough free memory, so new maps
     * may not be loaded.
     */
    bool memoryFull;
    /**
     * Array containing the evevations of all possible isohypses.
     */
    static const int isoLines[];
    /** */
    QString mapDir1;
    QString mapDir2;
    QString mapDir3;

        /** Should be deleted somtime ... */
    bool isFirst;
    /** generate new task name */
    QString genTaskName();
  /**
    * This function checks all possible mapdirectories for the mapfile.
    * If found, it returns true and returns the complete path in pathName.
    */
  bool locateFile(const QString& fileName, QString & pathName);
  /**
    * this function serves as a substitute for the not existing QDir::entryInfoList with complete path information
    */
  void addDir(QStringList& list, const QString& path, const QString& filter);

  /** JD
    * This function extracts the QDateTime entry from a kfl/kfc file.
    * It doesn't check anything.
    * Need this to identify new kfl files and to 'recompile' them.
    */
  QDateTime getDateFromMapFile( const QString& path );
  /** JD end */

/** @AP: Compares two projection objects for equality.
    Returns true if equal; otherwise false */

  bool compareProjections(ProjectionBase* p1, ProjectionBase* p2);

  QGuardedPtr<WaitScreen> ws;

  /**
    * List of all drawn isohypses.
    */
  QSortedList<isoListEntry> regIsoLines;
  /**
   * Elevation where the next search for the current elevation will start.
   * Set to one level higher than the current level by findElevation().
   */
  int _nextIsoLevel;
  int _lastIsoLevel;
  bool _isoLevelReset;
  isoListEntry* _lastIsoEntry;


protected: // Protected attributes
  /** Contains a reference to the currently selected flighttask */
  FlightTask * currentTask;
};

#endif
