package  
{
	import display.MinedDisplay;
	import display.Preloader;
	import entities.Character;
	import entities.Testificate;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	import flash.ui.Keyboard;
	import geom.Polygon2D;
	import geom.Utils;
	import light.LightEngine;
	import map.Generator;
	import map.Map;
	import map.Renderer;
	import starling.display.Image;
	import starling.display.Shape;
	import starling.display.Sprite;
	import starling.events.EnterFrameEvent;
	import starling.events.Event;
	import starling.events.KeyboardEvent;
	import starling.events.Touch;
	import starling.events.TouchEvent;
	import starling.events.TouchPhase;
	import tiles.TileNames;
	
	/**
	 * ...
	 * @author RedMaster
	 */
	public class Root extends Sprite 
	{
		public function Root() 
		{
			super();
			C.starling.addEventListener(Events.RESOURCES_LOADED, init);
		}
		
		private var _renderer:Renderer;
		private var _char:Character;
		private var _engine:LightEngine;
		private var _generator:Generator = new Generator();
		private var _shadows:Shape = new Shape();
		private var _shadowOverlay:Image;
		private var _charImg:Image;
		private var _selectionImg:Image;
		private var _mined:MinedDisplay;
		
		private var _cursor:Point = new Point();
		private var _cursorBlock:Point = new Point();
		
		private var _pressed:Boolean = false;
		private var u:Boolean = false;
		private var d:Boolean = false;
		private var l:Boolean = false;
		private var r:Boolean = false;
		
		private var _testificate:Testificate;
		private var _tImage:Image;
		
		private var rect:Rectangle = new Rectangle();
		private var _map:Map;
		private var _pol:Polygon2D = new Polygon2D();
		private var _b:uint = 0;
		private var _l:uint = 0;
		private var _p:Point = new Point();
		
		private function init(e:Event):void
		{
			Log.log(this, "Starting root init");
			
			_charImg = new Image(C.assets.getTexture("debug"));
			_charImg.width = _charImg.height = 20;
			
			_selectionImg = new Image(C.assets.getTexture("selector"));
			_selectionImg.width = 32;
			_selectionImg.height = 32;
			
			_engine = new LightEngine(_shadows, new Point(500, 310.5), 100, 800, 0x000000);
			C.lightEngine = _engine;
			
			var sx:uint = 512;
			var sy:uint = 512;
			
			_generator.generate(Math.random() * int.MAX_VALUE, sx, sy);
			_generator.map.recalculateGlobalLight();
			_generator.map.scaleX = _generator.map.scaleY = 32;
			
			_map = _generator.map;
			
			_renderer = new Renderer(C.assets.getTextureAtlas("tiles"), new Point(32, 32), _generator.map);
			addChild(_renderer);
			
			_charImg.x = 500 - 10;
			_charImg.y = 625 / 2 - 10;
			addChild(_charImg);
			
			_char = new Character(_generator.map.spawn.x, _generator.map.spawn.y, _generator.map);
			
			addChild(_shadows);
			
			_shadowOverlay = new Image(C.assets.getTexture("shadow_overlay"));
			addChild(_shadowOverlay);
			
			addChild(_selectionImg);
			
			_mined = new MinedDisplay();
			_mined.total = _map.goldCount;
			addChild(_mined);
			
			addChild(C.debugShape);
			
			addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown);
			addEventListener(KeyboardEvent.KEY_UP, onKeyUp);
			addEventListener(EnterFrameEvent.ENTER_FRAME, onEnterFrame);
			addEventListener(TouchEvent.TOUCH, onTouch);
		}
		private function onKeyDown(e:KeyboardEvent):void
		{
			switch(e.keyCode)
			{
				case Keyboard.W:
					u = true;
					break;
				case Keyboard.A:
					l = true;
					break;
				case Keyboard.S:
					d = true;
					break;
				case Keyboard.D:
					r = true;
					break;
			}
		}
		private function onKeyUp(e:KeyboardEvent):void
		{
			switch(e.keyCode)
			{
				case Keyboard.W:
					u = false;
					break;
				case Keyboard.A:
					l = false;
					break;
				case Keyboard.S:
					d = false;
					break;
				case Keyboard.D:
					r = false;
					break;
			}
		}
		
		private function rebuildGeometry():void //WARNING: Индусский код! Трудно понять, как он работает!
		{
			_engine.clearPolygons();
			rect = _renderer.viewportRectangle;
			for (var i:uint = 0; i < rect.width; i++)
			{
				for (var j:uint = 0; j < rect.height; j++)
				{
					_b = _map.getBlock(rect.x + i, rect.y + j);
					if (!TileNames.isHard(_b)) continue;
					if (_b == TileNames.getId("bounds")) continue;
					_l = _map.getLight(rect.x + i, rect.y + j);
					if (_l == Map.NULL) continue;
					_p.x = _renderer.x + i * 32;
					_p.y = _renderer.y + j * 32;
					
					//_pol.clearPoints();
					
					if (_map.getLight(rect.x + i, rect.y + j - 1) == 0)
					{
						_pol.clearPoints();
						_pol.addPoint(new Point(_p.x, _p.y));
						_pol.addPoint(new Point(_p.x + 32, _p.y));
						_engine.addPolygon(_pol.clone());
					}
					if (_map.getLight(rect.x + i, rect.y + j + 1) == 0)
					{
						_pol.clearPoints();
						_pol.addPoint(new Point(_p.x + 32, _p.y + 32));
						_pol.addPoint(new Point(_p.x, _p.y + 32));
						_engine.addPolygon(_pol.clone());
					}
					if (_map.getLight(rect.x + i - 1, rect.y + j) == 0)
					{
						_pol.clearPoints();
						_pol.addPoint(new Point(_p.x, _p.y + 32));
						_pol.addPoint(new Point(_p.x, _p.y));
						_engine.addPolygon(_pol.clone());
					}
					if (_map.getLight(rect.x + i + 1, rect.y + j) == 0)
					{
						_pol.clearPoints();
						_pol.addPoint(new Point(_p.x + 32, _p.y));
						_pol.addPoint(new Point(_p.x + 32, _p.y + 32));
						_engine.addPolygon(_pol.clone());
					}
				}
			}
		}
		
		private function updateBlockCursor():void
		{
			_cursorBlock = getBlockPosUnderPoint(_cursor);
			_selectionImg.x = _renderer.x + _cursorBlock.x * 32;
			_selectionImg.y = _renderer.y + _cursorBlock.y * 32;
			if (Utils.distance(new Point(500, 312.5), _cursor) > 100)
				_selectionImg.alpha = 0.3;
			else
				_selectionImg.alpha = 1;
		}
		
		private function onTouch(event:TouchEvent):void
		{
			var t:Touch = event.getTouch(this, null);
			if (t) _cursor = t.getLocation(this);
			t = event.getTouch(this, TouchPhase.BEGAN);
			if (t) _pressed = true;
			t = event.getTouch(this, TouchPhase.ENDED);
			if (t) _pressed = false;
		}
		
		private function getBlockPosUnderPoint(position:Point):Point
		{
			var p:Point = position.clone();
			p.x = Math.floor((position.x - _renderer.x) / 32);
			p.y = Math.floor((position.y - _renderer.y) / 32);
			return p;
		}
		
		private function updateBlockDamage():void
		{
			if (!_pressed) return;
			if (_selectionImg.alpha < 1) return;
			updateBlockCursor();
			var p:Point = _renderer.getGlobalBlockPos(_cursorBlock);
			if (TileNames.getName(_generator.map.damageBlock(p.x, p.y, 1)) == "gold")
				_mined.increase();
		}
		
		private function onEnterFrame(e:EnterFrameEvent):void
		{
			C.debug.clear();
			if (u) _char.walk(Character.UP);
			if (d) _char.walk(Character.DOWN);
			if (l) _char.walk(Character.LEFT);
			if (r) _char.walk(Character.RIGHT);
			_char.update();
			_renderer.setPosition(_char.x - 490, _char.y - 302.5);
			_renderer.update();
			_shadows.graphics.clear();
			rebuildGeometry();
			_engine.update();
			updateBlockCursor();
			updateBlockDamage();
			_testificate.update();
			_tImage.x = (_testificate.x - _renderer.position.x);
			_tImage.y = (_testificate.y - _renderer.position.y);
		}
	}
}