var Puzzle = Class.create();
var n = 4;

var myListener = new Object();
myListener.onInit = function()
{
    this.position = 0;
}
myListener.onUpdate = function() {}

Puzzle.prototype = {
	initialize: function( id ) {
		this.id = id;
		this.opt = Object.extend({
			showOn: null
		},arguments[1] || { });			
		this.tiles = new Array();
		this.elm = new Element( "div", {
			id: "puzzle"
		});
		this.loadMp3Player();
		this.createRetryButton();
		if ( this.opt.showOn!=null ) {
			$(this.opt.showOn).appendChild( this.elm );
		} else {
			document.body.appendChild( this.elm );
		}		
		this.createNew();
	},
	
	loadMp3Player: function() {
		if ( !$('mp3player') && navigator.mimeTypes && navigator.mimeTypes["application/x-shockwave-flash"] ) {
			var div = new Element("div");
			div.innerHTML = '<object class="playerpreview" id="mp3player" type="application/x-shockwave-flash" data="/player_mp3_js.swf" width="1" height="1">'+
		        '<param name="movie" value="player_mp3_js.swf" />'+
		        '<param name="AllowScriptAccess" value="always" />'+
				'<param name="FlashVars" value="listener=myListener&amp;interval=500" />'+              
				'</object>';
			document.body.appendChild(div);
		}
	},
	
	createRetryButton: function() {
		var elm = Builder.node( "div", { id: "nochmal" },
			[
				Builder.node( "div",
					{
						id: "nochmal_button"
					})
			]
		);
		
		if ( this.opt.showOn!=null ) {
			$(this.opt.showOn).appendChild( elm );
		} else {
			document.body.appendChild( elm );
		}		
		var button = elm.firstDescendant();
		Event.observe( button, "click", function() {
			new Effect.Move( elm, { x: 294, y: 0, mode: "relative" } );
			this.createNew();
		}.bind(this));
	},
	
	createNew: function() {
		this.elm.innerHTML = "";
		this.tiles = new Array();
		var field = this.getScrambled();
		for ( var y=1; y<=n; y++ ) {
			for ( var x=1; x<=n; x++ ) {
				var tx = ((field[y-1][x-1]-1) % n) + 1;
				var ty = Math.ceil((field[y-1][x-1] / n));
				if (!( tx==n && ty==n )) { 
					var tile = new Tile( this, tx, ty, x, y ); 
					this.tiles.push( tile );
					this.elm.appendChild( tile.elm );
				} else {
					// Position der freien Kachel speichern
					this.freeTile = { x: x, y: y };
				}
			}
		}
		if ( this.isCompleted() ) {
			this.createNew();
		}
		this.missingTile = new Tile( this, n, n, n, n );
	},
	
	setBounds: function( tileWidth, tileHeight ) {
		var width = n * tileWidth;
		var height = n * tileHeight;
		$('puzzle').setStyle({
			width: width + "px",
			height: height + "px",
			marginLeft: (Math.round( width/2 ) * -1) + "px",
			marginTop: (Math.round( height/2 ) * -1) + "px"
		});
	},

	getScrambled: function() {
		var field = new Array(n);
		for ( var y=1; y<=n; y++ ) {
			field[y-1] = new Array(n);
			for ( var x=1; x<=n; x++ ) {
				field[y-1][x-1] = (y-1)*n + x;
			}
		}
		// Position der freien Kachel
		var wx = n-1;
		var wy = n-1;
		
		for ( var i=0; i<200; i++ ) {
			var ri = Math.floor( Math.random() * 4 ) + 1;
			var wpos = this.move( field, wx, wy, ri );
			wx = wpos.x;
			wy = wpos.y;
		}
		// freies Feld nach rechts unten verschieben
		while ( wx != n-1 || wy != n-1 ) {
			if ( wx != n-1 ) wx = (this.move( field, wx, wy, 2 )).x;
			if ( wy != n-1 ) wy = (this.move( field, wx, wy, 3 )).y;
		}
		//this.showArray(field);
		return field;
	},
	
	showArray: function(a) {
		for ( var y=0; y<a.length; y++ ) {
			for ( var x=0; x<a.length; x++ ) {
				$('debug').innerHTML += a[y][x] + " ";
			}
			$('debug').innerHTML += "<br/>";
		}
 
	},
	
	move: function( field, x, y, ri ) {
		var tx = x;
		var ty = y;
		switch(ri) {
			case 1:
				ty--;
			break;
			case 2:
				tx++;
			break;
			case 3:
				ty++;
			break;
			case 4:
				tx--;
			break;
		}		
		if ( tx < 0 || tx >=n || ty < 0 || ty >=n ) {
			return { x: x, y: y };
		}
		// tauschen
		var h = field[y][x];
		field[y][x] = field[ty][tx];
		field[ty][tx] = h;
		return { x: tx, y: ty };
	},
	
	isCompleted: function() {
		var wrong = this.tiles.find( function( tile ) {
			return (!tile.isOnRightPos());
		});
		return ( typeof(wrong) == "undefined" );
	},
	
	gameCompleted: function() {
		playSound( "fanfare.mp3" );
		this.freeTile = null; 
		this.elm.appendChild( this.missingTile.elm );
		this.missingTile.elm.style.display = "none";
		//Effect.Pulsate( missingTile.elm, { pulses: 10, duration: 4 } );
		Effect.Appear( this.missingTile.elm, { duration: 5 } );
		new Effect.Move( "nochmal", { x: -294, y: 0, mode: "relative", queue: "end" } );
	}
}

var Tile = Class.create();

Tile.prototype = {
	initialize: function( puzzle, origX, origY, x, y ) {
		this.src = "/puzzletile.php?id="+puzzle.id+"&x="+origX+"&y="+origY; 
		this.puzzle = puzzle;
		this.x = x;
		this.y = y;
		this.origX = origX;
		this.origY = origY;
		this.elm = new Element( "img", {
			"class": "kachel"
		});
		this.image = new Image();
		this.image.onload = function() {
			this.elm.src = this.image.src,
			this.setPosition();
		}.bind(this);
		this.image.src = this.src;
		Event.observe( this.elm, "click", this.onClick.bind(this) );
		Event.observe( this.elm, "mousedown", function(e){e.preventDefault();} );

	},
	
	setPosition: function() {
		this.puzzle.setBounds(this.image.width, this.image.height);
		this.elm.setStyle({
			top: ((this.y-1) * this.image.height) + "px",
			left: ((this.x-1) * this.image.width) + "px" 
		});	
	},
	
	isOnRightPos: function() {
		return ( this.x == this.origX && this.y == this.origY );
	},
	
	onClick: function() {
		if ( this.puzzle.freeTile == null ) return;
		var dx = this.puzzle.freeTile.x - this.x;
		var dy = this.puzzle.freeTile.y - this.y;
		
		if ( dx * dy == 0 && Math.max(Math.abs(dx),Math.abs(dy)) == 1 ) {
			this.move( dx, dy );
		}
	},
	
	move: function( dx, dy ) {
		this.puzzle.freeTile.x = this.x;
		this.puzzle.freeTile.y = this.y;
		
		this.x += dx;
		this.y += dy;
		
		var px = (this.x-1) * this.elm.width;
		var py = (this.y-1) * this.elm.height;
		playSound( "slide.mp3" );
		new Effect.Move(this.elm, { x: px, y: py, mode: 'absolute', duration: 0.6 });
		if (this.puzzle.isCompleted()) {
			this.puzzle.gameCompleted();
		}
	}
}

function playSound( file ) {
		if (!$('mp3player')) return;
		$('mp3player').SetVariable("method:setUrl", "/sounds/" + file);
		$('mp3player').SetVariable("method:play", "");
		$('mp3player').SetVariable("enabled", "true");	
}

