/***************************** LICENSE START ***********************************

 Copyright 2012 ECMWF and INPE. This software is distributed under the terms
 of the Apache License version 2.0. In applying this license, ECMWF does not
 waive the privileges and immunities granted to it by virtue of its status as
 an Intergovernmental Organization or submit itself to any jurisdiction.

 ***************************** LICENSE END *************************************/

// File MvIconDataBase
// Gilberto Camara - ECMWF Jun 97
//
// .NAME:
//  MvIconDataBase
//
// .AUTHOR:
//  Gilberto Camara and Fernando Ii
//
// .SUMMARY:
//  Implements a data base of Data Units and VisDefs
//  and a m:n relation between a DataUnit and a VisDef
//
// .CLIENTS:
//  Presentable
//
// .RESPONSABILITIES:
//  - Store the dataunits and visdef,
//  - Retrieve them based on a key (Id) or an icon name
//  - Given a DataUnit, retrieve the corresponding VisDef
//
// .COLLABORATORS:
//  MvIcon, STL classes (list, multimap)
//
// .BASE CLASS:
//
// .DERIVED CLASSES:
//
// .REFERENCES:
//
#pragma once

#include <list>
#include <map>
#include <string>

#include "MvIcon.h"

// Relation types
// Variablel MV_PREL_COUNT__ is hardcoded. If the list of relations
// below is updated this variable needs to be updated too accordingly.
const int MV_PREL_COUNT__ = 7;
enum
{
    PRES_DATAUNIT_REL,
    PRES_VISDEF_REL,
    PRES_TEXT_REL,
    PRES_LEGEND_REL,
    PRES_IMPORT_REL,
    PRES_VIEW_REL,
    PRES_LAYER_REL,
    DATAUNIT_VISDEF_REL,
    ICON_LAYER_REL,
    REL_COUNT__
};

// Icon list types
enum
{
    DB_DATAUNIT,
    DB_VISDEF,
    DB_TEXT,
    DB_LEGEND,
    DB_LAYER,
    DB_IMPORT,
    DB_VIEW,
    DB_COUNT__
};

//  Definitions for the Icon List
using MvIconList = std::list<MvIcon>;

//  Definitions for the Link List
using MvLinkList = std::list<std::string>;

// Definitions of the iterators that will loop through the lists
using MvListCursor = MvIconList::iterator;

// Definition for a relation to store m:n relationships
using MvRelation = std::multimap<int, int>;

// Definition for the pairs of entries in the relation
using MvEntryPair = MvRelation::value_type;

// Definition for the iterator that loops through the relation pairs
using MvRelationCursor = MvRelation::iterator;

// Definition for a relation to store m relationships
using MvMapRelation = std::map<int, MvIconList>;

// Definition for the pairs of entries in the MvMapRelation
using MvMapEntryPair = MvMapRelation::value_type;

// Definition for the iterator that loops through the MvMapRelation pairs
using MvMapRelationCursor = MvMapRelation::iterator;

class MvIconDataBase
{
public:
    // Contructors
    MvIconDataBase() = default;
    MvIconDataBase(const MvIconDataBase&);

    // Destructor
    ~MvIconDataBase();

    //---------------------------------------------
    // --- Methods for the Data Unit
    //---------------------------------------------

    // Inserts a new DataUnit into the DataUnit List
    bool InsertDataUnit(MvIcon& newDataUnit, int presentableId = 0);


    //---------------------------------------------
    // --- Methods for the VisDef
    //---------------------------------------------

    // Inserts a new VisDef into the VisDef List
    bool InsertVisDef(MvIcon& newVisDef);


    //---------------------------------------------
    // --- Methods for the Layer
    //---------------------------------------------

    // Set info
    bool LayerInfo(int, const char*, int);
    bool IconInfo(int, const char*, int);

    bool LayerTransparency(int id, int val)
    {
        return LayerInfo(id, "TRANSPARENCY", val);
    }

    bool LayerVisibility(int id, int val)
    {
        return LayerInfo(id, "VISIBILITY", val);
    }

    bool LayerStackingOrder(int id, int val)
    {
        return LayerInfo(id, "STACKING_ORDER", val);
    }

    bool IconTransparency(int id, int val)
    {
        return IconInfo(id, "TRANSPARENCY", val);
    }

    bool IconVisibility(int id, int val)
    {
        return IconInfo(id, "VISIBILITY", val);
    }

    bool IconStackingOrder(int id, int val)
    {
        return IconInfo(id, "STACKING_ORDER", val);
    }

    // Retrieve info
    int LayerInfo(int, const char*);
    int IconInfo(int, const char*);

    int LayerTransparency(int id)
    {
        return LayerInfo(id, "TRANSPARENCY");
    }

    int LayerVisibility(int id)
    {
        return LayerInfo(id, "VISIBILITY");
    }

    int LayerStackingOrder(int id)
    {
        return LayerInfo(id, "STACKING_ORDER");
    }

    int IconTransparency(int id)
    {
        return IconInfo(id, "TRANSPARENCY");
    }

    int IconVisibility(int id)
    {
        return IconInfo(id, "VISIBILITY");
    }

    int IconStackingOrder(int id)
    {
        return IconInfo(id, "STACKING_ORDER");
    }

    int LayerIndex()
    {
        return layerList_.size();
    }

    bool RetrieveIconFromLayer(int, MvIcon&);

    //---------------------------------------------
    // --- Methods for the DataUnit-VisDef Relation
    //---------------------------------------------

    // Rewinds the cursor
    void DataUnitVisDefRelationRewind()
    {
        duvdRelationCursor_ = dataUnitVisDefRelation_.begin();
    }

    // Retrieves the next VisDef, from the current cursor position,
    // given a Data Unit ID
    bool NextVisDefByDataUnitId(const int dataunitId, MvIcon& theVisDef);

    // Retrieve all visdefs associated a data unit
    bool RetrieveVisDefList(const MvIcon& dataUnit, MvIconList& visdefList);

    // Remove all visdefs associated to a data unit
    bool RemoveAllVisDefsByDataUnit(MvIcon& dataUnit, const MvRequest* vd = nullptr);

    // Remove all visdefs associated to a data unit list
    // according to its class (if defined)
    void RemoveAllVisDefsByDataUnitList(MvIconList& dataUnitList, const MvRequest* vd = nullptr);

    // Remove Data Unit from the database
    void RemoveDataUnit(MvIcon& theDataUnit);

    // Remove all Data Units, associated with a specific
    // presentable Id, from the database
    void RemoveDataUnit(const int presentableId);

    // Remove all Data Units from the database
    void RemoveDataUnit();

    // Remove all VisDefs, associated with a specific
    // presentable Id and for a given class (if presente),
    // from the database
    void RemoveVisDef(const int presentableId, const MvRequest* vd = nullptr);

    // Remove all VisDefs  from the database
    void RemoveVisDef();


    //--------------------------------------------------
    // --- Methods for the Presentable-VisDef Relation
    //--------------------------------------------------

    // Rewinds the cursor
    void PresentableVisDefRelationRewind()
    {
        prvdRelationCursor_ = presentableVisDefRelation_.begin();
    }

    // Retrieves the next VisDef, from the current cursor position,
    // given a Presentable Id
    bool NextVisDefByPresentableId(const int presentableId, MvIcon& theVisDef);

    // Retrieve the visdef list associated to a data unit plus its n-dimensional
    // flag and a presentable
    bool VisDefListByDataUnitAndPresentableId(const int presentableId, const char* dataUnitName, int, MvIconList& visdefList);

    // Remove VisDefs associated to a presentable, given a
    // certain class (if selected)
    void RemoveVisDefFromPresRel(const int presentableId, const MvRequest* vd = nullptr);


    //--------------------------------------------------
    // --- Methods for the Presentable-DataUnit Relation
    //--------------------------------------------------

    // Rewinds the cursor
    void PresentableDataUnitRelationRewind()
    {
        prduRelationCursor_ = presentableDataUnitRelation_.begin();
    }

    // Retrieves the next DataUnit, from the current cursor position,
    // given a Presentable Id
    bool NextDataUnitByPresentableId(const int presentableId, MvIcon& theVisDef);

    // Verify if there is any DataUnit related to the Presentable Id
    bool PresentableHasData(const int presentableId);


    //--------------------------------------------------------
    // --- Methods which apply to both the Presentable-VisDef
    //     and Presentable-DataUnit Relations
    //--------------------------------------------------------

    // Removes all data units, given an Id
    bool RemoveAllDataUnitsFromPresRel(MvIcon& theDataUnit);

    // Removes Presentable-DataUnit Relation given the identification
    bool RemoveDataUnitFromPresRel(MvIcon& theDataUnit, int presentableId);

    //  Removes all entries which are related to the presentable
    void RemovePresentable(const int PresentableId);

    //--------------------------------------------------
    // --- Method for dealing with dataRequests
    //--------------------------------------------------

    // Includes dataunits from a request
    MvIcon InsertDataUnit(const MvRequest&, int presentableId = 0, int index = -1);

    // Inserts a visdef
    void InsertVisDef(MvIcon&, const int, MvIcon&);
    MvIcon InsertVisDef(const MvRequest&, const int, MvIcon&);
    void InsertVisDef(MvIcon&, const int);

    //--------------------------------------------------
    // --- General methods
    //--------------------------------------------------

    // Removes all data (DataUnit,VisDef,PText)
    void RemoveAllData();

    // Prints the Data Base contents
    void Print();

    //-----------------------------------------------------------------
    // --- General methods to retrieve, remove, update, replace and insert info
    //-----------------------------------------------------------------

    // Retrieve one icon giving a relation id
    bool RetrieveIcon(const int, const int, MvIcon&);

    // Retrive all icons related to a giving relation id
    int RetrieveIcon(const int, const int, MvIconList&);

    // Retrieve an icon from its list giving an id
    bool RetrieveIconFromList(const int, const int, MvIcon&);

    // Retrieve all Layers related to a giving presentable id
    int RetrieveIcon(const int, MvIconList&);
    int RetrieveIcon1(const int, MvIconList&);

    // Get icon list
    MvIconList* IconList(const int);

    // Insert an icon (relation, list and layer) giving a relation id
    void InsertIcon(const int, const int, MvIcon&, bool, const int = -1);

    // Insert an icon (relation and list) giving a relation id.
    // index = position in the tree (-1 = add it in the end but before foreground)
    // exclusive = false: add it to the list
    //             true : delete all existing icons and then insert it
    void InsertIcon(const int, const int, MvIcon&, const int index = -1, bool exclusive = false);

    // Insert a Text icon (relation and list) giving a relation id (presentable id)
    // index = position in the tree (-1 = add it into the end but before foreground)
    // This function is particular to insert icons of type Text because:
    // a) if parameter TEXT_MODE = TITLE then only one instance is allowed, i.e.,
    //    replace the existing icon.
    // b) otherwise, add this icon to the plot engine (multiple texts)
    void InsertIconText(const int, MvIcon&, const int index = -1);

    // Insert an icon to its list
    void InsertIcon(const int, const MvIcon&, const int);

    // Insert a relation-icon entry
    void InsertIconRelation(const int, const int, const int);

    // Insert the layer icon
    void InsertLayerIcon(const int, MvIcon&, int);

    // Check if icon exists
    bool CheckIcon(const int, const int);

    // Removes one icon from the database
    bool RemoveOneIcon(const int);

    // Remove all icons from the database given a relation type
    void RemoveIcon(const int);

    // Remove icon(s) from the database given a relation type and id.
    // If a iconId is also given then only that icon will be removed.
    void RemoveIcon(const int, const int, const int iconId = -1);

    // Remove an icon from its list giving an id
    void RemoveIconFromList(const int, const int);

    // Removes all icons from the icons pair relation
    bool RemoveIconFromRel(const int, const int);

    // Updates the icon request, given its unique Id
    bool UpdateIcon(const int, const int, const MvRequest&);

    // Updates the icon request, given its unique Id
    bool UpdateIcon(const int, MvRequest&);

    //-----------------------------------------------------------------
    // --- Methods for dealing with searches
    //-----------------------------------------------------------------

    // Find an icon given its ID
    bool FindIcon(int, MvIcon&);

    // Find an icon given its name
    bool FindIcon(const std::string&, MvIcon&);

    // Find icon type id.
    // Returns -1 if icon type not found
    int FindIconTypeId(int);

    // Find the Presentable Id associated to a given icon Id.
    // If input icon is a visdef and if it is connected to a DataUnit,
    // not to a Presentable, then returns the PresentableId associated
    // to its DataUnit and the second argument returns its DataUnitId
    int FindPresentableId(int, int&);

private:
    // No copy allowed
    MvIconDataBase& operator=(const MvIconDataBase&);

    // Utility functions for adding icons only if they do not already exist
    bool InsertIfNew(MvIcon&, MvIconList&, MvRelation& relation, int relationId = 0);
    void RelationInsertIfNew(MvRelation& relation, const int firstId, const int secondId);
    bool ExistsInRelation(MvRelation& relation, const int firstId, const int secondId);

    // All the data links are created by CreateLink routine and they
    // will be removed by calling DeleteLink in the Destructor
    void CreateLink(MvRequest&);
    void DeleteLink();

    // Utility functions for handling Relations and Lists
    MvRelation* IconRelation(const int);
    int IconType(const int);

    // Members
    // Definitions for the objects lists
    MvIconList dataunitList_,
        visdefList_,
        textList_,
        legendList_,
        layerList_,
        importList_,
        viewList_;

    // Definitions for the DataUnit - VisDef pairs
    // Each DataUnit may be related to one or more VisDefs
    MvRelation dataUnitVisDefRelation_;
    MvRelationCursor duvdRelationCursor_;

    // Definition for the Presentable - VisDef Relation
    MvRelation presentableVisDefRelation_;
    MvRelationCursor prvdRelationCursor_;

    // Definition for the Presentable - DataUnit Relation
    MvRelation presentableDataUnitRelation_;
    MvRelationCursor prduRelationCursor_;

    // Definition for the Presentable - PText Relation
    MvRelation presentableTextRelation_;

    // Definition for the Presentable - Legend Relation
    MvRelation presentableLegendRelation_;

    // Definition for the Presentable - Layer Relation
    MvMapRelation presentableLayerRelation_;

    // Definition for the Presentable - Import Relation
    MvRelation presentableImportRelation_;

    // Definition for the Presentable - View Relation
    MvRelation presentableViewRelation_;

    // Definition for the Layer - Icon Relation
    MvRelation iconLayerRelation_;

    // List of dataunit links
    MvLinkList linkList_;
};
