
/*****************
 Copyright 2007 European Centre for Medium-Range Weather Forecasts (ECMWF)
 
 Licensed under the Apache License, Version 2.0 (the "License"); 
 you may not use this file except in compliance with the License. 
 You may obtain a copy of the License at 
 
 	http://www.apache.org/licenses/LICENSE-2.0
 
 Unless required by applicable law or agreed to in writing, software 
 distributed under the License is distributed on an "AS IS" BASIS, 
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
 See the License for the specific language governing permissions and 
 limitations under the License.

 *******************************  LICENSE  *******************************/
 
#include "Layer.h"
#include "BaseDriver.h"
#include "AnimationRules.h"

#include "SceneVisitor.h"
#include "TextVisitor.h"
#include "LegendVisitor.h"
#include "Symbol.h"
#include "BaseDriver.h"

#include "HistoVisitor.h"

//===================================
//
// Layer
//
//===================================

Layer::Layer() : 
	visibility_(true), 
	zindex_(1), 
	transparency_(0), 
	state_(new_layer),
	id_(""),
	parent_(0),
	object_(0)

{
}

Layer::Layer(BasicSceneObject* object) : 
	visibility_(true), 
	zindex_(1), 
	transparency_(0), 
	state_(new_layer),
	id_(""),
	parent_(0),
	object_(object)
{
}

Layer::~Layer()
{
}

void Layer::execute(int , const BaseDriver&, const Layout&) const
{
	assert(false);
}

void Layer::getReady(int) const
{
}

void Layer::getReady() const
{
}

void  Layer::collect(ValuesCollector&  values)
{
	values.clear();
}

void Layer::newLayer(const BaseDriver& driver)
{
	driver.newLayer(*this); 
}

void Layer::closeLayer(const BaseDriver& driver)
{
	driver.closeLayer(*this); 
}

void Layer::redisplay(const BaseDriver& driver) const 
{
	driver.redisplay(*this); 
}

void Layer::print(ostream& out) const
{ 
	out << "layer[" << name_;
	string sep = "";
	for (vector<pair<string, string>  >::const_iterator icon = icons_.begin(); icon != icons_.end(); ++icon) {
		out << ", [" << icon->first << ", " << icon->second << "]";
		sep = "]";
	}
	out << sep << "]"; 
}

string Layer::timeStamp(const string& fmt) const
{
	return from_.tostring(fmt);
}

string Layer::timeBegin(const string& fmt) const
{
	return from_.tostring(fmt);
}

string Layer::timeEnd(const string& fmt) const
{
	return to_.tostring(fmt);
}

static string kml("%Y-%m-%dT%H:%M:00Z");

string Layer::kmlTimeBegin() const 
{ 
	return timeBegin(kml); 
}

string Layer::kmlTimeEnd() const 
{ 
	return timeEnd(kml);  
}

string Layer::kmlTimeStamp() const
{
	return timeStamp(kml);
}

void Layer:: execute(const BaseDriver& ) const 
{
}

void Layer::collectText(vector<TextVisitor*>& texts, LegendVisitor* legend)
{
	if ( !visibility_) return; 
	if ( !object_) 
		return;

		for (vector<TextVisitor*>::iterator text = texts.begin(); text != texts.end(); ++text) {
			 (*text)->visit(*object_);
			myTexts_[*text] = (*text)->texts();
		}
		if ( legend) 
			 legend->visit(*object_);
}

const string& Layer::metadata(const string& param)
{
	static string empty;
	map<string, string>::iterator data = metadata_.find(param);
	 
	return (data != metadata_.end() ) ? data->second : empty;
}

void Layer::metadata(const string& param, const string& value)
{
	metadata_[param] = value;
}




//===================================
//
// SingleLayer
//
//===================================

SingleLayer::SingleLayer(StepLayer* parent, BasicSceneObject* object) : 
		Layer(object),
		objects_(0), parentLayer_(parent)
{
}

SingleLayer::~SingleLayer()
{
}

void SingleLayer::set(LayoutVisitor* visitor) const	
{
	visitor->newLayout();	
	objects_->push_back(visitor->layoutPtr());
}



void SingleLayer::print(ostream& ) const
{
}

void SingleLayer::redisplay(const BaseDriver& ) const
{
}

void SingleLayer::collect(MetaDataCollector& infos)
{
	if(object_)
	  	object_->visit(infos);
}

void SingleLayer::collect(ValuesCollector& values)
{
	object_->visit(values);
}


void SingleLayer::magnify(const BaseDriver& driver, float ,float )
{
	MagnifierCollector magnifier;
	for (vector<LayoutVisitor*>::iterator visitor = parentLayer_->firstVisitor(); 
					visitor != parentLayer_->endVisitor(); ++visitor)
	{
		(*visitor)->set(magnifier);
	}
	magnifier.setParent(parentLayer_);
	object_->visit(magnifier);
	magnifier.visit(driver);
}

void SingleLayer::execute(const BaseDriver& driver) const
{
	if ( !parentLayer_->visibility() )
		return;
	
	assert(objects_);
	
	objects_->redisplay(driver);
}
void SingleLayer::update(const Layout& parent)
{
	assert(objects_);
	objects_->width(parent.width());
	objects_->height(parent.height());
	objects_->x(parent.x());
	objects_->y(parent.y());
}
void SingleLayer::getReady() const
{
	if ( !parentLayer_->visibility() )
		return;
	if ( parentLayer_->parent()->state() == geometry_changed) {
		assert(objects_);
		objects_->clear();
	}
	if ( !objects_ ) {
		objects_ = new Layout();
		objects_->name("singlelayer");
		objects_->parent(parentLayer_->parent());
		for (vector<LayoutVisitor*>::iterator visitor = parentLayer_->firstVisitor(); 
							visitor != parentLayer_->endVisitor(); ++visitor) {
			set(*visitor);
			(*visitor)->visit(*object_);
		}
	}
}


Layer* SingleLayer::baseLayer()
{ 
	return parentLayer_;
}


void SingleLayer::histogram(const BaseDriver& driver,const string& visdefName,const string& visdefClass)
{
    HistoVisitor histogram;
    MetviewIcon icon(visdefName,visdefClass);
    histogram.dataVisdefIcon(icon);
    object_->visit(histogram);
    histogram.redisplay(driver);
}


//===================================
//
// StepLayer
//
//===================================

StepLayer::StepLayer() 
{
}

StepLayer::~StepLayer() 
{
}

void StepLayer::redisplay(const BaseDriver& driver) const 
{  
	
	driver.redisplay(*this); 
}

void StepLayer::execute(int i, const BaseDriver& driver, const Layout& layout) const
{  
	if ( visibility_ && i < steps_.size() ) {
		steps_[i]->update(layout);
	    steps_[i]->execute(driver);
	}
}

void StepLayer::getReady(int i) const
{  
	if ( visibility_ )
	         steps_[i]->getReady();
}

void StepLayer::newLayer(const BaseDriver& driver)
{
	driver.newLayer(*this); 
}

void StepLayer::closeLayer(const BaseDriver& driver)
{
	driver.closeLayer(*this); 
}

int StepLayer::size()
{
	return 1;
}

Layer* StepLayer::get(int i) 
{
	return steps_[i];
}

void StepLayer::addStep(BasicSceneObject* object)
{
	SingleLayer* layer = new SingleLayer(this, object);
	layer->name(name_);
	layer->id(id_);
	steps_.push_back(layer );
}

void StepLayer::addVisitor(LayoutVisitor* visitor)
{
	visitors_.push_back(visitor);
}

void StepLayer::print(ostream& out) const
{
	out << "StepLayer[";
	out << "]";
}

//===================================
//
// StaticLayer
//
//===================================

void StaticLayer::redisplay(const BaseDriver& driver) const 
{  
	MagLog::dev() << "Static::redisplay-->" << *this << endl;
	if ( updateText_ ) {
		updateText_ = false;

		const_cast<StaticLayer*>(this)->push_back(layer_);
	}

	driver.redisplay(*this);
}

void StaticLayer::execute(const BaseDriver& driver) const
{  

	if ( visibility_ ) 
		redisplay(driver);
}
void StaticLayer::getReady() const
{  
	
}

void StaticLayer::collect(MetaDataCollector& infos)
{
	if(object_)
		object_->visit(infos);
}

void StaticLayer::collect(ValuesCollector& values)
{
	if(object_)
	 	object_->visit(values);
}

void StaticLayer::newLayer(const BaseDriver& driver)
{
	
		driver.newLayer(*this); 
}

void StaticLayer::closeLayer(const BaseDriver& driver)
{
	
		driver.closeLayer(*this); 
}

StaticLayer::StaticLayer() 
{
	layer_ = new Layout();
	layer_->name("staticlayer");
	updateText_ = true;
}
StaticLayer::StaticLayer(const Layout& layout)
{
	layer_ = layout.clone();
	updateText_ = true;
}
StaticLayer::StaticLayer(BasicSceneObject* object) : Layer(object) 
{
	layer_ = new Layout();
	layer_->name("staticlayer");
	updateText_ = true;;
}
void StaticLayer::update(const Layout& parent)
{
	layer_->name(parent.name());
		layer_->width(parent.width());
		layer_->height(parent.height());
		layer_->x(parent.x());
		layer_->y(parent.y());
}

void StaticLayer::clean()
{
	layer_->clear();
}

StaticLayer::~StaticLayer()
{
}

void StaticLayer::set(LayoutVisitor* visitor)
{
	//if ( layer_->isOrphan() )
			layer_->parent(parent_);

	visitor->newLayout();
	layer_->push_back(visitor->layoutPtr());
}

void StaticLayer::add(BasicGraphicsObject* object)
{
	if ( layer_->isOrphan() )
			layer_->parent(parent_);

	layer_->push_back(object);
}

void StaticLayer::print(ostream& out) const
{
	out << "StaticLayer[";
	out << "]";
}

void StaticLayer::histogram(const BaseDriver& driver,const string& visdefName, const string& visdefClass)
{
    HistoVisitor histogram;
    MetviewIcon icon(visdefName,visdefClass);
    histogram.dataVisdefIcon(icon);
    object_->visit(histogram);
    histogram.redisplay(driver);
}

//===================================
//
// NoDataLayer
//
//===================================

NoDataLayer::NoDataLayer(BasicSceneObject* object):StaticLayer(object) {}

NoDataLayer::~NoDataLayer() {}

void NoDataLayer::redisplay(const BaseDriver& driver) const 
{  
	
	if ( updateText_ ) {
			updateText_ = false;

			const_cast<NoDataLayer*>(this)->push_back(layer_);
		}

   driver.redisplay(*this);
}


//===================================
//
// TextLayer
//
//===================================

void TextLayer::getReady() const
{
	// Noothing to do!
}

void TextLayer::execute(const BaseDriver& driver) const
{
	// get the text for static later! 
	Layout* layout = new Layout();
	layout->parent(parent_);
	parent_->finishText(*layout);
			
	layout->redisplay(driver); 
}



void TextLayer::getInfo(int i, const BaseDriver&  driver) const
{
	  // Get the information for a specifi step!
	    parent_->executeInfo(i, driver); // here we get the information! 
	
		Layout* layout = new Layout();
		layout->parent(parent_);

        layout->name(parent_->layoutPtr()->name());
        layout->width(parent_->layoutPtr()->width());
        layout->height(parent_->layoutPtr()->height());
        layout->x(parent_->layoutPtr()->x());
        layout->y(parent_->layoutPtr()->y());
		parent_->finishText(*layout);
		
	   layout->redisplay(driver);
	   LegendVisitor* legend = parent()->legend();
	   if ( legend ) {
			Layout* layout = new Layout();
			layout->parent(parent_);
			layout->name(parent_->layoutPtr()->name());
	        layout->width(parent_->layoutPtr()->width());
	        layout->height(parent_->layoutPtr()->height());
	        layout->x(parent_->layoutPtr()->x());
	        layout->y(parent_->layoutPtr()->y());
		   legend->finish(*layout);
		   layout->redisplay(driver);	
		}
}

void TextLayer::collectText(vector<TextVisitor*>& texts, LegendVisitor* legend)
{
	for (vector<TextVisitor*>::iterator text = texts.begin(); text != texts.end(); ++text) {
				(*text)->visit();
				myTexts_[*text] = (*text)->texts();
	}
}


//===================================
//
// SceneLayer
//
//===================================

SceneLayer::SceneLayer() : rules_(0), currentIndex_(0),legend_(0), currentFrame_(0)
{
	layout_ = new Layout();
	
}

SceneLayer::~SceneLayer()
{

	for (vector<Layer*>::iterator layer = layers_.begin(); layer != layers_.end(); ++layer) {
		(*layer)->clear();
	}
}

bool SceneLayer::buildTree(const Layout& parent,  unsigned int frame, const BaseDriver& out) const
{
	if (frame >= numberOfSteps() ) return false;
	if ( !currentFrame_ ) {
		textHandler_.name("Titles");
		textHandler_.parent(const_cast<SceneLayer*>(this));
	}
	layout_->name(parent.name());
	layout_->width(parent.width());
	layout_->height(parent.height());
	layout_->x(parent.x());
	layout_->y(parent.y());



	getReady(frame);
	execute(frame, out);
	textHandler_.getInfo(frame, out);
	return ( frame+1 < numberOfSteps() );
}
void SceneLayer::redisplay(const BaseDriver& driver) const
{
	intarray frames = driver.getFrame_list();
	unsigned int nb = frames.size();
	switch ( mode_) {
		case paper: {
			textHandler_.name("Titles");
			textHandler_.parent(const_cast<SceneLayer*>(this));
			//StartPage *start = new StartPage();
			//start->redisplay(driver);
			 if ( nb == 0) {
			for ( int i = 0; i < numberOfSteps(); i++ )
			{
					//StartPage *start = new StartPage();
					//start->redisplay(driver);
					getReady(i);
					execute(i, driver);
					textHandler_.getInfo(i, driver);
					//EndPage *end = new EndPage();
					//end->redisplay(driver);
			}
			 }
			 else {
				 for (unsigned int n = 0; n < nb; n++) {
					 int i = frames[n] -1 ;
					 if ( i < 0 || i >= numberOfSteps() ) {
						 MagLog::warning() << " Export : could not find page " << i+1 << endl;
						 continue;
					 }


					 					getReady(i);
					 					execute(i, driver);
					 					textHandler_.getInfo(i, driver);

					 		
				 }
			 }
		}
			break;
		case basic:
			textHandler_.name("Titles");
			textHandler_.parent(const_cast<SceneLayer*>(this));
		    
		    if ( nb == 0) {
			for ( int i = 0; i < numberOfSteps(); i++ )
			{						
					getReady(i);
					execute(i, driver);
					textHandler_.getInfo(i, driver);
				
					
			}
		    }
		    else  {
		    	for ( unsigned int i = 0; i < nb; i++) {
		    		int f =  frames[i];
		    		getReady(f);
		    		execute(f, driver);
		    		textHandler_.getInfo(f, driver);
		    	}
		    }
		    	
			break;
		case interactif:
			
			
			
			
			visit(driver);
			textHandler_.name("Titles");
			textHandler_.parent(const_cast<SceneLayer*>(this));
			const_cast<SceneLayer*>(this)->add(&textHandler_);			
			// here we add the Layer dedicated to the text ! ...
			driver.redisplay(*this);
			break;		
	}
	
}

void SceneLayer::print(ostream& out) const
{
	out << "SceneLayer[";
	out << "]";
}

void SceneLayer::add(Layer* layer)
{
	layers_.push_back(layer);
	layer->parent(this); 
	layer->zindex(currentIndex_);
	currentIndex_++;
}

int SceneLayer::numberOfSteps() const
{
	int size =  (rules_) ? rules_->size() : 0;
	return std::max(1, size);
}

vector<Layer*>& SceneLayer::prepare(int i) const
{
	int size =  (rules_) ? rules_->size() : 0;

		if ( i >= size ) {
			vector<Layer*>* empty = new vector<Layer*>();		
			return *empty;
		}
	map<int, vector<Layer*> >::iterator step = steps_.find(i);
	if ( step != steps_.end() ) 
		return step->second;
	assert(rules_); 
	steps_.insert(make_pair(i, vector<Layer*>()));
	if ( i >= (int)(*rules_).size() )
	{
			for (vector<Layer*>::const_iterator layer = layers_.begin(); layer != layers_.end(); ++layer) {
				 if ( (*layer)->get() ) 
						  steps_[i].push_back( (*layer)->get() );
			}
			return steps_[i];
	}
	
	//std::sort(layers_.begin(), layers_.end());// For the zindex!
	
	AnimationStep* anim = (*rules_)[i];

		for (vector<Layer*>::const_iterator layer = layers_.begin(); layer != layers_.end(); ++layer) {
		       map<Layer*, int>::iterator l = anim->find(*layer);
		       if ( l == anim->end() ) {
		    	   if ( (*layer)->get() ) 
		    		   steps_[i].push_back( (*layer)->get() );
		       }
		       else 
		    	   steps_[i].push_back( (*layer)->get(l->second));
		} 
	return steps_[i];
} 

void  SceneLayer:: execute(int i, const BaseDriver& driver) const 
{
	// Look for the step! 
	int size =  (rules_) ? rules_->size() : 0;

	if ( i >= size )
	{
		if ( layers_.empty() ) {
			StaticLayer* layer = new StaticLayer(*layout_);

			layers_.push_back(layer);
			layers_.back()->parent(const_cast<SceneLayer*>(this));
		}
		for (vector<Layer*>::const_iterator layer = layers_.begin(); layer != layers_.end(); ++layer) {
			  (*layer)->update(*layout_);
			  (*layer)->execute(driver);
		}
		return;
	}
	
	AnimationStep* step = (*rules_)[i];
		
	for (vector<Layer*>::const_iterator layer = layers_.begin(); layer != layers_.end(); ++layer) {
		   (*layer)->update(*layout_);
	       map<Layer*, int>::iterator l = step->find(*layer);
	       if ( l == step->end() ) 
	    	   (*layer)->execute(driver);
	       else 
	    	   (*layer)->execute(l->second, driver, *layout_);
	}
}

void  SceneLayer::execute(Layer* stepLayer, int i, const BaseDriver& out) const
{
	// Look for the step! 
	int size =  (rules_) ? rules_->size() : 0;
	if ( i >= size ) {		
		// here we have to send the txt!
		stepLayer->getInfo(i, out);
		return;
	}
	// Make sure that we need to execute this later!
	bool found=false;
	for (vector<Layer*>::const_iterator layer = layers_.begin(); layer != layers_.end(); ++layer)
	{
		if(*layer == stepLayer)
		{
			found=true;
			break;
		}
	}

	if(!found)
		return;


	// Look for the step! 
	assert(rules_);    
	if  ( rules_->size() > i ) {    	
	   AnimationStep* step = (*rules_)[i];	
	   map<Layer*, int>::iterator l = step->find(stepLayer);	
	   if ( l != step->end() )
	    	stepLayer->execute(l->second, out, *layout_);
	   else
	    	stepLayer->getInfo(i, out);
    }
    else {
    	assert(false);
    	//stepLayer->execute(i, driver);
    }
}

Layer*  SceneLayer::findLayer(Layer* stepLayer,int i) const 
{
	bool found=false;
	for (vector<Layer*>::const_iterator layer = layers_.begin(); layer != layers_.end(); ++layer)
	{
		if(*layer == stepLayer)
		{
			found=true;
			break;
		}
	}

	if(!found)
		return 0;

	// Look for the step! 
	assert(rules_); 

	//Temporary fix!!
	if(i >= rules_->size())
		return stepLayer;

	AnimationStep* step = (*rules_)[i];
		
	map<Layer*, int>::iterator l = step->find(stepLayer);
	if (l == step->end()) 
		return 0;
	else 
		return stepLayer->get(l->second);
}

vector<Layer*>::iterator SceneLayer::beginLayer() const
{
	//std::sort(layers_.begin(), layers_.end());// For the zindex!
	
	return layers_.begin();
}

vector<Layer*>::iterator SceneLayer::endLayer() const
{
	return layers_.end();
}

void SceneLayer::getReady(int i ) const 
{
	    if ( legend_ ) 
	    	legend_->clear();
		// Look for the step! 
		     int size =  (rules_) ? rules_->size() : 0;
			if ( i >=  size )
				// Only Static Layers!
			         {
			                 for (vector<Layer*>::const_iterator layer = layers_.begin(); layer != layers_.end(); ++layer) {
			                           (*layer)->getReady();
			                 }
			         }
			else {
				assert(rules_);
				AnimationStep* step = (*rules_)[i];

				for (vector<Layer*>::const_iterator layer = layers_.begin(); layer != layers_.end(); ++layer) {
				       map<Layer*, int>::iterator l = step->find(*layer);
				       if ( l != step->end() ) 
				    	   (*layer)->getReady(l->second);
				}
			}
}

vector<Layer*>::iterator SceneLayer::beginLayer(int i ) const
{
	return prepare(i).begin();
}

vector<Layer*>::iterator SceneLayer::endLayer(int i ) const
{
	return prepare(i).end();
}

void SceneLayer::redisplayAll(const BaseDriver& driver) const
{
	for ( int i = 0; i <= numberOfSteps(); i++ )
	{
		getReady(i);
		execute(i, driver);
	}
}

void SceneLayer::finishText(Layout& layout)
{
	for (vector<TextVisitor*>::iterator text = textVisitors_.begin(); text != textVisitors_.end(); ++text) 
					(*text)->finish(layout);
}


void SceneLayer::executeInfo(int i, const BaseDriver&) const
{
	// Look for the step! 
		vector<Layer*> layers;
		int size =  (rules_) ? rules_->size() : 0;
		for (vector<TextVisitor*>::iterator text = textVisitors_.begin(); text != textVisitors_.end(); ++text) {
			// we reset the text entries... 
							(*text)->start();
		}
		if ( legend_ ) 
			legend_->clear();
		// We collect the static infos...
		textHandler_.collectText(textVisitors_, legend_);
		layers.push_back(&textHandler_);
	   // Then we have to ask all the layers to collect and update the texts entries !
			if ( i >= size )
			{		
				// here we have only static layers!
				for (vector<Layer*>::const_iterator layer = layers_.begin(); layer != layers_.end(); ++layer) {
					  (*layer)->collectText(textVisitors_, legend_);
					 layers.push_back(*layer);
				}
				
			}
			else { 
				assert(rules_);
			    
				if ( rules_->size() > 0 ) {
				AnimationStep* step = (*rules_)[i];
				
				for (vector<Layer*>::const_iterator layer = layers_.begin(); layer != layers_.end(); ++layer) {
					map<Layer*, int>::iterator l = step->find(*layer);
			       if ( l == step->end() ) {
			    	   // this is a static layer! 
			    	   (*layer)->collectText(textVisitors_, legend_);
			    	   layers.push_back(*layer);
			    	   
			       }
			       else {
			    	   (*layer)->get(l->second)-> collectText(textVisitors_, legend_);		      
			    	   layers.push_back((*layer)->get(l->second));
			       }
				}
				}
			}
			
			// All text has been collected now we build the final result
			for (vector<TextVisitor*>::iterator text = textVisitors_.begin(); text != textVisitors_.end(); ++text)  {
				// Each line ...
				vector<string> lines;
				(*text)->titles(lines);
				for (vector<string>::reverse_iterator line = lines.rbegin(); line != lines.rend(); ++line) {
					//for ecah layer!
					
					for (vector<Layer*>::iterator layer = layers.begin(); layer != layers.end(); ++layer) {
						
						vector<Text*>& texts = (*layer)->updateText(*text, *line);
						(*text)->update(texts);	
						texts.clear(); // we have used it.. clear it!
					}	
				}
			}
}


//==================================
//
// Misc
//
//==================================

void MagnifierCollector::visit(const BaseDriver& driver)
{
	assert(layout_);
	
	Symbol* points = new Symbol();
	points->setSymbol("magics_3"); // A little dot
	points->setHeight(0.2); 
	points->setColour(Colour("red")); 				
	
	for ( iterator point = begin(); point != end(); ++point)
		points->push_back(*point);
	
	layout_->push_back(points);
	layout_->redisplay(driver);
}


void MetviewIcon::visit(Layer& layer)
{
	if ( !iconClass_.empty() && !iconName_.empty() )
		layer.icon(iconName_, iconClass_);

	layer.id(iconId_);


}

void MetviewIcon::visit(MetaDataCollector& collector)
{
	if(information_.empty())
		return;

	if(collector.empty())
	{
		collector.insert(information_.begin(),information_.end());
	}
	else
	{
		for (map<string, string>::iterator key = collector.begin(); key != collector.end(); ++key )
		{
			if(information_.find(key->first) != information_.end())
			{
   				key->second = information_[key->first];
			}
		}
	}
}
