#include "textconfig.h"
#include "storage.h"
#include "config_classes.h"
#include <string>
#include <fstream>
#include <iostream>

#ifdef Revision
#undef Revision
#endif
#define Revision "textconfig.cpp $Revision: 1.5 $";
const Text_Config_Features feat;
const Text_Config_Features & Text_Config::_get_features( )
{
	return feat;
}
bool Text_Config::_load ( std::string * params, int params_num )
{
	if ( params_num < 1 ) return false;
	std::ifstream stream ( params[0].c_str() );
	std::string text, text1;
        std::cerr<<"Loading config file:"<<params[0]<<"."<<std::endl;
	while ( stream >> text )
	{
		text1 = text.substr ( 0, 1 );
		if ( text1 == "[" )
		{
			if ( text.substr ( 1, 2 ) != "/" )
				_read_block ( stream, text.substr ( text.find ( "[" ) + 1, text.find ( "]" ) - 1 ) );
		}
		else if ( text1 == "/" )
		{
			std::getline ( stream, text );
		}
		// Пропуск неверных символов (т.е. отсутствие блока)
		else
		{
			std::getline ( stream, text );
		}
	}
	return true;
}

bool Text_Config::_save ( std::string * params, int params_num )
{
	if ( params_num < 1 ) return false;
	std::string spacer=" ";
	if ( params_num==2)spacer=params[1];
	std::ofstream stream ( params[0].c_str() );
	std::map<std::string, std::string> &storage_map=_storage_.get_map();
	std::map<std::string, std::string>::iterator it;
	std::map<std::string, std::string>::iterator prev;
	int level=0;
	prev=storage_map.begin();
	for(it=storage_map.begin();it!=storage_map.end(); ++it)
	{
		std::string str, str1, str_prev;
		str=it->first;
		int diff_l_start=0;
		if(prev!=it)
		{
			//a->b->c d
			//a->v->e h
			int levels_cur=0;
			//Посчитаем кол-во уроней в текущей строке
			while( str.find("->")!=std::string::npos )
			{
				str=str.substr(str.find("->")+2, str.length());
				levels_cur++;
			}
			if(level>levels_cur)//Количество уровней разное, надо закрыть часть уровней
			{
				for(int a=levels_cur-1;a>=level;--a)
				{
					for(int b=0;b<a;b++)stream<<spacer;
					stream<<"[/]"<<std::endl;
				}
			}
			//Теперь надо закрыть различающиеся уровни
			str=it->first;
			str_prev=prev->first;
			while(str.find("->")!=std::string::npos )
			{
				std::string cur, prev;
				prev=str_prev.substr(0, str_prev.find("->"));
				cur=str.substr(0, str.find("->"));
				if(cur==prev)
				{
					str_prev=str_prev.substr(str_prev.find("->")+2, str_prev.length());
					str=str.substr(str.find("->")+2, str.length());
					diff_l_start++;
				}
				else break;
			}
			for(int a=level-1;a>=diff_l_start;--a)
			{
				for(int b=0;b<a;b++)stream<<spacer;
				stream<<"[/]"<<std::endl;
			}
		}
		level=diff_l_start;
		while( str.find("->")!=std::string::npos )
		{
			str1=str.substr(0, str.find("->"));
			str=str.substr(str.find("->")+2, str.length());
			for(int a=0;a<level;a++)stream<<spacer;
			stream<<"["<<str1<<"]"<<std::endl;
			level++;
		}
		for(int a=level-1;a>=0;--a)stream<<spacer;
		stream<<str<<" "<<it->second<<std::endl;
		prev=it;
	}
	//Закроем все
	for(int a=level-1;a>=0;--a)
	{
		for(int b=0;b<a;b++)stream<<spacer;
		stream<<"[/]"<<std::endl;
	}

	return false;
}

bool Text_Config::_set_value ( std::string name, std::string val, bool replace )
{
	if ( _storage_.exist ( name ) )
	{
		if ( replace ) _storage_.remove ( name );
		else return false;
	}
	return _storage_.insert ( name, val );
}

std::string Text_Config::_get_value ( std::string name, std::string def )
{
	if ( !_storage_.exist ( name ) )
	{
		_storage_.insert ( name, def );
		return def;
	}
	return _storage_.get ( name );
}
Config_Interface * _get_config_interface ( std::string *params, int params_num )
{
	return new Text_Config;
}

void Text_Config::_read_block ( std::istream& stream, const std::string blockname )
{
	std::string text, text1, tmp;
	while ( stream >> text )
	{
		tmp = text.substr ( 0, 1 );
		//Анализ выхода из блока
		if ( tmp == "[" )
		{
			if ( text.substr ( 1, 1 ) != "/" )
				//Имеется подблок. Обрабатываем его
				_read_block ( stream, blockname + "->" + text.substr ( text.find ( "[" ) + 1, text.find ( "]" ) - 1 ) );
			// Обнаружено окончание блока
			else return ;
		}
		//Пропуск комментария
		else if ( tmp == "/" ) std::getline ( stream, text );
		else
		{
			std::getline ( stream, text1 );
			_storage_.insert ( blockname+"->"+text, text1.substr ( 1 ) );
		}

	}

}


int Text_Config::_del_value(std::string name, bool is_delete_subvalues)
{
    ///@TODO удаление подмножества
    _storage_.remove(name);
    return 1;
}

class functor_wrapper
{
    config_functor *fun;
    public:
        functor_wrapper(config_functor *f):fun(f){};
        void operator() ( std::pair<std::string, std::string> value )
        {
            fun->operator ( )(value);
        }
};

void Text_Config::for_each(config_functor *functor)
{
    functor_wrapper wrp(functor);
    _storage_.for_each(wrp);
}
