/***************************** 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 *************************************/

//
// .NAME:
//  Presentable
//
// .AUTHOR:
//  Gilberto Camara, Baudoiun Raoult and Fernando Ii
//
// .SUMMARY:
//  Defines an abstract base class for the page hierarchy in PlotMod.
//  The Presentable class is an example of the Composite "pattern".
//
//  Its methods allow for the insertion and removal of nodes and
//  leaves on a tree structure, and also for the drawing method.
//
//  The building of the tree structure, from a description,
//  is done by the Builder class.
//
//  Other applications that use Presentable (such as Matching) are
//  implemented by the Visitor class.
//
// .DESCRIPTION:
//  Refer to the "Design Patterns" book, page 163 for more details
//
//
// .DESCENDENT:
//  Page, SubPage, DataObject, Text, Legend
//
// .RELATED:
//  PlotMod, Builder, Visitor, Device
//
// .ASCENDENT:
//
//

#pragma once

#include <memory>
#include <map>
#include <string>
#include <utility>
#include <vector>

#include "MvRequest.h"
#include "MvIconDataBase.h"
#include "DeviceData.h"
#include "Visitor.h"
#include "PlotModConst.h"
#include "PaperSize.h"
#include "Location.h"
#include "MatchingInfo.h"

class PmContext;
class Canvas;
class GraphicsEngine;
class DrawingPriority;
class PlotModView;
class Presentable;
class ObjectInfo;

using DrawPriorMap = std::map<std::string, std::pair<int, int>>;

using MacroVisDefMap = std::map<int, std::string>;

enum
{
    GETBYDATAUNIT,
    GETBYVISDEF
};

class Presentable
{
public:
    // Contructor
    // Builds a presentable without a request (used for data objects)
    Presentable();

    // Builds a presentable from a Request
    Presentable(const MvRequest& inRequest);

    Presentable(const Presentable&);

    virtual Presentable* Clone() const { return new Presentable(*this); }

    // Destructor
    virtual ~Presentable();

    // Members Information

    // Returns a reference to the object's associated request
    virtual MvRequest& Request() { return myRequest_; }

    // true : presentable is a window (interactive)
    // false: presentable is not a window
    virtual bool IsAWindow() { return myParent_->IsAWindow(); }

    virtual bool HasDrawTask();
    virtual void HasDrawTask(bool yesno) { hasDrawTask_ = yesno; }

    // Draws the presentable
    virtual void Draw();
    virtual void DrawProlog();
    virtual void DrawPageHeader() {}
    virtual void DrawTrailer() {}
    virtual void DrawTrailerWithReq(MvRequest&);
    virtual void DrawTask();       // Ask the server to draw me
    virtual bool CheckDrawTask();  // Check if there is any task to be performed

    // Methods for Inserting and Removing Children
    // Inserts a new child in the tree hierachy
    // Fails if the object is a leaf
    virtual void Insert(Presentable* p);

    // Remove an existing child from the tree hierarchy
    // Fails if the object is a leaf
    virtual void Remove(Presentable* p);

    virtual void CreateReply(MvRequest&) {}

    // Dealing with Drop
    virtual void Drop(PmContext& context);
    virtual void DropSimulate(PmContext& context);

    // Dealing with observers
    void NotifyObservers();

    // Zoom methods
    virtual void ZoomRequestByDef(int, const std::string&) {}
    virtual void ZoomRequestByLevel(int, int) {}
    virtual void ZoomInfo(int&, int&) {}  // "Should not executed this"

    // Layer methods
    virtual bool UpdateLayerTransparency(int, int) { return false; }
    virtual bool UpdateLayerVisibility(int, bool) { return false; }
    virtual bool UpdateLayerStackingOrder(int, int) { return false; }

    // Dealing with Contents
    virtual std::string MacroPlotIndexName(bool = false) { return ""; }
    virtual void contentsRequest(MvRequest&) {}

    virtual std::string Name();
    virtual std::string MacroName();

    // Flag indicanting if drop came from Contents Window or Macro
    virtual void SetDropShouldStay(bool) {}
    virtual bool DropShouldStay() const { return false; }

    virtual void SetContentsDataUnit(int) {}
    virtual int ContentsDataUnit() const { return 0; }

    // Register to draw trailer later
    virtual void RegisterDrawTrailer() {}

    // Remove from tree structure, not database
    virtual void RemoveIcon(MvIcon&) {}
    virtual void RemoveMyData();
    virtual void RemoveAllData() {}
    virtual void RemoveAllDataChildren();

    // Remove icon from tree structure and database
    void RemoveIconWithId(const int);

    // Dealing with Macro
    // Create Macro code from the Display Window
    virtual void GenerateMacro() {}

    // Generate a description of the presentable
    virtual void DescribeYourself(ObjectInfo&) {}

    // Describe the drops (data units and visdefs)
    virtual void DescribeDrops(ObjectInfo&, MacroVisDefMap&);
    virtual void DescribeDrops(ObjectInfo&, MvRequest&);

    // Methods for Handling the Children and the Father
    const Presentable* Parent() const
    {
        return myParent_;
    }

    void Parent(Presentable* pp)
    {
        myParent_ = pp;
    }

    // Return number of children
    int NrOfChildren() const { return childList_.size(); }

    // Methods which traverse the tree hierarchy
    // Finds a sub-branch of the tree hierarchy whose
    // top node has the same ID as "treeNodeId"
    Presentable* FindBranch(const int treeNodeId) const;

    // Finds a sub-branch of the tree hierarchy whose
    // top node has a View specified by "viewName"
    Presentable* FindBranch(std::string viewName);

    // Finds a sub-branch of the tree hierarchy whose
    // top node has a request specified by "requestName"
    void FindBranchesByRequest(std::string requestName, std::vector<Presentable*>& presVec);

    // Finds a sub-branch of the tree hierarchy whose
    // node contains an icon specified by its Id
    Presentable* FindBranchByIconId(int, int&) const;
    int FindBranchIdByIconId(int, int&);

    // Finds the superpage associated to a presentable
    virtual Presentable* FindSuperPage(int index = -1);

    // Informs if the presentable has a dataObject
    virtual bool HasData();

    // Informs if the presentable has a child with a dataObject
    virtual bool ChildHasData();

    // Indicates that a presentable is not matched
    virtual void NotMatched() { hasMatch_ = false; }

    // Indicates that a match has been found for the presentable
    virtual void MatchFound() { hasMatch_ = true; }

    // Retrives the information about the object's matching
    virtual bool HasBeenMatched() { return hasMatch_; }

    // Initializes all of the presentables' children
    // to be un-matched (to be used in the beginning of
    // the matching procedure)
    virtual void InitMatching();

    // Indicates a reference matching info for the presentable
    virtual void SetMatchingInfo(const MatchingInfo& dataInfo)
    {
        matchingInfo_ = dataInfo;
    }

    // Retrive the matching info associated with the treeNode
    virtual const MatchingInfo& GetMatchingInfo() const
    {
        return matchingInfo_;
    }

    // Methods used for Drawing
    // Draws the presentable's children
    virtual void DrawChildren();

    // Store the Layer info
    virtual void DrawLayerInfo(const int, const char* name = nullptr);

    virtual void DrawText() {}

    virtual int PageIndex();

    virtual int PaperPageIndex() const;
    virtual void PaperPageIndexV1(int);

    virtual bool PrintAll() { return false; }
    virtual void PrintAllV1(bool) {}

    virtual int PaperPageNumber(int) { return -1; }

    virtual void DrawDataVisDef() {}

    // Retrieve all requests for the whole tree.
    // The requests have already been built and saved internally, but
    // they are not updated automatically if the layers
    // visibility/order/transparency are modified by the uPlot Sidebar.
    // Boolean checkIconStatus = false means use the saved requests;
    // otherwise, rebuild the requests by analysing the whole tree.
    virtual void GetAllRequests(MvRequest&, bool checkIconStatus = false);

    //   virtual void EraseDraw ( int  = 0 ) {}
    //   virtual void EraseDefaultDraw ();

    // Methods which access the MvIconDataBase
    // This method is used to retrieve a valid visdef. It is called when
    // there are no visual definitions associated to a data unit. If last
    // arg is GETBYDATAUNIT, the first arg is interpreted as a dataunit class.
    // If last arg is GETBYVISDEF, first arg is the visdef class to retrive.
    virtual bool DefaultVisDefList(const char*, MvIconList&, int ndimflag = 0, int type = GETBYDATAUNIT);

    bool CheckValidVisDef(MvIcon&, MvRequest&) { return true; }

    // Retrieve icons/number of icons related to a Layer
    virtual bool RetrieveIconsFromLayer(int, MvIconList&);
    virtual int RetrieveNumberIconsFromLayer(int);

    // Retrieve the Texts associated to the node
    virtual bool RetrieveTextList(MvIconList&);
    virtual bool RetrieveTextTitle(MvIconList&);
    virtual void RetrieveTextAnnotation(MvIconList&);

    // Retrieve the Legend associated to the tree
    virtual bool RetrieveLegend(MvIcon&);

    // Retrieve the Import list associated to the node
    // Returns false if there are no Import icons.
    virtual bool RetrieveImportList(MvIconList&);

    // Retrieves the icon database associated to the
    // tree branch (normally, a superpage)
    virtual MvIconDataBase& IconDataBase() const
    {
        return myParent_->IconDataBase();
    }

    // Retrieve data unit info
    void GetDataUnitInfo(MvRequest&);

    //  Dealing with Devices and GraphicsEngine
    virtual GraphicsEngine& GetGraphicsEngine() const;
    virtual PlotModView& GetView() const;

    // Dealing with Canvas
    virtual Canvas& GetCanvas() const;
    virtual void SetCanvas(Canvas*) {}
    virtual bool HasCanvas() { return false; }

    // Dealing with Printing
    virtual void PendingDrawingsAdd();
    virtual void PendingDrawingsRemove();
    virtual bool PendingDrawings()
    {
        return (pendingDrawings_ != 0);
    }

    void HasReceivedNewpage(bool flag)
    {
        hasNewpage_ = flag;
    }

    bool HasReceivedNewpage() const
    {
        return hasNewpage_;
    }

    // Dealing with DeviceData
    DeviceData* ReleaseDeviceData();
    void SetDeviceData(DeviceData* devdata);
    DeviceData* GetDeviceData() const { return deviceData_.get(); }

    virtual void Visit(Visitor& v) { VisitChildren(v); }

    void VisitChildren(Visitor& v);

    // Set/Get the location for the presentable
    virtual void SetLocation(Location pos) { myLocation_ = pos; }

    Rectangle GetLocation() { return myLocation_; }

    // Members and Object Information
    // true : presentable is visible and will be drawn
    // false: presentable is not visible
    virtual bool IsVisible() { return isVisible_; }

    // Set the visibility for the presentable
    virtual void SetVisibility(bool visibility)
    {
        isVisible_ = visibility;
    }

    // Returns the object's unique identification
    int Id() const { return presentableId_; }

    virtual long PictureId(const char*, bool = false)
    {
        return 0;
    }

    virtual PaperSize GetChildSize(Presentable&);

    virtual PaperSize GetMySize()
    {
        return myParent_->GetChildSize(*this);
    }

    virtual void NeedsRedrawing(bool yesno)
    {
        needsRedrawing_ = yesno;
    }

    virtual bool NeedsRedrawing() { return needsRedrawing_; }

    // Set the projection associated to the canvas
    virtual void SetProjection(const MvRequest&) {}

    virtual bool CanDoZoom() { return false; }

    virtual void SetDrawPriority(MvRequest&) {}

    virtual DrawingPriority& GetDrawPriority();

    // Indicate//determine whether a page is visited in background
    virtual bool VisitInBackground() const { return false; }
    virtual void SetVisitInBackground(bool) {}

    virtual bool RemoveData() { return removeData_; }

    virtual void RemoveData(bool yesno) { removeData_ = yesno; }

    // Used to indicate Contents drop on a window
    bool DroppedHere() { return droppedHere_; }
    void DroppedHere(int Id) { droppedHere_ = (Id == presentableId_); }

    // Insert icons to the database
    virtual bool InsertCommonIcons(const MvRequest&);
    virtual Page* InsertOnePage(MvRequest&)
    {
        // "Should not be here" << std::endl;
        return nullptr;
    }

    // Sets redrawing flags and does AddTask if needed
    virtual void RedrawIfWindow(int = 0) {}

    virtual void DataUnit(MvIcon&) {}

    // Dealing with Export plotting
    virtual bool ExportPlot(MvRequest*, bool = false) { return false; }
    virtual MvRequest ExportToEcCharts() { return {}; }

    // Dealing with Print plotting
    virtual void PrintFile(MvRequest&) {}

    virtual void SetRequest(const MvRequest&);

    // Dealing with rebuilding the visualization tree
    void Refresh(bool refresh) { refresh_ = refresh; }
    bool Refresh() { return refresh_; }

    // Handle Coastlines icon
    // Provide coastline information
    virtual void ProcessCoastlines(MvRequest&, bool, bool foundDU = false);

    // Split icon coastlines into background and foreground coastlines
    virtual void SplitCoastlines(MvRequest&, MvRequest&, MvRequest&);

    // Build a coastline background/foreground icon derived from a coastline icon
    virtual void CoastlinesBackground(MvRequest&, MvRequest&);
    virtual void CoastlinesForeground(MvRequest&, MvRequest&);

protected:
    bool DescribeVisDefList(ObjectInfo&, MvIconList&, MvIcon&, std::string&, bool, MacroVisDefMap&);

    // Members
    static int treeNodeCounter_;              // used to obtain unique Id
    MvRequest myRequest_;                     // request used to build me
    int presentableId_;                       // unique Id
    Presentable* myParent_;                   // next level up on the tree
    std::unique_ptr<DeviceData> deviceData_;  // information on the device
    Location myLocation_;                     // position of the presentable

    // Definition for the tree hierarchy of the Presentable class
    using MvChildList = std::list<Presentable*>;
    using MvChildIterator = std::list<Presentable*>::iterator;
    using MvChildConstIterator = std::list<Presentable*>::const_iterator;

    MvChildList childList_;      // list of children
    bool hasMatch_;              // indicates that a object has been matched
    MatchingInfo matchingInfo_;  // matching information

    bool isVisible_;  // indicates if the presentable is visible

    bool hasNewpage_;  // indicates if the presentable
                       // has received a newpage directive

    int pendingDrawings_;  // number of pending drawings
    bool needsRedrawing_;  // Needed when scrolling to find out
                           // if presentable needs redrawing

    bool removeData_;  // To be used when removing icons
                       // True if data is to be removed
                       // False removes data drawing only

    bool hasDrawTask_;  // Used to indicate if the presentable
                        // has been put in the Task list to be drawn

    bool droppedHere_;  // indicates if Contents Drop was
                        // done in this window

    bool refresh_;  // tag to rebuild/not the visualization tree

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