package FlDosBox
{
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.geom.ColorTransform;
	import flash.geom.Matrix;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	
	/**
	 * ...
	 * @author Michael Miriti
	 */
	public class FlDosBox extends Sprite
	{
		[Embed(source="../../assets/font/8x12_alpha.png")]
		private static var _font:Class;
		
		private var _charsBitmap:Bitmap = new _font() as Bitmap;
		private var _canvas:BitmapData;
		
		// Количество символов в шаблоне (ширина)
		private static const FONT_CHARS_H:int = 16;
		// Количество символов в шаблоне (высота)
		private static const FONT_CHSRS_V:int = 16;
		// ширина одного символа
		private static const FONT_CHAR_WIDTH:int = 8;
		// высота одного символа
		private static const FONT_CHAR_HEIGHT:int = 12;
		// палитра цветов
		private static const FONT_COLOR_PALETTE:Array = [0x000000, 0x000080, 0x008000, 0x008080, 0x800000, 0x800080, 0x808000, 0xc0c0c0, 0x808080, 0x0000ff, 0x00ff00, 0x00ffff, 0xff0000, 0xff00ff, 0xffff00, 0xffffff];
		
		private var _colorTransformPalette:Vector.<ColorTransform> = new Vector.<ColorTransform>();
		
		// номера знаков для отображения
		private var _g_CharVals:Vector.<Vector.<int>>;
		// номера цветов знаков из палитры
		private var _g_CharColr:Vector.<Vector.<int>>;
		// номера цветов фонов из палитры
		private var _g_CharBack:Vector.<Vector.<int>>;
		// битмапы символов
		private var _chars:Vector.<Vector.<BitmapData>>;
		// количество символов на экране (ширина)
		private var _charsW:int;
		// количество символов на экране (высота)
		private var _charsH:int;
		// масштаб выводимыз знаков
		private var _charsScale:uint;
		private var _dm:Matrix = new Matrix();
		
		private var _backBlank:Vector.<BitmapData>;
		private var _corette:Point = new Point();
		private var _timeLast:Number = new Date().getTime();
		
		/**
		 *
		 * @param	cWidth
		 * @param	cHeight
		 * @param	scale
		 */
		public function FlDosBox(cWidth:int = 80, cHeight:int = 25, scale:uint = 2)
		{
			super();
			
			for (var k:int = 0; k < FONT_COLOR_PALETTE.length; k++)
			{
				_colorTransformPalette[k] = new ColorTransform();
				_colorTransformPalette[k].color = FONT_COLOR_PALETTE[k];
			}
			
			_g_CharVals = new Vector.<Vector.<int>>();
			_g_CharColr = new Vector.<Vector.<int>>();
			_g_CharBack = new Vector.<Vector.<int>>();
			for (var i:int = 0; i < cWidth; i++)
			{
				_g_CharVals[i] = new Vector.<int>(cHeight);
				_g_CharColr[i] = new Vector.<int>(cHeight);
				_g_CharBack[i] = new Vector.<int>(cHeight);
				
			}
			
			clear();
			
			_charsW = cWidth;
			_charsH = cHeight;
			_charsScale = scale;
			
			initChars();
			
			_canvas = new BitmapData(cWidth * FONT_CHAR_WIDTH * scale, cHeight * FONT_CHAR_HEIGHT * scale, false, 0x0);
			addChild(new Bitmap(_canvas, "auto", true));
			addEventListener(Event.ENTER_FRAME, onEnterFrame);
		}
		
		public function window(wx:int, wy:int, ww:int, wh:int, fc:int, bc:int, shade:Boolean = false, shade_c:int = 0, shade_b:int = 0, shade_char:int = 177):void
		{
			if (shade)
			{
				fillBlock(wx + 1, wy + 1, ww, wh, shade_char, shade_c, shade_b);
			}
			fillBlock(wx, wy, ww, wh, 15, fc, bc);
			fillBlock(wx, wy, 1, wh, 185, fc, bc);
			fillBlock(wx + ww - 1, wy, 1, wh, 185, fc, bc);
			fillBlock(wx, wy, ww, 1, 204, fc, bc);
			fillBlock(wx, wy + wh - 1, ww, 1, 204, fc, bc);
			
			setChar(wx, wy, 200, fc, bc);
			setChar(wx + ww - 1, wy, 186, fc, bc);
			setChar(wx + ww - 1, wy + wh - 1, 187, fc, bc);
			setChar(wx, wy + wh - 1, 199, fc, bc);
		}
		
		/**
		 * Clear screen
		 */
		public function clear():void
		{
			for (var i:int = 0; i < _charsW; i++)
			{
				for (var j:int = 0; j < _charsH; j++)
				{
					_g_CharVals[i][j] = 15;
					_g_CharBack[i][j] = 0;
				}
			}
		}
		
		/**
		 * Get char at possition
		 *
		 * @param	px
		 * @param	py
		 * @return
		 */
		public function getChar(px:int, py:int):int
		{
			return _g_CharVals[px][py];
		}
		
		/**
		 * Get color at possition
		 *
		 * @param	px
		 * @param	py
		 * @return
		 */
		public function getColor(px:int, py:int):int
		{
			if ((px >= 0) && (px < _charsW) && (py >= 0) && (py < _charsH))
				return _g_CharColr[px][py];
			else
				return 0;
		}
		
		/**
		 * Get backgroung color
		 *
		 * @param	px
		 * @param	py
		 * @return
		 */
		public function getBack(px:int, py:int):int
		{
			return _g_CharBack[px][py];
		}
		
		/**
		 * Set char at position
		 *
		 * @param	px
		 * @param	py
		 * @param	char
		 * @param	color
		 * @param	back
		 */
		public function setChar(px:int, py:int, char:int, color:int = 8, back:int = 0):void
		{
			if ((char > 0) && (char < 256))
			{
				_g_CharVals[px][py] = char;
				_g_CharColr[px][py] = color;
				_g_CharBack[px][py] = back;
			}
		}
		
		/**
		 * Set string at possition
		 *
		 * @param	px
		 * @param	py
		 * @param	str
		 * @param	color
		 * @param	back
		 */
		public function setString(px:int, py:int, str:String, color:int = 8, back:int = 0):void
		{
			for (var i:int = 0; i < str.length; i++)
			{
				setChar(px + i, py, str.charCodeAt(i) - 1, color, back);
			}
		}
		
		/**
		 * Fill block
		 *
		 * @param	px
		 * @param	py
		 * @param	pw
		 * @param	ph
		 * @param	char
		 * @param	color
		 * @param	back
		 */
		public function fillBlock(px:int, py:int, pw:int, ph:int, char:int, color:int = 8, back:int = 0):void
		{
			for (var i:int = px; i < px + pw; i++)
			{
				for (var j:int = py; j < py + ph; j++)
				{
					setChar(i, j, char, color, back);
				}
			}
		}
		
		/**
		 *
		 */
		private function initChars():void
		{
			_backBlank = new Vector.<BitmapData>();
			for (var l:int = 0; l < FONT_COLOR_PALETTE.length; l++)
			{
				var newBackBlank:BitmapData = new BitmapData(FONT_CHAR_WIDTH * _charsScale, FONT_CHAR_HEIGHT * _charsScale, false, FONT_COLOR_PALETTE[l]);
				_backBlank.push(newBackBlank);
			}
			
			var ci:int = 0;
			_chars = new Vector.<Vector.<BitmapData>>();
			
			for (var j:int = 0; j < FONT_CHSRS_V; j++)
			{
				for (var i:int = 0; i < FONT_CHARS_H; i++)
				{
					_chars[ci] = new Vector.<BitmapData>();
					
					var newBmp:BitmapData = new BitmapData(FONT_CHAR_WIDTH, FONT_CHAR_HEIGHT);
					newBmp.copyPixels(_charsBitmap.bitmapData, new Rectangle(i * FONT_CHAR_WIDTH, j * FONT_CHAR_HEIGHT, FONT_CHAR_WIDTH, FONT_CHAR_HEIGHT), new Point(0, 0));
					
					var m:Matrix = new Matrix();
					var c:ColorTransform = new ColorTransform();
					
					m.scale(_charsScale, _charsScale);
					
					for (var k:int = 0; k < FONT_COLOR_PALETTE.length; k++)
					{
						c.color = FONT_COLOR_PALETTE[k];
						var newChar:BitmapData = new BitmapData(FONT_CHAR_WIDTH * _charsScale, FONT_CHAR_HEIGHT * _charsScale, true, 0x000000000);
						newChar.draw(newBmp, m, c);
						_chars[ci].push(newChar);
					}
					ci++;
				}
			}
		}
		
		/**
		 *
		 * @param	e
		 */
		private function onEnterFrame(e:Event):void
		{
			var newTime:Number = new Date().getTime();
			update(newTime - _timeLast);
			_timeLast = newTime;
			
			_dm.identity();
			_dm.scale(2, 2);
			for (var i:int = 0; i < _charsW; i++)
			{
				for (var j:int = 0; j < _charsH; j++)
				{
					var c:int = _g_CharColr[i][j];
					var b:int = _g_CharBack[i][j];
					var chr:BitmapData = _chars[_g_CharVals[i][j]][c];
					_corette.x = i * FONT_CHAR_WIDTH * _charsScale;
					_corette.y = j * FONT_CHAR_HEIGHT * _charsScale;
					if (b != -1)
						_canvas.copyPixels(_backBlank[b], _backBlank[b].rect, _corette);
					_canvas.copyPixels(chr, chr.rect, _corette, chr);
				}
			}
		}
		
		/**
		 *
		 * @param	deltaTime
		 */
		protected function update(deltaTime:Number):void
		{
		
		}
	}

}