/***************************** 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 "Language.h"

#include "Path.h"
#include "IconClass.h"
#include "Parameter.h"

typedef map<string,Language*> Map;
static Map languages;

static map<string,request*> lang_cache;
static map<string,rule*>    rule_cache;


Language::Language(const IconClass* c):
	inited_(false),
	lang_(0),
	rule_(0),
	flags_(0),
	class_(c)
{
	languages[c->name()] = this;
	if(languages.size() == 1)
		expand_flags(EXPAND_2ND_NAME);
}

Language::~Language()
{
	// Not called
	free_all_requests(lang_);
}
const char* Language::getInfo()  const
{
	return lang_->info ? lang_->info : "";
}

const char* Language::getKind() const
{
	return lang_->kind;
}

Language& Language::find(const IconClass* c)
{
	Map::iterator j = languages.find(c->name());
	if(j != languages.end())
		return *(*j).second;
	return *(new Language(c));
}

void Language::init()
{
	if(inited_) return;
		
	inited_ = true;

	string langs = class_->definitionFile().str();
	map<string,request*>::iterator j = lang_cache.find(langs);
	if(j != lang_cache.end())
		lang_ = (*j).second;
	else
	{
		//cout << "read " << langs << endl;
		lang_ = read_language_file(langs.c_str());
		lang_cache[langs] = lang_;
	}

	string rules = class_->rulesFile().str();
	map<string,rule*>::iterator k = rule_cache.find(rules);
	if(k != rule_cache.end())
		rule_ = (*k).second;
	else
	{
		//cout << "read " << rules << endl;
		rule_ = read_check_file(rules.c_str());
		rule_cache[rules] = rule_;
	}
	
	flags_ = class_->expandFlags();

	// Position to the right request
	while(lang_ && !(class_->name() == lang_->name) )
		lang_ = lang_->next;

	if(lang_ == 0) {
		lang_ = empty_request(0);
	}

	// Create the Parameters

	parameter *p = lang_ ? lang_->params :0 ;
	while(p)
	{
		params_.push_back(new Parameter(*this,p));
		p = p->next;
	}
}


Request Language::expand(const Request& r,long flags,bool ruleFlag)
{
	Request result = r;

	init();

	if(lang_ == 0)
		return result;

	reset_language(lang_);
	long save = expand_flags(flags);
	request *a;
	if ( ruleFlag )
		a = expand_all_requests(lang_,rule_,result);
	else
		a = expand_all_requests(lang_,0,result);

	expand_flags(save);


	if(a == 0)
		return result;

	return MvRequest(a,false);
}

Request Language::expand(const Request& r)
{
	return expand(r,flags_);
}


vector<string> Language::interfaces(const char* name)
{
	init();

	// Need something a little bit more "C++"

	vector<string> result;
	parameter *p = lang_->params;
	while(p)
	{
		if(p->interface)
		{
			const char* q = get_value(p->interface,"interface",0);
			if(q && strcmp(q,name) == 0)
				result.push_back(p->name);
		}
		p = p->next;
	}

	return result;
}

Request Language::interfaceRequest(const char* name) 
{
	init();
  	parameter *p = lang_->params;
	while(p)
	{
		if(p->interface)
		{			
		  	if(p->name && strcmp(p->name,name) ==0)
			{
				return Request(p->interface);	
			}
		}
		
		p = p->next;	
	}
	
  	return Request();
}

void Language::scan(LanguageScanner& s)
{
	init();
	for(vector<Parameter*>::iterator j = params_.begin(); j != params_.end(); ++j)
		s.next(*(*j));

}

static value *find_values(const request *r,char *parname)
{
    if(r)
    {
        parameter *p = r->params;
        while(p)
        {
            if(strcmp(p->name,parname) == 0)
                return p->values;
            p = p->next;
        }
    }
    return NULL;

}

Language::Language(const IconClass* c, const Request& def) :
	inited_(true),
	rule_(0),
	class_(c)
{
    const char *name, *ui;
    parameter *param, *lastparam = NULL;
    value     *val   = NULL;

    const request* r = def;
 
    lang_ = empty_request(c->name().c_str());
    languages[c->name()] = this;

    while (r) {
        name = get_value(r, "name", 0);
        if (!name) break;
        param = new_parameter(strcache(name), NULL);
        ui   = r->name;
        val = find_values(r, "values");
        param->values = clone_all_values(val);
        val = find_values(r, "default");
        param->default_values = clone_all_values(val);
        param->current_values = clone_all_values(val);
        param->interface = clone_one_request(r);

        set_value(param->interface, "interface", ui);
        strfree(param->interface->name);
        param->interface->name = strcache(name);

        if (lastparam) lastparam->next = param;
        else lang_->params = param;
        lastparam = param;

        r = r->next;
    }
   	flags_ = class_->expandFlags();



	// Position to the right request
	while(lang_ && !(class_->name() == lang_->name) )
		lang_ = lang_->next;

	// Create the Parameters

	parameter *p = lang_ ? lang_->params :0 ;
	while(p)
	{
		params_.push_back(new Parameter(*this,p));
		p = p->next;
	}

}
