/**
 * @author Egor Hmelyoff (egor@design.ru)
 * @copyright Art.Lebedev Studio (http://www.artlebedev.ru)
 */

jQuery.noConflict();

function randomNum(iMin, iMax){
	return Math.round(Math.random()*(iMax - iMin) + iMin);
}

function getAbsoluteCoords(oElement) {
	var oResult = { iTop : 0, iLeft : 0 };

	while(oElement){
		oResult.iTop += oElement.offsetTop;
		oResult.iLeft += oElement.offsetLeft;
		oElement = oElement.offsetParent;
	}
	
	return oResult;
}

var Snake={
	
	idMove: null,
	idEvt: null,
	paused: true,
	started: false,
	moveTime: 300,
	_hl: false,
	fill:	[
				[5,4,2,-1,3,2,4,5],
				[1,1,1,1,1,1,1,1],
			],
	
	points: new Array(),
	moved: new Array(),
	figures: new Array(),
	blockedAreas: new Array(),
	
	init: function(params){
		this.blockWidth=params.block.width;
		this.blockHeight=params.block.height;
		this._container=jQuery('#'+params.id);
		
		this.begin=params.begin;
		this.firstBlock=params.firstBlock;
		this._measurer=jQuery('#'+params.measurer);
		
		var _my = this;
		
		this._container.find('div').each(function(){
			switch(this.className){
				case 'snake':
					_my._snake = jQuery(this);
					break;
				case 'field':
					_my._field = jQuery(this);
					break;
				case 'start':
					_my._start = jQuery(this);
					break;
				case 'stop':
					_my._stop = jQuery(this);
					break;
				case 'intro':
					_my._intro = jQuery(this);
					break;
				case 'figures':
					_my._figures = jQuery(this);
					break;
			}
		})
		
		this._blocked=jQuery(".block");
		this.showText();

		this.initEvents();
		this.initFigures();
		this.measure();
		
		this.initTextLine();

		this.resetGame();
	},
	
	hide: function(){
		this._container.fadeOut("fast", function(){ jQuery(this).hide() });
		this.btnStart._in.fadeOut("fast", function(){ jQuery(this).hide() });
		this.btnStart._out.fadeOut("fast", function(){ jQuery(this).hide() });
		this.endText.fadeOut("fast", function(){ jQuery(this).hide() });
		this.endTextLine1.hide();
		this.endTextLine2.hide();
		this.pauseGame();
	},

	hideFast: function(){
		this._container.hide();
		this.btnStart._in.hide();
		this.btnStart._out.hide();
		this.endText.hide();
		this.endTextLine1.hideFast();
		this.endTextLine2.hideFast();
		this.pauseGame();
	},

	show: function(){
		this._container.show().fadeIn("fast");
		this.btnStart._in.show().fadeIn("fast");
		this.btnStart._out.show().fadeIn("fast");
		this.endText.show().fadeIn("fast");
		this.endTextLine1.show();
		this.endTextLine2.show();
		this.measure();
	},
	
	showText: function(){
		this.endText = jQuery("#EndText div");
		this.endText.show();
	},
	
	initTextLine: function(){

		this.endTextLine1 = new AdaptiveLine(function(){
			return { x: (Snake.endPoint.x-2)*Snake.blockWidth+5}
		}, function(){
			var _o = Snake.endText.find(".start");
			var _ofs = _o.offset();
			return { x: Snake.endPoint.x*Snake.blockWidth-10, y: _ofs.top+Math.round(_o.height()/2) }
		}, "#Lines");

		this.endTextLine2 = new AdaptiveLine(function(){
			var _o = Snake.endText.find(".end");
			return { x: _o.offset().left+10 }
		}, function(){
			var _o = Snake.endText.find(".end");
			var _ofs = _o.offset();
			return { x: $("#bodywidth").width(), y: _ofs.top+Math.round(_o.height()/2) }
			
		}, "#Lines");
	},
	
	initEvents: function(){
		
		jQuery(window).resize(function(){
			Snake.measure();
		})

		jQuery(document).keydown(function(evt){
			if(Snake.idEvt != evt.keyCode){
				Snake.idEvt = evt.keyCode;
				switch(evt.keyCode){
					case 37: // left
						Snake.moveLeft();
						break;
					case 38: // top
						Snake.moveTop();
						break;
					case 39: // right
						Snake.moveRight();
						break;
					case 40: // down
						Snake.moveDown();
						break;
					case 32: // space
						break;
				}
			}
		});

		jQuery(document).keyup(function(evt){
			Snake.idEvt = null;
		});


	},
	
	playControl: function(obj){
		var _o = jQuery(document.createElement("div"));
		_o.addClass("btn-start").appendTo(document.body).css({ left: (Snake.begin.left+2)*Snake.blockWidth, top: Snake.begin.top*Snake.blockHeight, width: obj.width(), height: obj.height() }).html("<img src='/i/d.gif' width='" + obj.width() + "' height='" + obj.height() + "' />");

		this.btnStart = { _in: jQuery(".btn-start"), _out: obj }
		
		this.btnStart._in.click(function(){
			if(!Snake.started){
				Snake.btnStart._out.addClass("pause").removeClass("start");
				Snake.startGame();
			} else {
				if(Snake.paused){
					Snake.btnStart._out.addClass("pause").removeClass("start");
					Snake.resumeGame();
				} else {
					Snake.btnStart._out.addClass("start").removeClass("pause");
					Snake.pauseGame();
				}
			}
		});
		
		this.btnStart._in.hover(function(){
			Snake.btnStart._out.addClass("over")
		}, function(){
			Snake.btnStart._out.removeClass("over")
			
		})
		
		this.btnStart._out.css({ left: (Snake.begin.left+2)*Snake.blockWidth, top: Snake.begin.top*Snake.blockHeight })
	},

	initFigures: function(){
		this._figures.find(".figure").each(function(){
			Snake.figures.push(new Figure(this));
		})
	},
	
	getNewFigure: function(){
		var f = new Array()
		for (var i=0; i < this.figures.length; i++) {
			if(this.figures[i].check())
				f.push(this.figures[i])
		};
		
		if(f.length != 0){
			var _f = f[randomNum(0, f.length-1)];
			_f.dec();
			return _f.obj.clone().appendTo(Snake._field);
		} else {
			return 0;
		}
	},
	
	measure: function(){
		this.setField(Math.max(jQuery(document.body).width(), this._measurer.width()), this._measurer.height());
		this._container.css({ height: Snake._measurer.height() })
	},
	
	setField: function(width, height){
		var _my = this;
		var width = Math.floor(width/this.blockWidth);
		var height = Math.floor(height/this.blockHeight-3);
		if(this.width != width){
			var width_old = this.width;
			this.width = width;
			this.recalculate(width-width_old);
		}
		
		if(this.height != height){
			this.height = height
		}
		
		this._field.css({ width: _my.width*_my.blockWidth, height: _my.height*_my.blockHeight});
	
		this.endPoint = { x: Snake.width-6, y: 5 }
		this.moveText();
		
		this.setBlockedArea();
	},
	
	moveText: function(){
		this.endText.css({ left: Snake.endPoint.x*Snake.blockWidth, top: Snake.endPoint.y*Snake.blockHeight })
	},
	
	setBlockedArea: function(){
		
		/* Set to null */
		if(jQuery("#Areas").length == 0){
			jQuery(document.body).append("<div id='Areas'></div>")
		} else {
			jQuery("#Areas").empty();
		}
		this.blockedAreas = new Array();
		

		this._blocked.each(function(){
			_j = jQuery(this);
			var _c = getAbsoluteCoords(this);
			var _lt = {
				l: Math.floor(_c.iLeft/Snake.blockWidth),
				t: Math.floor(_c.iTop/Snake.blockHeight)
			}
			var _wh = {
				w: Math.ceil((_c.iLeft+_j.width())/Snake.blockWidth)-_lt.l,
				h: Math.ceil((_c.iTop+_j.height())/Snake.blockWidth)-_lt.t
			}
			
			var d = document.createElement("div");
			d = jQuery(d);
			jQuery("#Areas").append(d);
			
			d.css({ left: _lt.l*Snake.blockWidth, top: _lt.t*Snake.blockHeight, width: _wh.w*Snake.blockWidth, height: _wh.h*Snake.blockHeight });
			
			Snake.blockedAreas.push({
				l: _lt.l,
				t: _lt.t,
				w: _wh.w,
				h: _wh.h,
				obj: d
			});
			
		})
	},
	
	/* Recalc some game params */
	recalculate: function(diff){
		if(diff){
			var _w = this.width - diff;
			var _i = null;
			for (var i=0; i < this.moved.length; i++) {
				if(!this.moved[i].free){
					if(this.moved[i].left == _w-1)
						_i = i;
				}
			};
			if(_i != null){
				if(this.moved[_i].getDirection() == 1){
					for (var i=_i; i < this.moved.length; i++) {
						if(!this.moved[i].free){
							if(diff < 0){
								this.moveBackward(this.moved[i], Math.abs(diff));
							} else {
								this.moveForward(this.moved[i], Math.abs(diff));
							}
						}
					};
				} else if (this.moved[_i].getDirection() == 3){
					for (var i=_i; i >= 0; i--) {
						if(!this.moved[i].free){
							if(diff < 0){
								this.moveForward(this.moved[i], Math.abs(diff));
							} else {
								this.moveBackward(this.moved[i], Math.abs(diff));
							}
						}
					}
				}
			}
		}
	},
	
	resetGame: function(){
		this.prepare();
	},
	
	startGame: function(){
//		this.prepare();
		this.started = true;
		this.paused = false;
		this._intro.fadeOut("normal");
	},
	
	pauseGame: function(){
		this.paused = true;
	},

	resumeGame: function(){
		this.paused = false;
	},
	
	prepare: function(){
		this.moved = new Array();
		
		this.moved.push(new Block(this._snake.clone().appendTo(Snake._field)));
		this.moved[0].setPosition(this.begin);
		this.moved[0].setDirection(1);
		this.moved[0].free = false;
		
		this.moved.push(new Block(this.getNewFigure()));
		this.moved[1].setPosition(this.firstBlock);
		
		this._start.css({ left: (Snake.begin.left+1)*Snake.blockWidth, top: (Snake.begin.top)*Snake.blockHeight })
		this._intro.css({ left: (Snake.firstBlock.left+1)*Snake.blockWidth, top: (Snake.firstBlock.top)*Snake.blockHeight })
		
		this.updateTimer();
	},
	
	/* Для запуска и пересчета скорости игры */
	updateTimer: function(){
		clearInterval(this.idMove);
		this.time = Math.round(this.moveTime-(this.moved.length*4));
		this.idMove=setInterval('Snake.move()', this.time);
	},
	
	move: function(){
		if(!this.paused && this.started){
			if(this.moveAvailable()){
				for (var i=0; i < this.moved.length; i++) {
					if(!this.moved[i].free){
						this.moveForward(this.moved[i], 1)
					} else {
						if(this.checkBelong(this.moved[i])){
							if(this.moved[i].parking){
								this.fillField(this.moved[i]);
							} else {
								this.attachBlock(this.moved[i]);
							}
						}
					}
				};
			} else {
				for (var i=0; i < this.moved.length; i++) {
					if(!this.moved[i].free){
						this.moveBackward(this.moved[i], 2);
					}
				}
				this.removeLast();
			}
			this.removePoints();
		}
	},
	
	moveBackward: function(block, i){
		block.moveOut();
		this.checkPointsBack(block);
		i--;
		if(i > 0){
			this.moveBackward(block, i)
		}
	},
	
	removeLast: function(){
		var last = null;
		for (var i=1; i < this.moved.length; i++) {
			if(!this.moved[i].free){
				last = i;
			}
		}
		if(this.moved[last]){
			for (var i=0; i < this.figures.length; i++) {
				if(this.figures[i].obj.attr("class") == this.moved[last].obj.attr("class")){
					this.figures[i].inc();
				}
			};
		
			this.moved[last].destroy();
			this.moved.splice(last, 1);
		}
		
		this.checkFree();
	},

	moveForward: function(block, i){
		this.checkPoints(block, false);
		block.move();
		i--;
		if(i > 0){
			this.moveForward(block, i)
		}
	},
	
	moveAvailable: function(){
		var dir = this.checkPoints(this.moved[0], true);
		var n = this.moved[0].pseudoMove(dir);
		return this.checkAvail(n, true, this.moved[0]);
	},
	
	checkAvail: function(n, highlight, cur){
		var avail = true;
		for (var i=1; i < this.moved.length; i++) {
			if(!this.moved[i].free){
				if(this.moved[i].left == n.left && this.moved[i].top == n.top){
					avail = false;
					this.showStop(cur);
				}
			}
		}

		for (var j=0; j < this.blockedAreas.length; j++) {
			if(n.left >= this.blockedAreas[j].l && n.top >= this.blockedAreas[j].t && n.left < this.blockedAreas[j].l+this.blockedAreas[j].w && n.top < this.blockedAreas[j].t+this.blockedAreas[j].h){
				avail = false;
				if(highlight){
					this.highlight(this.blockedAreas[j].obj);
					this.showStop(cur);
				}
			}
		};
		
		return avail;
	},

	showStop: function(point){
		this._stop.stopAll().css({ opacity: 1, left: point.left*Snake.blockWidth, top: point.top*Snake.blockHeight }).animate({ opacity: 0 }, 1000);
	},
	
	highlight: function(obj, point){
		if(!this._hl){
			this._hl = true;
			obj.css({ opacity: 0, backgroundColor: '#999999' }).animate({ opacity: 0.2 }, 100).animate({ opacity: 0 }, 100, function(){
				Snake._hl = false;
			})
		}
	},

	attachBlock: function(block){
		var last = this.getLastMoved();
		block.setDirection(last.getDirection());
		block.setPosition(last);
		block.moveOut();
		block.setMoved();
		
		this.checkFree();
		
		this.updateTimer();
	},
	
	checkFree: function(){
		var newBlock = true;
		var blocks = 0
		for (var i=0; i < this.moved.length; i++) {
			if(this.moved[i].free){
				newBlock = false;
			} else {
				blocks++;
			}
		}
		
		if(newBlock){
			var _n = this.addBlock();
			if(_n == false){
				this.endGame();
			}
		} else {
			this.removeParking();
		}
	},
	
	endGame: function(){
		this.addParking();
/*		this.pauseGame();
		this.fillField();*/
	},

	addParking: function(){
		_n = {
			left: Snake.endPoint.x-3,
			top: Snake.endPoint.y
		}
		if(this.checkAvail(_n, false)){

			this.moved.push(new Block(this._container.find('.parking').clone().appendTo(Snake._field)));
			this.moved[this.moved.length-1].parking = true;
			this.moved[this.moved.length-1].direction = true;
			this.moved[this.moved.length-1].setPosition({
				left: _n.left,
				top: _n.top
			});
		} else {
			setTimeout(function(){ Snake.addParking() }, 200);
		}
	},
	
	removeParking: function(){
		for (var i=0; i < this.moved.length; i++) {
			if(this.moved[i].parking){
				this.moved[i].destroy();
				this.moved.splice(i, 1);
				this.checkFree();
				break;
			}
		};
	},
	
	fillField: function(parking){
		this.pauseGame();
		for (var i=0; i < this.moved.length; i++) {
			this.moved[i].clear();
		};
		this.moved[0].setPosition(parking);
		this.moved[0].setDirection(parking.direction);
		this.moved[0].obj.animate({ left: $(document.body).width()+20 }, 1500, function(){
			jQuery(this).hide();
		})
		parking.obj.fadeOut("fast");
		this.fillFigure();
	},
	
	fillFigure: function(){
		for (var i=0; i < this.fill[0].length; i++) {
			if(this.fill[0][i] != -1){
				var f = this.getMoveFigure(this.fill[0][i]);
				f.setDirection(0);
				f.obj.animate({ left: (Snake.endPoint.x-10+i)*Snake.blockWidth, top: Snake.blockHeight*(Snake.endPoint.y+1) }, 500)
			} else {
				this._container.find(".player").hide().css({ left: (Snake.endPoint.x-10+i)*Snake.blockWidth, top: Snake.blockHeight*(Snake.endPoint.y+1) });
				setTimeout(function(){
					Snake._container.find(".player").show().fadeIn("normal");
					 jQuery("#EndText").css({ zIndex: 50 });
				}, 1200)
			}
		};
		for (var i=0; i < this.fill[1].length; i++) {
			var f = this.getMoveFigure(this.fill[1][i]);
			f.setDirection(0);
			f.obj.animate({ left: (Snake.endPoint.x-10+i)*Snake.blockWidth, top: Snake.blockHeight*(Snake.endPoint.y) }, 500)
		};
	},
	
	getMoveFigure: function(t){
		for (var i=0; i < this.moved.length; i++) {
			if(this.moved[i].obj.is(".figure")){
				var _p = this.moved[i].obj.attr("class")
				var _type = _p.substr(_p.indexOf('p_')+2, 1);
				if(_type == t){
					var _m = this.moved[i] 
					this.moved.splice(i, 1);
					return _m;
				}
			}
		};
	},
	
	addBlock: function(){
		var _n = {
			left: randomNum(0, Snake.width-1),
			top: randomNum(0, Snake.height-1)
		}
		if(this.checkAvail(_n, false)){
			
			var _f = this.getNewFigure();
			
			if(_f == 0){
				return false
			} else {
				this.moved.push(new Block(_f));
				this.moved[this.moved.length-1].setPosition({
					left: _n.left,
					top: _n.top
				});
				return true;
			}
		} else {
			return this.addBlock()
		}
	},
	
	getLastMoved: function(){
		var m = new Array();
		for (var i=0; i < this.moved.length; i++) {
			if(!this.moved[i].free){
				m.push(this.moved[i]);
			}
		};
		return m[m.length-1]
	},
	
	moveTop: function(){
		var d = this.moved[0].getDirection();
		if(this.checkDirection(d, 0)){
			this.points.push({ left: Snake.moved[0].left, top: Snake.moved[0].top, direction: 0, old: Snake.moved[0].getDirection() })
		}
	},
	
	moveRight: function(){
		var d = this.moved[0].getDirection();
		if(this.checkDirection(d, 1)){
			this.points.push({ left: Snake.moved[0].left, top: Snake.moved[0].top, direction: 1, old: Snake.moved[0].getDirection() })
		}
	},

	moveDown: function(){
		var d = this.moved[0].getDirection();
		if(this.checkDirection(d, 2)){
			this.points.push({ left: Snake.moved[0].left, top: Snake.moved[0].top, direction: 2, old: Snake.moved[0].getDirection() })
		}
	},

	moveLeft: function(){
		var d = this.moved[0].getDirection();
		if(this.checkDirection(d, 3)){
			this.points.push({ left: Snake.moved[0].left, top: Snake.moved[0].top, direction: 3, old: Snake.moved[0].getDirection() })
		}
	},

	checkDirection: function(d, cur){
		var k = d;
		var _d = [(++d > 3) ? 0 : d, (--k < 0) ? 3 : k];
		if(_d[0] == cur || _d[1] == cur)
			return true
		else
			return false
	},
	
	checkBelong: function(block){
		if(block.left == this.moved[0].left && block.top == this.moved[0].top)
			return true
		else
			return false
	},
	
	checkPoints: function(block, b){
		for (var i=0; i < this.points.length; i++) {
			if(this.points[i].left == block.left && this.points[i].top == block.top)
				if(!b)
					block.setDirection(this.points[i].direction)
				else
					return this.points[i].direction
		};
	},

	checkPointsBack: function(block){
		for (var i=0; i < this.points.length; i++) {
			if(this.points[i].left == block.left && this.points[i].top == block.top)
				block.setDirection(this.points[i].old)
		};
	},
	
	removePoints: function(){
		var _d = new Array();
		for (var i=0; i < this.points.length; i++) {
			var _delete = true;
			for (var j=0; j < this.moved.length; j++) {
				if(this.moved[j].left == this.points[i].left && this.moved[j].top == this.points[i].top)
					_delete = false;
			};
			if(_delete)
				this.points.splice(i, 1);
		};
	}
	
}


function Figure(obj){
	this.obj = jQuery(obj);
	this.init();
}

Figure.prototype = {
	init: function(){
		
		this.use = 0;
		
		this.black = false;
		if(this.obj.is('.black'))
			this.black = true;
		
		var _c = this.obj.attr("class");
		var _c = _c.split(' ');
		for (var i=0; i < _c.length; i++) {
			if(_c[i].indexOf('c_') != -1){
				this.count = _c[i].substr(2);
			}
			if(_c[i].indexOf('p_') != -1){
				this.iType = _c[i].substr(2);
			}
		};
	},
	
	check: function(){
		if(this.use != this.count && this.use < this.count)
			return true
		else
			return false
	},
	
	dec: function(){
		this.use++;
	},
	
	inc: function(){
		this.use--;
	}
}