package ;
import haxe.ds.StringMap;
import flixel.group.FlxSpriteGroup;
import openfl.Assets;
import flixel.tweens.FlxEase;
import flixel.util.FlxPoint;
import flixel.tweens.FlxTween;
import flixel.FlxSprite;
import haxe.xml.Fast;
import flixel.group.FlxGroup;

enum Anim
{
	NONE;
	REVEAL;
	CANCEL;
	THROW;
	SIGN;
	SEAL;
	DELIVER;
}

enum Mode
{
	HIDDEN;
	PAPER;
	ENVELOPE;
	TRASH;
}

class Form extends FlxSpriteGroup
{
	var desk:Desk;
	var id:String;
	var paper:FlxSprite;
	var envelope:FlxSprite;
	var trash:FlxSprite;
	var tween:FlxTween;
	var sign:FlxSprite;
	var posInFolder:FlxPoint;
	var fields:Array<Field> = new Array<Field>();
	var signed:Bool;

	public var mode(default,set):Mode;

	static var parkX = 188;
	static var parkY = 11;
	static var kDiscardY = 360;

	public function new(desk_:Desk, fast:Fast, posInFolder_:FlxPoint)
	{
		super();

		desk = desk_;
		posInFolder = posInFolder_;

		id = fast.att.id;

		// create paper
		paper = new FlxSprite();
		var paperBitmapData = Assets.getBitmapData("assets/images/Form-" + id + "-Paper.png");
		paper.loadGraphic(paperBitmapData);
		add(paper);

		// create fields
		var fieldColor = Std.parseInt(fast.att.fieldColor);
		var textColor = Std.parseInt(fast.att.textColor);
		var paperColor = paperBitmapData.getPixel(0,0);

		for (fieldFast in fast.nodes.field)
		{
			var field = new Field(desk, id, fieldFast.att.id, fieldColor, textColor, paperColor);
			fields.push(field);
			add(field);
		}
		var fieldIndex = 0;
		for (y in 0...paperBitmapData.height)
		{
			var fieldStartX = -1;
			for (x in 0...paperBitmapData.width)
			{
				var isField = ((paperBitmapData.getPixel(x,y) & 0x00ffffff) == fieldColor);
				if (isField && fieldStartX < 0)
				{
					fieldStartX = x;
				}
				else if (!isField && fieldStartX >= 0)
				{
					if (fieldIndex < fields.length)
					{
						var field = fields[fieldIndex];
						field.width = x - fieldStartX;
						field.text = " ";
						field.x = Math.floor(fieldStartX);
						field.y = Math.floor(y - field.font.getFontHeight());

						fieldIndex++;
						if (fieldIndex == fields.length) break;
					}

					fieldStartX = -1;
				}
			}
		}

		// create sign
		sign = new FlxSprite();
		sign.loadGraphic("assets/images/Sign.png");
		sign.visible = false;
		sign.x = Std.parseInt(fast.att.signX);
		sign.y = Std.parseInt(fast.att.signY);
		add(sign);

		// create envelope
		envelope = new FlxSprite();
		envelope.loadGraphic("assets/images/Form-" + id + "-Envelope.png");
		envelope.y = Math.floor(paper.height/2 - envelope.height/2);
		add(envelope);

		// create trash
		trash = new FlxSprite();
		trash.loadGraphic("assets/images/Form-" + id + "-Trash.png");
		trash.x = Math.floor(paper.width/2 - trash.width/2);
		trash.y = Math.floor(paper.height/2 - trash.height/2);
		add(trash);

		mode = HIDDEN;
	}

	public function deliverOrTrash()
	{
		if (signed && mode == ENVELOPE && desk.canDeliverForm(id, getHash()))
			playAnim(DELIVER);
		else
			playAnim(THROW);
	}

	public function playAnim(anim:Anim)
	{
		if (tween != null) { tween.cancel(); tween = null; }

		switch (anim)
		{
			case REVEAL:
				var changedMode = (mode != PAPER);

				mode = PAPER;
				// reset fields
				for (field in fields) { field.text = "..."; field.lock(false); }

				if (x == parkX && y == parkY && !changedMode)
				{
					// bounce up
					this.tween = FlxTween.tween(this, { y:parkY-10 }, 0.05, { ease:FlxEase.sineIn, complete:
						function(tween:FlxTween) { this.tween = FlxTween.tween(this, { y:parkY }, 0.1, { ease:FlxEase.sineOut }); }
					} );
				}
				else
				{
					x = posInFolder.x;
					y = posInFolder.y;
					this.tween = FlxTween.tween(this, { x:parkX }, 0.1, { ease:FlxEase.quadOut, complete:
						function(tween:FlxTween) { this.tween = FlxTween.tween(this, { x:parkX, y:parkY }, 0.1, { ease:FlxEase.quadOut }); }
					});
				}
			case CANCEL:
				this.tween = FlxTween.tween(this, { y:kDiscardY }, 0.2, { ease:FlxEase.sineOut, complete:
					function(tween:FlxTween) { mode = HIDDEN; }
				} );
			case THROW:
				// bounce down, change to trash, then move off top
				y = parkY + 20;
				var wasSealed = (mode == ENVELOPE);
				mode = TRASH;
				Main.playSound("Trash.mp3");
				this.tween = FlxTween.tween(this, { y:parkY }, 0.15, { ease:FlxEase.sineOut, complete:
						function(tween:FlxTween) { this.tween = FlxTween.tween(this, { y:-trash.height-20 }, 0.15, { ease:FlxEase.sineIn, startDelay:0.5, complete:
						function(tween:FlxTween) { mode = HIDDEN; desk.reportFormError(id, signed, wasSealed, getHash()); }
					}); }
				});

			case SIGN:
				// bounce down
				y = parkY + 20;
				sign.visible = true;
				signed = true;
				for (field in fields) field.lock(true);
				this.tween = FlxTween.tween(this, { y:parkY }, 0.15, { ease:FlxEase.sineOut });
			case SEAL:
				// bounce up
				y = parkY + 20;
				mode = ENVELOPE;
				this.tween = FlxTween.tween(this, { y:parkY }, 0.15, { ease:FlxEase.sineOut });
			case DELIVER:
				Main.playSound("Deliver.mp3");
				this.tween = FlxTween.tween(this, { y:-paper.height }, 0.15, { ease:FlxEase.sineOut, complete:
					function(tween:FlxTween)
					{
						if (mode == ENVELOPE)
							desk.reportFormSignSealedDelivered(id, getHash());
//						else
//							desk.reportFormError(signed, false, getHash());
						mode = HIDDEN;
					}
				} );
			case _:
		}
	}

	function getHash():Map<String,String>
	{
		var hash = new Map<String,String>();
		for (field in fields) hash.set(field.id, field.text);
		return hash;
	}

	function set_mode(m:Mode)
	{
		mode = m;
		switch (mode)
		{
			case HIDDEN:
				visible = false;
			case PAPER:
				visible = true;
				paper.visible = true;
				envelope.visible = false;
				sign.visible = false;
				signed = false;
				trash.visible = false;
				for (field in fields) field.visible = true;
			case ENVELOPE:
				visible = true;
				paper.visible = false;
				envelope.visible = true;
				sign.visible = false;
				trash.visible = false;
				for (field in fields) field.visible = false;
			case TRASH:
				visible = true;
				paper.visible = false;
				envelope.visible = false;
				sign.visible = false;
				trash.visible = true;
				for (field in fields) field.visible = false;
		}
		return m;
	}

	public override function update()
	{
		super.update();

		x = Math.floor(x);
		y = Math.floor(y);
	}
}
