package com.netgrind {
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.Sprite;
	import flash.geom.ColorTransform;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	
	/**
	 * ...
	 * @author netgrind
	 */
	public class cText extends CVBox{
		
		[Embed(source = "/fonts/5px.png")]public var defaultFont:Class;
		public var defaultOrder:Array =  ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '.', ',', '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '-', '_', '+', '=', '/', '\\', '?', '"', '\'', '|', '<', '>', '~', ':', ';'];
		public var defaultWidths:Array = [ 5 ,  5 ,  5 ,  5 ,  5 ,  5 ,  5 ,  5 ,  5 ,  5 ,  5 ,  5 ,  5 ,  5 ,  5 ,  5 ,  5 ,  5 ,  5 ,  5 ,  5 ,  5 ,  5 ,  5 ,  5 ,  5 ,  5 ,  5 ,  5 ,  5 ,  5 ,  5 ,  5 ,  5 ,  5 ,   5,   3,   3,   3,   5,   5,   5,   5,   5,   5,   5,   5,   5,   5,   5,   5,   5,   5,    5,   5,   5,    5,   3,   5,   5,   5,   3,   3];
		public var defaultSize:int = 5;
		public var defaultScale:int = 2;
		private var _defaultColor:uint = UtilsArt.addAlpha(Defaults.black, 1);
		public var defaultDelay:int = 0;
		public var spaceSize:Number = defaultSize;
		public var defaultKerning:Number = 1;
		public var kerning:Number =  1;
		public var defaultLineBuffer:Number = 10;
		
		public var monoSpace:Boolean = true;
		
		private var _text:String;
		private var _font:Bitmap;
		private var _width:Number = 300;
		private var _delay:int = 0;
		
		public var chars:Vector.<Bitmap>;
		public var words:Vector.<CHBox>;
		public var lines:Vector.<CHBox>;
		
		private var _color:ColorTransform = new ColorTransform();
		
		public static const markupOpen:String = '[';
		public static const markupClose:String = ']';
		private var _centered:Boolean;
		private var _scale:Number = 1;
		private var _sin:Array;
		private var _shake:Array;
		private var _sinMode:Boolean = false;
		private var _shakeMode:Boolean = false;
		
		public function cText(txt:String = ''):void {
			_color.color = defaultColor;
			_font = new defaultFont();
			_delay = defaultDelay;
			_scale = defaultScale;
			_sin = [];
			_shake = [];
			buffer = defaultLineBuffer;
			text = txt;
			Scheduler.invokeEvery(update);
		}
		
		public function update():void {
			var i:int	
			for (i = 0; i < _sin.length; i++) {
				chars[_sin[i]].y = Math.sin(Scheduler.c*5 - (chars[_sin[i]].localToGlobal(new Point()).x)*.05) * 3;
			}
			for (i = 0; i < _shake.length; i++) {
				chars[_shake[i]].x = Math.random()*4-2;
				chars[_shake[i]].y = Math.random()*4-2;
			}
		}
		
		public function get text():String {	return _text;}		
		public function set text(value:String):void {
			_text = value;
			clearText();
			drawText();
		}
		
		public function appendText(txt:String):void {
			var len:int = _text.length;
			_text += txt;
			drawText(len);
		}
		
		public function clear():void {
			text = '';
		}
		
		private function drawText(startAt:int = 0 ):void {
			var delay:int = 0;
			for (var i:int = startAt; i < _text.length; i++) {
				var char:String = _text.charAt(i);
				if (char == '\n'||char.charCodeAt()==13) {
					addCharacter(' ');
					newLine();
				}else if (char == markupOpen) {
					i++;
					var command:String = '';
					while (_text.charAt(i) != markupClose) {
						command += _text.charAt(i);
						i++;
					}
					parseComamnd(command);
				}else {
					delay += _delay;
					addCharacter(char);	
					if(char==' '){
						var w:int = 0
						var add:Number = 0;
						if (i!=0&&_text.charAt(i - 1) == '\n') {
							add=-kerning;
						}
						while (_text.charAt(i) == ' ') {
							i++;
							w++;
						}
						var size:Number = (w * kerning + w * spaceSize-spaceSize)+add;
						currentWord.addChild(UtilsArt.makeRectangle(size*_scale, 1,0,0));
						i--;
					}
					if (delay != 0) {
						Scheduler.invokeIn(drawText, delay, i+1);
						return;
					}
				}
			}			
		}
		
		private function parseComamnd(command:String):void {	
			var a:Array = command.split(' ');
			if (command.indexOf('color') != -1) {
				if (command.indexOf('/') != -1) {
					_color.color = defaultColor;
				}else {
					_color.color = parseInt(a[1], 16);
				}
			}else if (command.indexOf('size') != -1) {
				if (command.indexOf('/') == 0) {
					_scale = defaultScale;
				}else {
					_scale = parseInt(a[1], 10);
				}
			}else if (command.indexOf('delay')!=-1) {
				if (command.indexOf('/') == 0) {
					_delay = defaultDelay;
				}else {
					_delay = parseInt(a[1], 10);
				}
			}else if (command.indexOf('pause') != -1) {
				var oldDelay:int = _delay;
				_delay = parseInt(a[1], 10);
				Scheduler.invokeIn(setDelay, _delay-1,oldDelay);
			}else if (command.indexOf('sine') != -1) {
				if (command.indexOf('/') == 0) {
					_sinMode = false;
				}else {
					_sinMode = true;
				}
			}else if (command.indexOf('shake') != -1) {
				if (command.indexOf('/') == 0) {
					_shakeMode = false;
				}else {
					_shakeMode = true;
				}
			}
		}
		
		private function setDelay(delay:int):void {
			_delay = delay;
		}
		
		private function getBlankLine():CHBox {
			var h:CHBox = new CHBox();
			h.buffer = (spaceSize)*_scale;
			return h
		}
		
		private function getBlankWord():CHBox {
			var h:CHBox = new CHBox();
			h.buffer = kerning*_scale;
			return h
		}
		
		private function addCharacter(char:String):void {
			char = char.toLowerCase();
			if (char == ' ') {
				var h:CHBox = getBlankWord();
				words.push(h);
				currentLine.addChild(currentWord);
			}else {
				var ndx:int = defaultOrder.indexOf(char);
				if (ndx == -1) {
					trace('ERROR: char not supported - ' + char.charCodeAt(0));
					return;
				}
				var c:Bitmap = new Bitmap(new BitmapData(monoSpace?defaultSize:defaultWidths[ndx], defaultSize,true,0));
				c.bitmapData.copyPixels(_font.bitmapData, new Rectangle(ndx * defaultSize, 0, monoSpace?defaultSize:defaultWidths[ndx], defaultSize), Defaults.pointZero);
				var holder:Sprite = new Sprite();
				holder.addChild(c);
				currentWord.addChild(holder);
				c.transform.colorTransform = _color ;
				c.width *= _scale;
				c.height *= _scale;
				chars.push(c);
				if (_sinMode)_sin.push(chars.length - 1);
				if (_shakeMode)_shake.push(chars.length - 1);
				if (currentLine.width > _width && currentLine.numChildren!=1) {
					newLine();
				}
			}
		}
		
		private function newLine():void {
			var w:CHBox
			if(currentWord.parent == currentLine)w = currentLine.removeChild(currentWord) as CHBox;
			var l:CHBox = getBlankLine();
			addChild(l);
			lines.push(l);
			if (w) {
				l.addChild(w);
				if (w.numChildren != 0) w.removeChildAt(0);
			}
			buffer = defaultLineBuffer;
		}
		
		private function get currentWord():CHBox {
			return(words[words.length - 1]);
		}
		private function get currentLine():CHBox {
			return(lines[lines.length - 1]);
		}
		
		//public override function get width():Number {return this.width;}		
		public override function set width(value:Number):void {
			_width = value;
			text = _text;
		}
		
		public function get defaultColor():uint {
			return _defaultColor;
		}
		
		public function set defaultColor(value:uint):void {
			_defaultColor = value;
			_color.color = value;
			text = text;
		}
		
		public function get font():Bitmap {return _font;}		
		public function set font(value:Bitmap):void {
			_font = value;
			text = text;
		}
		
		public function get centered():Boolean {
			return _centered;
		}
		
		public function set centered(value:Boolean):void {
			_centered = value;
			if (value) {
				alignment = CENTER;
			}
			update();
		}
		
		private function clearText():void {
			kill();
			chars = new Vector.<Bitmap>;
			words = new Vector.<CHBox>;
			lines = new Vector.<CHBox>;
			words.push(getBlankWord());
			lines.push(getBlankLine());
			addChild(lines[0]);
			lines[0].addChild(words[0]);			
			_sin = [];
			_shake = [];
			_sinMode = false;
			_scale = defaultScale;
			_color.color = defaultColor;
			buffer = defaultLineBuffer*_scale;
			Scheduler.invokeEvery(update);
		}
		
		public function cleanup(): void {
			kill();
		}
		
		private function kill():void {
			Utils.removeAllChildrenIn(this);
			chars = null;
			words = null;
			lines = null;
			Scheduler.cancel(drawText);
			Scheduler.cancel(update);
			Scheduler.cancel(setDelay);
		}
		
		
		
	}
	
}