/***************************** LICENSE START ***********************************

 Copyright 2014 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 "Parameter.h"
#include <mars.h>
#include "Request.h"
#include "Language.h"
#include <ctype.h>

//======================================================================
class GuessInterface : public ParameterScanner {

	map<string,int> choices_;

	void next(const Parameter&, const char* name,const char*) ;

public:
	GuessInterface(Parameter&);
	string choice();

};

GuessInterface::GuessInterface(Parameter& /*p*/)
{
	choices_["on_off"] = 4;
	choices_["menu"]   = 3; //combobox
	choices_["string"] = 2; //textedit line 
	choices_["text"]   = 1; //textedit line with lists
}

void GuessInterface::next(const Parameter&, const char* name,const char*)
{
	if(*name == '/'  ||
	   *name == '@'  ||
	   *name == '"'  ||
	   *name == '*'  ||
	   *name == '\'' ) choices_["menu"] = 0;

	if(*name == '/')
		choices_["string"] = 0;

	if(*name != 'O' || (strcmp(name,"ON") != 0 && strcmp(name,"OFF") != 0))
		choices_["on_off"] = 0;

}

string GuessInterface::choice()
{
	int max = 0;
	string result = "text";

	for(map<string,int>::iterator j = choices_.begin(); j != choices_.end(); ++j)
	{	
		if((*j).second > max) 
		{
			max    = (*j).second;
			result = (*j).first;
		}
	}
	
	return result;
}

//======================================================================

Parameter::Parameter(Language& l,parameter* p):
	lang_(l),
	param_(p),
	multiple_(false)
{
	
	if(param_->interface == 0) 
		param_->interface = empty_request(0);

	if(get_value(param_->interface,"interface",0) == 0 )
	{
		// Try to gues 

		GuessInterface guess(*this);
		scan(guess);
		string choice = guess.choice();

		set_value(param_->interface,"interface",choice.c_str());
		if(get_value(param_->interface,"help",0) == 0)
			set_value(param_->interface,"help",choice.c_str());
	}
	else if(strcmp(get_value(param_->interface,"interface",0),"colour") ==0)
	{
		// We need to see if it is a list
		GuessInterface guess(*this);
		scan(guess);
		string choice = guess.choice();

		//If it can hold a list it is a colourlist
		if(choice == "text")
		{
			set_value(param_->interface,"interface","colourlist");
			if(get_value(param_->interface,"help",0) == 0 || 
			   strcmp(get_value(param_->interface,"help",0),"help_colour") == 0)
				set_value(param_->interface,"help","help_colourlist");
		}
		//otherwise a single colour
		else
		{  
			if(get_value(param_->interface,"help",0) == 0)
				set_value(param_->interface,"help","help_colour");	
		}
	}
	
	const char *h;
	if( (h = get_value(param_->interface,"hidden",0)) != 0  && (*h == 'T' || *h == 't'))
	{
		set_value(param_->interface,"interface","none");
	}

	if( (h = get_value(param_->interface,"visible",0)) != 0  && (*h == 'f' || *h == 'F'))
	{
		set_value(param_->interface,"interface","none");
	}
	
	//if( ( h= get_value(param_->interface,"exclusive",0)) !=0  && (*h == 'T' || *h == 't'))
	//{
	//	multiple_=false;
	//} 
	
	h=interface();
	
	if( h != 0)
	{  
	  	if(strcmp(h,"text") == 0)
		{
	  		multiple_ = true;
		}	
	
		else if(strcmp(h,"icon") == 0)
		{
	  		const char * ev=get_value(param_->interface,"exclusive",0);
			if(ev !=0  && (*ev == 'F' || *ev == 'f'))
	  			multiple_ = true;
		}
		else if(strcmp(h,"any") == 0)
		{
			// if 'exclusive' is set, then do not split elements into a list
			// - interface=text does this spltting; string does not
			const char * ev=get_value(param_->interface,"exclusive",0);
			if(ev !=0  && (*ev == 'F' || *ev == 'f'))
				multiple_ = true;
                
			if(multiple_)
				set_value(param_->interface,"interface","text");
			else
				set_value(param_->interface,"interface","string");    
		}        
	}
		
	//No helper if the interface is "none"		
	if( h == 0 || strcmp(h,"none") == 0)
	{
	  	set_value(param_->interface,"help","none");
	}
	
	const char* b = get_value(param_->interface,"beautify",0);
	beautify_ = (b == 0) || (*b != 'f');

	name_ = beautify(param_->name);

	value* v = param_->default_values;
	while(v)
	{
		defaults_.push_back(v->name);
		v = v->next;
	}
}

Parameter::~Parameter()
{
}

const char* Parameter::name() const
{
	return param_->name;
}

void Parameter::scan(ParameterScanner& s) const
{
	scan(s,param_->values);
}

void Parameter::scan(ParameterScanner& s,const value* v) const
{
	while(v)
	{
		if(v->ref)
			scan(s,v->ref);
		else
			s.next(*this, v->name,v->other_names?v->other_names->name:0);
		v = v->next;
	}
}

Request Parameter::interfaceRequest() const 
{
	return Request(param_->interface);
}

const char* Parameter::help() const
{
	return get_value(param_->interface,"help",0);
}

const char* Parameter::help_text() const
{
	return get_value(param_->interface,"help_text",0);
}

const char* Parameter::help_icon() const
{
	const char* p = get_value(param_->interface,"help_icon",0);
	return p ? p : "";
}

const char* Parameter::interface() const
{
	return get_value(param_->interface,"interface",0);
}

const string& Parameter::beautify(const string& name) const
{
	map<string,string>::const_iterator j = beau_.find(name);
	if(j != beau_.end()) return (*j).second;

	string& result = const_cast<Parameter*>(this)->beau_[name];
	bool up = true;
	result = name;

	for(int it=0; it < static_cast<int>(result.length()); ++it)
	{
		char j = result[it];
		if(j == '_' || j == ' ')
		{
			up = true;
			result[it] = ' ';	
		}
		else 
		{
			result[it] = up ? toupper(j) : tolower(j);
			up = false;
		}
	}

	return result;
}

const string& Parameter::beautifiedName() const            
{
	return name_;
}

const string& Parameter::beautifiedName(const string& name) const            
{
	if(beautify_)
		return beautify(name);
	else
		return name;
}

bool Parameter::multiple() const
{
	return multiple_;
}

bool Parameter::hasDefaults() const
{
	return param_->default_values != 0;
}

const vector<string>& Parameter::defaults() const
{
	return defaults_;
}
