package com.techlabs.puzzle {

	import away3d.containers.ObjectContainer3D;
	
	import com.techlabs.puzzle.events.PuzzleEvent;
	
	import flash.display.Bitmap;

	/**
	 * ...
	 * @author Timo Virtanen
	 */
	public class PuzzleBoard extends ObjectContainer3D {
		private var _boardWidth:int;
		private var _boardHeight:int;

		private var _pieceWidth:Number;
		private var _pieceHeight:Number;

		private var _padding:int;
		private var _moving:Boolean;

		private var _pieces:Array = new Array();

		public function PuzzleBoard() {
			_boardWidth = SlidingPuzzle.size + SlidingPuzzle.padding * SlidingPuzzle.subdivisions;
			_boardHeight = SlidingPuzzle.size + SlidingPuzzle.padding * SlidingPuzzle.subdivisions;

			_pieceWidth = SlidingPuzzle.size / SlidingPuzzle.subdivisions;
			_pieceHeight = SlidingPuzzle.size / SlidingPuzzle.subdivisions;

			_padding = SlidingPuzzle.padding;
		}

		public function createPuzzle(images:Array):void {
			clearBoard();

			var pieceCount:int = 0;
			var lastPiece:int = SlidingPuzzle.subdivisions * SlidingPuzzle.subdivisions;

			for(var yp:int = 0; yp < SlidingPuzzle.subdivisions; yp++) {
				for(var xp:int = 0; xp < SlidingPuzzle.subdivisions; xp++) {
					if (++pieceCount == lastPiece)
						break;
					var image:Bitmap = images[yp][xp];
					var piece:PuzzlePiece = new PuzzlePiece(image, {width:_pieceWidth, height:_pieceHeight, segmentsH:3, segmentsW:3});
					piece.addEventListener(PuzzleEvent.CLICK, clickHandler);

					piece.addEventListener(PuzzleEvent.MOVE, moveHandler);
					piece.addEventListener(PuzzleEvent.READY, moveHandler);

					piece.x = xp * _pieceWidth + xp * _padding;
					piece.z = -(yp * _pieceHeight + yp * _padding);

					addChild(piece);
					_pieces.push(piece);
				}
			}
			centerBoard();
		}

		public function shuffle():void {
			var p:PuzzlePiece;
			var direction:int;
			for(var i:int = 0; i < 200; i++) {
				do {
					p = _pieces[int(Math.random() * _pieces.length - 1)];
					direction = checkNeighbours(p);
				} while(direction == -1);
				p.move(direction, false);
			}
		}

		private function clickHandler(e:PuzzleEvent):void {
			if (_moving)
				return ;
			var direction:int = checkNeighbours(e.piece);
			if (direction > 0) {
				e.piece.move(direction);
			}
		}

		private function moveHandler(e:PuzzleEvent):void {
			if (e.type == PuzzleEvent.MOVE)
				_moving = true;
			else if (e.type == PuzzleEvent.READY)
				_moving = false;
		}

		private function checkNeighbours(piece:PuzzlePiece):int {
			var empty:Boolean;

			// LEFT
			if (piece.x > 0) {
				empty = isEmptySpace(piece.x - _pieceWidth - _padding, piece.z);
				if (empty)
					return PuzzlePiece.LEFT;
			}

			// RIGHT
			if (piece.x < _boardWidth - _pieceWidth - _padding) {
				empty = isEmptySpace(piece.x + _pieceWidth + _padding, piece.z);
				if (empty)
					return PuzzlePiece.RIGHT;
			}

			// DOWN
			if (piece.z < 0) {
				empty = isEmptySpace(piece.x, piece.z + _pieceHeight + _padding);
				if (empty)
					return PuzzlePiece.UP;
			}

			// UP
			if (piece.z > -_boardHeight + _pieceHeight + _padding) {
				empty = isEmptySpace(piece.x, piece.z - _pieceHeight - _padding);
				if (empty)
					return PuzzlePiece.DOWN;
			}
			
			return -1;
		}

		private function isEmptySpace(xp:int, zp:int):Boolean {
			for each(var p:PuzzlePiece in _pieces) {
				if (p.x == xp) {
					if (p.z == zp) {
						return false;
					}
				}
			}
			return true;
		}

		private function clearBoard():void {
			for each(var p:PuzzlePiece in _pieces) {
				p.removeEventListener(PuzzleEvent.CLICK, clickHandler);
				p.removeEventListener(PuzzleEvent.MOVE, moveHandler);
				p.removeEventListener(PuzzleEvent.READY, moveHandler)
				removeChild(p);
			}
			_pieces = new Array();
		}

		private function centerBoard():void {
			x = -(_boardWidth * .5 - _pieceWidth * .5);
			z = _boardHeight * .5 - _pieceHeight * .5;
		}

	}

}
