package CharacterExport
{
	import flash.utils.*;
	import GraphicExport.*;
	import flash.display.*;
	import flash.geom.*;
	import flash.display.Sprite;
	import djarts.core.*;
	import flash.net.FileReference;
	import flash.events.*;

	public class AnimPieceExportBuilder
	{
		protected var sets:Array;
		protected var output:ByteArray = new ByteArray();
		public function get Output():ByteArray { return output; }
		
		protected var sheets:Array = [];
		
		protected var sheetWidth, sheetHeight;
		
		protected var pieces:Array = [];
		protected var pieceNodes:Array = [];
		
		public static const OUTPUT_VERSION = 3;
		
		public function AnimPieceExportBuilder(sets:Array)
		{
			output.endian = Endian.LITTLE_ENDIAN;
			this.sets = sets;
			
			for (var i in sets)
			{
				for (var j in sets[i].Pieces)
				{
					if (sets[i].Pieces[j].IsAnimated)
					{
						var exporter:CharacterExporter = sets[i].Pieces[j].Exporter;
						var usedPieces:Array = exporter.GetAllPieces();
						for (var k in usedPieces)
						{
							pieces.push(usedPieces[k]);
						}
					}
					else
					{
						pieces.push(sets[i].Pieces[j]);
					}
				}
				//pieces = pieces.concat(sets[i].Pieces);
			}
			
			sheetWidth = sheetHeight = ExportBuilder.DetermineMinimumSheetSize(pieces);

			this.sheetWidth = sheetWidth;
			this.sheetHeight = sheetHeight;
			
			sheets.push(new SpriteSheet(sheetWidth, sheetHeight));
			
			var piecePad = 2;
			
			for (var i = 0; i < pieces.length; i++)
			{
				var piece = pieces[i];
				var bd:BitmapData;
				if (piece is AnimationPiece)
				{
					bd = piece.Data;
				}
				if (piece is Piece)
				{
					bd = piece.FullData;
				}
				
				var usedNewSheet = false;
				for (var sheetIndex = 0; sheetIndex < sheets.length; sheetIndex++)
				{
					var sheet:SpriteSheet = sheets[sheetIndex];
					//if (this.ForceSpriteSheet) sheet = this.ForceSpriteSheet;
					if (!sheet.sheetFull)
					{
						var node:RectangleNode = sheet.GetAllocator().Insert(bd.width + piecePad * 2, bd.height + piecePad * 2);
						if (node)
						{
							pieceNodes[i] = node;
							
							sheet.GetBitmap().copyPixels(bd, bd.rect, new Point(node.Rect.x + piecePad, node.Rect.y + piecePad));
							break;
						}
					}
					if (sheetIndex == sheets.length - 1)
					{
						if (usedNewSheet)
						{
							throw new Error("This piece is probably too big!");
						} else {
							usedNewSheet = true;
							var newSheet:SpriteSheet = new SpriteSheet(sheetWidth, sheetHeight);
							newSheet.SheetIndex = sheets.length;
							sheets.push(newSheet);
						}
					}
				}				
			}
			
			output.writeUnsignedInt(OUTPUT_VERSION);
			
			output.writeUnsignedInt(sheetWidth);
			output.writeUnsignedInt(sheetHeight);
			output.writeUnsignedInt(sheets.length);
			for (var i = 0; i < sheets.length; i++)
			{
				var png:ByteArray = PNGExportHelper.GetExportPNG(sheets[i].GetBitmap());
				
				output.writeUnsignedInt(png.length);
				output.writeBytes(png);
			}
			
			output.writeUnsignedInt(sets.length);
			
			for (var i = 0; i < sets.length; i++)
			{
				output.writeUTF(sets[i].Name);
				
				
				output.writeUnsignedInt(sets[i].Pieces.length);
				var setPieces:Array = sets[i].Pieces;
				for (var j = 0; j < setPieces.length; j++)
				{
					var currentPiece:AnimationPiece = setPieces[j];
					
					//output.writeUnsignedInt(currentPiece.Index);
					output.writeUTF(currentPiece.Key);
					
					output.writeBoolean(currentPiece.IsAnimated);
					if (currentPiece.IsAnimated)
					{
						ExportBuilder.WriteCharacterExport(output, currentPiece.Exporter, this.pieces, this.pieceNodes, piecePad);
					}
					else
					{												
						
						
						var index = pieces.indexOf(currentPiece);
						var node:RectangleNode = pieceNodes[index];
						
						output.writeUnsignedInt(node.Host.HostTexture.SheetIndex);
						output.writeUnsignedInt(node.Rect.left + piecePad);
						output.writeUnsignedInt(node.Rect.top + piecePad);
						output.writeUnsignedInt(node.Rect.width - piecePad * 2);
						output.writeUnsignedInt(node.Rect.height - piecePad * 2);
						
						output.writeInt(setPieces[j].Offset.x); //pieceSequence.CenterPoint.x);
						output.writeInt(setPieces[j].Offset.y); //pieceSequence.CenterPoint.y);
					}
				}
			}
			output.compress();
		}
	}
}