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

#include "Presentable.h"

#include <Assertions.hpp>
#include "MvDecoder.h"
#include "DrawingPriority.h"
#include "GraphicsEngine.h"
#include "MvLayer.h"
#include "ObjectList.h"
#include "PmContext.h"
#include "Root.h"
#include "Task.h"

int Presentable::treeNodeCounter_ = 0;

// -- METHOD :  Default Constructor
//
// -- INPUT  :  (none)
//
// -- OUTPUT :  (none)
Presentable::Presentable():
    myRequest_       (                     ),
    presentableId_   ( treeNodeCounter_++  ),
    myParent_        ( 0                   ),
    myLocation_      ( 0., 0., 1., 1.      ),
    hasMatch_        ( false               ),
    matchingInfo_    ( MvRequest ("EMPTY" )),
    isVisible_       ( false               ),
    hasNewpage_      ( false               ),
    pendingDrawings_ ( 0                   ),
    needsRedrawing_  ( true                ),
    removeData_      ( true                ),
    hasDrawTask_     ( false               ),
    droppedHere_     ( false               ),
    refresh_         ( false               )
{
    // Empty
}

// -- METHOD :  Constructor
//
// -- PURPOSE:  Build a new presentable from a request 
//
// -- INPUT  :  request
//
// -- OUTPUT :  

Presentable::Presentable(const MvRequest& inRequest):
	myRequest_       ( inRequest ),
	presentableId_   ( treeNodeCounter_++),
	myParent_        ( 0 ),
	myLocation_      ( inRequest ),
	hasMatch_        ( false ),
	matchingInfo_    ( MvRequest ("EMPTY") ),
	isVisible_       ( false ),
	hasNewpage_      ( false ),
	pendingDrawings_ ( 0     ),
	needsRedrawing_  ( true  ),
//	inAnimation_     ( false ),
	removeData_      ( true  ),
	hasDrawTask_     ( false ),
	droppedHere_     ( false ),
	refresh_		 ( false )
{
	// Empty
}

// -- METHOD :  Copy constructor

Presentable::Presentable(const Presentable& old ):
	myRequest_       (old.myRequest_       ),
	presentableId_   ( treeNodeCounter_++  ),
	myParent_        ( 0                   ),
	myLocation_      ( old.myLocation_     ),
	hasMatch_        ( old.hasMatch_       ),
	matchingInfo_    ( old.matchingInfo_   ),
	isVisible_       ( old.isVisible_      ),
	hasNewpage_      ( false               ),
	pendingDrawings_ ( 0                   ),
	needsRedrawing_  ( true                ),
//	inAnimation_      ( false              ),
	removeData_      ( true                ),
	hasDrawTask_     ( false               ),
	droppedHere_     ( false               ),
	refresh_		 ( old.refresh_	       )
{
  // Ignore the observers for now, should not be copied,
  // as this copy constructor is at the moment 
  // for non-interactive devices. Consequently, device
  // data is not copied.
  //Childlist will be rebuilt in DuplicateChildren function.
}

void Presentable::SetRequest(const MvRequest& in)
{
	myRequest_=in;
	myLocation_=in;	
}

bool Presentable::HasDrawTask()
{
	if ( myParent_ )
		return hasDrawTask_ | myParent_->HasDrawTask() ;
	else
		return hasDrawTask_;
}

#if 0
void Presentable::DuplicateChildren(const Presentable& old)
{
  MvIconDataBase& dataBase = IconDataBase();
  MvIconDataBase& oldDB = old.IconDataBase();
  // Now go through the childlist and copy construct
  // all the children
  MvChildConstIterator ii = old.childList_.begin();
  MvIconList vdList,duList,ptextList;

  MvListCursor jj;
  for ( ; ii != old.childList_.end(); ii++ )
    {

      Presentable *oldPresentable = *ii;
      Presentable *newPresentable = oldPresentable->Clone();
      Insert(newPresentable);

      newPresentable->DuplicateChildren(*oldPresentable);

      // Now get everything attached to old and attach
      // it to new also.
      // Empty lists, functions below just add data.
      vdList.erase(vdList.begin(),vdList.end());
      duList.erase(duList.begin(),duList.end());
      ptextList.erase(ptextList.begin(),ptextList.end());

      // VisDefs
      oldDB.VisDefListByPresentableId(oldPresentable->Id(),
				 vdList);
      for ( jj = vdList.begin(); jj != vdList.end(); jj++ )
	dataBase.PresentableVisDefRelation(newPresentable->Id(),
					   (*jj).Id() );

      // Data units
      oldDB.DataUnitListByPresentableId(oldPresentable->Id(),
					 duList);
      for ( jj = duList.begin(); jj != duList.end(); jj++ )
	{
	  MvIcon visDef;
	  dataBase.PresentableDataUnitRelation(newPresentable->Id(),
					       (*jj).Id() );

	  // Then attach any visdefs for this data unit.
	   oldDB.DataUnitVisDefRelationRewind();
	   while ( oldDB.NextVisDefByDataUnitId((*jj).Id(),visDef) )
	     dataBase.DataUnitVisDefRelation((*jj).Id(),visDef.Id() );
	}


      // Ptexts 
      oldDB.PTextListByPresentableId(oldPresentable->Id(),
				     ptextList);
      for ( jj = ptextList.begin(); jj != ptextList.end();
	    jj++ )
	dataBase.PresentablePTextRelation(newPresentable->Id(),
					  (*jj).Id() );
    }

   // I am the SuperPage, check VisDefs and Texts associated with me
   if ( this->FindSuperPage () == this )
   {
	// Clean auxiliary lists
        vdList.erase(vdList.begin(),vdList.end());
        ptextList.erase(ptextList.begin(),ptextList.end());

	// VisDefs
        oldDB.VisDefListByPresentableId(old.Id(), vdList);
        for ( jj = vdList.begin(); jj != vdList.end(); jj++ )
	    dataBase.PresentableVisDefRelation(Id(), (*jj).Id() );

        // Ptexts 
        oldDB.PTextListByPresentableId(old.Id(), ptextList);
        for ( jj = ptextList.begin(); jj != ptextList.end(); jj++ )
	    dataBase.PresentablePTextRelation(Id(), (*jj).Id() );
   }
}
#endif

// -- METHOD : Destructor
//
// -- PURPOSE: Remove the non-automatic members of the presentable
//
// -- INPUT  :
//
// -- OUTPUT :
Presentable::~Presentable()
{
	// First of all, remove the presentable from the parent list
	// the presentable may be anywhere in the hierarchy
	if ( myParent_ )
		myParent_->Remove(this);

	// Then, for all its children, delete them
	MvChildIterator child = childList_.begin();
	while ( child != childList_.end() )
	{
          // Before deletion, make the parent point to NULL
		// This is necessary because otherwise the top
		// statement would generate a recursive call
		(*child)->myParent_ = 0; //Don't get called back

		// Create a temporary pointer to store the child's address
		Presentable* pt = (*child);
		
          // Remove the child from the list
		childList_.erase(child++);

		// Ok, now the child's parent points to NULL and we can 
		// safely call the child's destructor
		delete pt;
	}

	set<PresentableObserver*> o = observers_;
	observers_.clear();

	for(set<PresentableObserver*>::iterator j= o.begin(); j != o.end(); ++j)
		(*j)->Dead(this);
}

string
Presentable::Name()
{
	ostringstream ostr;
	ostr << "Presentable" << Id();
	return ostr.str();
}

// -- METHOD :  MacroName
//
// -- PURPOSE:  Provide the presentable's macro name (in which
//              spaces are changed to underscores)
// -- INPUT  :  (none)
//
// -- OUTPUT :  A valid name for macro
string
Presentable::MacroName()
{
	string str = (const char*) ObjectInfo::SpaceToUnderscore ( this->Name().c_str() );
	return str;
}

// --   METHOD  :  Insert
// --   PURPOSE :  Include the presentable in my child list
//
// --   INPUT   :  A pointer to a presentable

void
Presentable::Insert (Presentable* p )
{
	require (p != 0);
	require (p->myParent_ == 0);

        // Test if child is at a lower depth than parent
	childList_.push_back(p);

	p->myParent_ = this;

	// Notify the change
	NotifyObservers();
}

// --   METHOD  : Remove
// --   PURPOSE : Erase the presentable from my child
//                (should be used in connection with delete)

void
Presentable::Remove (Presentable* p )
{
	require (p != 0);
	require (p->myParent_ == this); // Am I his father ??

     // Test if child is at a lower depth than parent
	// Remove the child from the tree
	MvChildIterator child = find (childList_.begin(), childList_.end(), p);
	
	ensure ((*child) == p);
	childList_.erase(child);

	//  The child no longer has a father
        //  (a.k.a. "abandon the child")
	p->myParent_ = 0;

	// Notify the change
	NotifyObservers();
}

struct DropFunctor {
	PmContext& context_;
	DropFunctor(PmContext& context) : context_(context) {}

	void operator()(Presentable* p)
	{
		context_.RewindToAfterDrop(); p->Drop(context_);
	}
};

void
Presentable::Drop( PmContext& context )
{
	for_each ( childList_.begin() ,childList_.end(), DropFunctor(context) );
}

void
Presentable::DropSimulate ( PmContext& context )
{
	if ( !context.InRequest() )
		return;

	for (MvChildIterator ii = childList_.begin(); ii != childList_.end(); ii++)
		(*ii)->Drop(context);
}

#if 0

// -- METHOD :  
//
// -- PURPOSE:   
//
// -- INPUT  :
//
// -- OUTPUT : 
void
Presentable::SetVisibility ( bool visibility )
{
	isVisible_ = visibility;
}

// -- Methods used for Matching 


// --   METHOD  : DataInserted
// --   PURPOSE : Indicates that the presentable (or one of its
//                children) is on a tree branch with dataObjects
//
void 
Presentable::DataInserted()
{

}

// --   METHOD  : DataRemoved
// --   PURPOSE : Indicates that the presentable contains no dataObjects

void 
Presentable::DataRemoved()
{

}
#endif

// --   METHOD :   HasData
// --   PURPOSE:   Informs if the presentable has a dataObject
//
bool
Presentable::HasData()
{
	// Retrieve the Icon Data Base
	MvIconDataBase& iconDataBase = this->IconDataBase();

	return iconDataBase.PresentableHasData ( presentableId_ );
}

// --   METHOD :   ChildHasData
// --   PURPOSE:   Informs if the presentable has a child with a dataObject
//
bool
Presentable::ChildHasData()
{
	// Retrieve the Icon Data Base
	MvIconDataBase& iconDataBase = this->IconDataBase();

	// Search all the children
	// OBS: It would be better to use MvChildConstIterator. However
	// HP compiler gives an error.
	MvChildIterator child;
	for (child = childList_.begin(); child != childList_.end(); ++child)
	{
		if ( iconDataBase.PresentableHasData ( (*child)->Id() ) )
		     return true;
	}

	return false;
}

// --   METHOD  : InitMatching
// --   PURPOSE : Resets all presentables' children to be unmatched
//
struct InitMatchingFunctor {
	void operator()(Presentable* p) { p->NotMatched(); }
};

void
Presentable::InitMatching()
{
	for_each(childList_.begin(),childList_.end(),InitMatchingFunctor());
}

// --   METHOD  : DrawChildren
// --   PURPOSE : Tell all my children to draw themselves
struct DrawFunctor {
	void operator()(Presentable* p) { p->Draw(); }
};

void
Presentable::DrawChildren()
{
	for_each ( childList_.begin() ,childList_.end(), DrawFunctor() );
}


// --   METHOD  : RemoveAllDataChildren
// --   PURPOSE : Tell all my children to remove data
struct RemoveAllDataFunctor {
	void operator()(Presentable* p) { p->RemoveAllData(); }
};

void
Presentable::RemoveAllDataChildren()
{
   for_each ( childList_.begin() ,childList_.end(), RemoveAllDataFunctor() );
}

void
Presentable::RemoveMyData()
{
   MvIconDataBase& iconDataBase = this->IconDataBase();

   // Remove Data Units
   MvIconList duList;
   //if ( iconDataBase.DataUnitListByPresentableId ( this->Id(), duList ) )
   if ( iconDataBase.RetrieveIcon ( PRES_DATAUNIT_REL, this->Id(), duList ) )
   {
      MvListCursor  duCursor;
      for ( duCursor = duList.begin(); duCursor != duList.end(); ++duCursor)
      {
         MvIcon& theDataUnit = *( duCursor );
         this->RemoveIcon ( theDataUnit );
         iconDataBase.RemoveDataUnit(theDataUnit);
      }
   }

   // Remove PTexts
   MvIconList ptList;
   //if ( iconDataBase.TextListByPresentableId ( this->Id(), ptList ) )
   if ( iconDataBase.RetrieveIcon ( PRES_TEXT_REL, this->Id(), ptList ) )
   {
      MvListCursor  ptCursor;
      for ( ptCursor = ptList.begin(); ptCursor != ptList.end(); ++ptCursor)
      {
         MvIcon& thePText = *( ptCursor );
         this->RemoveIcon ( thePText );
      }
   }
}

#if 0
// --   METHOD  : RemoveAllVisDefChildren
// --   PURPOSE : Tell all my children to remove visdefs
struct RemoveAllVisDefFunctor {
	void operator()(Presentable* p) { p->RemoveAllVisDef(); }
};

void
Presentable::RemoveAllVisDefChildren()
{
	for_each ( childList_.begin() ,childList_.end(), RemoveAllVisDefFunctor() );
}

void
Presentable::RemoveAllVisDef()
{
	RemoveAllVisDefChildren();
	RemoveMyVisDef();
}

void
Presentable::RemoveMyVisDef( const MvRequest* cl)
{
	MvIconDataBase&   iconDataBase = this->IconDataBase();

	// Remove VisDefs related to DataUnits
	MvIconList vdList,duList;
	if ( iconDataBase.DataUnitListByPresentableId ( this->Id(), duList ) )
	{
		iconDataBase.RetrieveVisDefList ( duList, vdList );
		RemoveMyVisDef (vdList,cl);
	}

	// Remove VisDefs from Presentable
	vdList.clear();
	if ( iconDataBase.VisDefListByPresentableId ( this->Id(), vdList ) )
		RemoveMyVisDef (vdList,cl);
}

void
Presentable::RemoveMyVisDef (MvIconList& iconList, const MvRequest* req)
{
	MvListCursor  lCursor;
	for ( lCursor = iconList.begin(); lCursor != iconList.end(); ++lCursor)
	{
		MvIcon& theVisDef = *( lCursor );

		// Remove visdef if they are of the same class
		// Exception: PCONT(NORMAL) and PCONT(ISOTACHS)
		// are assumed to belong to different classes
		if ( req )
		{
			if (!ObjectInfo::CheckVisDefClass(*req,theVisDef.Request()) )
				continue;
		}

		this->RemoveIcon ( theVisDef );
	}
}

// --   METHOD  : RemoveAllPTextChildren
// --   PURPOSE : Tell all my children to remove ptexts
struct RemoveAllPTextFunctor {
	void operator()(Presentable* p) { p->RemoveAllPText(); }
};

void
Presentable::RemoveAllPTextChildren()
{
	for_each ( childList_.begin() ,childList_.end(), RemoveAllPTextFunctor() );
}

void
Presentable::RemoveAllPText()
{
	RemoveAllPTextChildren();
	RemoveMyPText();
}

void
Presentable::RemoveMyPText()
{
	MvIconDataBase&   iconDataBase = this->IconDataBase();

	// Remove PTexts from Presentable
	MvIconList ptList;
	if ( iconDataBase.PTextListByPresentableId ( this->Id(), ptList ) )
	{
		MvListCursor  lCursor;
		for ( lCursor = ptList.begin(); lCursor != ptList.end(); ++lCursor)
		{
			MvIcon& thePText = *( lCursor );
			this->RemoveIcon ( thePText );
		}
	}
}

// --   METHOD  : SaveChildren
// --   PURPOSE : Tell all my children to save themselves 
struct SaveFunctor {
	void operator()(Presentable* p) { p->Save(); }
};

void
Presentable::SaveChildren()
{
	for_each ( childList_.begin(), childList_.end(), SaveFunctor () );
}
#endif

// --   METHOD  : FindBranch
// --   PURPOSE : Find a branch of the tree which has a node Id
// --   INPUT   : Presentable Id ( unique )
Presentable*
Presentable::FindBranch (const int treeNodeId) const
{
	require (treeNodeId > 0 );

	// Check for the current node
	if ( treeNodeId == presentableId_ )
		return (Presentable*)this;

	Presentable* node = 0;

	// Look at the descendents
	MvChildConstIterator child;
	for (child = childList_.begin(); child != childList_.end(); ++child)
	{
		if ( ( node = (*child)->FindBranch (treeNodeId)  ) != 0 )
			return (Presentable*) node;
	}

	return 0;
}

// --   METHOD  : FindBranchesByRequest
// --   PURPOSE : Find branches of the tree which have an specific request
// --   INPUT   : String requestName, vector<Presentable*>& presVec
void
Presentable::FindBranchesByRequest(string requestName,vector<Presentable*>& presVec)
{
	// Check for the current node
        const char *name=myRequest_.getVerb();
	if(name && strcmp(name,requestName.c_str()) == 0)
		presVec.push_back((Presentable*)this);

	// Look at the descendents
	MvChildIterator child;
	for (child = childList_.begin(); child != childList_.end(); ++child)
	{
		(*child)->FindBranchesByRequest(requestName,presVec);
	}
}

Presentable*
Presentable::FindBranchByIconId (int iconId, int& dataId) const
{
   // Retrieve the Icon Data Base
   MvIconDataBase& iconDataBase = this->IconDataBase();

   // Find the presentable Id related to the icon Id
   int presId = iconDataBase.FindPresentableId(iconId,dataId);
   if ( presId < 0 )
      return 0;

   // Find the presentable related to the given node id
   Presentable* pres = this->FindBranch(presId);

   return pres;
}

int
Presentable::FindBranchIdByIconId (int iconId, int& dataId)
{
   Presentable* pres = this->FindBranchByIconId(iconId,dataId);
   return (pres ? pres->Id() : -1);
}


#if 0
// --   METHOD  : FindBranch
// --   PURPOSE : Find a branch of the tree which has an specific View
// --   INPUT   : String viewName
Presentable*
Presentable::FindBranch (string viewName)
{
	// Check for the current node
        if ( FindView(viewName) )
		return (Presentable*)this;

	// Look at the descendents
	Presentable* node = 0;
	MvChildConstIterator child;
	for (child = childList_.begin(); child != childList_.end(); ++child)
	{
		if ( ( node = (*child)->FindBranch (viewName)) != 0 )
			return (Presentable*) node;
	}
	return 0;
}
#endif

// --   METHOD  : FindSuperPage
// --   PURPOSE : Find the superpage of the tree which has a node Id
// --   INPUT   : Presentable Id ( unique )
Presentable*
Presentable::FindSuperPage () const
{
	// Go up the tree, until a superpage is found
	// ( all superpages are children of the root )
	if ( myParent_->Id() == 0 )
		return (Presentable*) this;
	else
		return myParent_->FindSuperPage();
}

void
Presentable::PendingDrawingsAdd ()
{
	require ( myParent_ != 0 );
	myParent_->PendingDrawingsAdd ();
}

void
Presentable::PendingDrawingsRemove ()
{
	require ( myParent_ != 0 );
	myParent_->PendingDrawingsRemove ();
}

#if 0
bool
Presentable::DrawingIsFinished()
{
	require ( myParent_ != 0 );
	return  myParent_->DrawingIsFinished ();
}

Location
Presentable::GetDrawingArea ()
{
	require ( myParent_ != 0 );
	return  myParent_->GetDrawingArea ();
}

void
Presentable::SetDrawingArea ( Location loc )
{
	require ( myParent_ != 0 );
	myParent_->SetDrawingArea ( loc );
}
#endif

void
Presentable::GetAllRequests( MvRequest& fullReq, bool checkIconStatus )
{
   Presentable* sp = this->FindSuperPage();
   sp->GetAllRequests(fullReq,checkIconStatus);
}

// -- METHOD  :  DefaultVisDefList
//
// -- PURPOSE : This method will retrieve the default visdef list 
//              associated to a Presentable
//
//         If there is no default visdef associated this Presentable
//         this method will go up the tree until the Root treeNode
//         (the top of the tree), which in this case, the user's default
//         visdef list will be retrieved.
//         This method also checks the type of the visdef to be retrieved:
//         NDIM_FLAG = 0 (no check), 1 (1-D data), 2 (2-D data).
bool
Presentable::DefaultVisDefList ( const char* className, MvIconList& visdefList, int ndim_flag, int type)
{
   require (className != 0);
 
   bool usingDefault = false;
   bool found = false;

   // Retrieve the Icon Data Base
   MvIconDataBase& iconDataBase = this->IconDataBase();

   // Try to find a visdef associated to the presentable
   visdefList.clear();  //initialise list
   if ( type == GETBYVISDEF )
   {
      MvIconList tmpList;
      iconDataBase.RetrieveIcon(PRES_VISDEF_REL,presentableId_,tmpList);
      MvListCursor ii;
      MvIcon currentVisDef;
      for ( ii = tmpList.begin(); ii != tmpList.end(); ii++ )
      {
         currentVisDef = *ii;
         if ( currentVisDef.Request().getVerb() == className )
            visdefList.push_back(currentVisDef);
      }
      found = visdefList.size() > 0;
   }
   else
      found = iconDataBase.VisDefListByDataUnitAndPresentableId( presentableId_, className, ndim_flag, visdefList );

   // If not found, try to find Visdefs up in the tree
   if ( !found )
      usingDefault = myParent_->DefaultVisDefList(className, visdefList, ndim_flag, type);
   else //If Visdef(s) are found, check if there is at least one valid.
   {    //Be careful, only make this check if type is GETBYDATAUNIT
      if ( type != GETBYVISDEF && !ObjectList::CheckValidVisDefList ( className, visdefList ) )
         usingDefault = myParent_->DefaultVisDefList(className, visdefList, ndim_flag, type);
   }

   ensure(visdefList.size() > 0);

     // FAMI022012 Remove this code temporarily. In the new visualisation scheme
     // the DataObject::DrawDataVisDef() function is in charge to insert Visdefs
     // into the DataBase
#if 0
	// It is a Visdef default and I am the SuperPage
	// Save Visdefs default in the DataBase
	if ( usingDefault && this->FindSuperPage () == this )
//	if ( usingDefault && dynamic_cast <SuperPage> ( *this ) )
	{
		MvListCursor  vdCursor;
		for ( vdCursor = visdefList.begin(); vdCursor != visdefList.end(); ++vdCursor)
		{
			MvIcon& visDef = *( vdCursor );

			// Do not add PAXIS default to the database. This
			// is to avoid PAXIS be shown in the Contents
			// (Display Level). We need to rewrite the Drop 
			// behavior of PAXIS. It is not working properly at
			// moment, because the definition of PAXIS inside
			// the Vertical Profile View is causing some problems. 
//			if ( !ObjectList::IsAxis(visDef.Request().getVerb()) )
				iconDataBase.InsertVisDef ( visDef, Id() );
		}
	}
#endif

	return usingDefault;
}

bool
Presentable::RetrieveIconsFromLayer ( int layerId, MvIconList& iconList )
{
   // Find the unique icon associated to the input layer
   MvIconDataBase& dataBase = this->IconDataBase();
   MvIcon icon;
   if ( !dataBase.RetrieveIconFromLayer ( layerId, icon ) )
      return false;

   // If it is a dataunit icon then retrieve the connected visdefs too
   iconList.empty();
   if ( ObjectList::IsDataUnit(icon.IconClass()) )
   {
      // First try to find visdefs directly connected to this dataunit
      // (e.g. visdefs & dataunit dropped together).
      if ( !dataBase.RetrieveIcon ( DATAUNIT_VISDEF_REL, icon.Id(), iconList ) )
      {
         // Visdef connected to the dataunit not found. Go up the tree.
         // Find presentable branch related to the dataunit
         int dummy;
         Presentable* pres = this->FindBranchByIconId(icon.Id(),dummy);
         pres->DefaultVisDefList ( icon.IconClass(), iconList );
      }
   }

   iconList.push_front(icon);

   return true;
}

int
Presentable::RetrieveNumberIconsFromLayer ( int layerId )
{
   MvIconList iconList;
   this->RetrieveIconsFromLayer ( layerId, iconList );

   return iconList.size();
}

// -- METHOD  :  RetrieveTextList
//
// -- PURPOSE : This method will retrieve the Text list associated to a presentable.
//              There are two types of Text: Title and Annotation. One Page can have
//              only one Title type but many Annotations.
//              If there is no Title associated to this Presentable, this method will
//              go up the tree until the Root treeNode (the top of the tree) where the
//              user's default Title will be retrieved.
//              In paralel, if there is no Annotation associated to this Presentable,
//              this method will go up the tree until the Root treeNode. If it does not
//              find any Annotation, no defaul icon will be retrieved. There is no
//              requirement for a Page to have an Annotation icon.
//              
bool
Presentable::RetrieveTextList ( MvIconList& textList )
{
   bool usingDefault = RetrieveTextTitle(textList);

   RetrieveTextAnnotation(textList);

   ensure(textList.size() > 0);

   return usingDefault;
}

bool
Presentable::RetrieveTextTitle ( MvIconList& textList )
{
   bool usingDefault = false;

   // Retrieve Text icons associated to this presentable
   MvIconDataBase& dataBase = this->IconDataBase();
   MvIconList tList;
   int nIcons = dataBase.RetrieveIcon ( PRES_TEXT_REL, presentableId_, tList );

   // Find a Title
   if ( nIcons )
   {
      // Check if type is Title
      MvListCursor lCursor;
      for ( lCursor = tList.begin(); lCursor != tList.end(); ++lCursor)
      {
         if ( ObjectList::IsVisDefTextTitle((*lCursor).Request()) )
         {
            textList.push_back((*lCursor));
            return false;
         }
      }
   }

   // Title not found. Search up to the tree.
   usingDefault = myParent_->RetrieveTextTitle(textList);

   ensure(textList.size() > 0);
   return usingDefault;
}

void
Presentable::RetrieveTextAnnotation ( MvIconList& textList )
{
   // Retrieve Text icons associated to this presentable
   MvIconDataBase& dataBase = this->IconDataBase();
   MvIconList tList;
   int nIcons = dataBase.RetrieveIcon ( PRES_TEXT_REL, presentableId_, tList );

   // Find Annotation icons
   bool found = false;
   if ( nIcons )
   {
      MvListCursor lCursor;
      for ( lCursor = tList.begin(); lCursor != tList.end(); ++lCursor)
      {
         // Check if type is Annotation
         if (  ObjectList::IsVisDefTextAnnotation( (*lCursor).Request()) )
         {
            textList.push_back((*lCursor));
            found = true;
         }
      }
   }

   // If no Annotation icons was not found then search up to the tree
   if ( !found )
      myParent_->RetrieveTextAnnotation(textList);

   return;
}

// -- METHOD  :  RetrieveLegend
//
// -- PURPOSE : This method will retrieve the Legend associated to a presentable.
//              If there is no Legend associated to the presentable, this method will
//              go up the tree until the Root treeNode (the top of the tree)
//              that will retrieve the user's default legend.
bool
Presentable::RetrieveLegend ( MvIcon& iconLeg )
{
   bool usingDefault = false;

   // Try to find a legend associated to the presentable
   MvIconDataBase& dataBase = this->IconDataBase();
   if (!dataBase.RetrieveIcon ( PRES_LEGEND_REL,presentableId_,iconLeg ))
      usingDefault = myParent_->RetrieveLegend(iconLeg);

   return usingDefault;
}

// -- METHOD  :  RetrieveImportList
//
// -- PURPOSE : This method will retrieve the Import list. If there is no
//              Import icon here it will go up to the tree until reaches the
//              Root treeNode (the top of the tree). It returns false if no
//              Import icons are found.
bool
Presentable::RetrieveImportList ( MvIconList& importList )
{
   bool found = true;

   // Try to find Import icons associated to the presentable
   MvIconDataBase& dataBase = this->IconDataBase();
   if (!dataBase.RetrieveIcon ( PRES_IMPORT_REL, presentableId_, importList ))
      found = myParent_->RetrieveImportList(importList);

   return found;
}

// -- METHOD : SetDeviceData
//
// -- PURPOSE: Store the device information for later use
//             ( note the use of a "smart pointer")
//
// -- INPUT  : pointer to a device data
//
// -- OUTPUT : (none)
void
Presentable::SetDeviceData ( DeviceData* devdata )
{ 
	require ( devdata != 0 );
	auto_ptr <DeviceData> p ( devdata );
	deviceData_ = p;
}

DeviceData*
Presentable::ReleaseDeviceData ( )
{
	require ( deviceData_.get() != 0 );

	return deviceData_.release();
}

// -- METHOD :  GetGraphics Engine
//
// -- PURPOSE:  Retrieve the grapics engine associated to the presentable
//
GraphicsEngine&
Presentable::GetGraphicsEngine() const 
{
	require ( myParent_ != 0 );
	return myParent_->GetGraphicsEngine();
}

PlotModView&
Presentable::GetView() const
{
	require ( myParent_ != 0 );
	return myParent_->GetView();
}

// -- METHOD :  GetCanvas
//
// -- PURPOSE:  Retrieve the canvas associated to the presentable
//
Canvas&
Presentable::GetCanvas() const
{
	require ( myParent_ != 0 );
	return myParent_->GetCanvas();
}

#if 0
bool
Presentable::CanScroll()
{
	require ( myParent_ != 0 );
	return myParent_->CanScroll();
}


// -- METHOD :  GetCanvases
//
// -- PURPOSE:  Return list of canvas, get from Page or EditMapPage
CanvasList
Presentable::GetCanvases () 
{
	require ( myParent_ != 0 );
	return myParent_->GetCanvases ();
}
#endif

DrawingPriority&
Presentable::GetDrawPriority() 
{
	require ( myParent_ != 0 );
	return myParent_->GetDrawPriority();
}

// -- METHOD :  Visitor
//
// -- PURPOSE:  Implement the visitor pattern by allowing the
//              visitor to visit all my children
// -- INPUT  :  a visitor
//
struct VisitFunctor {
	Visitor& visitor_;
	VisitFunctor(Visitor& visitor) : visitor_ ( visitor ) {}
	void operator()(Presentable* p) { p->Visit( visitor_); }
};

void
Presentable::VisitChildren( Visitor& v )
{
	for_each ( childList_.begin(), childList_.end(), VisitFunctor(v) );
}

#if 0
struct ContentsFunctor {
	MvRequest& request_;
	ContentsFunctor ( MvRequest& request) : request_ ( request ) {}
	void operator()(Presentable* p) { p->ChildrenContents ( request_ ); }
};

void
Presentable::ChildrenContents( MvRequest& request )
{
	for_each ( childList_.begin(), childList_.end(), ContentsFunctor ( request ) );
}

void
Presentable::IncludeContents ( MvRequest& request )
{
	request = request + myRequest_;
}

MvRequest
Presentable::ContentsRequest ()
{
	MvRequest dropRequest ("DROP");

	dropRequest ("DROP_ID") = presentableId_; // not really necessary

	dropRequest ("_INTERNAL") = "YES"; // information for later use

	// Include here all the information on tree contents

	// Include my contents
	this->IncludeContents ( dropRequest );

	// Include the contents of my children

	this->ChildrenContents ( dropRequest );
 
return dropRequest;
}
#endif

PaperSize
Presentable::GetChildSize ( Presentable& child )
{
	PaperSize size = this->GetMySize();

	Rectangle rect = child.GetLocation();

	double height = size.GetHeight() * (rect.bottom - rect.top);
	double width  = size.GetWidth() * (rect.right - rect.left);

	return PaperSize ( width, height );
}

#if 0
void
Presentable::Print()
{
	myParent_->Print();
}

void
Presentable::PrintPreview()
{
	myParent_->PrintPreview();
}

void
Presentable::Undo()
{
	MvChildIterator child;

	for ( child = childList_.begin(); child != childList_.end(); ++child)
	{
		(*child)->Undo();		
	}
}

void
Presentable::Redo()
{
	MvChildIterator child;

	for ( child = childList_.begin(); child != childList_.end(); ++child)
	{
		(*child)->Redo();		
	}
}

void
Presentable::Reset()
{
	MvChildIterator child;

	for ( child = childList_.begin(); child != childList_.end(); ++child)
	{
		(*child)->Reset();		
	}
}
#endif

void
Presentable::DescribeDrops ( ObjectInfo& myDescription, MacroVisDefMap& vdMap )
{
   // Retrieve the Icon Data Base
   MvIconDataBase& dataBase = this->IconDataBase();

   // Get an indexed name for the page. Need to be called even if
   // there are no drops, beacuse it updates the index.
   string macroIndexName = this->MacroPlotIndexName();

   // 1) Describe Texts
   //    Find any texts associated with the presentable
   MvIconList iconList;
   dataBase.RetrieveIcon ( PRES_TEXT_REL, Id(), iconList );

   // Loop over text icons
   bool first = true;
   string ptextDrops;
   MvListCursor lCursor;
   for ( lCursor = iconList.begin(); lCursor != iconList.end(); ++lCursor)
   {
      MvIcon icon = *lCursor;
      MvRequest iconRequest = icon.Request();

      // Skip icon according to its status
      if ( (const char*)iconRequest("_SKIP_MACRO") ||
           (const char*)iconRequest("_DEFAULT")    ||
           !dataBase.IconVisibility(icon.Id()) )
         continue;

      // Add comment
      if ( first )
      {
         myDescription.PutNewLine ( "" );
         myDescription.PutNewLine ( "# Title and annotations descriptions" );
         first = false;
      }

      // Save icon name and its stacking order info
      string sdesc = (const char*)myDescription.Convert(iconRequest);
      ptextDrops = ptextDrops + ", " + sdesc;
   }

   // 2) Describe Legends
   //    Find legend associated with the presentable
   iconList.clear();
   dataBase.RetrieveIcon ( PRES_LEGEND_REL, Id(), iconList );

   // Loop over legend icons
   first = true;
   string mlegDrops;
   for ( lCursor = iconList.begin(); lCursor != iconList.end(); ++lCursor)
   {
      MvIcon icon = *lCursor;
      MvRequest iconRequest = icon.Request();

      // Skip icon according to its status
      if ( (const char*)iconRequest("_SKIP_MACRO") ||
           (const char*)iconRequest("_DEFAULT")    ||
           !dataBase.IconVisibility(icon.Id()) )
         continue;

      // Add comment
      if ( first )
      {
         myDescription.PutNewLine ( "" );
         myDescription.PutNewLine ( "# Legend description" );
         first = false;
      }

      // Save icon name and its stacking order info
      string sdesc = (const char*)myDescription.Convert(iconRequest);
      mlegDrops = mlegDrops + ", " + sdesc;
   }

   // 3) Describe isolated Visdefs (not connected to the data)
   //    Find the list of Visdefs associated to the presentable
   iconList.clear();
   dataBase.RetrieveIcon ( PRES_VISDEF_REL, Id(), iconList );

   // Loop over visdefs
   string listDrops;
   MvIcon dummy;
   DescribeVisDefList(myDescription,iconList,dummy,listDrops,true,vdMap);

   // 4) Describe dataunits and associated visdefs
   //    Find the list of data units associated to the presentable
   iconList.clear();
   dataBase.RetrieveIcon ( PRES_DATAUNIT_REL, Id(), iconList );

   // Loop over dataunits
   MvListCursor du = iconList.begin();
   while ( du != iconList.end() )
   {
      // If dataunit is not visible then process the next one
      MvIcon currentDataUnit = *du;
      int visible = dataBase.IconVisibility(currentDataUnit.Id());
      if ( visible != 1 )
      {
         ++du;
         continue;
      }

      // Convert dataunit to macro code
      if ( !(int)currentDataUnit.Request()("_SKIP_MACRO") && visible == 1 )
      {
         string dataUnitName = (const char*)myDescription.ConvertDataUnitToMacro ( currentDataUnit );
         if ( dataUnitName.empty() )
         {
            ++du;
            continue;
         }

         // Save icon name and its stacking order info
         listDrops = listDrops + string(", ") + dataUnitName;

         int use_mode = currentDataUnit.Request()("_USE_MODE");
         if ( use_mode )
         {
            ++du;
            continue;
         }
      }

      // Find all visdefs associated to the data unit even if it
      // is tagged as _SKIP_MACRO. This is to cope with requests
      // built by some applications, e.g., XSection:
      // (netcdf_xy_matrix, mcont, netcdf_xy_points, mgraph).
      // In this case, althought the netcdf_xy_points request has 
      // a tag _SKIP_MACRO, the mgraph request must be processed.
      MvIconList visdefList;
      dataBase.RetrieveVisDefList ( (*du) , visdefList );
      DescribeVisDefList(myDescription,visdefList,*du,listDrops,true,vdMap );
      ++du;
   }

   // 5) Handle Drawing Priority (is it needed?)
   if ( this->FindSuperPage () != this ) // Not a SuperPage
   {
      // Describe priority
      DrawingPriority& pageDrawPriority = this->GetDrawPriority ();
      string priorName = pageDrawPriority.DescribeYourself ( myDescription, MacroName() );

      if ( !priorName.empty() )
         listDrops = ptextDrops + mlegDrops + listDrops + "," + priorName;
   }

   // 6) Finalise macro code
   //    Skip superpage, but should produce the plot command for a
   //    map without data
   if ( this->FindSuperPage () != this )
   {
      // Set build layout function
      myDescription.PutNewLine("");
      myDescription.PutNewLine("# Call function to build layout (defined at end of macro)");
      myDescription.PutNewLine("dw = build_layout()");

      // Set plot command
      myDescription.SetPlotAction();
      myDescription.PutNewLine ( ""  );
      myDescription.PutNewLine ( "# Plot command"  );
      string str = "plot ( " + macroIndexName + ptextDrops + mlegDrops + listDrops + " )";
      myDescription.PutNewLine ( str.c_str() );
   }
}

void
Presentable::DescribeDrops ( ObjectInfo& myDescription, MvRequest& iconsReq )
{
   // Retrieve the Icon Data Base
//   MvIconDataBase& dataBase = this->IconDataBase();

   // Get an indexed name for the page. Need to be called even if
   // there are no drops, beacuse it updates the index.
   string macroIndexName = this->MacroPlotIndexName();

   // Main loop: describe drops
   myDescription.PutNewLine ( "" );
   string listDrops;
   while ( iconsReq )
   {
      // Skip icon according to its status
      if ( (const char*)iconsReq("_SKIP_MACRO") ||
           (const char*)iconsReq("_DEFAULT")    ||
           ObjectList::IsView(iconsReq.getVerb()) )  // View was already described elsewhere
      {
         iconsReq.advance();
         continue;
      }

      // Convert icon to Macro code and save its name.
      // Certain type of icons needs a customised function.
      MvRequest req = iconsReq.justOneRequest();
      string sdesc;
      string iclass = (const char*)ObjectInfo::IconClass(req);
      if (ObjectList::IsDataUnit(iclass.c_str()))
      {
         MvIcon ireq(req,true);
         sdesc = (const char*)myDescription.ConvertDataUnitToMacro ( ireq );
      }
      else
         sdesc = (const char*)myDescription.Convert(req);

      if ( !sdesc.empty() )
         listDrops = listDrops + ", " + sdesc;

      iconsReq.advance();
   }

   // Finalise macro code.
   // Skip superpage, but should produce the plot command for a
   // map without data
   if ( this->FindSuperPage () != this )
   {
      // Set build layout function
      myDescription.PutNewLine("");
      myDescription.PutNewLine("# Call function to build layout (defined at end of macro)");
      myDescription.PutNewLine("dw = build_layout()");

      // Set plot command
      myDescription.SetPlotAction();
      myDescription.PutNewLine ( ""  );
      myDescription.PutNewLine ( "# Plot command"  );
      string str = "plot ( " + macroIndexName + listDrops + " )";
      myDescription.PutNewLine ( str.c_str() );
   }
}

bool Presentable::DescribeVisDefList( ObjectInfo &myDescription,
                                      MvIconList& visdefList, MvIcon& dataUnit,
                                      string& listDrops, bool addToDrops,
                                      MacroVisDefMap& vdMap )
{
   // Retrieve the Icon Data Base
   MvIconDataBase& dataBase = this->IconDataBase();

   // Loop over visdefs
   bool found = false;
   MvListCursor vd = visdefList.begin();
   while ( vd != visdefList.end() )
   {
      // Skip visdef which is target not to be plotted
      MvIcon currentvd = *vd;
      MvRequest currentvdRequest = currentvd.Request();
      if ( (const char*)currentvdRequest("_SKIP_MACRO")  || (const char*)currentvdRequest("_DEFAULT") )
      {
         ++vd;
         continue;
      }

      // Only generate the definition if it hasn't been done before
      MacroVisDefMap::iterator ii = vdMap.find(currentvd.Id());
      string visDefName;
      if ( ii == vdMap.end() )
      {
         myDescription.PutNewLine ( "" );
         visDefName = myDescription.Convert(currentvdRequest);
         vdMap[currentvd.Id()] = visDefName;
      }
      else
         visDefName = (*ii).second.c_str();

      // Save icon name and its stacking order info
      currentvdRequest.rewind();
      if ( ( dataUnit.Id() == 0 || CheckValidVisDef ( dataUnit, currentvdRequest ) ) &&
           addToDrops &&
           dataBase.IconVisibility(currentvd.Id()) )
      {
         found = true;
         listDrops = listDrops + string(", ") + visDefName;
      }
      ++vd;
   }

   return found;
}

int
Presentable::PageIndex ()
{
	ensure ( myParent_ != 0);

	return myParent_->PageIndex ();
}

int
Presentable::PaperPageIndex () const
{
	ensure ( myParent_ != 0);

	return myParent_->PaperPageIndex ();
}

void
Presentable::PaperPageIndex ( int paperPageIndex )
{
	ensure ( myParent_ != 0);

	myParent_->PaperPageIndex ( paperPageIndex );
}

#if 0
void
Presentable::EraseDefaultDraw ()
{
   for ( MvChildIterator ii = childList_.begin(); ii != childList_.end(); ii++ )
      (*ii)->EraseDefaultDraw ();
}
#endif

// Process the dropping of common icons
bool
Presentable::InsertCommonIcons ( const MvRequest& req )
{
    // Retrieve the Icon Data Base
    MvIconDataBase& dataBase = this->IconDataBase();

   // Test if icon came from Contents edition window
   const char* verb = req.getVerb();
   if ( (const char*)req("_CONTENTS_ICON_EDITED") )
   {
      // Icon already exists in the data base, replace it
      int iconId = (int)req("_CONTENTS_ICON_EDITED");
      if ( ObjectList::IsVisDefText ( verb ) )
         dataBase.UpdateIcon ( DB_TEXT, iconId, req );

      else if ( ObjectList::IsVisDefLegend ( verb ) )
         dataBase.UpdateIcon ( DB_LEGEND, iconId, req );

      else if ( ObjectList::IsVisDefImport ( verb ) )
         dataBase.UpdateIcon ( DB_IMPORT, iconId, req );

      else  // Nothing to be inserted
        return false;
   }
   else
   {
      MvIcon icon(req,true);
      if ( ObjectList::IsVisDefText ( verb ) )
         dataBase.InsertIconText( presentableId_, icon );

      else if ( ObjectList::IsVisDefLegend ( verb ) )
         dataBase.InsertIcon( PRES_LEGEND_REL, presentableId_, icon, -1, true );

      else if ( ObjectList::IsVisDefImport ( verb ) )
         dataBase.InsertIcon( PRES_IMPORT_REL, presentableId_, icon );

      else  // Nothing to be inserted
         return false;
   }

    // Redraw this presentable
    RedrawIfWindow();
    NotifyObservers();

    return true;
}

void Presentable::Draw ()
{
    // Draw all my children
    DrawChildren ();
}

void Presentable::DrawProlog ()
{
     MvChildIterator child;
	for ( child = childList_.begin(); child != childList_.end(); ++child )
		(*child)->DrawProlog();
}

void Presentable::DrawTrailer( MvRequest& fullReq )
{
     // Get children requests
     MvChildIterator child;
     for ( child = childList_.begin(); child != childList_.end(); ++child )
          (*child)->DrawTrailer(fullReq);
}

void Presentable::DrawLayerInfo ( const int iconRelId, const char* name )
{
    // Retrieve the Graphics Engine and the data base info
    GraphicsEngine& ge = GetGraphicsEngine();
    MvIconDataBase& dataBase = IconDataBase();

    // Call the Graphics Engine to store the Layer info.
    // If it does not exist, create a default one.
    MvIcon iconLayer;
    if ( !dataBase.RetrieveIcon( ICON_LAYER_REL,iconRelId,iconLayer ) )
    {
        MvLayer layer(name);
        MvIcon icon(layer.Request(),true);
        dataBase.InsertIcon( ICON_LAYER_REL,iconRelId,icon );
        ge.Draw ( icon.Request() );
    }
    else
        ge.Draw ( iconLayer.Request() );

    return;
}

void Presentable::DrawTask ()
{
   // Ask the Root to perform the drawing
   Root::Instance().DrawTask();
}

bool Presentable::CheckDrawTask ()
{
   if ( this->HasDrawTask() )
      return true;

   // Check if any of my children has some task to be performed
   MvChildIterator child;
   for ( child = childList_.begin(); child != childList_.end(); ++child )
      if ( (*child)->CheckDrawTask() )
         return true;

   return false;
}

void Presentable::NotifyObservers()
{
	set<PresentableObserver*> o = observers_;
	for(set<PresentableObserver*>::iterator j= o.begin(); j != o.end(); ++j)
		(*j)->Notify(*this);
}

void Presentable::GetDataUnitInfo ( MvRequest& out )
{
   // Get icon data base
   MvIconDataBase& iconDataBase = this->IconDataBase();

   // Get data unit list
   MvIconList* iconList = iconDataBase.IconList(DB_DATAUNIT);
   MvListCursor lCursor = iconList->begin();
   if ( lCursor == iconList->end() )
   {
      cout << "NO DATA UNIT AVAILABLE" << endl;
      return;
   }

   // Process only the first data unit
   // Revise this later if the whole list of data units is required
   //while (lCursor != iconList->end())
   {
      // Build a new data decoder, which will provide information
      // about the data
      auto_ptr<Decoder> decoder ( DecoderFactory::Make ((*lCursor).Request() ) );
      ensure (decoder.get() != 0);

      // Read data headers (one by one)
      while ( decoder->ReadNextData() )
      {
         // Get data unit info
         MvRequest req = decoder->Request();
         out.addValue("DATE",(int)req("DATE"));
         out.addValue("TIME",(int)req("TIME"));
         out.addValue("STEP",(int)req("STEP"));
         out.addValue("EXPVER",(const char*)req("EXPVER"));
      }

      ++lCursor;
   }
}

void
Presentable::ProcessCoastlines ( MvRequest& coastRequest, bool calledFromMacro, bool foundDU )
{
   // Two main procedures:
   // A) if input icon came from a Macro then:
   //    1) keep it in the same position as defined in the Plot command:
   //       FOREGROUND or BACKGROUND
   //    2) create an empty icon as a companion (FOREGROUND or BACKGROUND)
   // B) if the icon came from a Drop then:
   //    1) split it by creating the FOREGROUND and BACKGROUND icons
   //    2) replace the ones defined in the Page level

   bool exclusive;  // true: dropped icon; false: icon came from Macro
   MvRequest backReq, foreReq;

   // Icon from a Macro
   MvIconDataBase& dataBase = IconDataBase();
   if ( calledFromMacro )
   {
      string name;
      exclusive = false;
      bool foreground = foundDU;
      if ( foreground )
      {
         foreReq = coastRequest;
         foreReq.unsetParam("_APPL"); // remove tag stating that this came from Macro
         if ( (const char*)foreReq("_NAME") )
            name = (const char*)foreReq("_NAME");
         else
            name = "<Coastlines>";

         // Create background request and unset drawings
         backReq = ObjectList::CreateDefaultRequest ("MCOAST", EXPAND_NO_DEFAULT);
         backReq ("MAP_COASTLINES") = "OFF";
         backReq ("MAP_LABEL") = "OFF";
         backReq ("MAP_GRID") = "OFF";
      }
      else
      {
         backReq = coastRequest;
         backReq.unsetParam("_APPL"); // remove tag stating that this came from Macro
         if ( (const char*)backReq("_NAME") )
            name = (const char*)backReq("_NAME");
         else
            name = "<Coastlines>";

         // Create foreground request and unset drawings
         foreReq = ObjectList::CreateDefaultRequest ("MCOAST", EXPAND_NO_DEFAULT);
         foreReq ("MAP_COASTLINES") = "OFF";
         foreReq ("MAP_LABEL") = "OFF";
         foreReq ("MAP_GRID") = "OFF";
      }

      // Set tags and update request names
      string fname;
      fname = name + "(FG)";
      foreReq("_NAME") = fname.c_str();
      foreReq("_PLOTTING_ORDER") = "FOREGROUND";

      fname.clear();
      fname = name + "(BG)";
      backReq("_NAME") = fname.c_str();
      backReq("_PLOTTING_ORDER") = "BACKGROUND";
   }
   else // icon from a Drop
   {
      // Split icon
      exclusive = true;
      this->SplitCoastlines(coastRequest,backReq,foreReq);
   }

   // Create foreground icon and save it in the dataBase
   MvIcon icon(foreReq,true);
   dataBase.InsertIcon( PRES_VISDEF_REL, presentableId_, icon, -1, exclusive );

   // Create background icon and save it in the dataBase
   if ( backReq )
   {
      MvIcon icon(backReq,true);
      dataBase.InsertIcon( PRES_VISDEF_REL, presentableId_, icon, -1, false );
   }

   // Redraw this presentable
   RedrawIfWindow();
}

void
Presentable::SplitCoastlines(MvRequest& req, MvRequest& backReq, MvRequest& foreReq)
{
   // Split icon coastlines into background and foreground coastlines
   this->CoastlinesBackground(req,backReq);
   this->CoastlinesForeground(req,foreReq);
}

void
Presentable::CoastlinesBackground(MvRequest& req, MvRequest& backReq)
{
   // Build a coastline background icon derived from a coastline icon
   // By default, Coastline will only be plotted on the foreground, unless
   // there is a sea/land shade to be drawn on the background.
   backReq.clean();
   bool draw = false;
   const char* onoff = (const char*)req( "MAP_COASTLINE_LAND_SHADE" );
   if ( onoff && strcmp(onoff,"ON") == 0 )
      draw = true;

   onoff = (const char*)req( "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 = req;
      backReq ("MAP_BOUNDARIES") = "OFF";
      backReq ("MAP_CITIES") = "OFF";
      backReq ("MAP_RIVERS") = "OFF";

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

      // Set background tag and update icon name
      string name;
      if ( (const char*)backReq("_NAME") )
         name = (const char*)backReq("_NAME");
      name += "(BG)";
      backReq("_NAME") = name.c_str();
      backReq("_PLOTTING_ORDER") = "BACKGROUND";
   }
}

void
Presentable::CoastlinesForeground(MvRequest& req, MvRequest& foreReq)
{
   // Build a coastline foreground icon derived from a coastline icon
   // Account for land-sea shading. If they are setted to ON then
   // they were previously drawn on the Background by default.
   foreReq = req;
   const char* onoff = (const char*)req( "MAP_COASTLINE_LAND_SHADE" );
   if ( onoff && strcmp(onoff,"ON") == 0 )
      foreReq ("MAP_COASTLINE_LAND_SHADE") = "OFF";

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

   // Set foreground tag and update icon name
   string name;
   if ( (const char*)foreReq("_NAME") )
      name = (const char*)foreReq("_NAME");
   name += "(FG)";
   foreReq("_NAME") = name.c_str();
   foreReq("_PLOTTING_ORDER") = "FOREGROUND";
}

void
Presentable::RemoveIcon ( const int iconId )
{
   // Get icon structure given an id.
   // This is needed because if icon is a Coastlines then its
   // companion (foreground or background) should be deleted too.
   MvIcon icon;
   MvIconDataBase& dataBase = this->IconDataBase();
   if ( !dataBase.FindIcon ( iconId, icon ) )
      return;

   // Remove icon from the database
   if ( !dataBase.RemoveOneIcon(iconId) )
      return;   // icon not deleted

   // If icon is a coastline delete its companion
   MvRequest iconReq = icon.Request();
   string verb =  (const char*)iconReq.getVerb();
   if ( ObjectList::IsVisDefCoastlines( verb.c_str() ) )
   {
      // Get icon name
      string name = (const char*)iconReq("_NAME");
      if ( name.empty() )
         return;

      // Get its companion name, if exists
      string namec;
      std::size_t found = name.find("(FG)");
      if (found != std::string::npos)
      {
         namec = name.substr(0,found);
         namec += "(BG)";
      }
      else
      {
         found = name.find("(BG)");
         if (found != std::string::npos)
         {
            namec = name.substr(0,found);
            namec += "(FG)";
         }
      }

      // Remove companion icon from the database, if exists
      if ( !namec.empty() )
      {
         // Find icon and remove it
         namec = mbasename(namec.c_str());
         if ( dataBase.FindIcon ( namec.c_str(), icon ) )
            dataBase.RemoveOneIcon( icon.Id() );
      }
   }

   // Icon was deleted. Redraw the whole map.
   this->HasDrawTask(true);
   this->DrawTask();
}

#if 0
void Presentable::Add(PresentableObserver* o)
{
	observers_.insert(o);
}

void Presentable::Remove(PresentableObserver* o)
{
	observers_.erase(o);
}

void PresentableObserver::Observe(Presentable& p)
{
	p.Add(this);
	observed_.insert(&p);
}

void PresentableObserver::Forget(Presentable& p)
{
	p.Remove(this);
	observed_.erase(&p);
}

void PresentableObserver::ForgetAll()
{
	set<Presentable*>& o = observed_;
	for(set<Presentable*>::iterator j= o.begin(); j != o.end(); ++j)
		(*j)->Remove(this);
	observed_.clear();
}

PresentableObserver::~PresentableObserver()
{
	ForgetAll();
}
#endif

void PresentableObserver::Dead(Presentable* p)
{
	observed_.erase(p);
}
