/**
 * MAZE
 */
var MAZE = function(cols, rows){
	this.cfg = {
		width: 10,
		height: 10,
		wMargin: 5,
		hMargin: 5,
		maxLoop: 5000,
		cols: 10,
		rows: 10
	};
	this.cluster = {};
	this.build(cols, rows);
};

MAZE.prototype.build = function(cols, rows){
	var _arr = [];
	var _col = [];
	var _row = [];
	var _num = 0;
	this.cfg.cols = cols;
	this.cfg.rows = rows;
	for(var i=0;i<rows;i++){
		_arr[i] = [];
		for(var j=0;j<cols;j++){
			_arr[i][j] = _num++;
		}
	}
	for(var i=0;i<rows;i++){
		_col[i] = [];
		for(var j=0;j<=cols;j++){
			_col[i][j] = (j==0 || j==cols) ? 3 : 1 ;
		}
	}
	for(var i=0;i<=rows;i++){
		_row[i] = [];
		for(var j=0;j<cols;j++){
			_row[i][j] = (i==0 || i==rows) ? 3 : 1 ;
		}
	}
	this.cluster =  {
		el: _arr,
		col: _col,
		row: _row
	};
	this._breakWark();
};

MAZE.prototype._fillNumber = function(tg, num){
	var c = this.cluster.el;
	for (var i = 0, max = c.length; i < max; i++) {
		for (var j = 0, max2 = c[i].length; j < max2; j++) {
			if(c[i][j] == tg){
				c[i][j] = num;
			}
		}
	}
};
MAZE.prototype._isAllFill = function(){
	var check = null;
	var c = this.cluster.el;
	for (var i = 0, max = c.length; i < max; i++) {
		for (var j = 0, max2 = c[i].length; j < max2; j++) {
			if(check == null){
				check = c[i][j];
			}else if(check != c[i][j]){
				return false;
			}
		}
	}
	return true;
};
MAZE.prototype._borderBreak = function(){
	var c = this.cluster;
	var cfg = this.cfg;
	var type = (Math.round(Math.random()) == 0) ? 'col' : 'row' ;
	switch(type){
		case 'row':
			var colNum = Math.floor(Math.random()*cfg.cols);
			var rowNum = Math.floor(Math.random()*cfg.rows);
			if(rowNum <= 0) rowNum = 1;
			if(c[type][rowNum][colNum] == 1){
				var num1 = c.el[rowNum-1][colNum];
				var num2 = c.el[rowNum][colNum];
				if(num1 == num2){
					c[type][rowNum][colNum] = 2;
				}else{
					
					this._fillNumber(Math.max(num1, num2), Math.min(num1, num2));
					c[type][rowNum][colNum] = 0;
				}
			}
			break;
		case 'col':
			var colNum = Math.floor(Math.random()*cfg.cols);
			var rowNum = Math.floor(Math.random()*cfg.rows);
			if(colNum <= 0) colNum = 1;
			if(c[type][rowNum][colNum] == 1){
				var num1 = c.el[rowNum][colNum-1];
				var num2 = c.el[rowNum][colNum];
				if(num1 == num2){
					c[type][rowNum][colNum] = 2;
				}else{
					
					this._fillNumber(Math.max(num1, num2), Math.min(num1, num2));
					c[type][rowNum][colNum] = 0;
				}
			}
			break;
		default:
			break;
	}
};
MAZE.prototype._breakWark = function(){
	var i = 1;
	while(!this._isAllFill() && (i%this.cfg.maxLoop != 0 || window.confirm('処理を継続しますか ?'))){
		this._borderBreak();
		i++;
	}
};
MAZE.prototype.drow = function(id){
	var cfg = this.cfg;
	var w = cfg.width;
	var h = cfg.height;
	var wm = cfg.wMargin;
	var hm = cfg.wMargin;
	var cols = cfg.cols;
	var rows = cfg.rows;
	var tg = (typeof(id)=='string') ? $('#'+id) : id ;
	var col = this.cluster.col;
	var row = this.cluster.row;
	
	tg.css('width', (w * cols + wm * 2) + "px");
	tg.css('height', (h * rows + hm * 2) + "px");
	
	col[0][0] = 0;
	col[rows-1][cols] = 0;
	
	for (var i = 0, max = col.length; i < max; i++) {
		for (var j = 0, max2 = col[i].length; j < max2; j++) {
			if(col[i][j] > 0){
				tg.drawLine(j*w+wm, i*h+hm, j*w+wm, i*h+h+hm);
			}
		}
	}
	
	for (var i = 0, max = row.length; i < max; i++) {
		for (var j = 0, max2 = row[i].length; j < max2; j++) {
			if(row[i][j] > 0){
				tg.drawLine(j*w+wm, i*h+hm, j*w+w+wm, i*h+hm);
			}
		}
	}
	
	col[0][0] = 3;
	col[rows-1][cols] = 3;
};
MAZE.prototype.setWidth = function(_num){
	this.cfg.width = _num;
};
MAZE.prototype.setHeight = function(_num){
	this.cfg.height = _num;
};
MAZE.prototype.setMarginWidth = function(_num){
	this.cfg.wMargin = _num;
};
MAZE.prototype.setMarginHeight = function(_num){
	this.cfg.hMargin = _num;
};

MAZE.prototype.getWidth = function(){
	return this.cfg.width;
};
MAZE.prototype.getHeight = function(){
	return this.cfg.height;
};
MAZE.prototype.getMarginWidth = function(){
	return this.cfg.wMargin;
};
MAZE.prototype.getMarginHeight = function(){
	return this.cfg.hMargin;
};
MAZE.prototype.getCols = function(){
	return this.cfg.cols;
};
MAZE.prototype.getRows = function(){
	return this.cfg.rows;
};

MAZE.prototype.isTopWall = function(_x, _y){
	var row = this.cluster.row;
	if(row[_y][_x] > 0){
		return true;
	}
	return false;
};
MAZE.prototype.isRightWall = function(_x, _y){
	var col = this.cluster.col;
	if(col[_y][_x+1] > 0){
		return true;
	}
	return false;
};
MAZE.prototype.isBottomWall = function(_x, _y){
	var row = this.cluster.row;
	if(row[_y+1][_x] > 0){
		return true;
	}
	return false;
};
MAZE.prototype.isLeftWall = function(_x, _y){
	var col = this.cluster.col;
	if(col[_y][_x] > 0){
		return true;
	}
	return false;
};


/**
 * MAZE_BOT
 */
var MAZE_BOT = function(maze){
	this._maze = maze;
	this._map = null;
	this._pos = {x:0, y:0};
	this._defpos = {x:0, y:0};
	this._isStart = false;
	this._name = 'MAZE_BOT_' + (new Date()).getTime();
	this._view = null;
	this.duration = 10;
	this.createMap();
};

MAZE_BOT.prototype.createMap = function(){
	var _arr = [];
	var point;
	var tgX = this._maze.getRows()-1;
	var tgY = this._maze.getCols()-1;
	var col = this._maze.getCols();
	var row = this._maze.getRows();
	for (var i = 0; i < row; i++) {
		_arr[i] = [];
		for (var j = 0; j < col; j++) {
			point = Math.abs((tgX + tgY) - (i + j));
			_arr[i][j] = point;
		}
	}
	this._map = _arr;
};

MAZE_BOT.prototype.createView = function(id){
	if(this._view) return;
	this._view = $(document.createElement('div'));
	this._view.width(this._maze.getWidth());
	this._view.height(this._maze.getHeight());
	this._view.css('position', 'absolute');
	this._view.css('background-color', '#FF0000');
	var _parent = (typeof(id) == 'string') ? $('#'+id) : $(id) ;
	_parent.append(this._view);
};

MAZE_BOT.prototype.setPos = function(x, y){
	var m = this._maze;
	this._defpos.x = this._pos.x = x;
	this._defpos.y = this._pos.y = y;
	var x = m.getWidth() * x + m.getMarginWidth();
	var y = m.getHeight() * y + m.getMarginHeight();
	this._view.css('top', y + 'px');
	this._view.css('left', x + 'px');
};
MAZE_BOT.prototype.moveTo = function(x, y){
	var m = this._maze;
	var x = m.getWidth() * x + m.getMarginWidth();
	var y = m.getHeight() * y + m.getMarginHeight();
	this._view.animate({
		top: y + 'px',
		left: x + 'px'
	},
	{
		duration: this.duration,
		complete: (function(o){
			var obj = o;
			return function(){
				obj.cycle();
			};
		})(this)
	});
};
MAZE_BOT.prototype.reNumberMap = function(){
	var x = this._pos.x;
	var y = this._pos.y;
	var maze = this._maze;
	var map = this._map;
	var max = maze.getCols() * maze.getRows();
	
	if(map[y][x] == 0) return false;
	
	var pointSum = 0;
	var spaceCount = 0;
	if(!(maze.isTopWall(x, y) || map[y-1][x] >= max)){
		pointSum += map[y-1][x];
		spaceCount++;
	}
	if(!(maze.isRightWall(x, y) || map[y][x+1] >= max)){
		pointSum += map[y][x+1];
		spaceCount++;
	}
	if(!(maze.isBottomWall(x, y) || map[y+1][x] >= max)){
		pointSum += map[y+1][x];
		spaceCount++;
	}
	if(!(maze.isLeftWall(x, y) || map[y][x-1] >= max)){
		pointSum += map[y][x-1];
		spaceCount++;
	}
	
	if(spaceCount > 1){
		map[y][x] = Math.min(
			Math.floor(pointSum / spaceCount) + 1,
			max
		);
	}else{
		map[y][x] = max;
	}
	
	return true;
};
MAZE_BOT.prototype.nextPos = function(){
	var x = this._pos.x;
	var y = this._pos.y;
	var maze = this._maze;
	var map = this._map;
	var max = maze.getCols() * maze.getRows();
	var min = maze.getCols() * maze.getRows();
	var obj = {x:x, y:y};
	
	if(!maze.isTopWall(x, y) && map[y-1][x] < max){
		if(map[y-1][x] < min){
			min = map[y-1][x];
			obj = {x:x, y:y-1};
		}
	}
	if(!maze.isRightWall(x, y) && map[y][x+1] < max){
		if(map[y][x+1] < min){
			min = map[y][x+1];
			obj = {x:x+1, y:y};
		}
	}
	if(!maze.isBottomWall(x, y) && map[y+1][x] < max){
		if(map[y+1][x] < min){
			min = map[y+1][x];
			obj = {x:x, y:y+1};
		}
	}
	if(!maze.isLeftWall(x, y) && map[y][x-1] < max){
		if(map[y][x-1] < min){
			min = map[y][x-1];
			obj = {x:x-1, y:y};
		}
	}
	this._pos = obj;
};

MAZE_BOT.prototype.cycle = function(){
	if(this._isStart && this.reNumberMap()){
		this.nextPos();
		this.moveTo(this._pos.x, this._pos.y);
	}else if(this._isStart){
		this.kill();
	}
};

MAZE_BOT.prototype.start = function(){
	this._isStart = true;
	this.createMap();
	this.setPos(this._defpos.x, this._defpos.y);
	this.cycle();
};
MAZE_BOT.prototype.stop = function(){
	this._isStart = false;
};
MAZE_BOT.prototype.kill = function(){
	this.stop();
	this._view.animate({
		opacity: '0'
	}, 500);
};
MAZE_BOT.prototype.restart = function(){
	this.stop();
	this.start();
};
MAZE_BOT.prototype.isStart = function(){
	return this._isStart;
};
MAZE_BOT.prototype.name = function(){
	return this._name;
};


/**
 * Custom
 */
var mazeObj = null;
var mazeBots = [];
var isCtrl = false;
function createMaze(){
	if (isCtrl) {
		var w = $('#mazeWidth').val();
		var h = $('#mazeHeight').val();
		for (var i in mazeBots) {
			mazeBots[i].kill();
		}
		mazeObj = new MAZE(w, h);
		$('#myCanvas').empty();
		mazeObj.drow('myCanvas');
	}
};
function createBot(){
	if (isCtrl) {
		var s = $('#botSpeed').val();
		var mb = new MAZE_BOT(mazeObj);
		mb.createView('myCanvas');
		mb.setPos(0, 0);
		mb.duration = Number(s);
		mb.start();
		mazeBots.push(mb);
	}
};
$(function(){
	isCtrl = true;
	createMaze();
});




