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

//
// This is the exemplar object for the GeoView class
//

#include <Assertions.hpp>
#include <MvRequestUtil.hpp>

#include "GeoView.h"
#include "MvPath.hpp"
#include "ObjectList.h"
#include "Page.h"
#include "PmContext.h"
#include "MvDecoder.h"
#include "PlotMod.h"
#include "PlotModTask.h"
#include "SubPage.h"
#include "MvLog.h"

class GeoViewFactory : public PlotModViewFactory
{
    // Virtual Constructor - Builds a new GeoView
    virtual PlotModView* Build(Page& page,
                               const MvRequest& contextRequest,
                               const MvRequest& setupRequest)
    {
        return new GeoView(page, contextRequest, setupRequest);
    }

public:
    GeoViewFactory() :
        PlotModViewFactory("GeoView") {}
};

static GeoViewFactory geoViewFactoryInstance;

GeoView::GeoView(Page& owner,
                 const MvRequest& viewRequest,
                 const MvRequest& setupRequest) :
    PlotModView(owner, viewRequest, setupRequest),
    PlotModService(this)
{
#if 1
    // Create a coastline request, if one does not exist
    MvRequest coastRequest = viewRequest_.getSubrequest("COASTLINES");
    if (!ObjectList::IsVisDefCoastlines(coastRequest.getVerb())) {
        coastRequest = ObjectList::UserDefaultRequest("MCOAST");
        // Remove later and add the code below
        viewRequest_("COASTLINES") = coastRequest;
    }
    // Split the coastline request into geolayers
    // this->
    coastRequest.print();
#else
    // Get GeoLayers request. If it does not exist, create a default one. Otherwise,
    // make sure that GEO_COASTLINE and GEO_GRID are defined.
    // The GeoLayers can not be added to the DB yet because the Page (the owner
    // of this view) will only be added to the DB later.
    MvRequest glReq = viewRequest_.getSubrequest("GEO_LAYERS");
    if (!glReq) {
        this->GeoLayersDefaultRequest(glReq);
        this->UpdateViewRequestGeoLayers(glReq);
        // viewRequest_ ( "GEO_LAYERS" ) = glReq;
    }
    else {
        this->CheckAddGeoLayers(glReq);
        this->UpdateViewRequestGeoLayers(glReq);
        // viewRequest_ ( "GEO_LAYERS" ) = glReq;
    }
#endif
}

GeoView::GeoView(const GeoView& old) :
    PlotModView(old),
    PlotModService(old)
{
}

string GeoView::Name()
{
    int id = Owner().Id();
    return (const char*)ObjectInfo::ObjectName(viewRequest_, "GeoView", id);
}

// If a group of Visdefs and DataUnits were dropped, the Context organize
// them to ensure that all the VisDefs are always after each DataUnit
void GeoView::Drop(PmContext& context)
{
    MvLog().dbg() << "GeoView::Drop";

    // Check if GeoLayers are already registered in the DB
    // There are 2 reasons for not having any GeoLayers in the DB:
    // 1) There are no GeoLayers associated to this View
    // 2) There are GeoLayers associated to this View, but they have
    //    not being registerede yet because it is the first drawing of the page.
    MvIconDataBase& dataBase = Owner().IconDataBase();
    ///    bool found = dataBase.CheckIcon ( PRES_GEOLAYERS_REL,Owner().Id() );
    ///    if ( !found ) // Insert only background geolayers
    ///       this->InsertGeoLayers(0);
    /// dataBase.Print();
    // Process the drop
    MvRequest dropRequest = context.InRequest();
    MvIcon dataUnit;
    while (dropRequest) {
        // VisDefs are processed in one single goal. This is because the processing
        // of a single or a group of visdefs is different. It is assumed that
        // visdefs always come after a dataunit (if it exists).
        MvLog().dbg() << " -> REQ";
        MvRequest vdRequestList;
        if (this->RetrieveVisdefList(dropRequest, vdRequestList)) {
            Owner().InsertVisDef(vdRequestList, dataUnit);

            if (!dropRequest)  // no more drops
                break;
        }

        MvRequest request = dropRequest.justOneRequest();
        const char* verb = request.getVerb();
        //        if ( strcmp(verb,"DRAWING_PRIORITY") == 0 )
        //        {
        //            Owner().SetDrawPriority ( request );

        // Redraw this page
        //            if (  request ("_APPL") != Cached ("macro") )
        //            {
        //                Owner().EraseDraw();
        //                Owner().RedrawIfWindow();
        //            }
        //        }
        if (ObjectList::IsDataUnit(verb) == true) {
            // MvIconDataBase& dataBase = Owner().IconDataBase();
            dataUnit = dataBase.InsertDataUnit(request, Owner().Id());
            Owner().InitMatching();
            DecodeDataUnit(dataUnit);
        }
        else if (ObjectList::IsWeatherSymbol(verb)) {
            PlotMod::Instance().addWeatherSymbol(request);
            // Update view (if applicable)
        }
        else if (ObjectList::IsView(verb) == true) {
            this->UpdateViewWithReq(request);
        }
        else if (ObjectList::IsVisDefCoastlines(verb)) {
            this->UpdateCoastlines(request);
        }
        else if (ObjectList::IsService(verb, "visualise", true)) {
            // Call the service to process the request.
            // After CallService is finished, function PlotModService::endOfTask
            // should be called and this function should perform the drawing.
            Owner().HasDrawTask(false);
            CallService(request, context);

            // Avoid this drop to be send to visualization. The result of the
            // service call is the one that will be send to the visualization
            // procedure later
            // Owner().NeedsRedrawing(false);
        }
        else if ((const char*)verb == PLOTSUPERPAGE) {
            context.AdvanceTo(PLOTSUPERPAGE);
            return;
        }
        else if ((const char*)verb == NEWPAGE) {
            context.AdvanceTo(NEWPAGE);
            return;
        }
        else {
            Owner().InsertCommonIcons(request);
        }

        dropRequest.advance();
    }

    dataBase.Print();
    // Insert only foreground geolayers
    ///    if ( !found )
    ///       this->InsertGeoLayers(999);
    /// dataBase.Print();

    context.AdvanceToEnd();
}

void GeoView::InsertDataRequest(MvRequest& dropRequest)
{
    MvIconDataBase& dataBase = Owner().IconDataBase();

    while (dropRequest) {
        MvRequest request = dropRequest.justOneRequest();

        // Initialise the Matching
        Owner().InitMatching();

        MvIcon dataUnit = dataBase.InsertDataUnit(request);
        DecodeDataUnit(dataUnit);

        dropRequest.advance();
    }
}

// Decode the data unit and send each field to the page for matching
void GeoView::DecodeDataUnit(MvIcon& dataUnit)
{
    ensure(dataUnit.Id() > 0);

    int subpageId;
    MvIconDataBase& dataBase = Owner().IconDataBase();

    // Build a new data decoder, which will provide information about the data
    std::unique_ptr<Decoder> decoder(DecoderFactory::Make(dataUnit.Request()));
    ensure(decoder.get() != 0);

    // Inquire if this Page is empty
    bool empty = Owner().ChildHasData() ? false : true;

    // Read data headers (one by one)
    // retrieve the data offset and matching info
    // Pass this information to the page for matching
    int dimFlag = 0;
    while (decoder->ReadNextData()) {
        long offset = decoder->CurrentOffset();
        long nextDataOffset = offset;

        MatchingInfo dataInfo = decoder->CreateMatchingInfo();

        MvRequest iconRequest = dataInfo.Request();
        if (IsParameterSet(iconRequest, "MY_COMPANION")) {
            if (decoder->ReadNextData()) {
                nextDataOffset = decoder->CurrentOffset();
                MatchingInfo nextDataInfo = decoder->CreateMatchingInfo();

                // Are they companions ?
                if (!matchingCriteria_.IsPair(dataInfo, nextDataInfo) ||
                    !matchingCriteria_.Match(dataInfo, nextDataInfo)) {
                    // No, so plot them separately
                    dimFlag = dimFlag | 1;
                    if (Owner().InsertDataUnit(dataUnit.Id(), offset, offset, dataInfo, subpageId) == false)
                        break;

                    if (Owner().InsertDataUnit(dataUnit.Id(), nextDataOffset, nextDataOffset, nextDataInfo, subpageId) == false)
                        break;
                }
                else {
                    // Yes, so plot them together
                    dimFlag = dimFlag | 2;
                    if (Owner().InsertDataUnit(dataUnit.Id(), offset, nextDataOffset, dataInfo, subpageId) == false)
                        break;
                }
            }
            else  // An isolated field, who just happens to have a companion defined.
            {
                dimFlag = dimFlag | 1;
                if (Owner().InsertDataUnit(dataUnit.Id(), offset, nextDataOffset, dataInfo, subpageId) == false)
                    break;
            }
        }
        else {
            // It is an isolated field
            dimFlag = dimFlag | 1;
            if (Owner().InsertDataUnit(dataUnit.Id(), offset, nextDataOffset, dataInfo, subpageId) == false)
                break;
        }

        MvRequest decRequest = decoder->Request();

#if 0
//F TEMPORARY SOLUTION FOR VISUALISATION OF SATELLITE
//F IMAGES PRODUCED AT INPE (use Cylindrical projection)
//F		if ( (int)decRequest ("_ORIGCENTRE") ==  46 ) continue;
//F		else {

        const char* repres = decRequest ( "REPRES" );
        if ( ObjectList::IsImage(repres) )
        {
            std::string myName = this->Name ();
            if ( myName != "Satellite" )
            {
                MvRequest ownerReq = Owner ().Request ();

                // To change the view to Satellite, two requirements are needed:
                // 1. current View has to be a default one
                // 2. current View is empty (no data) 
                MvRequest viewRequest = ownerReq.getSubrequest( "VIEW" );
                if ( ((int)viewRequest ( "_DEFAULT" ) == 1) && empty )
                {
                    this->ConvertToSatellite ( decRequest );

                    // PlotMod service will be called again to decode this grib file
                    return;
                }
            }
        }
//F		}
#endif

        empty = false;
    }

    // Some decoders will want to update the data requests
    MvRequest dataRequest;
    if (decoder->UpdateDataRequest(dataRequest))
        dataBase.UpdateIcon(DB_DATAUNIT, dataUnit.Id(), dataRequest);

    // If the dataset contains single and companion fields then
    // tell Magics to plot single and companion fields separately
    // Otherwise, if there is no Overlay Control customized by the user
    // then always overlay
    //     if ( single && companion )
    //          viewRequest_("MAP_OVERLAY_CONTROL") = "NEVER";
    //     else if ( !viewRequest_.getSubrequest("OVERLAY_CONTROL") )
    //          viewRequest_("SUBPAGE_OVERLAY_MODE") = "ALWAYS";

    // Update icon request to indicate a vector drawing
    MvRequest req = dataUnit.Request();
    req("_NDIM_FLAG") = dimFlag;
    dataUnit.SaveRequest(req);
}

void GeoView::DrawBackground()
{
#if 1
    viewRequest_.print();
    // Expand coastlines request. This is only needed to check if the layers are on or off.
    MvRequest coastRequest = viewRequest_.getSubrequest("COASTLINES");
    MvRequest expRequest = ObjectList::ExpandRequest(coastRequest, EXPAND_DEFAULTS);

    // Split coastline request according to the foreground and background default rules
    std::string name = (const char*)coastRequest("_NAME");
    MvIconList iconList;
    {
        // this->CoastGetBackground(iconList);
        //  Check if land shade is to be drawn on the background
        const char* on = (const char*)expRequest("MAP_COASTLINE_LAND_SHADE");
        if (on && strcmp(on, "ON") == 0) {
            // Get request
            MvRequest newRequest("MCOAST");
            newRequest("MAP_COASTLINE_LAND_SHADE") = "ON";
            CopySomeParameters(coastRequest, newRequest, "MAP_COASTLINE_LAND_SHADE_");
            newRequest("MAP_COASTLINE") = "ON";  // ERROR: REPLACE TO OFF WHEN MAGICS IS FIXED
            newRequest("MAP_LABEL") = "OFF";
            newRequest("MAP_GRID") = "OFF";

            // Update icon name
            std::string newName = name + "_LandShade";
            newRequest("_NAME") = newName.c_str();

            // Add to the list
            MvIcon glIcon(newRequest, true);
            iconList.push_back(glIcon);
        }

        // Check if sea shade is to be drawn on the background
        on = (const char*)expRequest("MAP_COASTLINE_SEA_SHADE");
        if (on && strcmp(on, "ON") == 0) {
            // Get request
            MvRequest newRequest("MCOAST");
            newRequest("MAP_COASTLINE_SEA_SHADE") = "ON";
            CopySomeParameters(coastRequest, newRequest, "MAP_COASTLINE_SEA_SHADE_");
            newRequest("MAP_COASTLINE") = "ON";  // ERROR: REPLACE TO OFF WHEN MAGICS IS FIXED
            newRequest("MAP_LABEL") = "OFF";
            newRequest("MAP_GRID") = "OFF";

            // Update icon name
            std::string newName = name + "_SeaShade";
            newRequest("_NAME") = newName.c_str();

            // Add to the list
            MvIcon glIcon(newRequest, true);
            iconList.push_back(glIcon);
        }
    }

    // Retrieve the graphics Engine
    GraphicsEngine& ge = Owner().GetGraphicsEngine();

    // Draw background GeoLayers
    MvListCursor glCursor;
    for (glCursor = iconList.begin(); glCursor != iconList.end(); ++glCursor) {
        MvIcon icon = *(glCursor);

        // Draw the layer info
        Owner().DrawLayerInfo(icon.Id());

        // Draw icon
        ge.Draw(icon.Request(), true);
    }

/*
   bool draw = false;
   std::string ON = "ON";

   // Get DrawingPriority from Page
   //DrawingPriority& tmpDrawingPriority = Owner().GetDrawPriority ();

   // Expand coastlines request
   MvRequest coastRequest = viewRequest_.getSubrequest ("COASTLINES");
   MvRequest expRequest = ObjectList::ExpandRequest (coastRequest, EXPAND_DEFAULTS);
expRequest.print();
   // Account for land-sea shading and for the drawing order
   // Check if Coastline Land Shade is to be drawn on the background
   std::string onoff = (const char*)expRequest ( "MAP_COASTLINE_LAND_SHADE" );
   if ( onoff == ON )
   {
      //int drawPrior = tmpDrawingPriority.GetPriority ( "COASTLINE_LAND_SHADE" );
      //if ( drawPrior == 999 )
         //coastRequest ("MAP_COASTLINE_LAND_SHADE") = "OFF";
      //else
         draw = true;
   }

   // Check if Coastline Sea Shade is to be drawn on the background
   onoff = (const char*)expRequest ( "MAP_COASTLINE_SEA_SHADE" );
   if ( onoff == ON )
   {
      //int drawPrior = tmpDrawingPriority.GetPriority ( "COASTLINE_SEA_SHADE" );
      //if ( drawPrior == 999 )
         //coastRequest ("MAP_COASTLINE_SEA_SHADE") = "OFF";
      //else
         draw = true;
   }

   // Check if Coastline is to be drawn on the background
   onoff = (const char*)expRequest ( "MAP_COASTLINE" );
   if ( onoff == ON )
   {
      //int drawPrior = tmpDrawingPriority.GetPriority ( "COASTLINE" );
      //if ( drawPrior == 999 && draw == false )
         //coastRequest ("MAP_COASTLINE") = "OFF";
      //else
         //draw = true;
   }

   // Draw Coastline on the background
   if ( draw )
   {
      // By default Boundaries, Cities and Rivers are plotted in the Foreground.
      coastRequest ("MAP_BOUNDARIES") = "OFF";
      coastRequest ("MAP_CITIES") = "OFF";
      coastRequest ("MAP_RIVERS") = "OFF";

      // Unset other drawings
      coastRequest ("MAP_GRID") = "OFF";
      coastRequest ("MAP_LABEL") = "OFF";

string name = (const char*)coastRequest("_NAME");
name += "_landshade";
coastRequest("_NAME") = name.c_str();
      // Draw the layer info      newRequest("MAP_COASTLINE") = "ON";

      MvIcon icon(coastRequest,true);
      Owner().DrawLayerInfo( icon.Id() );

      // Ask the graphics engine to draw the coastlines
      GraphicsEngine& ge = Owner().GetGraphicsEngine();
      ge.Draw ( coastRequest, true );
   }

   //Owner().SetProjection ( viewRequest_ );
*/
#else
    // Retrieve the graphics Engine
    GraphicsEngine& ge = Owner().GetGraphicsEngine();

    // Retrieve GeoLayers from the database.
    MvIconList iconList;
    if (!this->RetrieveGeoLayersDB(iconList)) {
#if 1
        // There are 2 reasons for not having any GeoLayers in the DB:
        // 1) There are no GeoLayers associated to this View
        // 2) There are GeoLayers associated to this View, but they have
        //    not being registerede yet

        // Get GeoLayers from the request
        MvRequest glReq = viewRequest_.getSubrequest("GEO_LAYERS");

        // There are no GeoLayers associated to this View.
        // Create a default one
        if (!glReq) {
            this->GeoLayersDefaultRequest(glReq);
            viewRequest_("GEO_LAYERS") = glReq;
        }

        // Get GeoLayers from the View request as a list of requests
        GetGeoLayersList(glReq);

        // Insert GeoLayers into the DB
        this->InsertGeoLayersDB(glReq);

        // The DB now contains some GeoLayers
        this->RetrieveGeoLayersDB(iconList);
#endif
        // PlotMod::Instance().errorMessage("ERROR: Geoview::DrawBackground, GeoLayer(s) expected");
    }

    MvIconDataBase& db = Owner().IconDataBase();
    db.Print();

    // Draw background GeoLayers
    MvListCursor glCursor;
    for (glCursor = iconList.begin(); glCursor != iconList.end(); ++glCursor) {
        MvIcon icon = *(glCursor);

        // Draw the layer info
        Owner().DrawLayerInfo(icon.Id());

        // Draw icon
        ge.Draw(icon.Request(), true);
    }
#endif
}

void GeoView::Draw(SubPage* subPage)
{
    MvIconDataBase& db = Owner().IconDataBase();
    db.Print();

#if 1
    DrawPriorMap drawPriorMap;
    subPage->GetDrawPrior(&drawPriorMap);
    CommonDraw(subPage, drawPriorMap);
#else
    MvIconList duList;
    int count = dataBase.RetrieveIcon(PRES_DATAUNIT_REL, subPage->Id(), duList);
    MvListCursor listCursor = duList.begin();
    while (listCursor != duList.end()) {
        MvIcon duIcon = *listCursor;

        //(*listCursor).SaveRequest(req,true);

        ++listCursor;
    }
#endif

    db.Print();
}

void GeoView::DrawForeground()
{
    // Expand coastlines request. This is only needed to check if the layers are on or off.
    MvRequest coastRequest = viewRequest_.getSubrequest("COASTLINES");
    MvRequest expRequest = ObjectList::ExpandRequest(coastRequest, EXPAND_DEFAULTS);

    // Split coastline request according to the foreground default rules
    std::string name = (const char*)coastRequest("_NAME");
    MvIconList iconList;
    {
        // this->CoastGetForeground(iconList);
        //  Check if coastline is to be drawn on the foreground
        const char* on = (const char*)expRequest("MAP_COASTLINE");
        if (on && strcmp(on, "ON") == 0) {
            // Get request
            MvRequest newRequest("MCOAST");
            newRequest("MAP_COASTLINE") = "ON";
            CopySomeParameters(coastRequest, newRequest, "MAP_COASTLINE_");
            newRequest("MAP_COASTLINE_LAND_SHADE") = "OFF";
            newRequest("MAP_COASTLINE_SEA_SHADE") = "OFF";
            newRequest("MAP_GRID") = "OFF";
            newRequest("MAP_LABEL") = "OFF";

            // Update icon name
            std::string newName = name + "_Coastline";
            newRequest("_NAME") = newName.c_str();

            // Add to the list
            MvIcon glIcon(newRequest, true);
            iconList.push_back(glIcon);
        }

        // Check if noundaries is to be drawn on the foreground
        on = (const char*)expRequest("MAP_BOUNDARIES");
        if (on && strcmp(on, "ON") == 0) {
            // Get request
            MvRequest newRequest("MCOAST");
            newRequest("MAP_BOUNDARIES") = "ON";
            CopySomeParameters(coastRequest, newRequest, "MAP_BOUNDARIES_");
            CopySomeParameters(coastRequest, newRequest, "MAP_DISPUTED_BOUNDARIES");
            CopySomeParameters(coastRequest, newRequest, "MAP_ADMINISTRATIVE_BOUNDARIES");
            newRequest("MAP_COASTLINE") = "OFF";
            newRequest("MAP_LABEL") = "OFF";
            newRequest("MAP_GRID") = "OFF";

            // Update icon name
            std::string newName = name + "_Boundaries";
            newRequest("_NAME") = newName.c_str();

            // Add to the list
            MvIcon glIcon(newRequest, true);
            iconList.push_back(glIcon);
        }

        // Check if cities is to be drawn on the foreground
        on = (const char*)expRequest("MAP_CITIES");
        if (on && strcmp(on, "ON") == 0) {
            // Get request
            MvRequest newRequest("MCOAST");
            newRequest("MAP_CITIES") = "ON";
            CopySomeParameters(coastRequest, newRequest, "MAP_CITIES_");
            newRequest("MAP_COASTLINE") = "OFF";
            newRequest("MAP_LABEL") = "OFF";
            newRequest("MAP_GRID") = "OFF";

            // Update icon name
            std::string newName = name + "_Cities";
            newRequest("_NAME") = newName.c_str();

            // Add to the list
            MvIcon glIcon(newRequest, true);
            iconList.push_back(glIcon);
        }

        // Check if rivers is to be drawn on the foreground
        on = (const char*)expRequest("MAP_RIVERS");
        if (on && strcmp(on, "ON") == 0) {
            // Get request
            MvRequest newRequest("MCOAST");
            newRequest("MAP_RIVERS") = "ON";
            CopySomeParameters(coastRequest, newRequest, "MAP_RIVERS_");
            newRequest("MAP_COASTLINE") = "OFF";
            newRequest("MAP_LABEL") = "OFF";
            newRequest("MAP_GRID") = "OFF";

            // Update icon name
            std::string newName = name + "_Rivers";
            newRequest("_NAME") = newName.c_str();

            // Add to the list
            MvIcon glIcon(newRequest, true);
            iconList.push_back(glIcon);
        }

        // Check if grid is to be drawn on the foreground
        on = (const char*)expRequest("MAP_GRID");
        if (on && strcmp(on, "ON") == 0) {
            // Get request
            MvRequest newRequest("MCOAST");
            newRequest("MAP_GRID") = "ON";
            CopySomeParameters(coastRequest, newRequest, "MAP_GRID_");
            newRequest("MAP_COASTLINE") = "OFF";
            newRequest("MAP_LABEL") = "OFF";

            // Update icon name
            std::string newName = name + "_Grid";
            newRequest("_NAME") = newName.c_str();

            // Add to the list
            MvIcon glIcon(newRequest, true);
            iconList.push_back(glIcon);
        }

        // Check if label is to be drawn on the foreground
        on = (const char*)expRequest("MAP_LABEL");
        if (on && strcmp(on, "ON") == 0) {
            // Get request
            MvRequest newRequest("MCOAST");
            newRequest("MAP_LABEL") = "ON";
            CopySomeParameters(coastRequest, newRequest, "MAP_LABEL_");
            newRequest("MAP_COASTLINE") = "OFF";
            newRequest("MAP_GRID") = "OFF";

            // Update icon name
            std::string newName = name + "_Label";
            newRequest("_NAME") = newName.c_str();

            // Add to the list
            MvIcon glIcon(newRequest, true);
            iconList.push_back(glIcon);
        }
    }
    // Retrieve the graphics Engine
    GraphicsEngine& ge = Owner().GetGraphicsEngine();

    // Draw background GeoLayers
    MvListCursor glCursor;
    for (glCursor = iconList.begin(); glCursor != iconList.end(); ++glCursor) {
        MvIcon icon = *(glCursor);

        // Draw the layer info
        Owner().DrawLayerInfo(icon.Id());

        // Draw icon
        ge.Draw(icon.Request(), true);
    }

    /*
bool draw   = false;
   std::string ON   = "ON";
   std::string LAST = "LAST";

   // Retrieve the graphics Engine
   GraphicsEngine& ge = Owner().GetGraphicsEngine();

   // Get DrawingPriority from Page
   //DrawingPriority& tmpDrawingPriority = Owner().GetDrawPriority ();

   // Expand coastlines request
   MvRequest coastRequest = viewRequest_.getSubrequest ("COASTLINES");
   MvRequest expRequest = ObjectList::ExpandRequest (coastRequest, EXPAND_DEFAULTS);

   // Account for land-sea shading and for the drawing order
   // Check if Coastline Land Shade is to be drawn on the foreground
   std::string onoff = (const char*)expRequest ( "MAP_COASTLINE_LAND_SHADE" );
   if ( onoff == ON )
   {
      //int drawPrior = tmpDrawingPriority.GetPriority ( "COASTLINE_LAND_SHADE" );
      //if ( drawPrior == 999 )
         //draw = true;
      //else
         coastRequest ("MAP_COASTLINE_LAND_SHADE") = "OFF";
   }

   // Check if Coastline Sea Shade is to be drawn on the foreground
   onoff = (const char*)expRequest ( "MAP_COASTLINE_SEA_SHADE" );
   if ( onoff == ON )
   {
      //int drawPrior = tmpDrawingPriority.GetPriority ( "COASTLINE_SEA_SHADE" );
      //if ( drawPrior == 999 )
         //draw = true;
      //else
         coastRequest ("MAP_COASTLINE_SEA_SHADE") = "OFF";
   }

   // Check if Coastline is to be drawn on the foreground
   onoff = (const char*)expRequest ( "MAP_COASTLINE" );
   if ( onoff == ON )
   {
      //int drawPrior = tmpDrawingPriority.GetPriority ( "COASTLINE" );
int drawPrior = 999;
      // If MAP_COASTLINE was already ploted in the background but SEA/LAND
      // SHADE was selected, MAGICS needs that MAP_COASTLINE be set to ON.
      // If both MAP_COASTLINE and SEA/LAND SHADE are to be drawn,
      // Magics needs a double PCOAST
      if ( drawPrior != 999 && draw == false )
         coastRequest ("MAP_COASTLINE") = "OFF";
      else if ( drawPrior == 999 && draw == true )
      {
         // Unset other drawings and set land/sea shade request
         MvRequest finalRequest = coastRequest;
         finalRequest ("MAP_GRID")  = "OFF";
         finalRequest ("MAP_LABEL") = "OFF";
         finalRequest ("MAP_BOUNDARIES") = "OFF";
         finalRequest ("MAP_CITIES") = "OFF";
         finalRequest ("MAP_RIVERS") = "OFF";

         // Unset Sea/Land Shade
         coastRequest ("MAP_COASTLINE_LAND_SHADE") = "OFF";
         coastRequest ("MAP_COASTLINE_SEA_SHADE")  = "OFF";

         // Draw the layer info
         MvIcon icon(finalRequest,true);
         Owner().DrawLayerInfo( icon.Id() );

         // Draw Coastline sea/land shade
         ge.Draw ( finalRequest, true );
      }
   }

   // Draw the layer info
   MvIcon icon(coastRequest,true);
   Owner().DrawLayerInfo( icon.Id() );

   // Draw Coastline and/or other options (Grid,Label,...) on the foreground
   ge.Draw ( coastRequest, true );
*/
    // Owner().SetProjection ( viewRequest_ );
    //  Retrieve the graphics Engine
    //    GraphicsEngine& ge = Owner().GetGraphicsEngine();

    // Ask the graphics engine to draw the coastlines
    //   ge.DrawGeoLayersFront ( viewRequest_ );

    //   Owner().SetProjection ( viewRequest_ );
}

// Describe the contents of the view for saving into a macro
void GeoView::DescribeYourself(ObjectInfo& description)
{
    // convert my request to macro
    std::string defView = DEFAULTVIEW;
    std::transform(defView.begin(), defView.end(), defView.begin(), ::tolower);
    std::set<Cached> skipSet;
    description.ConvertRequestToMacro(viewRequest_, PUT_END, MacroName().c_str(), defView.c_str(), skipSet);
}

bool GeoView::CallService(const MvRequest& req, PmContext& context)
{
    MvRequest appRequest = req;
    appRequest("_CONTEXT") = viewRequest_;

    // Find service name
    std::string service = ObjectList::FindService(appRequest.getVerb(), "visualise");

    // Call service
    if (service.size()) {
        (new PlotModTask(this, context, service.c_str(), appRequest))->run();
        return true;
    }
    else {
        MvLog().popup().err() << "GeoView CallService-> Service not found";
        return false;
    }
}

bool GeoView::CheckAddGeoLayers(MvRequest& glReq)
{
    bool geoUpdated = false;
    if (IsParameterSet(glReq, "GEO_COASTLINE") == false) {
        MvRequest coast = ObjectList::UserDefaultRequest("GEO_COASTLINE");
        glReq("GEO_COASTLINE") = coast;
        geoUpdated = true;
    }
    if (IsParameterSet(glReq, "GEO_GRID") == false) {
        MvRequest coast = ObjectList::UserDefaultRequest("GEO_GRID");
        glReq("GEO_GRID") = coast;
        geoUpdated = true;
    }

    return geoUpdated;
}

void GeoView::UpdateViewWithReq(MvRequest& viewRequest)
{
    if (strcmp(viewRequest_.getVerb(), viewRequest.getVerb()) == 0)
    // ObjectList::IsGeographicalView( viewRequest.getVerb() ) )
    {
        // Update GeoLayers information
        // MvRequest glReq = viewRequest("GEO_LAYERS");
        // if ( this->InsertGeoLayers ( glReq ) )
        // viewRequest("GEO_LAYERS") = glReq;

        // Update view request
        viewRequest_ = viewRequest;

        // Redraw this page
        Owner().RedrawIfWindow();
        Owner().NotifyObservers();

        // Initialize zoom stack
        Owner().InitZoomStacks();
    }
    else {
        // Changing GeoView to another view is disabled at the moment.
        MvLog().popup().err() << "Changing GeoView to another View is currently disabled";
    }
}

void GeoView::UpdateCoastlines(MvRequest& glReq)
{
    // The behaviou of dropping a Coastlines icon is different depending on
    // the running mode: interactive = replace Coastlines, batch = add Coastlines.
    // if ( PlotMod::Instance().IsInteractive() )
    if ((const char*)glReq("_APPL") && strcmp((const char*)glReq("_APPL"), "macro") == 0) {
        // COUT <<"Add"<<endl;
    }
    else {
        viewRequest_("COASTLINES") = glReq;
    }

    // Update GeoLayers information
    //            if (  request ("_APPL") != Cached ("macro") )
    //      this->InsertGeoLayers ( glReq, index );
    //      viewRequest_("GEO_LAYERS") = glReq;

    // Redraw this page
    Owner().RedrawIfWindow();
    Owner().NotifyObservers();
}

void GeoView::UpdateViewRequestGeoLayers(MvRequest& in)
{
    in.print();
    // Get GeoLayers as a list
    MvRequest glReq;
    this->GetGeoLayersList(in, glReq);

    // Update view request
    MvRequest outReq(in.getVerb());
    while (glReq) {
        // Make sure the _STACKING_ORDER parameter exists
        MvRequest glReqOne = glReq.justOneRequest();
        if (!IsParameterSet(glReqOne, "_STACKING_ORDER")) {
            // Get the default value
            MvRequest expReq = ObjectList::ExpandRequest(glReqOne, EXPAND_DEFAULTS);
            glReqOne("_STACKING_ORDER") = expReq("_STACKING_ORDER");
        }

        // Add parameter to the output request
        outReq.setValue(glReqOne.getVerb(), glReqOne);
        glReq.advance();
    }

    outReq.print();
    viewRequest_("GEO_LAYERS") = outReq;
}

void GeoView::GeoLayersDefaultRequest(MvRequest& glReq)
{
    // Get user default request
    MvRequest req = ObjectList::UserDefaultRequest("GEOLAYERS");
    req.print();

    // Decode the request
    this->DecodeGeoLayers(req, glReq);
    glReq.print();
    // If the GeoCoast and GeoGrid are not defined by the user, create default ones.
    // It is assumed that the GeoCoast and GeoGrid should be plotted by default.
    CheckAddGeoLayers(glReq);
    glReq.print();
}

void GeoView::DecodeGeoLayers(const MvRequest& glReq, MvRequest& outReq)
{
    // Get each non-hidden parameter and decode it
    outReq.clean();
    outReq.setVerb(glReq.getVerb());
    MvRequest req;
    for (int i = 0; i < glReq.countParameters(); i++) {
        const char* param = glReq.getParameter(i);
        if (param[0] == '_') {
            outReq(param) = (const char*)glReq(param);
            continue;
        }

        // Build the icon path/filename
        std::string fn = MakeUserDefPath(glReq(param));

        // Read the icon contents
        req.read(fn.c_str());

        // Save the request
        outReq(param) = req;
    }
}

bool GeoView::GetGeoLayersList(MvRequest& glReq)
{
    // Get geolayers request
    MvRequest req = viewRequest_.getSubrequest("GEO_LAYERS");

    return this->GetGeoLayersList(req, glReq);
}

bool GeoView::GetGeoLayersList(MvRequest& in, MvRequest& out)
{
    // Get geolayers request
    out.clean();
    for (int i = 0; i < in.countParameters(); i++) {
        const char* caux = in.getParameter(i);
        if (caux[0] != '_')  // skip internal parameters
            out = out + in.getSubrequest(caux);
    }

    return (out ? true : false);
}

#if 0
void GeoView::InsertGeoLayers( int index )
{
viewRequest_.print();
   // Get GeoLayers from the request
   MvRequest glReq = viewRequest_.getSubrequest ("GEO_LAYERS");

   // There are no GeoLayers associated to this View. Create a default one.
   if ( !glReq )
   {
      this->GeoLayersDefaultRequest(glReq);
      viewRequest_ ( "GEO_LAYERS" ) = glReq;
   }

   // Update geolayers info into the database
   this->InsertGeoLayersDB(index);
}

bool GeoView::InsertGeoLayers( MvRequest& glReq, int index )
{
   // If input parameter is empty then create a user default GeoLayers.
   // If input parameter is a GeoLayers icon then make sure that both GeoCoast
   // and GeoGrid are instantiated.
   // If input parameter is a single GeoLayers feature (river, town, ...)
   // then insert/replace it in the View and DB.
   MvRequest listReq;
   bool geoUpdated = false;
   if ( !glReq ) // Create default
   {
      this->GeoLayersDefaultRequest(glReq);
      geoUpdated = true;
   }
   else if ( strcmp(glReq.getVerb(),"GEOLAYERS") == 0 )  // GeoLayers icon
   {
      // Check and add the mandatory GeoLayers features
      geoUpdated = this->CheckAddGeoLayers(glReq);
   }
   else  // single GeoLayers feature
   {
      // If there is no GeoLayers defined yet, create a default one
      MvRequest vglReq = viewRequest_.getSubrequest ("GEO_LAYERS");
      if ( !vglReq )
         this->GeoLayersDefaultRequest(vglReq);

      // Update the new GeoLayers request taking into consideration the stacking order
      MvRequest glReqOrg = vglReq(glReq.getVerb());
      MvRequest glReqNew;
      CopyParametersAndStackingOrder( glReqOrg,glReq,index,glReqNew );
glReqNew.print();
       // Insert/replace new GeoLayer feature in the View request
      vglReq(glReq.getVerb()) = glReqNew;

      glReq = vglReq;
      geoUpdated = true;
   }
glReq.print();
   // Get GeoLayers as a list of requests
   this->GetGeoLayersList ( glReq, listReq );
listReq.print();

   // Delete existing geo objects from the DB
   this->RemoveGeoLayersDB();
MvIconDataBase& dataBase = Owner().IconDataBase();
dataBase.Print();

   // Update geolayers info in the database
   this->InsertGeoLayersDB(listReq,index);
dataBase.Print();

   return geoUpdated;
}
#endif

#if 0
void GeoView::InsertGeoLayersDB( int index )
{
   // Get GeoLayers from the View request as a list of requests
   MvRequest glReq;
   this->GetGeoLayersList ( glReq );
glReq.print();

   // Update geolayers info in the database
   InsertGeoLayersDB( glReq, index );
}

void GeoView::InsertGeoLayersDB( MvRequest& glReq, int index )
{
   // Retrieve the Icon Data Base
   MvIconDataBase& dataBase = Owner().IconDataBase();

   // Insert all layers taking into consideration the drawing order.
dataBase.Print();
   glReq.rewind();
   while ( glReq )
   {
glReq.justOneRequest().print();
      // Insert one layer. If it already exists, just update it.
      int index1 = IsParameterSet(glReq,"_STACKING_ORDER") ? (int)glReq("_STACKING_ORDER") : -1;
      if ( index == -1 || index == index1 )
      {
         MvIcon glIcon(glReq.justOneRequest(),true);
         dataBase.InsertIcon ( PRES_GEOLAYERS_REL,Owner().Id(),glIcon, true, index1 );
      }
      glReq.advance();
   }
dataBase.Print();

   return;
}
#endif

#if 0
// Retrieve GeoLayers.
// Return false if there are no GeoLayers associated to this view.
bool GeoView::RetrieveGeoLayersDB ( MvIconList& llayers )
{
   // Get the geolayers associated to the presentable
   MvIconDataBase& dataBase = Owner().IconDataBase();
   return dataBase.RetrieveIcon ( PRES_GEOLAYERS_REL,Owner().Id(),llayers );
}

void GeoView::RemoveGeoLayersDB()
{
   // Delete the geolayers associated to the presentable
   MvIconDataBase& dataBase = Owner().IconDataBase();
   dataBase.RemoveIcon(PRES_GEOLAYERS_REL,Owner().Id());
}
#endif

#if 0
void GeoView::ConvertToSatellite ( MvRequest& decRequest )
{
   MvRequest newViewReq = ObjectList::CreateDefaultRequest ( "SATELLITEVIEW");

   newViewReq ( "SUBPAGE_MAP_SUB_SAT_LONGITUDE" ) = decRequest ( "_IMAGE_MAP_SUB_SAT_LONGITUDE" );
   newViewReq ( "INPUT_IMAGE_COLUMNS"           ) = decRequest ( "_IMAGE_MAP_COLUMNS"           );
   newViewReq ( "INPUT_IMAGE_ROWS"              ) = decRequest ( "_IMAGE_MAP_ROWS"              );
   newViewReq ( "SUBPAGE_MAP_INITIAL_COLUMN"    ) = decRequest ( "_IMAGE_MAP_INITIAL_COLUMN"    );
   newViewReq ( "SUBPAGE_MAP_INITIAL_ROW"       ) = decRequest ( "_IMAGE_MAP_INITIAL_ROW"       );
   newViewReq ( "SUBPAGE_MAP_SUB_SAT_X"         ) = decRequest ( "_IMAGE_MAP_SUB_SAT_X"         );
   newViewReq ( "SUBPAGE_MAP_SUB_SAT_Y"         ) = decRequest ( "_IMAGE_MAP_SUB_SAT_Y"         );
   newViewReq ( "SUBPAGE_MAP_X_EARTH_DIAMETER"  ) = decRequest ( "_IMAGE_MAP_X_EARTH_DIAMETER"  );
   newViewReq ( "SUBPAGE_MAP_Y_EARTH_DIAMETER"  ) = decRequest ( "_IMAGE_MAP_Y_EARTH_DIAMETER"  );
   newViewReq ( "SUBPAGE_MAP_GRID_ORIENTATION"  ) = decRequest ( "_IMAGE_MAP_GRID_ORIENTATION"  );
   newViewReq ( "SUBPAGE_MAP_CAMERA_ALTITUDE"   ) = decRequest ( "_IMAGE_MAP_CAMERA_ALTITUDE"   );

   this->UpdateView ( newViewReq );
}
#endif

#if 0
void
GeoView::ReplaceArea ( const Location& coordinates, int izoom)
{
     // If the zoom level is 0 (original request) and the geographical area was
     // not given by the user then unset parameter AREA. The default geographical
     // area will be computed by Magics.
     if ( izoom == 0 )
     {
          if ( (const char*)viewRequest_("_DEFAULT_AREA") )
          {
               viewRequest_.unsetParam("AREA");
               return;
          }
     }

   // Initialize the bounding box in geodetic coordinates
   viewRequest_ ( "AREA" ) = coordinates.Bottom();
   viewRequest_ ( "AREA" ) += coordinates.Left();
   viewRequest_ ( "AREA" ) += coordinates.Top();
   viewRequest_ ( "AREA" ) += coordinates.Right();
}
#endif

#if 0
void GeoView::DescribeSubrequest ( ObjectInfo& description,
			      MvRequest& request,
			      const Cached& name,
			      const Cached& verb)
{
	Cached macroName = ObjectInfo::SpaceToUnderscore ( name );
	description.ConvertRequestToMacro ( request, PUT_END,macroName,verb );
}

void GeoView::SaveRequest ( const Cached& path, MvRequest& viewRequest )
{
	Cached fileName = MakeIconName ( path, "GeoView" );
	
	// WARNING - this command should not be needed, but there is a "feature"
	// in GenApp that does not allow a complete definition to be overrriden
	// by a name
	viewRequest.unsetParam ("COASTLINES");
	
	viewRequest.save ( (const char*) fileName );

	// If icon, create description for Metview UI
	Cached iconFile = MakeIconDescriptionName( fileName );
  
	UtWriteIconDescriptionFile ( iconFile, "MAPVIEW" );
}

// Attach a psymb request, return the id for the it's visdef, and
// fill in the request with the visdef's request.
int GeoView::CheckPSymb(MvRequest &symbRequest)
{
	MvIconDataBase&  dataBase = Owner().IconDataBase();
  
	dataBase.PresentableVisDefRelationRewind();

	bool found = false;
	MvIcon visDef;
	int visDefId;

	// Check if it's already attached.
	while ( dataBase.NextVisDefByPresentableId ( Owner().Id(), visDef ) )
	{
		MvRequest vdRequest = visDef.Request();
		if ( vdRequest.getVerb() == Cached("PSYMB") )
		{
			symbRequest = vdRequest;
			found = true;
			visDefId = visDef.Id();
		}
	} 

	// If not found, attach one from the viewRequest, or a default request.
	if ( ! found ) 
	{
		symbRequest = viewRequest_.getSubrequest ("SYMBOL");
		if ( symbRequest.getVerb() == Cached( "PSYMB" ) )
		{
			symbRequest = ObjectList::UserDefaultRequest ( "PSYMB" );
			viewRequest_ ( "SYMBOL" ) = symbRequest;
		}

		// Add the visdef to the database.
		MvIcon symbIcon(symbRequest);
		dataBase.InsertVisDef(symbIcon);
		//dataBase.PresentableVisDefRelation(Owner().Id(), symbIcon.Id() );
		visDefId = symbIcon.Id();
	}
	return visDefId;
}
#endif
