module gedo.file.config;



private import std.string;
private import std.ctype;
private import gedo.file.path;
private import gedo.text.convert;



private enum Area
{
	INDENT,
	KEY,
	SEPERATOR,
	VALUE,
}



public class Config
{
public:
	this(string name)
	{
		_path = toPath(name);

		_data = load(_path);
	}


	void save()
	{
		if(isConfigChanged())
		{
			auto keys = _data.keys;

			char[] text = "";

			keys.sort;

			foreach(k ; keys)
			{
				text ~= k ~ " " ~ _data[k] ~ "\n";
			}

			.gedo.file.path.write(_path, text);
		}
	}


	void set(string key, string value)
	{
		_data[key] = value;
	}


	void set(string key, int value)
	{
		_data[key] = .std.string.toString(value);
	}


	void set(string key, float value)
	{
		_data[key] = .std.string.toString(value);
	}


	void set(string key, bool value)
	{
		_data[key] = .std.string.toString(value);
	}


	string get(string key, string value)
	{
		if(auto p = key in _data)
		{
			return *p;
		}
		else
		{
			return value;
		}
	}


	int get(string key, int value)
	{
		if(auto p = key in _data)
		{
			return .gedo.text.convert.toInt(*p);
		}
		else
		{
			return value;
		}
	}


	float get(string key, float value)
	{
		if(auto p = key in _data)
		{
			return .gedo.text.convert.toReal(*p);
		}
		else
		{
			return value;
		}
	}


	bool get(string key, bool value)
	{
		static const string TRUE_STRING = .std.string.toString(true);

		if(auto p = key in _data)
		{
			return (*p == TRUE_STRING);
		}
		else
		{
			return value;
		}
	}


private:
	string[string] _data;
	string         _path;


	bool isConfigChanged()
	{
		auto savedConfig = load(_path);

		if(savedConfig.length != _data.length)
		{
			return true;
		}

		foreach(key, value; savedConfig)
		{
			if(!(key in _data))
			{
				return true;
			}
			if(value != _data[key])
			{
				return true;
			}
		}

		return false;
	}


	static string[string] load(string path)
	{
		string[string] data;

		if(.gedo.file.path.exist(path))
		{
			auto text = cast(char[]).gedo.file.path.read(path);

			foreach(line; splitlines(text))
			{
				Area area = Area.INDENT;

				char[] key;
				char[] value;
				uint   head;
				uint   tail;

				foreach(i, c; line)
				{
					switch(area)
					{
					case Area.INDENT:
						if(!isspace(c))
						{
							area = Area.KEY;
							head = i;
						}
						break;

					case Area.KEY:
						if(isspace(c))
						{
							area = Area.SEPERATOR;

							key = line[head .. i];
						}
						break;

					case Area.SEPERATOR:
						if(!isspace(c))
						{
							area = Area.VALUE;

							head = tail = i;
						}
						break;

					case Area.VALUE:
						if(!isspace(c))
						{
							tail = i;
						}
						break;
					}
				}

				if(area == Area.VALUE)
				{
					value = line[head .. tail+1];

					data[key] = value;
				}
			}
		}

		return data;
	}


	static string toPath(string name)
	{
		version(Windows)
		{
			return "$HOME/"~name~".cfg";
		}
		else
		{
			return "$HOME/."~name~".conf";
		}
	}
}
