package {

	import flash.display.MovieClip;
	import flash.display.Loader;
	import flash.events.*;
	import flash.text.*;
	import flash.net.URLRequest;
	import flash.utils.*;
	import flash.net.*;
	import flash.ui.Keyboard;
	import flash.utils.getTimer;
	import flash.geom.*;
	import flash.display.StageAlign;
	import flash.display.StageScaleMode;
	import com.adobe.crypto.MD5;
	import flash.system.fscommand;
	import flash.desktop.*;
	
	import djarts.core.*;
	import djarts.events.*;
	import djarts.components.*;
	import djarts.utils.*;
	import djarts.resources.*;
	import djarts.display.*;
	
	import djarts.utils.Base64;
	import com.adobe.images.JPGEncoder;
	import flash.display.BitmapData;
	
	import com.adobe.serialization.json.JSON;
	import com.adobe.serialization.json.*;
	import flash.display.Stage3D;
	import flash.display.Bitmap;
	import Packer.AsyncGraphicPacker;
	import Defs.GraphicDef;
	import Defs.HeroDef;
	import CharacterExport.CharacterExporter;
	import CharacterExport.ExportBuilder;
	import CharacterExport.PieceLibrary;
	import GraphicExport.IconPacker;
	import GraphicExport.SkelAnimPacker;
	import Defs.MapDef;
	import GraphicExport.AnimSetPacker;
	import GraphicExport.AnimPiecePacker;
	import GraphicExport.ScenePacker;

	import flash.filesystem.*;

	public class GraphicExport extends MovieClip
	{
	
		var UILayer:MovieClip = new MovieClip();
		public static var ISLOCAL = true;
		public static var wrapper:Socket = null;
		private static var instance:GraphicExport = null;
		public function GraphicExport()
		{
			instance = this;
			GraphicFactory.FAILEDGRAPHICASBLANK = true;
			GameSettings.ISLOCAL = true;

			DialogManager.Instance().SetUILayer(UILayer);
			DialogManager.Instance().SetUIOverLayer(UILayer);

			DialogManager.Instance().ResolutionChanged(stage.width, stage.height);
			
			this.stage.addChild(UILayer);
			
			this.removeChild(newGraphicDialog);
			
			Init();
			
			try
			{
				NativeApplication.nativeApplication.addEventListener("invoke", ApplicationInvoked);
			}
			catch (e)
			{
				// not an air runtime app
				ConnectWrapper(7890);	// try default port
			}
			
		}
		
		public function ApplicationInvoked(e)
		{
			if (e.arguments.length == 1)
			{
				ConnectWrapper(parseInt(e.arguments[0]));
			}
			else
			{
				StartUI();
			}
		}
		
		private function WrapperIOError(e)
		{
			Log("Couldn't connect wrapper");
			Log(e.toString());
			StartUI();
		}
		
		private function WrapperConnect(e:Event)
		{
			wrapper = e.target as Socket;
			Log("Wrapper Connected");
			_strace("Wrapper Connected");
			wrapper.addEventListener(ProgressEvent.SOCKET_DATA, WrapperData);
			
			FlashConsole.Instance().Show();
		}
		
		private function WrapperData(e:ProgressEvent)
		{
			var data:String = wrapper.readUTF();
			DispatchCommand(com.adobe.serialization.json.JSON.decode(data));
		}
		
		private var inJob = false;
		private var jobs:Array = new Array();
		
		private function DispatchCommand(msg)
		{
			Log("Sent command: " + com.adobe.serialization.json.JSON.encode(msg));						
			if (msg.hasOwnProperty("command"))
			{
				var cmd = msg.command;
				switch (cmd)
				{
					case "job":
						jobs.push(msg);
						CheckNewJob();
					break;
					case "quit":
						Log("Quitting");
						fscommand("quit");
						NativeApplication.nativeApplication.exit();
					break;
					case "log":
						Log(cmd.string);
					break;
					default:
						//Log("Sent command: " + com.adobe.serialization.json.JSON.encode(msg));						
					break;
				}
			}
		}
		
		private function CheckNewJob()
		{
			if (!inJob && jobs.length > 0)
			{
				var job = jobs.shift();
				inJob = true;
				
				NewGraphicDialog.fakeID++;
				
				var graphicData = {id:NewGraphicDialog.fakeID,graphic:job.input,v:1,fs:0,p:0,type:job.type};

				//"export_params":{"uses":["background"],"available_sizes":["default"],"compress":false}}
				
				var graphicDef = new Defs.GraphicDef(graphicData);
				
				ExportItem(graphicDef,
					function()
					{
						SendCommand({command:"done", job_num:parseInt(job.job_num)});
						inJob = false;
						CheckNewJob();
					}
				);
			}
		}
		
		public static function SendCommand(obj)
		{
			if (wrapper != null)
			{
				wrapper.writeUTF(com.adobe.serialization.json.JSON.encode(obj));
				wrapper.flush();
				//if (obj.hasOwnProperty("command") && obj.command == "print")
				//{
				//	instance.Log(obj.string);
				//}
			}
		}
		
		private function ConnectWrapper(port)
		{
			Log("Attempting to connect wrapper");
			try
			{
				var s = new Socket();
				s.addEventListener(IOErrorEvent.IO_ERROR, WrapperIOError);
				s.addEventListener(Event.CONNECT, WrapperConnect);
				s.connect("localhost", port);
			} catch (e)
			{
				Log("Error establishing wrapper connection");
				StartUI();
				return;
			}
		}
		
		
		public function Init()
		{

			_strace("Initializing game params!!");

			//Set a scale mode for window resizing
			stage.align = StageAlign.TOP_LEFT;
			stage.scaleMode = StageScaleMode.NO_SCALE;

			GameSettings.GameplayArea = new Rectangle(0, 0, stage.stageWidth, stage.stageHeight);
			
			ResourceManager.Instance().Init(ISLOCAL, "RootGame");
			
			ResourceManager.Instance().SetLocations([""]);
			
			GameSettings.Instance().SetStage(this.stage);
			Globals.Instance().SetStage(this.stage);

			FlashConsole.Instance().Admin = true;
			

			stage.addEventListener(Event.ENTER_FRAME, EnterFrame);
			
			this.addChild(previewHolder);
			CreateUI();
			ActivateExportButtons(false);
		}
		
		var exportButtons:Array = [];
		public function ActivateExportButtons(active)
		{
			for(var i = 0; i < exportButtons.length; i++)
			{
				exportButtons[i].Enabled = active;
			}
			
			this.heuristicCheck.Enabled = active;
			this.edgeExpand.Enabled = active;
			this.skeletal_scale.type = active ? TextFieldType.INPUT : TextFieldType.DYNAMIC;
		}
		
		protected function CreateUI()
		{
			/*
			var maxWidth = 0;
			for (var i = 0; i < exportButtons.length; i++) maxWidth = Math.max(maxWidth, exportButtons[i].width);
			
			var startX = buttonArea.x + (maxWidth / 2); //stage.stageWidth - 110;
			var startY = buttonArea.y + 20;
			for(var i = 0; i < exportButtons.length; i++)
			{
				this.addChild(exportButtons[i])
				exportButtons[i].x = startX;
				exportButtons[i].y = startY;
				maxWidth = Math.max(maxWidth, exportButtons[i].width);				
				if (exportButtons[i].GetButtonText() == "Generic Use")
				{
					addChild(genericUseText);
					genericUseText.x = startX - exportButtons[i].width / 2;
					genericUseText.y = startY + 18;
					startY += 25;
				}
				
				if (exportButtons[i].GetButtonText() == "Single ID")
				{
					addChild(singleIdText);
					singleIdText.x = startX - exportButtons[i].width / 2;
					singleIdText.y = startY + 18;
					startY += 25;
				}
				
				if (exportButtons[i].GetButtonText() == "Single Asset")
				{
					addChild(singleAssetText);
					singleAssetText.x = startX - exportButtons[i].width / 2;
					singleAssetText.y = startY + 18;
					startY += 25;
				}
				
				startY += 35;
				if (startY > buttonArea.y + buttonArea.height - 20)
				{
					startY = buttonArea.y + 20;
					startX += (maxWidth + 20);
					maxWidth = 0;
				}
			}
			*/

			heuristicCheck.Checked = false;
			heuristicCheck.OnClickParam = heuristicCheck;
			heuristicCheck.OnClick = ClickedHeuristic;
			heuristicCheck.Text = "Flat Animated Clip Heuristic";
			
			edgeExpand.Checked = false;
			edgeExpand.OnClickParam = edgeExpand;
			edgeExpand.OnClick = ClickedEdgeExpand;
			edgeExpand.Text = "Expand edge alpha.";
			
			PNGExportHelper.UseExpandedBitmaps = true;
			edgeExpand.Checked = PNGExportHelper.UseExpandedBitmaps;
			
			this.skeletal_scale.addEventListener(Event.CHANGE, SkeletalScaleChanged);
		}
		
		public function StartUI()
		{
			ActivateExportButtons(true);
			ShowNewGraphicDialog();
		}
		
		public function ShowNewGraphicDialog()
		{
			newGraphicDialog.Show(this);
		}
		
		var skeletalScale = 1;
		private function SkeletalScaleChanged(e:Event)
		{
			try
			{
				var number = Number(skeletal_scale.text);
				skeletalScale = number;
			} catch(exception){
				
			}
		}
		
		private function ClickedHeuristic(button:Checkbox)
		{
			AsyncGraphicPacker.UseFlatHeuristic = !AsyncGraphicPacker.UseFlatHeuristic;
			button.Checked = AsyncGraphicPacker.UseFlatHeuristic;
		}
		
		private function ClickedEdgeExpand(button:Checkbox)
		{
			PNGExportHelper.UseExpandedBitmaps = !PNGExportHelper.UseExpandedBitmaps;
			button.Checked = PNGExportHelper.UseExpandedBitmaps;
		}
		
		var outputFormat = "json_png_set";
		
		protected var lastTime = null;
		protected function EnterFrame(e:Event)
		{
			var now = getTimer() / 1000.0;
			if (lastTime == null) lastTime = now;
			
			var timeElapsed = now - lastTime;
			
			ResourceManager.Instance().StartUpdateLoop();
			
			EnterFrameManager.Instance().EnterFrame(new TimeElapsedEvent(timeElapsed), timeElapsed);
			
			ResourceManager.Instance().EndUpdateLoop();
			
			HeroSpriteLoader.Instance().Update(1);
			
			lastTime = now;
		}
		
		protected var graphicPreloader:GraphicPreloader = new GraphicPreloader();
		
		protected function DoneAll()
		{
			ActivateExportButtons(true);
			_strace("========= DONE ALL =========");
		}
		
		protected var lastCallback;
		public function ExportItem(def:Defs.GraphicDef, callback = null)
		{			
			this.lastCallback = callback;
			Log("Exporting " + def.ID + " " + def != null);
			var graphicDefs:Array = [def];
			
			var type = def.Type;
			
			var assetDef:Defs.GraphicDef = null;
			if (def.ExportParams.hasOwnProperty("asset_id"))
			{
				assetDef = GameData.Instance().GetGraphicDefByID(def.ExportParams.asset_id);
				type = assetDef.Type;
			}
			Log(" type: " + type);
			switch (type)
			{
				case Defs.GraphicDef.EXPORT_FORMAT_SPRITESHEET:
					if (def.ExportParams.hasOwnProperty("export_animation"))
					{
						var graphicPacker:AsyncGraphicPacker = new AsyncGraphicPacker();
						graphicPacker.ExportDefs(graphicDefs, DoneAsset, def, outputFormat);
					} else {
						var iconPacker:IconPacker = new IconPacker(DoneAsset, def, previewHolder, outputFormat);
						iconPacker.ExportDefs(graphicDefs);
					}
					break;
				case Defs.GraphicDef.EXPORT_FORMAT_CACHEDCLIP:
					break;
				case Defs.GraphicDef.EXPORT_FORMAT_SKELANIM:
					var skelPacker:SkelAnimPacker = new SkelAnimPacker(DoneAsset, def, previewHolder,
						assetDef && assetDef.ExportParams.hasOwnProperty("export_type") ? assetDef.ExportParams.export_type : null, skeletalScale, outputFormat);
					skelPacker.ExportDefs(graphicDefs);
					break;
				case Defs.GraphicDef.EXPORT_FORMAT_ANIMSETS:
					var animSetPacker:AnimSetPacker = new AnimSetPacker(DoneAsset, def, previewHolder);
					animSetPacker.ExportDef(graphicDefs[0]);
					break;
				case Defs.GraphicDef.EXPORT_FORMAT_ANIMPIECES:
					var animPiecePacker:AnimPiecePacker = new AnimPiecePacker(DoneAsset, def, previewHolder);
					animPiecePacker.ExportDefs(graphicDefs);
					break;
				case Defs.GraphicDef.EXPORT_FORMAT_SCENE:
					var scenePacker:ScenePacker = new ScenePacker(DoneAsset, def, previewHolder, outputFormat);
					scenePacker.ExportDef(graphicDefs[0]);
					break;
				default:
					_strace("COULDN'T DETERMINE EXPORT FORMAT");
					break;
			}
		}
		
		public function Log(logStr)
		{
			logText.text += logStr + "\n";
		}
		
		protected function DoneAsset(output, assetDef:Defs.GraphicDef)
		{
			Log(assetDef.Folder + assetDef.Name);
			
			var fileExport:FileExportSet = null;

			if (output is FileExportSet) fileExport = output;
			if (output is JSONPNGSet)
			{
				fileExport = new FileExportSet();
				output.AssetName = assetDef.Name;
				fileExport.AddJSONPNGSet(output);
			}
			
			if (output is ByteArray)
			{
				fileExport = new FileExportSet();
				fileExport.Add(assetDef.Name, output);
			}
			
			fileExport.Save(lastCallback);

		}
		
		
	}
	 
}
