module gedo.gui.digiteditor;



private import std.math;
private import gedo.gui.label;
private import gedo.gui.cursor;
private import gedo.gui.dialog;
private import gedo.gui.component;
private import gedo.input.joystick;
private import gedo.video.ggl;
private import gedo.video.rect;
private import gedo.video.color;
private import gedo.video.staticmesh;



alias void delegate(DigitEditor editor) OnChangeValue;



public class DigitEditor : Component
{
public:
	struct Field
	{
		uint      scale;
		uint      value;
		Component delimiter;
	}


	this(Field[] fields)
	{
		{
			GGL_Vertex[3] vertices;
			GGL_Face[1]   faces;

			vertices[0].position[] = [-0.5f, 0.0f, 0.0f];
			vertices[1].position[] = [ 0.5f, 0.0f, 0.0f];
			vertices[2].position[] = [ 0.0f, 0.5f, 0.0f];

			faces[0].vertexIndices[] = [cast(ushort)0, 1, 2];

			vertices[0].texCoord[] = [0.0f, 0.0f];
			vertices[1].texCoord[] = [1.0f, 0.0f];
			vertices[2].texCoord[] = [0.5f, 1.0f];

			_cursor = new StaticMesh(vertices, faces);
		}

		_scales.length = fields.length;
		_links.length = fields.length;

		Component[] children;

		auto cc = 0;
		auto cd = 0;
		foreach(i, field; fields)
		{
			_scales[i] = field.scale;

			cc += field.scale;
			cd += field.scale;
			if(field.delimiter)
			{
				cc += 1;
			}
		}

		children.length = cc;
		_labels.length = cd;
		cc = cd = 0;
		foreach(field; fields)
		{
			auto k = field.value;
			foreach_reverse(i, inout label; _labels[cd .. cd+field.scale])
			{
				label = new DigitLabel(k % 10);

				k /= 10;

				children[cc + i] = label;
			}

			cc += field.scale;
			cd += field.scale;
			if(field.delimiter)
			{
				children[cc] = field.delimiter;
				cc += 1;
			}
		}

		Component.alignHorizontal(children, [0.0f, 0.0f]);
		foreach(child; children)
		{
			super.add(child);
		}
	}


	this(int value, int scale)
	{
		Field[1] fields;

		fields[0].value = value;
		fields[0].scale = scale;
		fields[0].delimiter = null;

		this(fields);
	}


	void resize()
	{
		float l = 0.0;
		float r = 0.0;
		float b = 0.0;
		float t = 0.0;

		auto isFirst = true;
		foreach(child; this)
		{
			auto cl = child.position[0] - child.size[0]*0.5;
			auto cr = cl + child.size[0];
			auto cb = child.position[1] - child.size[1]*0.5;
			auto ct = cb + child.size[1];

			if(isFirst)
			{
				isFirst = false;

				l = cl;
				r = cr;
				b = cb;
				t = ct;
			}
			else
			{
				if(cl < l)
				{
					l = cl;
				}
				if(cr > r)
				{
					r = cr;
				}
				if(cb < b)
				{
					b = cb;
				}
				if(ct > t)
				{
					t = ct;
				}
			}
		}

		size[0] = r - l;
		size[1] = t - b + _labels[_focus].size[0]*2.0 + 4.0;

		_isResized = true;
	}


	override void onUpdate()
	{
		++_time;

		if(!_isResized)
		{
			resize();
		}
	}


	override bool onAxisMove(int axis)
	{
		switch(axis)
		{
		case Axis.LEFT:
			--_focus;
			if(_focus < 0)
			{
				_focus = _labels.length - 1;
			}
			break;

		case Axis.RIGHT:
			++_focus;
			if(_focus >= _labels.length)
			{
				_focus = 0;
			}
			break;

		case Axis.UP:
			auto x = _labels[_focus].value + 1;
			if(x >= 10)
			{
				x = 0;
			}

			_labels[_focus].value = x;
			if(_onChangeValue)
			{
				_onChangeValue(this);
			}
			break;

		case Axis.DOWN:
			auto x = _labels[_focus].value - 1;
			if(x < 0)
			{
				x = 9;
			}

			_labels[_focus].value = x;
			if(_onChangeValue)
			{
				_onChangeValue(this);
			}
			break;
		}

		return true;
	}


	override void onDraw()
	{
		if(_time & 16)
		{
			auto label = _labels[_focus];

			Vector2D p = label.position[];

			p[1] += label.size[1]*0.5;

			GGL_pushMatrix();

			translate(p);

			GGL_scale(label.size[0], label.size[0], 1.0);

			_cursor.draw();

			GGL_popMatrix();

			p[1] -= label.size[1];

			GGL_pushMatrix();

			translate(p);

			GGL_scale(label.size[0], label.size[0], 1.0);

			GGL_rotate(.std.math.PI, 0.0, 0.0, 1.0);

			_cursor.draw();

			GGL_popMatrix();
		}
	}


	override bool onClick()
	{
		sync();

		return true;
	}


	void cbChangeValue(OnChangeValue dg)
	{
		_onChangeValue = dg;
	}


	int value(int index)
	{
		auto a = 0;
		foreach(scale; _scales[0 .. index])
		{
			a += scale;
		}

		auto labels = _labels[a .. a + _scales[index]];
		
		int v = 0;
		foreach(label; labels)
		{
			v = v*10 + label.value;
		}

		return v;
	}


	void link(int index, DigitLabel label)
	{
		_links[index] = label;
	}


	void sync()
	{
		foreach(i, label; _links)
		{
			if(label)
			{
				label.value = value(i);
			}
		}
	}


	Table createTable()
	{
		auto table = new Table(1, 1);

		table.set(0, 0, this);

		return table;
	}


private:
	OnChangeValue _onChangeValue;
	DigitLabel[]  _labels;
	DigitLabel[]  _links;
	StaticMesh    _cursor;
	uint[]        _scales;
	uint          _time;
	bool          _isResized;
	int           _focus;
}
