/***************************** 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 Root.CC
// Gilberto Camara and Fernando Ii - ECMWF Mar 97

#include "Root.h"

#include <Assertions.hpp>
#include "MagPlusService.h"
#include "ObjectList.h"
#include "PlotMod.h"
#include "SuperPage.h"
#include "Task.h"

Root* Root::rootInstance_;

Root::Root() 
{
	install_exit_proc(Root::ServerDead,0 );
}

void Root::ServerDead(int, void *)
{
	delete rootInstance_;
}

Root& Root::Instance()
{
	return *rootInstance_;
}

bool
Root::DefaultVisDefList (const char* className, MvIconList& visdefList, int type)
{
	// Pre-condition
	require (visdefList.size() == 0); // visdefList should be empty
	require (className != 0);

   // Find out the name of the default VisDef(s) associated to the data unit
	string str;
	if ( type == GETBYVISDEF )
	  	str = className;
	else
	    	str = ObjectList::DefaultVisDefClass ( className );

     // Add all default visdefs to the list
     size_t ip1,ip2,ip;
     ip1 = 0;
     do
     {
          // Get visdef name
          ip = str.find('/',ip1);
          ip2 = ( ip != string::npos ) ? (ip - ip1) : ip;
          string str1 = str.substr(ip1,ip2);
          ip1 = ip2+1;

          // Create default visdef
          MvRequest visdefRequest = ObjectList::UserDefaultRequest ( str1.c_str() );

          // Now we have all the information to create the VisDef
      MvIcon newVisDef ( visdefRequest );

          // Insert the visdef into the list
          visdefList.push_back(newVisDef);

     } while (ip != string::npos);

	// Post-condition
	ensure(visdefList.size() >= 1);

	return true; // Using default
}

bool Root::RetrieveTextList ( MvIconList& textList )
{
   // Create a default request
   MvRequest textRequest = ObjectList::CreateDefaultRequest("MTEXT");

   // Insert the text into the list
	MvIcon newText ( textRequest,true );
	textList.push_back( newText );

   return true;
}

bool Root::RetrieveLegend ( MvIcon& legIcon )
{
   // Create a default request
   MvRequest legRequest = ObjectList::CreateDefaultRequest("MLEGEND");

    // Copy the default request to the icon.
    // Make sure that the icon has an ID; otherwise, create a new one.
    if ( legIcon.Id() )
        legIcon.SaveRequest(legRequest,true);
    else
    {
        MvIcon auxIcon(legRequest,true);
        legIcon = auxIcon;
    }

   return true;
}

Presentable* Root::FindSuperPage( int index )
{
   Presentable* sp = 0;
   int nr = NrOfChildren();

   // Indicate to build a new superpage
   if ( HasReceivedNewpage() || nr == 0 || index > (nr-1) )
   {
      HasReceivedNewpage(false);
      return sp;
   }

   // Negative index indicates to get the last superpage
   MvChildIterator ii = childList_.begin();
   int idx = (index < 0 ) ? nr-1 : index;
   for (int i = 0; i < idx; ++i, ++ii);

   sp = (*ii);

   return sp;
}

void Root::Clean()
{
     // Delete all children
     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)->Parent(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;
     }
}

void Root::AddDrawTask()
{
     if (  !this->HasDrawTask () )
     {
          AddTask( *(Presentable*)this, &Presentable::DrawProlog );
          AddTask( *(Presentable*)this, &Presentable::Draw );
          AddTask( *(Presentable*)this, &Presentable::DrawTrailer );
          this->HasDrawTask ( true );
     }
}

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

   // Check if any 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 Root::DrawTask ()
{
   // Check if there is something to be drawn
   if ( this->CheckDrawTask() )
   {
      this->AddDrawTask();
      TaskBase::Flush();
   }
}

void Root::DrawTrailer()
{
   // Nothing to be drawn
   if (  !this->HasDrawTask () )
      return;

   // First request indicates if the visualization tree needs to be rebuilt
   MvRequest fullReq;
   if ( this->Refresh() )
      fullReq += MvRequest("REFRESH");
   else
   {
      fullReq += MvRequest("CLEAR");
      this->Refresh(true);
   }

   // Second request are the output devices
   fullReq = fullReq + PlotMod::Instance().OutputFormat()("OUTPUT_DEVICES");

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

   // Call MAGICS to process the request
   MagPlusService::Instance().SetRequest ( fullReq );

   // Process weather room
#ifdef METVIEW_WEATHER_ROOM
   SuperPage* sp = (SuperPage*)this->FindSuperPage();
   sp->plotWeatherRoom(true);
#endif

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