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

// File SuperPage.CC
// Gilberto Camara and Fernando Ii - ECMWF Mar 97

#ifndef NOMETVIEW_QT
#include "uPlotBase.h"
#endif

#include "SuperPage.h"

#include <Assertions.hpp>
#include "MacroVisitor.h"
#include "MvApplication.h"
#include "ObjectList.h"
#include "Page.h"
#include "PlotMod.h"
#include "PmContext.h"

int SuperPage::nrSuperPages_ = 0;

#ifndef NOMETVIEW_QT
uPlotBase* SuperPage::plotApplication_=0;
#endif

SuperPage::SuperPage    ( const MvRequest& superpageRequest ):
	Presentable     ( superpageRequest   ),
	iconDataBase_   ( new MvIconDataBase ),
	preferences_    ( *this              ),
//	macroType_      ( SCREEN_MACRO       ),
//	zoomPageId_     ( 0                  ),
//	printPreview_   ( false              ),
//	contentsActive_ ( false              ),
	pageIndex_      ( 1                  ),
	superPageIndex_ ( 1                  ),
//	paperPageIndex_ ( 1                  ),
	printIndex_     ( 0                  )

{
   // bool calledFromMacro = ObjectInfo::CalledFromMacro(superpageRequest);
   // Retrieve the subrequest describing the Pages
   MvRequest pagesRequest = superpageRequest.getSubrequest ( PAGES );

   // Check if the request is a PAGE request
   // If it does not exist, create one PAGE request
   Cached pageVerb = pagesRequest.getVerb();
   if ( pageVerb != PLOTPAGE )
       pagesRequest = ObjectList::CreateDefaultRequest ( "PLOT_PAGE" );

   // Rewind the request
   pagesRequest.rewind();

   // Loop through the request, create new Pages
   // and insert them as children of the superpage
   while ( pagesRequest )
   {
      // Extract the page request
      MvRequest newpageRequest = pagesRequest.justOneRequest();

      // Create a new page
      //Presentable* page = new Page ( newpageRequest );
      Page* page = new Page ( newpageRequest );
      ensure ( page != 0 );

      // Insert the page in the superpage's child list
      this->Insert ( page );

      // Goto the next page request
      pagesRequest.advance();
   }

   // Store my size
   double width  = superpageRequest ( "CUSTOM_WIDTH" );
   double height = superpageRequest ( "CUSTOM_HEIGHT" );
   if ( width <= 0 || height <= 0 )
   {
       // default A4 landscape
       width = 29.7;
       height = 21.0;
   }
   size_ = PaperSize ( width, height );

   // Create and store the device information
   this->SetDeviceInfo ( superpageRequest );

#ifndef NOMETVIEW_QT
   // Save information in uPlot
   if (PlotMod::Instance().IsWindow() && plotApplication_)
   plotApplication_->SetPresentable(*this);
#endif

   nrSuperPages_++;
   // The purpose of this is to keep PlotMod alive when called in batch. Macro will die once it gets
   // a reply request from PlotMod, and take other modules down before plotting is finished.
   if ( nrSuperPages_ == 1 && ! PlotMod::Instance().IsInteractive() )
       MvApplication::setKeepAlive(true);
}


SuperPage::SuperPage(const SuperPage &old) :
    Presentable(old),
//  size_(old.size_),
//  macroFileName_(old.macroFileName_),
    preferences_(old.preferences_),
//  macroType_(old.macroType_),
//  zoomPageId_(0),
//  printPreview_(old.printPreview_),
//  contentsActive_(old.contentsActive_),
    pageIndex_(1),
    superPageIndex_(1),
//  paperPageIndex_(1),
//  backDrawEnabled_(old.backDrawEnabled_),
  printIndex_(0)
{
	// Make a new icon db from the old one
	auto_ptr<MvIconDataBase> iconDb( new MvIconDataBase(old.IconDataBase() ) );
	iconDataBase_ = iconDb;

	// Set new owner for preferences
	preferences_.Owner(*this);

	// Member myDevice_ is intentionally not copied
	nrSuperPages_++;

	// Should never kick in, nrSuperPages_ should be at least 2 here.
	if ( nrSuperPages_ == 1 && ! PlotMod::Instance().IsInteractive() )
		MvApplication::setKeepAlive(true);
}

SuperPage::~SuperPage()
{ 
	nrSuperPages_--;

        // If called from macro, we don't need to keep PlotMod artificially alive any more.
	if ( nrSuperPages_ == 0 && ! PlotMod::Instance().IsInteractive() )
	  MvApplication::setKeepAlive(false);
}

// -- METHOD  : Create Reply
//
// -- PURPOSE : Indicate to MetviewUI and to Macro the ids 
//              of the superpage and pages
//
// -- INPUT   : A reply request 
//
// -- OUTPUT  : An updated reply request (which is included 
//              in the Context)
//
// -- OBS     : Please see the PmContext class ( especially
//              the destructor )

void
SuperPage::CreateReply ( MvRequest& replyRequest )
{
	// First, for all its children, include the drop id
	MvChildIterator child = childList_.begin();

	int k = 0;
	while ( child != childList_.end() )
	{
		MvRequest pageReply ( "DROP" );
		pageReply.setValue  ( "DROP_ID", (*child)->Id() );

		//If the superpage  has been called from a Macro,
		//  then it needs to ask Macro to notify when finished.
		if ( PlotMod::Instance().CalledFromMacro () && k++ == 0)
			pageReply ( "_NOTIFY" ) = "NEWPAGE";

		replyRequest += pageReply;
		++child;
	}

// This facility was removed due to backward compatibilities.
// The "count(superpage)" command  should return only the number 
// of pages and not the number of pages plus one (the superpage id).
  // Return drop id for superpage at the end.
//  MvRequest myReply ( "DROP" );
//  myReply.setValue  ( "DROP_ID", Id() );
//  replyRequest = replyRequest + myReply;
}

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

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

void
SuperPage::Drop ( PmContext& context )
{
   MvRequest dropRequest = context.InRequest();

   // Accept VisDefs in the Super Page, if other icon needs the same add here
   while ( dropRequest )
   {
      MvRequest request =  dropRequest.justOneRequest();
      Cached verb = request.getVerb();

      if ( this->DroppedHere () )
      {
         if ( ObjectList::IsVisDef ( verb ) == true )
            this->InsertVisDef ( request );
         else
            this->InsertCommonIcons(request);
      }
      dropRequest.advance();
   }

   // Send to Page
   for_each ( childList_.begin(), childList_.end(), DropFunctor(context) );
}

#if 0
// -- METHOD  : Close
//
// -- PURPOSE : Save and delete a superpage
//
// -- OBS     : This is achieved by sending a request to PlotMod
//              indicating the presentable to be deleted

void
SuperPage::Close()
{
	// Delete all structures and exit
	//command exit(0) should do the job
        Presentable* treeNode = Root::Instance().FindBranch (Id());
          if (treeNode == 0)
          {
                   cout << "SuperPage::Close " << endl;
                   cout << " ** Error - Cannot associate page with DropId" << endl;
                   return;
          }
 
          // delete the tree node and its children
          delete treeNode;
//	  exit(0);

MvRequest closeRequest ("CLOSE");
closeRequest ("DROP_ID") = Id();
MvApplication::callService ( "uPlotBatch", closeRequest, 0 );
}

// -- METHOD  : Save in File
//
// -- PURPOSE : Save the contents of the superpage

void
SuperPage::SaveInFile()
{
	// Don't save if called from a macro

	if ( ObjectInfo::CalledFromMacro ( myRequest_ ) == false )
	{
	}
		// My pages may have changed their views

// SuperPage shouldn't save the views associated to the pages, 
// unless the users ask explicitly for that. A tool for that 
// should be built.
// It will make sense only when the view associated to the page 
// can be replaced.
//		this->SaveChildren ();

}
#endif


// -- METHOD :  Name 
//
// -- PURPOSE:  Inform the superpage's name 
//
// -- INPUT  :  (none)
//
// -- OUTPUT :  The name of the superpage
string
SuperPage::Name()
{
	return  (const char*)ObjectInfo::ObjectName ( myRequest_, "SuperPage", Id() );
}

// -- METHOD :   Draw
// 
// -- PURPOSE:   Draws a superpage
//
// -- INPUT  :   (none)
//
// -- OUTPUT : 	 Drawing on window or paper
//	
void
SuperPage::Draw()
{
	HasDrawTask ( true );

	printIndex_ = 0;

	// Draw all my children
	DrawChildren ();

	this->HasDrawTask ( false );
}

void
SuperPage::DrawProlog()
{
     // Call all my children
	MvChildIterator child;
	for ( child = childList_.begin(); child != childList_.end(); ++child )
		(*child)->DrawProlog();
}

void
SuperPage::DrawTrailer( MvRequest& fullReq )
{
   // Nothing to be drawn
   if ( !this->HasDrawTask () )
      return;

// This was needed to send the driver info to Magics for each newpage.
// Now, Magics only receive the driver info once (FAMI20150514)
   // Retrieve from the request the Output Device description
//   fullReq = fullReq + myRequest_("_OUTPUT_DEVICES");

   // Get all requests
   GetAllRequests( fullReq );

   // Reset the draw task
   this->HasDrawTask ( false );
}

void
SuperPage::GetAllRequests( MvRequest& fullReq )
{
     // Add the superpage request
     MvRequest sp("SUPERPAGE");
     sp( "SUPER_PAGE_X_LENGTH") = size_.GetWidth();
     sp( "SUPER_PAGE_Y_LENGTH") = size_.GetHeight();
     fullReq += sp;

	// Get all page requests
     MvChildIterator child;
     for ( child = childList_.begin(); child != childList_.end(); ++child )
          (*child)->DrawTrailer ( fullReq );
}

#if 0
void
SuperPage::HasReceivedNewpage( bool isLast )
{
        if ( NeedsRedrawing ( ) ) this->Draw ();

//D	if ( this->IsAWindow () ) return;

	if ( isLast )
	{
//D		MvChildIterator child = childList_.begin();
//D		Page* page = (Page*) (*child);			  
//D		page->DrawTrailer ();
		this->DrawTrailer();
		hasNewpage_ = true;
	}
	else
		superPageIndex_ = paperPageIndex_ + 1;
}
#endif

// -- METHOD :  SetDeviceInfo
//
// -- PURPOSE:   Create and initialise the superpage's device
//               (called by the constructor)
// -- INPUT  :   The request which created the superpage
//
// -- OUTPUT :   (none)
//
// -- OBS    :   The device class will implement the "Visitor"
//               pattern, and this method will enable it
//               to "visit" the superpage and its children

void
SuperPage::SetDeviceInfo ( const MvRequest& inRequest )
{
	// The input request contains the necessary information
	// for creating a device driver
	
	// The Create Request method will generate an
	// appropriate device Request
	MvRequest deviceRequest = Device::CreateRequest ( inRequest );

	auto_ptr <Device> dev ( DeviceFactory::Make ( deviceRequest ) );

	myDevice_ = dev;

	// The device is a visitor - this command will trigger
	// its visit (i.e., its traversal through the page hierarchy)
	myDevice_->Initialise( *this );
}

void
SuperPage::SetDeviceInfo ( )
{
//	ensure ( myDevice_ == 0);

	// The device is a visitor - this command will trigger
	// its visit (i.e., its traversal through the page hierarchy)
	myDevice_->Initialise( *this );
}

// --- METHOD : GenerateMacro
// --- PURPOSE: Generate a macro file with the contents of the superpage
//
// --- INPUT  : Name of the macro file the be written
//              Type of the macro (can be:
//                  SCREEN_MACRO - Reproduce the output of the screen
//       	    ZOOM_AREA    - Zoom into a single page
//
// --- OUTPUT : Macro program written (by the class MacroDevice)

void
SuperPage::GenerateMacro( )
{
	// Restart the page index count (used later)
    pageIndex_ = 1;

	// Update the macro type for later use
//	macroType_ = type;

	// Update the macrofile name, if screenmacro, put file in the superpage directory,
	// otherwise put in temporary directory.
	macroFileName_ = MacroVisitor::CreateFileName ( myRequest_ );

	// Create a new visitor
	auto_ptr <Visitor> vis ( new MacroVisitor ( macroFileName_ ) );

	// Visit me
	vis->Visit (*this);

	// Visit all my children
	Presentable::Visit ( *vis );

	// Post a message on the screen
	string message = "Macro Generated in File " + macroFileName_;
	PlotMod::Instance().UserMessage (message);
}

// -- METHOD :  Visit
//
// -- PURPOSE:  Implement the visitor pattern
//
// -- INPUT  :  visitor (XDevice or PSDevice or MacroVisitor)
//
// -- OUTPUT :  (none)
void
SuperPage::Visit ( Visitor& v )
{ 
	// Visit me
	v.Visit (*this);

	// Visit all my children
	Presentable::Visit ( v );
}

// -- METHOD :  GetMySize
//
// -- PURPOSE:  Return the presentable's size 
//
// -- INPUT  :  (none)
//
// -- OUTPUT :  The size of the superpage window
//              (which is always in paper coordinates)
PaperSize
SuperPage::GetMySize()
{
	return size_;
}

#if 0
// -- METHOD :  SetMySize
//
// -- PURPOSE:  Update the presentable's size 
//
// -- INPUT  :  Dimensions width and height
//
// -- OUTPUT :  (none)

void
SuperPage::SetMySize ( double width, double height )
{
	size_ = PaperSize ( width, height );

	SuperPageWidget* myWidget = (SuperPageWidget*) deviceData_.get();
	myWidget->UpdateSize();
}
#endif

#if 0
// -- METHOD :  IsAWindow
//
// -- PURPOSE:  Determine if the superpage is a window 
//
// -- INPUT  :  (none)
//
// -- OUTPUT :  true/false

bool
SuperPage::IsAWindow ()
{
	MvRequest req = myDevice_->DeviceRequest();

        if ( IsParameterSet(req,"OUTPUT_DEVICES") )
	{
		MvRequest req1 = req("OUTPUT_DEVICES");
                if ( strcmp(req1.getVerb(),"QtDriver") == 0 )
		     return true;
	}

	return false;
}
#endif


#if 0
// -- METHOD: PrintPreview
//
// -- PURPOSE: set printing mode to Preview'

void
SuperPage::PrintPreview()
{
	printPreview_ = true;
}

// -- METHOD: Print
//
// -- PURPOSE: Print the current request.
//			   This is done in three steps:
//             1. Create a temporary ps file by calling SuperPage::PrintJob (see below)
//			   2. Call the following printer command:
//			    	 <$METVIEW_PRINTER_COMMAND> -P<$METVIEW_PRINTER> <temp.ps>
//				  If environment variable $METVIEW_PRINTER_COMMAND is not defined
//				  then uses the lpr command.
//				  If environment variable $METVIEW_PRINTER is not defined
//				  then uses the default lpr printer.
//             3. Delete the temporary ps file
//                

//This is done in five steps:
//             1. Ask the preferences member to establish the
//                user's printer choices
//             2. The "preferences" object will ask GenApp to
//                show an Editor with the Printer Preferences menu
//             3. After GenApp returns, the "preferences" object
//                will call the superpage's method "PrintJob" (see below)
//             4. The SuperPage::PrintJob will duplicate the hierarchy,
//                including all dataunits and visdefs, set device according
//                to given printrequest, and just call DrawProlog, Draw and
//                DrawTrailer to draw the new superpage.
//             5. Printing is finalised from MagicsPicturAction. When the 
//                trailer is received, plotmod generates the postscript file
//                and sends itself a close request. The CloseAction will delete
//                the superpage, and the PSDevice destructor will put the file
//                where it should be ( file,preview, printer).
//                
void
SuperPage::Print()
{
	printPreview_ = false;

	// Create the ps file
	// Get the process number to build the ps temporary file name
	// This file should be deleted in the uPlot destructor
    stringstream sid;
	sid << getpid();
    string psname = sid.str() + "tmpfile.ps";
	string tmpfile = MakeTmpPath(psname.c_str());
	PrintJob(tmpfile);
	
	// Call printer command
	string com;
	const char* prcom = getenv("METVIEW_PRINTER_COMMAND");
	const char* printer = getenv ("METVIEW_PRINTER");
	prcom ? com = prcom : com = "lpr";
	if ( printer )
	{
		com += " -P";
		com += printer;
	}
	com += " " + tmpfile;

//	/opt/kde3/bin/kprinter
	system(com.c_str());
	
	// Send message to the user, if printer command is not defined
	if ( !prcom )
	{
		string message = "Print Job sent to printer: ";
		printer ? message += printer : message += "default";
    	PlotMod::UserMessage ( message );
	}

// Need to move this command to the destructor???
// Maybe it should destroy all the temporary files
// together: rm -f <pid>*
	// Delete the temporary ps file
	string del = "rm -f " + tmpfile;
	system(del.c_str());
}

// -- METHOD: PrintJob
//
// -- PURPOSE: Duplicates SuperPage hierarchy, including all dataunits
//		       and visdefs, set device according to given printrequest,
//			   and just call DrawProlog, Draw and DrawTrailer to draw 
//			   the new superpage.

// Remove this routine
void SuperPage::PrintJob()
{
#if 0 //D It is not need anymore
  MvRequest printReq = preferences_.PrinterRequest();

  MvRequest superpageReq = myRequest_;
  superpageReq("_DRIVER") = printReq;
  superpageReq("_PRINT_OPTION")  = printReq("PRINT_OPTION");

  SuperPage *printSuperPage = new SuperPage(*this);
  Root::Instance().Insert(printSuperPage);
  printSuperPage->DuplicateChildren(*this);

  myRequest_ = superpageReq;
  printSuperPage->SetDeviceInfo(superpageReq);

  printSuperPage->NeedsRedrawing(true);

  printSuperPage->hasNewpage_ = true;  

  // Refresh tag: do not need to rebuild the visualization tree
  printSuperPage->myRequest_("_REFRESH") = "OFF";

  // Draw 
  AddTask( *printSuperPage, &SuperPage::DrawProlog );
  AddTask( *printSuperPage, &SuperPage::Draw );
  AddTask( *printSuperPage, &SuperPage::DrawTrailer );

  TaskBase::Flush();
 
 #endif
 }
 
void SuperPage::PrintJob( string& tmpfile )
{
	// Define postscript driver
	MvRequest subreq("PSDriver");
	subreq("OUTPUT_NAME") = tmpfile.c_str();
	
	// Add postscript driver to the printer manager
	MvRequest printReq("PRINTER_MANAGER");
	printReq("OUTPUT_DEVICES") = subreq;

	// Add printer manager to the request
  	MvRequest superpageReq = myRequest_;
  	superpageReq("_DRIVER") = printReq;
  	superpageReq("_PRINT_OPTION")  = printReq("PRINT_OPTION");

	// Clone the visualized superpage
  	SuperPage *printSuperPage = new SuperPage(*this);
 	Root::Instance().Insert(printSuperPage);
  	printSuperPage->DuplicateChildren(*this);

	// Update variables
  	myRequest_ = superpageReq;
  	printSuperPage->SetDeviceInfo(superpageReq);
 	printSuperPage->NeedsRedrawing(true);
  	printSuperPage->hasNewpage_ = true;  

  	// Refresh tag: do not need to rebuild the visualization tree
 	printSuperPage->myRequest_("_REFRESH") = "OFF";

  	// Draw 
  	printSuperPage->DrawProlog();
  	printSuperPage->Draw();
  	printSuperPage->DrawTrailer();
	
	// Check if it is destroying everything, including
	// removing it from the list of superpages????????????
	// The object has not been destroyed because variable
	// nrSuperPages_ is static and > 1.
	delete printSuperPage;
}

// -- METHOD: PrintingFinished
//   Probably not needed anymore.
// -- PURPOSE: Called by MacroService after the macro has 
//             finished printing to print a message indicating
//             if the job has been completed
//
// -- INPUT:   The reply Request from the Macro Service
//
void
SuperPage::PrintingFinished( MvRequest& replyRequest )
{
	int errCode = replyRequest ( "ERR_CODE" );

	// If we are not in print preview mode, generate a message
	// on the screen

	if ( printPreview_ == false )
	{
		if ( errCode == 0 )
			PlotMod::UserMessage ( "Print Job Finished" );
		else
		{
			PlotMod::SystemError ( (const char*) replyRequest ( "ERROR" ), "Printing" );
		}
	}
}




// -- METHOD:  PostMessage
//
// -- PURPOSE: Put a warning on the screen
//			   (done by the SuperPageWidget)
//
void
SuperPage::PostMessage ( const char* title, const char* message )
{
	// Are we in interactive mode ?
	if ( PlotMod::IsInteractive() == true )
	{
		SuperPageWidget* myWidget = (SuperPageWidget*) deviceData_.get();
		myWidget->PostMessage ( title, message );
	}
}

// -- METHOD:  EditPrinterPreferences
//
// -- PURPOSE: Called by the interface to edit the
//             printer preferences
//
void
SuperPage::EditPrinterPreferences()
{
	preferences_.EditPrinterPreferences();

}

void
SuperPage::EditInterfacePreferences()
{
	preferences_.EditInterfacePreferences();
}

void
SuperPage::SetCursorType ( CursorType option )
{
	preferences_.SetCursorType ( option );
}

void
SuperPage::SetInputType ( InputType option )
{
	preferences_.SetCursorType ( POINTERCURSOR );
	preferences_.SetInputType ( option );
}

#if 0
void
SuperPage::StartMapEditor()
{
	// Call a Request which is sent directly to PlotMod

	MvRequest mapRequest ("EDIT_MAP");

	mapRequest ( "CUSTOM_WIDTH"  ) = size_.GetWidth();
	mapRequest ( "CUSTOM_HEIGHT" ) = size_.GetHeight();

	mapRequest ( "PATH"   ) = ObjectInfo::ObjectPath ( myRequest_ );

	MvApplication::callService ( "uPlot", mapRequest, 0 );	
}	
#endif

void
SuperPage::MouseMode()
{
	cout << "SuperPage::MouseMode" << endl;
}

void
SuperPage::UpdateWidget ( MvRequest& newpageRequest, const int treeNodeId, int& newTreeNodeId)
{
        // Find a sub-branch in the tree hierarchy
	Presentable* oldPage = FindBranch ( treeNodeId );

	// Delete old page
	// ????????? IMPORTANTE ????????????
	// FAMI0698 PLEASE CHECK IF ALL THE DESTRUCTORS HAS BEEN
	// CALLED (THE MEMORY SHOULD BE CLEANED PROPERLY)
	delete oldPage;

	// Create a new page	
	Presentable* page = new Page ( newpageRequest );
	ensure ( page != 0 );
	newTreeNodeId = page->Id();

	// Insert the page in the superpage's child list
	this->Insert ( page );

	// Create and store the device information
	page->Visit ( *myDevice_ );
}
#endif

// --  METHOD  : MacroPlotIndexName
//
// --  PURPOSE : Provide a sequential index to all pages
//                associated to the superpage
// --  INPUT   : none
//
// --  OUTPUT  : An index into the name returned by plot_superpage.
//
//               Has the side effect of updating member pageIndex_.
//
string
SuperPage::MacroPlotIndexName(bool useIndex)
{
	int index;
  	if ( useIndex)
        index = pageIndex_++;
	else
		index = childList_.size() + 1;

	ostringstream ostr;
	ostr << "dw[" << index << "]";
	return ostr.str();
}

// -- METHOD :  Describe Device
//
// -- PURPOSE:  Generate the device description in macro syntax
//
// -- INPUT  :  a description object
//
// -- OUTPUT :  an updated description object
//
void
SuperPage::DescribeDevice ( ObjectInfo& myDescription )
{
   myDescription.PutNewLine ( "" );
   myDescription.PutNewLine ( "# Device description" );

   // Generate description for file
   MvRequest reqDev( "PSOUTPUT" );
   string filename = (const char*)ObjectInfo::ObjectPath ( myRequest_ );
   filename += "/ps";
   reqDev("OUTPUT_NAME") = filename.c_str();
   myDescription.ConvertRequestToMacro ( reqDev,PUT_END,"File","ps_output"  );

   // Check running mode 
   myDescription.PutNewLine ( "" );
   myDescription.PutNewLine ( "# Checks running mode" );
   myDescription.PutNewLine ( "mode = runmode()" );
   myDescription.PutNewLine ( "if mode = 'batch' or mode = 'execute' then" );
   myDescription.PutNewLine ( "   setoutput(File)" );
   myDescription.PutNewLine ( "end if" );
}

// -- METHOD :  Describe Yourself
//
// -- PURPOSE:  Generate the superpage description in macro syntax
//
// -- INPUT  :  a description object
//
// -- OUTPUT :  an updated description object
//
void
SuperPage::DescribeYourself ( ObjectInfo& myDescription )
{
   myDescription.PutNewLine ( "" );
   myDescription.PutNewLine ( "# SuperPage description" );

   set<Cached> skipSet;
   skipSet.insert("PAGES");
   myDescription.ConvertRequestToMacro ( myRequest_, PUT_LAST_COMMA,
                                         MacroName().c_str(),"plot_superpage",
                                         skipSet);

   // Print the page list
   int size = myDescription.MaximumParameterNameLength(myRequest_);
   string pageList = ListMyPages();
   myDescription.FormatLine ("PAGES",pageList.c_str(),"",size);

   // Close superpage request
   myDescription.PutNewLine ( ")"  );
   myDescription.PutNewLine ( "# plot_superpage returns a list of drop identifiers." );
   myDescription.PutNewLine ( "# Index 1 is for first page, and so on.\n" );
   string ret = "return " + MacroName();
   myDescription.PutNewLine( ret.c_str() );
}

// --  METHOD  : ListMyPages
//
// --  PURPOSE : Provide a listing all all pages
//                associated to the superpage
// --  INPUT   : none
//
// --  OUTPUT  : list of page name ( enclosed in [..] )
//
string
SuperPage::ListMyPages()
{
	// Put an enclosing brace
 	string pageNames = "[ ";
 
 	MvChildIterator child = childList_.begin();
	int npages = 1;
	while ( child != childList_.end() )
	{
		// Put a comma separator
		if ( npages > 1 )
			pageNames += ", ";

		// Get the name of the page
		pageNames += (*child)->MacroName();

		++child;
		++npages;
	}
 	
	// Put a termination brace
	pageNames += " ]";

	return pageNames;
}

void
SuperPage:: PrintAll ( bool printAll )
{
	if ( printAll )
		myRequest_ ( "_PRINT_OPTION" ) = "ALL";
	else
		myRequest_ ( "_PRINT_OPTION" ) = "VISIBLE";
}

bool
SuperPage:: PrintAll ()
{
	return ( myRequest_ ( "_PRINT_OPTION" ) == Cached ( "ALL" ) );
}

void
SuperPage::InsertVisDef ( MvRequest& visdefRequest  )
{
   // Retrieve the Icon Data Base
   MvIconDataBase& dataBase = this->IconDataBase();

   // Test if Visdef came from Contents edition window
   int visdefId = visdefRequest( "_CONTENTS_ICON_EDITED" );
   if (visdefId != 0)
   {
      // Visdef already exists in the data base replace in data base
      dataBase.UpdateIcon ( DB_VISDEF, visdefId, visdefRequest );
      EraseDraw(visdefId);
   }
   else
   {
      // Insert the visdef in the data base
      EraseDefaultDraw();
      MvIcon dummy;
      dataBase.InsertVisDef ( visdefRequest, Id(), dummy );
   }

   // Draw me later on
   RedrawIfWindow();
   NotifyObservers();
}

void
SuperPage::RemoveIcon ( MvIcon& icon )
{
	Cached verb =  icon.Request().getVerb();
	if ( ObjectList::IsVisDef     ( verb ) ||
	     ObjectList::IsVisDefText ( verb )    )
	{
		MvChildIterator child;
		for ( child = childList_.begin(); child != childList_.end(); ++child )
			(*child)->RemoveIcon ( icon );
	}
}

#if 0
void
SuperPage::NeedsRedrawing(bool yesno)
{
	for (MvChildIterator ii = childList_.begin(); ii != childList_.end(); ii++)
		(*ii)->NeedsRedrawing(yesno);
}

bool
SuperPage::NeedsRedrawing()
{
	for (MvChildIterator ii = childList_.begin(); ii != childList_.end(); ii++)
		if ( (*ii)->NeedsRedrawing() )
			return true;

	return false;
}
#endif

void
SuperPage::EraseDraw (int visdefId)
{
	for ( MvChildIterator ii = childList_.begin(); ii != childList_.end(); ii++ )
		(*ii)->EraseDraw (visdefId);
}

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

void SuperPage::RedrawIfWindow(int visdefId)
{
  for ( MvChildIterator ii = childList_.begin(); ii != childList_.end(); ii++ )
    (*ii)->RedrawIfWindow (visdefId);		
}

void
SuperPage::SetInputPresentableId ( int presentableId )
{
      	// Build heading request with drop id
	MvRequest vistool = "VISTOOL";

	MvRequest window = "DROP";
	window ( "DROP_ID" ) = presentableId;
	vistool ( "WINDOW" ) = window;

	MvRequest setup = "vistool";
	setup ( "service" ) = "gribtool";
	setup ( "mode" ) = "Default";
	setup ( "type" ) = "button";
	setup ( "interest" ) = "POSITION";
	setup.addValue  ( "interest", "CHANGE_WINDOW" );
	setup.addValue  ( "interest", "CONTENTS" );
	setup.addValue  ( "interest", "CLOSE_WINDOW" );
	setup ( "pixmap" ) = "/cc/od/graphics/icons/pw_sight.icon" ;
	vistool ( "SETUP" ) = setup;

	vistool ( "TITLE" ) = "Plot Window 1";
	vistool ( "SOURCE" ) = "uPlot";

//	VISTOOL,
//	    WINDOW     = (DROP,
//	    DROP_ID    = 1
//
//	),
//	    SETUP      = (vistool,
//	    service    = gribtool,
//	    mode       = Default,
//	    type       = button,
//	    interest   = POSITION/CHANGE_WINDOW/CONTENTS/CLOSE_WINDOW,
//	    pixmap     = '/cc/od/graphics/icons/pw_sight.icon'
//
//	),
//	    TITLE      = Plot Window 1

//	MvApplication::callService ( "gribtool", vistool, 0 );
	GribToolService::Instance().CallGribTool ( vistool );
}
#endif

// -- METHOD  :  RetrieveTextList
//
// -- PURPOSE : This method will retrieve the Text list. If there is no
//              TextList it will go up to the Root treeNode (the top of
//              the tree) to retrieve the user's default Text list.
bool
SuperPage::RetrieveTextList ( MvIconList& textList )
{
   bool usingDefault = false;

   // Try to find Texts associated to the presentable
   if (!iconDataBase_->RetrieveIcon ( PRES_TEXT_REL, presentableId_, textList ))
      usingDefault = myParent_->RetrieveTextList(textList);

   ensure(textList.size() > 0);

   // It is a Text default and I am the SuperPage
   // Save Texts default in the DataBase
   if ( usingDefault )
   {
      MvListCursor  vdCursor;
      for ( vdCursor = textList.begin(); vdCursor != textList.end(); ++vdCursor)
      {
         MvIcon& text = *( vdCursor );
         iconDataBase_->InsertIcon( PRES_TEXT_REL, presentableId_, text );
      }
   }

   return usingDefault;
}

// -- METHOD  :  RetrieveLegend
//
// -- PURPOSE : This method will retrieve the Legend. If there is no
//              Legend it will go up to the Root treeNode (the top of
//              the tree) to retrieve the user's default Legend.
bool
SuperPage::RetrieveLegend ( MvIcon& legIcon )
{
   bool usingDefault = false;

   // Try to find a visdef associated to the presentable
   if (!iconDataBase_->RetrieveIcon ( PRES_LEGEND_REL,presentableId_,legIcon ))
      usingDefault = myParent_->RetrieveLegend(legIcon);

   // It is a Legend default and I am the SuperPage
   // Save Legend default in the DataBase
   if ( usingDefault )
      iconDataBase_->InsertIcon( PRES_LEGEND_REL,presentableId_ ,legIcon);

   return usingDefault;
}

#if 0
void
SuperPage::SetBackgroundDraw ( bool truefalse )
{
	backDrawEnabled_ = truefalse;
//D	this->NotifyObservers();

	//Temporary code to test the animation procedure
	if (backDrawEnabled_)
	{
                // Draw only the first page (test)
		MvChildIterator child = childList_.begin();
		Page* page = (Page*) (*child);
		page->DrawProlog();
		page->Draw();

		// Change PGRIB to GRIBLOOP
		MvRequest fullReq;
		GetAllRequests(fullReq);

		MvRequest fullNewReq;
		while (fullReq)
		{
			MvRequest newReq = fullReq.justOneRequest();
			if ( strcmp(newReq.getVerb(),"PGRIB") == 0 )
			{
				newReq.setVerb("GRIBLOOP");
			}
			fullNewReq = fullNewReq + newReq;
			fullReq.advance();
		}

                // Call MAGICS to process the request
cout << "SuperPage::SetBackgroundDrawCCCCCCCC" << endl;
fullNewReq.print();
                MagPlusService::Instance().SetRequest( fullNewReq );
	}
}

void
SuperPage::PrintInfo ()
{
	cout << "SuperPage " << presentableId_ << endl;
	MvChildIterator child = childList_.begin();
	while ( child != childList_.end() )
	{
		Page *page = (Page*) (*child);
		page->PrintInfo(); 

		++child;
	}
}
#endif

int
SuperPage::IncrementPrintIndex ()
{
	printIndex_++;
	return printIndex_;
}

#if 0
void
SuperPage::ZoomRequest( int treeNodeId, const Location& zoomCoord )
{
	// Find which child to send the information
	MvChildConstIterator child;
	for (child = childList_.begin(); child != childList_.end(); ++child)
	{
		if ( treeNodeId == (*child)->Id() )
		{
			// Update page geographical area
			Page *page = (Page*) (*child);
			page->ZoomRequest(zoomCoord);

			// Rebuild page request
         page->HasDrawTask(true);
         page->DrawTask();

            // Process pending actions
            TaskBase::Flush();
            return;
        }
    }

    PlotMod::Instance().UserMessage ( "Page to perform the zoom not found" );
}
#endif

void
SuperPage::ZoomRequest( int treeNodeId, const string& zoomInfo)
{
    // Find which child to send the information
    MvChildConstIterator child;
    for (child = childList_.begin(); child != childList_.end(); ++child)
    {
        if ( treeNodeId == (*child)->Id() )
        {
            // Update page info
            Page *page = (Page*) (*child);
            page->ZoomRequest(zoomInfo);

            // Rebuild page request
            page->HasDrawTask(true);
            page->DrawTask();
            return;
        }
    }

    PlotMod::Instance().UserMessage ( "Page to perform the zoom not found" );
}

void
SuperPage::ZoomRequest( int treeNodeId, int izoom )
{
   // Find which child to send the information
   MvChildConstIterator child;
   for (child = childList_.begin(); child != childList_.end(); ++child)
   {
      if ( treeNodeId == (*child)->Id() )
      {
         // Update page geographical area
         Page *page = (Page*) (*child);
         page->ZoomRequest(izoom);

         // Rebuild page request
         page->HasDrawTask(true);
         page->DrawTask();
         return;
      }
   }

   PlotMod::Instance().UserMessage ( "Page to perform the zoom not found" );
}

bool
SuperPage::UpdateLayerTransparency ( int id, int value)
{
    // Retrieve the Icon Data Base
    MvIconDataBase& dataBase = this->IconDataBase();

    // Update transparency value in the data base
    return dataBase.UpdateLayerTransparency( id, value );
}

bool
SuperPage::UpdateLayerVisibility ( int id, bool onoff)
{
    // Retrieve the Icon Data Base
    MvIconDataBase& dataBase = this->IconDataBase();

    // Update transparency value in the data base
    return dataBase.UpdateLayerVisibility( id, onoff );
}

bool
SuperPage::UpdateLayerStackingOrder ()
{
    // Retrieve the Icon Data Base
    MvIconDataBase& dataBase = this->IconDataBase();

    // Update transparency value in the data base
    return dataBase.UpdateLayerStackingOrder();
}

bool
SuperPage::ExportPlot ( MvRequest* req, bool sync )
{
   MvRequest inReq = *req;

   // Create printer request
   MvRequest printerReq( "PRINTER_MANAGER" );
   printerReq("DESTINATION") = MVFILE;
   printerReq("OUTPUT_DEVICES") = inReq;

   // Retrieve current plot request without output formats
   MvRequest plotReq;
   GetAllRequests( plotReq );

   // Create the full request: output formats + plot requests
   MvRequest newReq = printerReq + plotReq;

   // Call uPlotBatch (syncronous or asyncronous) to do the job
   if ( sync )
   {
      int err;
      MvApplication::waitService ( "uPlotBatch", newReq, err );
      if ( err )
         return false;
   }
   else
      MvApplication::callService ( "uPlotBatch", newReq, 0 );

   return true;
}

void
SuperPage::PrintFile ( MvRequest& req )
{
   // Create output format request
   MvRequest driverReq("PSOUTPUT");
   string fileName = tempnam(getenv("METVIEW_TMPDIR"),"plot");
   fileName += ".ps";
   driverReq("OUTPUT_FULLNAME") = fileName.c_str();
   if ( (const char*)req("_OUTPUT_FRAME_LIST") )
   {
      for ( int i = 0; i < req.countValues("_OUTPUT_FRAME_LIST"); i++ )
         driverReq.addValue("OUTPUT_FRAME_LIST",(int)req("_OUTPUT_FRAME_LIST",i));
      req.unsetParam(("_OUTPUT_FRAME_LIST"));
   }

   // To avoid the printer to clip the bottom and left sides of the plot
   driverReq("OUTPUT_PS_SCALE") = 0.96;

   // Create printer request
   MvRequest printerReq = req;
   printerReq("OUTPUT_DEVICES") = driverReq;

   // Retrieve current plot requests
   MvRequest fullReq;
   GetAllRequests( fullReq );

   // Create the full request: printer request + plot requests
   MvRequest newReq = printerReq + fullReq;

   // Call uPlotBatch to do the job
   MvApplication::callService ( "uPlotBatch", newReq, 0 );

   return;
}

Page*
SuperPage::InsertOnePage(MvRequest& superpageRequest)
{
	// Retrieve the subrequest describing the Page
	MvRequest pagesRequest = superpageRequest.getSubrequest ( PAGES );

	// Check if the request is a PAGE request
	// If it does not exist, create one PAGE request
	const char* pageVerb = pagesRequest.getVerb();
	if ( strcmp(pageVerb,PLOTPAGE) )
		pagesRequest = ObjectList::CreateDefaultRequest ( "PLOT_PAGE" );

	// Create a new Page 
	// and insert it as a child of the superpage
	// Extract the page request 
	MvRequest newpageRequest = pagesRequest.justOneRequest();

	// Create a new page
	Page* page = new Page ( newpageRequest );
	ensure ( page != 0 );
		
	// Insert the page in the superpage's child list
	this->Insert ( page );

	// Create and store the device information	
	this->SetDeviceInfo ( );

	return page;
}

void
SuperPage::contentsRequest( MvRequest& req)
{
    // Find which child to send the information
    int treeNodeId = req("DROP_ID");
    MvChildConstIterator child;
    for (child = childList_.begin(); child != childList_.end(); ++child)
    {
        if ( treeNodeId == (*child)->Id() )
        {
            // Update page geographical area
            Page *page = (Page*) (*child);
            page->contentsRequest(req);

            // Rebuild page request
            page->HasDrawTask(true);
            page->DrawTask();
            return;
        }
    }

     PlotMod::Instance().UserMessage ( "Page to perform the zoom not found" );
}

#ifndef NOMETVIEW_QT
#ifdef METVIEW_WEATHER_ROOM
void
SuperPage::plotWeatherRoom( bool sync )
{
   plotApplication_->plotWeatherRoom(sync);
}
#endif
#endif
