/***************************** 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:
//  Page
//
// .AUTHOR:
//  Gilberto Camara and Fernando Ii
//
// .SUMMARY:
//  Defines a concrete Page class for the page hierarchy in PlotMod.
//  The Page class is an example a Component class
//  of the Composite "pattern".
//
//  Its methods allow for the insertion and removal of nodes and
//  on a tree structure, and also for the drawing method.
//
//
// .DESCRIPTION:
//  Refer to the "Design Patterns" book, page 163 for more details
//
//
// .DESCENDENT:
//
//
// .RELATED:
//  PlotMod, DataObject, SubPage, Text, Legend
//  Builder, Visitor, Device, DataUnit
//
// .ASCENDENT:
//  Presentable
//

#pragma once

#include <memory>

#include "Presentable.h"
#include "PlotModView.h"
#include "GraphicsEngine.h"
#include "PmProjection.h"
#include "DrawingPriority.h"
#include "ZoomStacks.h"
#include "MatchingInfo.h"

class Page : public Presentable
{
public:
    // Constructors
    Page(MvRequest& pageRequest);
    Page(const Page&);
    Presentable* Clone() const override { return new Page(*this); }

    // Destructor
    ~Page();

    // Methods
    // Overriden from Presentable class

    // Return my name
    std::string Name() override;

    bool IsVisible() override {return true;}

    // Draw me and all my children
    void Draw() override;

    //  draws the presentable
    void DrawProlog() override;

    // Draw page header
    void DrawPageHeader() override;

    // Register to draw trailer later
    void RegisterDrawTrailer() override;

    // Respond to a drop action
    void Drop(PmContext& context) override;

    // Return the graphics engine (one per page)
    GraphicsEngine& GetGraphicsEngine() const override
    {
        return *engine_;
    }

    // Accept a visitor
    void Visit(Visitor& v) override;

#if 0
	virtual void DrawBackground ( Canvas& canvas, bool emptyBack = false );
	// Draw the background (ask my view to do it )
	// Obs: draws shared background, not to be used on PostScript

	virtual void DrawForeground ( Canvas& canvas, bool emptyFore = false );
	// Draw the foreground (ask my view to do it )
	// Obs: draws shared foreground, not to be used on PostScript

//D	virtual void DrawFrame ( Canvas& canvas );
	// Draw the frame (ask my view to do it )

	virtual void DrawNewPage ( Canvas& canvas );
	// Draw the frame (ask my view to do it )
#endif

    // Zoom request given a new location to be added to the stack
    //virtual void ZoomRequest ( const Location& zoomCoord );

    // Zoom request given an index from the stack
    void ZoomRequest(int izoom);

    // Zoom request given a string containing the zoom info
    void ZoomRequest(const std::string& zoomInfo);

    // Retrieve zoom information
    void ZoomInfo(int& zoomNumberOfLevels, int& zoomCurrentLevel) override;

    // Replace the geographical area and plot the result
    //virtual void ReplaceArea ( const Location& zoomCoord, int zoom=-1 );

    // Generate a description of the page
    void DescribeYourself(ObjectInfo&) override;

#if 0
	virtual void NeedsRedrawing(bool yesno);
	// Sets all subpages to the same state (bool yesno) of page.

        virtual bool NeedsRedrawing();
	// Checks all subpages, returns true if one of then are true.
  
        virtual void RedrawIfWindow(int visdefId = 0);
        // Sets redrawing flags and does AddTask if needed.

	virtual void SetPageSize ( double top, double left, double bottom, double right );
	// Update Page's size
#endif

    void SetContentsDataUnit(int dataUnitId) override { dataUnitId_ = dataUnitId;}
    int ContentsDataUnit() const override { return dataUnitId_; }

    virtual std::string MacroPlotIndexName(bool = true) override
    {
        return myParent_->MacroPlotIndexName(true);
    }

    void SetDropShouldStay(bool drop) override { dropShouldStay_ = drop; }
    bool DropShouldStay() const override { return dropShouldStay_; }

    // Local methods
    // Insert a new data unit (used in response to a drop action)
    bool InsertDataUnit(int, long, long, MatchingInfo&, int&);

    // Insert a new visdef ( used in response to a drop action )
    void InsertVisDef(MvRequest&, MvIconList&);

    // Insert a new visdef that came from a drop in the Plot window.
    // If visdef was dropped alone, first check if it has already being in use.
    // If yes, replace it. If not, remove all the old visdefs and then applied
    // this new one.
    // If visdef was dropped together with a dataunit, add visdef to that dataunit.
    void InsertVisDefFromWindow(MvRequest&, MvIconList&);

    // Insert visdefs to dataunit
    bool InsertVisDefToDataUnit(MvRequest&, MvIcon&);

    // Insert visdefs to the presentable
    void InsertVisDefToPresentable(MvRequest&);

    // Remove icon from tree structure
    void RemoveIcon(MvIcon&) override;

    // Remove all data icon from tree structure
    void RemoveAllData() override;

    // Create rows*columns subpages
    void CreateSubpages();

    ZoomStacks* GetZoomStacks()
    {
        return &zoomStacks_;
    }

    void InitZoomStacks()
    {
        zoomStacks_.ClearAll();
    }

    // Remove Page relationships from the DataBase
    void RemovePageFromDataBase();

#if 0
	bool RemoveSubPage ( SubPage* );
	// Remove SubPage from SubPages list

	void UpdateChildList ();
	// Look for Subpages with no data, remove then if they are not visible

	int FirstVisible() const { return firstVisible_; }
	// Return number of first visible page ( for Scroll interface )
#endif

    // Return number of visible subpages
    int NumberOfVisible() { return visibleCount_; }

    //	Location GetDrawingArea ()
    //		{ return drawingArea_; }

    //	void SetDrawingArea ( Location drawingArea )
    //		{ drawingArea_ = drawingArea; }

    //U	void EraseBackDraw ();
    //U	void EraseForeDraw ();

    // Set/Get the projection associated to the canvas
    void SetProjection(const MvRequest& viewRequest) override;

    PmProjection* GetProjection()
    {
        return (projection_.get());
    }

    // Return TRUE if there is a projection associated to the page
    bool HasProjection()
    {
        return (projection_.get() != nullptr);
    }

    // Return TRUE if zooming is allowed for this projection
    bool CanDoZoom() override;

    void SetDrawPriority(MvRequest& drawPriorRequest) override
    {
        drawingPriority_.SetPriority(drawPriorRequest);
    }

    DrawingPriority& GetDrawPriority() override
    {
        return drawingPriority_;
    }

    PlotModView& GetView() const override
    {
        return *myView_;
    }

    int FirstPrintable();

    int PaperPageNumber(int) override;

    // return list of canvas used by Page children
    //	virtual CanvasList GetCanvases();

    // Return pointer to the canvas associated to the first device with the fewest
    //  number of canvas. Also returns the associated subpage request.
    Canvas* GetNextCanvas(MvRequest& subpageReq);

    // Remove from child list
    bool RemovePresentable(Presentable*);

#if 0
	virtual void InputCoordinates ( const Location& , int );

	// Call the ToolPlus point script
	virtual void ExecuteToolPlusPointScript ( const Location& );

	// Call the ToolPlus area script
	virtual void ExecuteToolPlusAreaScript ( const Location& );

	virtual void SetInputPresentableId ( int presID )
		{ myParent_->SetInputPresentableId ( presID ); }

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

        virtual list<bool> ReadyChilds();

	virtual void PrintInfo();

	virtual void  StartMapEditor();
	// Initiate a map editor

	virtual void SaveView();
	// Save View in the disk.
#endif

    bool CheckValidVisDefWithIcl(MvIcon&, MvRequest&, MvIconList&);

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

    // Dealing with Contents tools
    void contentsRequest(MvRequest&) override;

    // Update View structure
    virtual void UpdateView(const MvRequest&);

protected:
    //Update certain data units for the new area
    virtual void UpdateDataForZoom(const std::string& zoomInfo);

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

    // Members
    std::unique_ptr<PlotModView> myView_;
    std::unique_ptr<GraphicsEngine> engine_;

    int firstVisible_;
    int visibleCount_;
    int dataUnitId_;

    ZoomStacks zoomStacks_;

    bool dropShouldStay_;

    std::unique_ptr<PmProjection> projection_;  // projection associated with page
    DrawingPriority drawingPriority_;
};
