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

// Methods for MapView.cc
//
//
// This is the exemplar object for the MapView  class
//
//

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

#include "MapView.h"
#include "ObjectList.h"
#include "GraphicsEngine.h"
#include "Page.h"
#include "PmContext.h"
#include "MagPlusService.h"
#include "MvDecoder.h"
#include "PlotMod.h"
#include "PlotModTask.h"

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

public:
	MapViewFactory() : PlotModViewFactory ( "MapView" ) {}
};

static MapViewFactory mapViewFactoryInstance;

MapView::MapView( Page&            owner,
		  const MvRequest& viewRequest,
		  const MvRequest& setupRequest ):
	PlotModView ( owner, viewRequest, setupRequest ),
	PlotModService   ( this )
{
	// Create a coastline request, if one does not exist
	MvRequest coastRequest = viewRequest_.getSubrequest ("COASTLINES");
	if ( !ObjectList::IsVisDefCoastlines(coastRequest.getVerb()) )
	{
		coastRequest = ObjectList::UserDefaultRequest ( "MCOAST" );
		viewRequest_ ( "COASTLINES" ) = coastRequest;
	}
}	

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

string
MapView::Name()
{
	int id = Owner().Id();
	return (const char*)  ObjectInfo::ObjectName ( viewRequest_, "MapView", 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
MapView::Drop ( PmContext& context )
{
   MvIconDataBase& dataBase = Owner().IconDataBase();

   // Process the drop
   MvRequest dropRequest;
   dropRequest.copyFromCurrentTo(context.InRequest(), NEWPAGE.c_str());
   MvIconList duList;
   bool foundDU = false;
   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.
      MvRequest vdRequestList;
      if ( this->RetrieveVisdefList (dropRequest,vdRequestList) )
      {
         Owner().InsertVisDef (vdRequestList, duList);

         // Clear dataUnitList variable to avoid a possible visdef in the next
         // iteraction to be associate to an old dataUnit.
         if ( !duList.empty() )
            duList.clear();

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

      MvRequest request = dropRequest.justOneRequest();
      Cached verb       = request.getVerb();
      if ( ObjectList::IsDataUnit ( verb ) == true )
      {
         MvIcon dataUnit = dataBase.InsertDataUnit ( request, Owner().Id() );
         duList.push_back(dataUnit);
         Owner().InitMatching();
         DecodeDataUnit ( dataUnit );

         foundDU = true;
         dropRequest.advance();
         continue;
      }

      // Update view (if applicable)
      if ( ObjectList::IsView ( verb ) == true )
         this->UpdateView ( request );

      else if ( ObjectList::IsVisDefCoastlines ( verb ) )
         this->ProcessCoastlines ( request, foundDU );

      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 if ( verb == Cached ( "DRAWING_PRIORITY" ) )
      {
         Owner().SetDrawPriority ( request );

         // Redraw this page
         if (  request ("_APPL") != Cached ("macro") )
         {
            Owner().EraseDraw();
            Owner().RedrawIfWindow();
         }
      }
      else
        Owner().InsertCommonIcons(request);

      // This request is not a dataUnit. Clear dataUnitList variable
      // to avoid a possible visdef in the next iteraction to be
      // associate to an old dataUnit.
      if ( !duList.empty() )
         duList.clear();

      dropRequest.advance();
   }

   context.AdvanceToEnd();
}

MvIconList
MapView::InsertDataRequest ( MvRequest& dropRequest )
{
   MvIconDataBase& dataBase = Owner().IconDataBase();

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

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

      // Insert dataUnit to the database
      MvIcon dataUnit = dataBase.InsertDataUnit ( request );
      DecodeDataUnit ( dataUnit );

      // Add dataUnit to the output list
      duList.push_back(dataUnit);

      dropRequest.advance();
   }

   return duList;
}

// Decode the data unit and send each field to the page for matching
void MapView::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
    auto_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;
    bool swap;
    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, swap ) ||
                    !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.
                    // Insert dataunit using the correct order of the offsets
                    // (i.e. u/v not v/u). This is a Magics requirement.
                    dimFlag = dimFlag | 2;
                    bool flag;
                    if ( swap )
                       flag = Owner().InsertDataUnit ( dataUnit.Id(), nextDataOffset, offset, dataInfo, subpageId );
                    else
                       flag = Owner().InsertDataUnit ( dataUnit.Id(), offset, nextDataOffset, dataInfo, subpageId );

                    if ( flag == 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 ();

//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) )
        {
            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		}
        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
MapView::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 );
}

void
MapView::UpdateView ( MvRequest& viewRequest )
{
   // uPlot recognises that MapView and GeoView are basically the same thing
   if ( ObjectList::IsGeographicalView( viewRequest.getVerb() ) )
//   if ( strcmp (viewRequest_.getVerb(),viewRequest.getVerb()) == 0)
   {
      // Ensure coastlines exist
      viewRequest_ = viewRequest;
      MvRequest coastRequest = viewRequest_.getSubrequest ("COASTLINES");
      if ( ! coastRequest )
      {
         coastRequest = ObjectList::UserDefaultRequest ( "MCOAST" );
         viewRequest_ ( "COASTLINES" ) = coastRequest;
      }

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

      Owner().InitZoomStacks();
   }
   else
   {
      // Changing View is disabled at the moment
      char text[128];
      sprintf(text,"Changing View (%s to %s) is currently disabled",viewRequest_.getVerb(),viewRequest.getVerb() );
      PlotMod::Instance().errorMessage(text);

      // The code below needs to be updated if uPlot will allow changing views
      #if 0
      RecreateData();
      viewRequest_ = viewRequest;

      // Create a view associated to the page
      auto_ptr <PlotModView> view ( PlotModViewFactory::Make (Owner(), viewRequest ) );
      Owner().SetView(view);
      #endif
   }
}

void
MapView::ProcessCoastlines ( MvRequest& coastRequest, bool foundDU )
{
    // Two main procedures:
    // A) if the icon came from a Macro then keep it in the same position
    //    as defined in the Plot command
    // B) if the icon came from a Drop then replace the one defined in
    //    the View request

    // Icon from a Macro
    if ( PlotMod::Instance().CalledFromMacro() )
    {
        MvIconDataBase& dataBase = Owner().IconDataBase();
        coastRequest("_PLOTTING_ORDER") = foundDU ? "FOREGROUND" : "BACKGROUND";
        MvIcon icon(coastRequest,true);
        dataBase.InsertIcon( PRES_VISDEF_REL, Owner().Id(), icon, -1, false );
    }
    else // icon from a Drop
        viewRequest_ ( "COASTLINES" ) = coastRequest;

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

#if 0
void
MapView::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

void
MapView::DrawBackground ( )
{
#if 1   // New code
   // Retrieve background request
   MvRequest backList;
   if ( this->RetrieveBackground(backList) == 0 )
      return;   // nothing to be plotted

   // Loop all requests
   GraphicsEngine& ge = Owner().GetGraphicsEngine();
   while ( backList )
   {
      // Draw the layer info
      MvRequest req = backList.justOneRequest();
      MvIcon icon(req,true);
      Owner().DrawLayerInfo( icon.Id() );

      // Ask the graphics engine to draw the coastlines
      ge.Draw ( req, true );
   
      backList.advance();
   }

   Owner().SetProjection ( viewRequest_ );

#else   // Old code, delete it later
   bool draw = false;
   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);

   // Account for land-sea shading and for the drawing order
   // Check if Coastline Land Shade is to be drawn on the background
   const char* onoff = (const char*)expRequest ( "MAP_COASTLINE_LAND_SHADE" );
   if ( onoff && strcmp(onoff,"ON") == 0 )
   {
      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 && strcmp(onoff,"ON") == 0 )
   {
      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 && strcmp(onoff,"ON") == 0 )
   {
      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";

      // Draw the layer info
      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_ );
#endif
}

void
MapView::DrawForeground ( )
{
#if 1  // New code
   // Retrieve foreground request
   MvRequest foreList;
   if ( this->RetrieveForeground(foreList) == 0 )
      return;  // nothing to be plotted

   // Loop all requests
   GraphicsEngine& ge = Owner().GetGraphicsEngine();
   while ( foreList )
   {
      // Draw the layer info
      MvRequest req = foreList.justOneRequest();
      MvIcon icon(req,true);
      Owner().DrawLayerInfo( icon.Id() );

      // Ask the graphics engine to draw the coastlines
      ge.Draw ( req, true );
   
      foreList.advance();
   }

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

#else  // Old code, delete it later
   bool draw   = false;
   string ON   = "ON";
   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
   const char* onoff = (const char*)expRequest ( "MAP_COASTLINE_LAND_SHADE" );
   if ( onoff && strcmp(onoff,"ON") == 0 )
   {
      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 && strcmp(onoff,"ON") == 0 )
   {
      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 && strcmp(onoff,"ON") == 0 )
   {
      int drawPrior = tmpDrawingPriority.GetPriority ( "COASTLINE" );

      // 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_ );
#endif
}

// Describe the contents of the view
// for saving into a macro
void 
MapView::DescribeYourself ( ObjectInfo& description )
{
   // Translate MAPVIEW to GEOVIEW by adding GEOVIEW parameters
   MvRequest tmpRequest = viewRequest_;
   if ( (const char*)tmpRequest("AREA") )
      tmpRequest("MAP_AREA_DEFINITION") = "CORNERS";

   // Translate json zoom definition to a Magics request
   if ( (const char*)tmpRequest("_ZOOM_DEFINITION") )
   {
      MvRequest req;
      string sjson = (const char*)tmpRequest("_ZOOM_DEFINITION");
      MagPlusService::Instance().decode(req, sjson );

      // Translate Magics request to a Metview request
      if ( (const char*)req("subpage_map_projection") )
         tmpRequest("MAP_PROJECTION") = (const char*)req("subpage_map_projection");

      if ( (const char*)req("subpage_map_area_definition") )
         tmpRequest("MAP_AREA_DEFINITION") = (const char*)req("subpage_map_area_definition");

      tmpRequest("AREA")  = req("subpage_lower_left_latitude");
      tmpRequest("AREA") +=req("subpage_lower_left_longitude");
      tmpRequest("AREA") +=req("subpage_upper_right_latitude");
      tmpRequest("AREA") +=req("subpage_upper_right_longitude");
   }

   // Convert my request to macro
   string defView = DEFAULTVIEW;
   std::transform(defView.begin(), defView.end(), defView.begin(), ::tolower);
   set<Cached> skipSet;
   description.ConvertRequestToMacro ( tmpRequest, PUT_END, MacroName().c_str(),defView.c_str(),skipSet);
}

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

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

	// Call service
	if ( service.size() )
	{
		( new PlotModTask (this, context, service.c_str(), appRequest ) )->run();
		return true;
	}
	else
	{
		cout << " ADD ERROR MESSAGE: SERVICE NOT FOUND" << endl;
		return false;
	}
}

int MapView::RetrieveBackground( MvRequest& backReq )
{
   // Get icons from the Database first. If there is none then get the icon
   // from the View.
   int ncount = this->RetrieveBackForeground("BACKGROUND",backReq);
   if ( ncount )
       return ncount;

   // Retrieve icon from the View
   // By default, Coastline will only be plotted on the foreground, unless
   // there is a sea/land shade to be drawn on the background
   backReq = viewRequest_.getSubrequest ("COASTLINES");

   // Account for land-sea shading defined in the View.
   // By default, if Coastline Land Shade is ON it will be drawn on the background
   bool draw = false;
   const char* onoff = (const char*)backReq( "MAP_COASTLINE_LAND_SHADE" );
   if ( onoff && strcmp(onoff,"ON") == 0 )
      draw = true;

   // By default, if Coastline Sea Shade is ON it will be drawn on the background
   onoff = (const char*)backReq( "MAP_COASTLINE_SEA_SHADE" );
   if ( onoff && strcmp(onoff,"ON") == 0 )
      draw = true;

   // Set Coastline to be drawn on the background
   if ( draw )
   {
      // By default Boundaries, Cities and Rivers are plotted on the Foreground
      backReq ("MAP_BOUNDARIES") = "OFF";
      backReq ("MAP_CITIES") = "OFF";
      backReq ("MAP_RIVERS") = "OFF";

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

      return 1;
   }

   backReq.clean();
   return 0;
}

int MapView::RetrieveForeground( MvRequest& foreReq )
{
   // Get icons from the Database first. If there is none then get the icon
   // from the View.
   int ncount = this->RetrieveBackForeground("FOREGROUND",foreReq);
   if ( ncount )
      return ncount;

   // Retrieve icon from the View
   foreReq = viewRequest_.getSubrequest ("COASTLINES");

   // Account for land-sea shading. If they are setted to ON then 
   // they were previously drawn on the Background by default. 
   const char* onoff = (const char*)foreReq ( "MAP_COASTLINE_LAND_SHADE" );
   if ( onoff && strcmp(onoff,"ON") == 0 )
      foreReq ("MAP_COASTLINE_LAND_SHADE") = "OFF";

   onoff = (const char*)foreReq ( "MAP_COASTLINE_SEA_SHADE" );
   if ( onoff && strcmp(onoff,"ON") == 0 )
      foreReq ("MAP_COASTLINE_SEA_SHADE") = "OFF";

   return 1;
}

int MapView::RetrieveBackForeground( const char* stype, MvRequest& req )
{
   // Get icons from the database (if any)
   req.clean();
   MvIconDataBase& dataBase = Owner().IconDataBase();
   MvIconList iconList;
   if ( dataBase.RetrieveIcon ( PRES_VISDEF_REL, Owner().Id(), iconList ) == 0 )
      return 0;

   // Save the requested type icons
   int ncount = 0;
   MvListCursor ii;
   for ( ii = iconList.begin(); ii != iconList.end(); ii++ )
   {
      MvRequest currentReq = (*ii).Request();
      if ( ObjectList::IsVisDefBackForeground(currentReq.getVerb()) )
      {
         if ( (const char*)currentReq("_PLOTTING_ORDER") &&
              (string(stype) == (const char*)currentReq("_PLOTTING_ORDER")) )
         {
            req = req + currentReq;
            ncount++;
         }
      }
   }

   return ncount;
}

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

void
MapView::SaveRequest ( const Cached& path, MvRequest& viewRequest )
{
	Cached fileName = MakeIconName ( path, "MapView" );
	
	// 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 MapView::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
