package ;
import flixel.util.FlxRandom;
import flixel.util.FlxTimer;
import flixel.tweens.FlxTween;
import flixel.FlxSprite;
import flixel.text.FlxBitmapTextField;
import flixel.FlxG;
import openfl.Assets;
import haxe.xml.Fast;
import flixel.group.FlxSpriteGroup;

enum Process
{
	SIGN;
	SEAL;
	DELIVER;
}

class Desk extends FlxSpriteGroup
{
	public var comboBox:ComboBox;
	var buttonBar:ButtonBar;
	var folders = new List<Folder>();
	var activeForm:Form;
	var feed:Feed;
	var jobs = new Array<Job>();
	var timeElapsed = 0.0;
	var session:Session;
	var errorMessage:FlxBitmapTextField;
	var resultCorrect:FlxSprite;
	var resultCorrectTimer:FlxTimer;

	var numJobsAdded = 0;
	var numJobsProcessed = 0;
	var numFormsFailed = 0;
	var nextJobSpawnTime = 0.0;
	var firstJobProcessedTime = 0.0;

	public function new()
	{
		super();

		session = Session.cur;

		var xml = Xml.parse(Assets.getText("assets/data/Forms.xml"));
		var fast = new Fast(xml.firstElement());

		errorMessage = new FlxBitmapTextField(Global.terminalFont);
		errorMessage.textColor = 0xadadad;
		errorMessage.alignment = flixel.text.pxText.PxTextAlign.CENTER;
		errorMessage.multiLine = true;
		errorMessage.fixedWidth = true;
		errorMessage.width = 160;
		errorMessage.x = 225;
		errorMessage.y = 20;
		add(errorMessage);

		resultCorrect = new FlxSprite();
		resultCorrect.loadGraphic("assets/images/Result-Correct.png");
		resultCorrect.x = 262;
		resultCorrect.y = 6;
		resultCorrect.visible = false;
		add(resultCorrect);

		resultCorrectTimer = new FlxTimer(null);

		buttonBar = new ButtonBar(this);
		add(buttonBar);

		var folderY = 50;
		for (formFast in fast.elements)
		{
			if (session.formIds.indexOf(formFast.att.id) < 0) continue;

			var folder = new Folder(this, formFast, 430, folderY);
			add(folder);
			folders.add(folder);
			folderY += 21;
		}

		// make tab larger on front folder
		if (folders.length != 0) folders.last().clearTabHitRect();

		feed = new Feed(session.index);
		add(feed);

		comboBox = new ComboBox();
		add(comboBox);

		nextJobSpawnTime = 2;

		FlxG.sound.music.fadeOut(2);
	}

	public function addJob(id:String)
	{
		var job = new Job(id, numJobsAdded);
		jobs.push(job);
		feed.addJob(job);

		numJobsAdded++;
	}

	public function showForm(form:Form)
	{
		for (folder in folders)
		{
			var other = folder.form;
			if (other == form)
				other.playAnim(REVEAL);
			else if (other.mode != HIDDEN)
				other.playAnim(CANCEL);
		}

		activeForm = form;
		buttonBar.resetToUnclicked();
		buttonBar.animateVisible(form != null);
		errorMessage.visible = false;
	}

	public function processForm(process:Process)
	{
		if (activeForm == null) return;

		switch (process)
		{
			case SIGN:
				activeForm.playAnim(SIGN);
			case SEAL:
				activeForm.playAnim(SEAL);
			case DELIVER:
				activeForm.deliverOrTrash();
		}
	}

	public function canDeliverForm(formId:String, hash:Map<String,String>)
	{
		for (job in jobs)
		{
			if (job.id == formId && job.matchesFormHash(hash)) return true;
		}
		return false;
	}

	public function reportFormError(formId:String, signed:Bool, sealed:Bool, hash:Map<String,String>)
	{
		var message = "";

		if (!signed)
			message += "Not signed\n";
		if (!sealed)
			message += "Not sealed\n";

		var job = feed.selectedJob;
		if (message.length == 0 && job != null)
		{
			if (formId != job.id)
			{
				message = "Wrong form";
			}
			else
			{
				for (fieldId in hash.keys())
				{
					if (job.formHash.exists(fieldId) && (hash[fieldId] != job.formHash[fieldId]))
						message += "Incorrect " + fieldId + "\n";
				}
			}
		}

		if (message.length == 0)
		{
			message = "Wasted paper";
		}

		errorMessage.text = message.toUpperCase();
		errorMessage.visible = true;

		numFormsFailed++;
	}

	public function reportFormSignSealedDelivered(formId:String, hash:Map<String,String>)
	{
		for (job in jobs)
		{
			if (job.id == formId && job.matchesFormHash(hash))
			{
				jobs.remove(job);
				feed.removeJob(job);

				numJobsProcessed++;
				firstJobProcessedTime = timeElapsed;
				resultCorrectTimer.start(0.25, function(timer:FlxTimer) { resultCorrect.visible = (timer.elapsedLoops % 2) == 1; }, 6 );
				break;
			}
		}
	}

	public function getFieldList(formId:String, fieldId:String):Array<String>
	{
		var selectedJob = feed.selectedJob;
		if (selectedJob == null) selectedJob = jobs[0];

		var fieldList = (selectedJob != null) ? selectedJob.getFieldList(fieldId, jobs) : new Array<String>();

		if (fieldList.length == 0)
			fieldList.push("...");

		return fieldList;
	}

	function addRandomJob()
	{
		if (session.formIds.length != 0)
		{
			var formId = session.formIds[Std.random(session.formIds.length)];
			addJob(formId);
		}
	}

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

		timeElapsed += FlxG.elapsed;

		if (session.wait && numJobsProcessed == 0 && numJobsAdded != 0)
		{
			// waiting for first job to get processed
		}
		else
		{
			// spawn next job
			if (timeElapsed > nextJobSpawnTime && numJobsAdded < session.jobCount)
			{
				addRandomJob();
				nextJobSpawnTime = timeElapsed + FlxRandom.floatRanged(1, 3);
			}
		}

		var playTimeElapsed = timeElapsed;
		if (session.wait)
		{
			if (numJobsProcessed == 0) playTimeElapsed = 0;
			else playTimeElapsed = timeElapsed - firstJobProcessedTime;
		}

		feed.time = Math.max(0, session.duration - playTimeElapsed);

		if (playTimeElapsed > session.duration || (session.jobCount != 0 && numJobsProcessed >= session.jobCount) || (numFormsFailed > 3))
		{
			// done
			var nightState = new NightState();
			if (session.jobCount == 0 || (numJobsProcessed >= 5 && numFormsFailed <= 3))
			{
				// success
				Session.advanceCur();
			}
			else if (Session.failedSessionIndex == session.index)
			{
				nightState.forceScreen = "fail";
			}
			else
			{
				Session.failedSessionIndex = session.index;
				nightState.forceScreen = "retry";
			}
			FlxG.switchState(nightState);
			return;
		}

		if (FlxG.keys.pressed.CONTROL)
		{
			if (FlxG.keys.justPressed.SPACE)
			{
				//addJob("screws");
				addRandomJob();
			}

			if (FlxG.keys.justPressed.E && jobs.length != 0)
			{
				var job = jobs[0];
				numJobsProcessed++;
				jobs.remove(job);
				feed.removeJob(job);
			}

			if (FlxG.keys.justPressed.F)
			{
				Session.advanceCur();
				FlxG.switchState(new NightState());
			}
		}
	}
}
