/**

Il programma fa uso della libreria JQuery per risolvere
i problemi di cross-browsing e per rendere più compatto il codice.

*/

// Costanti
var GSConst = {
	pgn: 'http://www.giocareascacchi.it/images/pgn/',
	icon: 'http://www.giocareascacchi.it/images/icons/',
	ajax: 'http://www.giocareascacchi.it/member/egame-ajax.php',
	GSChess: 'gsChess',			// ex jsGame
	GSTable: 'gsTable',			// ex jsGameTable
	GSMovePanel: 'gsMove',
	GSArrowPanel: 'gsArrow',
	GSOptionPanel: 'gsOption',
	GSWindow: 'gsWindow',
	GSRotate: 'gsRotate',
	GSExpFen: 'gsExpFen',
	GSImpFen: 'gsImpFen',
	GSImpPgn: 'gsImpPgn',
	GSExpPgn: 'gsExpPgn',
	GSReset: 'gsReset',
	GSSend: 'gsSend',
	GSLoading: 'gsLoading',
	GSMsgBoard: 'gsMsgBoard'
};

/**
	Gruppo di Funzioni che servono a compattare il codice
*/
var Doc = {
	// document.createElement()
	cE: function(html) {
		return document.createElement(html);
	}
}

/**
	Oggeto che memorizza tutte le impostazioni della partita. Non tutte le
	informazioni saranno utili per la tipologia di scacchiera scelta. Per esempio
	se sto utilizzando la scacchiera di analisi allora playMatch non mi interessa,
	neanche chesstempo.
*/
function GSInfo(elem) {
	this.elem = elem;				// Rappresenta l'oggetto DOM
	this.idElem = null;
	
	this.rotWhite = true;		// visualizzo secondo Bianco

	this.idGame = -1;
	this.setFen = false;
	this.getFen = false;
	this.setPgn = false;
	//this.getPgn = false;
	this.showMoves = false;
	this.flip = false;
	this.arrow = false;
	this.setup = false;
	this.fen = 'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1';
	this.notoverride = false;
	this.doReverse = false;
	this.playMatch = false;
	this.reset = false;
	this.send = false;
	this.chesstempo = false;
	this.pgnText = null;
	this.variant = null;
	
	// -------------------
	// Match
	
	this.memo = null;
	
	// -------------------
	// Le dimensioni dei seguenti due array sono identici.
	
	this.fens = new Array();			// Array dei Fen
	this.iFen = 0;							// Current Fen
	this.moves = new Array();			// Array delle mosse
	this.msg = new Array();				// Array dei Messaggi
	
	// -------------------
	// Movimento dei pezzi
		
	this.pieceDragged = false;
	this.move = null;
	
	// Funzione che mi serve a resettare tutte le variabili
	// per lo spostamento di un pezzo nella scacchiera
	this.resetPiece = function () {
		this.pieceDragged = false;
		this.move = null;
	}
}

/**
	Questa è la funzione che viene chiamata non appena la pagina è stata caricata,
	quindi si occupa di construire la scacchiera a partire dalle informazioni che
	sono fornite.
*/
function GSParser() {
	this.init = function() {
		$('.'+GSConst.GSChess).each(this.active);
	}
	
	this.active = function(i, elem) {
		// Aggiungo un id per ogni elemento trovato. Mi serve per
		// identificare correttamente la scacchiera con JQuery
		$(this).attr('id' , GSConst.GSChess+(i+1));
	
		var info = new GSInfo(this);
		info.idElem = i+1;
		
		//var inputs = elem.getElementsByTagName('input');
		var inputs = $('#'+this.id+' input');
		var leng = inputs.length;
		
		for (var i=0; i<leng; i++) {
			// Analisi e Base
			if (inputs[i].name == 'setFen') info.setFen = true;
			if (inputs[i].name == 'getFen') info.getFen = true;
			if (inputs[i].name == 'setPgn') info.setPgn = true;
			if (inputs[i].name == 'getPgn') info.getPgn = true;
			if (inputs[i].name == 'showMoves') info.showMoves = true;
			if (inputs[i].name == 'flip') info.flip = true;
			if (inputs[i].name == 'arrow') info.arrow = true;
			if (inputs[i].name == 'setup') info.setup = true;
			if (inputs[i].name == 'fen') info.fen = inputs[i].value;
			if (inputs[i].name == 'doReverse') info.doReverse = true;
			
			// Match (egames)
			if (inputs[i].name == 'match') info.playMatch = true;
			if (inputs[i].name == 'selectGameId') info.idGame = parseInt(inputs[i].value);
			if (inputs[i].name == 'notoverride') info.notoverride = true;
			if (inputs[i].name == 'reset') info.reset = true;
			if (inputs[i].name == 'send') info.send = true;
			
			// Chess Tactic Trainer
			if (inputs[i].name == 'chesstempo') info.chesstempo = true;
		}
		
		//var texts = elem.getElementsByTagName('textarea');
		var texts = $('#'+this.id+' textarea');
		leng = texts.length;
		
		for (var i=0; i<leng; i++) {
			if (texts[i].name == 'pgn') info.pgnText = texts[i].value.replace(/\<br[^\>]*\>/ig, '');
		}
		
		// Dopo aver preso le informazioni che c'erano svuoto tutto
		Utility.removeAllChilds(this);
		
		// ----------------------------------------------------------
		// In base alle informazioni reperite scelgo la modalità di
		// scacchiera da attivare
		
		if (info.chesstempo === true) {
			// Attivo il Chess Tactic Trainer
		}
		else if (info.playMatch === true) {
			// Attivo la modalità Egames
			var a = new GSEgame(info);
			a.init();
		}
		else if (info.playMatch === false && info.notoverride === true) {
			// Attivo la modalità di visualizzazione di una partita
			var a = new GSShowGame(info);
			a.init();
		}
		else {
			// Se arrivo qui vuol dire che devo attivare
			// la modalità di analisi
			var a = new GSAnalysis(info);
			a.init();
		}
	}
}

/**
	Oggetto che raccoglie elementi della scacchiera finale
*/
var GSElements = {

	/**
		Mi serve per riportare la scacchiera allo stato 0, dove non c'è
		alcun FEN, nè mossa inserita e dove la scacchiera ha la vista del Bianco
	*/
	reset: function(info) {
		info.fens = new Array();
		info.moves = new Array();
		info.msg = new Array();
		info.iFen = 0;
		
		// if (info.rotWhite !== true) GSElements.chessboard.rotateCoord(info);
	},
	
	/**
		Questa funzione mi serve per amministrare l'inserimento di un nuovo FEN,
		perchè se la stringa dice che tocca al Nero allora devo inserire come mossa
		"..." per il Bianco
	*/
	setFirstFen: function (info) {
		// Inserisco il FEN
		info.fens.push(info.fen);
		
		// Analizzo se devo inserire anche "..." come mossa
		var arr = info.fen.split(' ');
		if (arr[1] == 'b') GSElements.addMove(info, info.fen, '...', null);
	},
	
	addMove: function (info, fen, move, msgBoard) {
		info.moves.push(move);
		info.fens.push(fen);
		info.msg.push(msgBoard);
		info.iFen++;
	},
	
	/**
		Funzione che mi crea la tabella della scacchiera (vuota),
		comprensiva delle coordinate. La scacchiera è rivolta con
		il Bianco verso il basso
	*/
	createTableBoard: function(info) {
		// Creo la base della scacchiera
		var table = Doc.cE('table');
		$(table).attr({'id' : GSConst.GSTable+info.idElem, 'class' : GSConst.GSTable});
		
		var tbody = Doc.cE('tbody');	// per IE
		
		// Sintassi obbligatoria per IE
		table.appendChild(Doc.cE('thead'));
		table.appendChild(Doc.cE('tfoot'));
		table.appendChild(tbody);
		
		
		//Core.addEventListener(table, 'mousemove', ChessBoardManager.imgFollowMouse);
		//Core.addEventListener(table, 'click', ChessBoardManager.dragDropPiece);
		
		// Aggiungo le coordinate (colonne) in alto
		tbody.appendChild(GSElements.getTrRowCoord(info));
		
		for (var i=0; i<8; i++) {
			var tr = Doc.cE('tr');
			
			tr.appendChild(GSElements.getTdCoord(i, info));
		
			for (var j=0; j<8; j++) {
				var td = Doc.cE('td');
				// Coordinate della cella (univoci)
				td._x = i;
				td._y = j;
			
				if ((i+j)%2) td._styleName = 'c2';
				else td._styleName = 'c1';
				
				td.className = td._styleName;
			
				var div = Doc.cE('div');
				
				var img = Doc.cE('img');
				img.src = GSConst.pgn+'empty.gif';
			
				div.appendChild(img);
				td.appendChild(div);
				tr.appendChild(td);
			}
			
			tr.appendChild(GSElements.getTdCoord(i, info));
		
			tbody.appendChild(tr);
		}
		
		tbody.appendChild(GSElements.getTrRowCoord(info));
		
		return table;
	},
	
	listenerTableBoard: function (info) {
		$('#'+GSConst.GSTable+info.idElem)
			.click(function (event) {
				var src = $(event.target).attr('src');
				var x = $(event.target).parent().parent().attr('_x');
				var y = $(event.target).parent().parent().attr('_y');
				
				if (info.pieceDragged === true) {
					// Lascio il pezzo nella scacchiera
				
					if (typeof(x) != 'number') {
						// Ho rimesso il pezzo al suo posto
						$('#pieceDragged').attr('id', '');
						info.resetPiece();
						
						GSElements.chessboard.updateBoard(info);
					}
					else {
						// Ho appoggiato il pezzo su una casella, ora devo controllare
						// che la mossa sia corretta ed effettuare le modifiche e gli
						// aggiornamenti necessari
						info.move = info.move + GSlib.GSChessboard.coordToCol(y) + GSlib.GSChessboard.coordToRow(x);
						
						if (	$('#pieceDragged').children().attr('src').match(/P[bn].gif$/) != null && (x == 0 || x == 7)	) {
							// Qui devo creare il pannello della promozione
							
							var objFen = new GSlib.GSFen();
							objFen.analyze(info.fens[info.iFen]);
							info.who = objFen.who;
							
							$(GSElements.promotionPanel(info)).appendTo($('body'));
							GSElements.listenerPromotionPanel(info);
						}
						else GSElements.playMove(info, null);
					}
				}
				else if (typeof(src) == 'string' && info.pieceDragged === false && src != GSConst.pgn+'empty.gif') {
					
					if (info.memo == null || info.playMatch == false) {
						// Filtro solo le caselle (e tralascio le coordinate)
						$(event.target).parent().attr('id', 'pieceDragged');
						info.pieceDragged = true;
						info.move = GSlib.GSChessboard.coordToCol(y) + GSlib.GSChessboard.coordToRow(x);
					}
					
				}
			})
			.mousemove(function (event) {
				$('#pieceDragged').css({'left' : event.pageX - 20, 'top' : event.pageY + 1});
			}); 
	},
	
	playMove: function (info, prom) {
		var message = new GSlib.GSMoveMessage(info.fens[info.iFen], info.move, prom, info.variant);
		var mMan = new GSlib.GSMoveManager(message);
		var r = mMan.play();
		/* DEBUB */ // if (r === false) alert(mMan.log.get());
		
		if (r !== false) {
			// Se non sono all'ultima mossa cancello tutte le mosse
			// successive, in questo modo analizzo una seconda variante
			
			if (info.iFen + 1 < info.fens.length && info.notoverride === false) {
				info.fens.splice(info.iFen + 1, info.fens.length - info.iFen + 1);
				info.moves.splice(info.iFen, info.moves.length - info.iFen);
				info.msg.splice(info.iFen, info.msg.length - info.iFen);
			}
			
			if (info.iFen + 1 >= info.fens.length) {
				info.memo = r.move;
				GSElements.addMove(info, r.strFen, r.move, r.msg);
			}
		}
		
		$('#pieceDragged').attr('id', '');
		info.resetPiece();
		GSElements.chessboard.updateBoard(info);
		GSElements.refreshMove(info);
	},
	
	getTrRowCoord: function(info) {
		var tr = Doc.cE('tr');
		tr.appendChild(Doc.cE('td'));
		
		//if (info.rotWhite === true) {
		for (var i=0; i<8; i++) {
			var td = Doc.cE('td');
			td.className = 'gsTdCoord';
			var div = Doc.cE('div');
			div.className = 'gsCoord';
			var text = null;
			
			switch(i) {
				case 0: text = 'a'; break;
				case 1: text = 'b'; break;
				case 2: text = 'c'; break;
				case 3: text = 'd'; break;
				case 4: text = 'e'; break;
				case 5: text = 'f'; break;
				case 6: text = 'g'; break;
				case 7: text = 'h'; break;
			}
			
			div.appendChild(document.createTextNode(text));
			td.appendChild(div);
			tr.appendChild(td);
		}
		//}
		/**
		else {
			// Condizione che non dovrebbe mai verificarsi perchè
			// prima imposto la scacchiera secondo bianco, poi la rovescio.
			for (var i=0; i<8; i++) {
			
			}
		}
		*/
		
		tr.appendChild(Doc.cE('td'));
		return tr;
	},
	
	getTdCoord: function(i, info) {
		//if (info.rotWhite === true) {
		var td = Doc.cE('td');
		td.className = 'gsTdCoord';
		var div = Doc.cE('div');
		div.className = 'gsCoord';
		div.appendChild( document.createTextNode( ''+(8-i) ) );
		td.appendChild(div);

		return td;
		//}
		//return false;
	},
	
	chessboard: {
	
		/**
			Questa funzione aggiorna la scacchiera in base al FEN,
			scelto in base a info.fens[info.iFen]
		*/
		updateBoard: function(info) {
			var i,j,k;
			var imgs = $('#'+GSConst.GSTable+info.idElem+' img');
			
			// Ricavo la scacchiera
			var gsFen = new GSlib.GSFen();
			gsFen.analyze(info.fens[info.iFen]);
			var board = gsFen.board;
			
			if (info.rotWhite === false) {
				k=63;
				for (i=0; i<8; i++) {
					for (j=0; j<8; j++) {
						imgs[k].src = GSElements.chessboard.getPiece(board[i][j]);
						k--;
					}
				}
			}
			else {
				k=0;
				for (i=0; i<8; i++) {
					for (j=0; j<8; j++) {
						imgs[k].src = GSElements.chessboard.getPiece(board[i][j]);
						k++;
					}
				}
			}
		},
		
		/**
			Nel caso giri la scacchiera ho bisogno di aggiornare
			anche le coordinate nel modo corretto
		*/
		rotateCoord: function(info) {
			var arr = {
				'a':'h', 'b':'g', 'c':'f', 'd':'e', 'e':'d', 'f':'c', 'g':'b', 'h':'a',
				'1':'8', '2':'7', '3':'6', '4':'5', '5':'4', '6':'3', '7':'2', '8':'1'
			};
			$('#'+GSConst.GSTable+info.idElem+' .gsCoord').each(function () {
				$(this).text(arr[$(this).text()]);
			});
			
			// Ora devo aggiornare anche le coordinate nascoste delle celle
			// in modo da poter eseguire correttamente le mosse in sala di analisi
			// anche con la scacchiera rovesciata
			$('#'+GSConst.GSTable+info.idElem+' td').each(function () {
				var x = $(this).attr('_x');
				var y = $(this).attr('_y');
				if (typeof(x) == 'number') $(this).attr({'_x' : 7-x , '_y' : 7-y});
			});
			
		},
		
		/**
			Dato il pezzo in formato carattere, ritorna il nome
			dell'immagine associata
		*/
		getPiece: function(c) {
			var src = GSConst.pgn + 'empty.gif';
		
			switch(c) {
				case 'P': src = GSConst.pgn + 'Pb.gif'; break;
				case 'R': src = GSConst.pgn + 'Tb.gif'; break;
				case 'N': src = GSConst.pgn + 'Cb.gif'; break;
				case 'B': src = GSConst.pgn + 'Ab.gif'; break;
				case 'Q': src = GSConst.pgn + 'Db.gif'; break;
				case 'K': src = GSConst.pgn + 'Rb.gif'; break;
				case 'p': src = GSConst.pgn + 'Pn.gif'; break;
				case 'r': src = GSConst.pgn + 'Tn.gif'; break;
				case 'n': src = GSConst.pgn + 'Cn.gif'; break;
				case 'b': src = GSConst.pgn + 'An.gif'; break;
				case 'q': src = GSConst.pgn + 'Dn.gif'; break;
				case 'k': src = GSConst.pgn + 'Rn.gif'; break;
			}
			
			return src;
		}
	},
	
	createMovePanel: function (info) {
		var d1 = Doc.cE('div');
		$(d1).attr({'id' : GSConst.GSMovePanel+info.idElem, 'class' : GSConst.GSMovePanel});
		
		var i,k,len,tr;
		var t = Doc.cE('div');
		t.appendChild(document.createTextNode('Game'));
		t.className = 'moveTitle';
		d1.appendChild(t);
		
		var table = GSElements.createMoveTable(info);
		
		d1.appendChild(table);
		
		var $d = $('<div style="float:right;"></div>').append($(d1)).append($('<div id="' + GSConst.GSMsgBoard+info.idElem + '" class="' + GSConst.GSMsgBoard + '"></div>'));
		
		return $d[0];
	},
	
	createMoveTable: function (info) {
		var table = Doc.cE('table');
		var t = Doc.cE('tbody');	// per IE
		
		// Sintassi obbligatoria per IE
		table.appendChild(Doc.cE('thead'));
		table.appendChild(Doc.cE('tfoot'));
		table.appendChild(t);
		
		k=1;
		len = info.moves.length;
		tr = null;
		for (i=0; i<len; i++) {
			if (i%2 == 0) {
				tr = Doc.cE('tr');
				th = Doc.cE('th');
				th.appendChild(document.createTextNode(k+'.'));
				tr.appendChild(th);
				k++;
			}
			
			var td = Doc.cE('td');
			td._bgColor = '#ffffff';			// Per colpa di IE6 e IE7 non posso utilizzare 'inherit'
			td._info = info;
			td._i = i;
			td.appendChild(document.createTextNode(info.moves[i]));
			tr.appendChild(td);
			
			if (i%2 == 1 || (info.moves.length % 2 == 1 && i+1 == info.moves.length)) t.appendChild(tr);
		}
		
		return table;
	},
	
	// Fixato per IE6 e IE7
	listenerMove: function (info) {
		// Adesso che ho creato la tabella, rendo cliccabili le varie
		// mosse per spostarsi nelle varie posizioni.
		
		// Utilizzo la libreria JQuery
		$('#'+GSConst.GSMovePanel+info.idElem+' td')
			.mouseover(function () {$(this).css('backgroundColor', '#ebebeb').css('cursor', 'pointer');})
			.mouseout(function () {$(this).css('backgroundColor', this._bgColor);})
			.click(function () {
				info.iFen = this._i+1;
				var table = $('#'+GSConst.GSTable+info.idElem)[0];
				GSElements.chessboard.updateBoard(this._info, table);
				GSElements.updateMove(info);
			});
	},
	
	/**
		Significa cercare la mossa corrispondente all'iFen all'interno del pannello
		delle mosse e cambiare il suo colore di sfondo, mentre tutte le alter resettarle
		a Bianco.
		
		TODO: update move è MOLTO LENTO!!
	*/
	updateMove: function (info) {
		$('#'+GSConst.GSMovePanel+info.idElem+' td').attr('_bgColor', '#ffffff');
		if (info.iFen > 0) $('#'+GSConst.GSMovePanel+info.idElem+' td:eq('+(info.iFen-1)+')').attr('_bgColor', '#ebebeb');
		$('#'+GSConst.GSMovePanel+info.idElem+' td').trigger('mouseout');
		GSElements.updateMessage(info);
	},
	
	updateMessage: function (info) {
		if (info.msg[info.iFen-1] == null) $('#'+GSConst.GSMsgBoard+info.idElem).html('');
		else $('#'+GSConst.GSMsgBoard+info.idElem).html(info.msg[info.iFen-1]);
	},
	
	/**
		Questa funzione aggiorna le mosse nel pannello
	*/
	refreshMove: function (info) {
		var table = GSElements.createMoveTable(info);
		$('#'+GSConst.GSMovePanel+info.idElem+' table').remove();
		$('#'+GSConst.GSMovePanel+info.idElem).append(table);
		GSElements.listenerMove(info);
		GSElements.updateMove(info);
	},
	
	createArrowPanel: function(info) {
		var d = Doc.cE('div');
		$(d).attr({'id' : GSConst.GSArrowPanel+info.idElem, 'class' : GSConst.GSArrowPanel});
		$('<input type="button" name="lleft" value="<<">').appendTo($(d));
		$('<input type="button" name="left" value="<">').appendTo($(d));
		$('<input type="button" name="right" value=">">').appendTo($(d));
		$('<input type="button" name="rright" value=">>">').appendTo($(d));
		
		$(d).click(function (event) {
			if (event.target.value == '<<') info.iFen = 0;
			if (event.target.value == '<') {if (info.iFen > 0) info.iFen--;}
			if (event.target.value == '>') {if (info.iFen < info.fens.length-1) info.iFen++;}
			if (event.target.value == '>>') info.iFen = info.fens.length-1;
			
			GSElements.chessboard.updateBoard(info);
			GSElements.updateMove(info);
			
		});
		return d;
	},
	
	/**
		opt rappresenta un array che contiene le opzioni da inserire
		Opt: 'expfen', 'rot'
	*/
	createOptionPanel: function (info) {
		var d = Doc.cE('div');
		var d1 = Doc.cE('div');		// Prima linea di opzioni
		var d2 = Doc.cE('div');		// Seconda linea di opzioni
		var d3 = Doc.cE('div');		// Terza linea di opzioni
		var dw = Doc.cE('div');		// Finestra per i fen, i setup, ecc...
		$(d).attr({'id' : GSConst.GSOptionPanel+info.idElem, 'class' : GSConst.GSOptionPanel});
		$(dw).attr({'id' : GSConst.GSWindow+info.idElem, 'class' : GSConst.GSWindow});
		
		$(d1).appendTo($(d));
		$(d2).appendTo($(d));
		$(d3).appendTo($(d));
		$(dw).appendTo($(d));
		
		if (info.flip === true) $('<span id="'+GSConst.GSRotate+info.idElem+'">Rotate</span>').appendTo($(d1));
		if (info.getFen === true) $('<span id="'+GSConst.GSExpFen+info.idElem+'">Export FEN</span>').appendTo($(d1));
		if (info.getPgn === true) $('<span id="'+GSConst.GSExpPgn+info.idElem+'">Export PGN</span>').appendTo($(d1));
		
		if (info.setFen === true) $('<span id="'+GSConst.GSImpFen+info.idElem+'">Import FEN</span>').appendTo($(d2));
		if (info.setPgn === true) $('<span id="'+GSConst.GSImpPgn+info.idElem+'">Import PGN</span>').appendTo($(d2));
		
		if (info.reset === true) $('<span id="'+GSConst.GSReset+info.idElem+'">Reset</span>').appendTo($(d3));
		if (info.send === true) $('<span id="'+GSConst.GSSend+info.idElem+'">Send</span>').appendTo($(d3));
		
		return d;
	},
	
	listenerOptionPanel: function (info) {
		$('#'+GSConst.GSSend+info.idElem)
			.click (function() {
				if (info.memo != null) {
					// Faccio questo passaggio di informazione perchè così
					// se l'utente clicca una seconda volta su "Send" questo non ha effetto.
					var mossa = info.memo;
					info.memo = null;
					
					$('#' + GSConst.GSLoading+info.idElem)
						.html('<div><img src="' + GSConst.icon + 'loading.gif"> Loading, wait please...</div>');
						
					var message = info.msg[info.moves.length - 1];
					
					$.post(
						GSConst.ajax,
						{ idGame: info.idGame, m: mossa, msg: message },
						function (data, textStatus) {
							if (textStatus == 'success') {
								$('#' + GSConst.GSLoading+info.idElem).html('');
								window.location.reload(true);
							}
						},
						'text'
					);
					
				}
			});
		$('#'+GSConst.GSReset+info.idElem)
			.click (function() {
				if (info.memo != null) {
					info.memo = null;
					info.moves.splice(info.moves.length-1, 1);
					info.fens.splice(info.fens.length-1, 1);
					info.iFen = info.fens.length-1;
					
					GSElements.chessboard.updateBoard(info);
					GSElements.refreshMove(info);
				}
			});
		$('#'+GSConst.GSRotate+info.idElem)
			.click (function() {
				if (info.rotWhite === true) info.rotWhite = false;
				else info.rotWhite = true;
				GSElements.chessboard.rotateCoord(info);
				GSElements.chessboard.updateBoard(info);
			});
		$('#'+GSConst.GSExpFen+info.idElem)
			.click (function() {
				// Rimuovo tutto quello che c'era in precedenza
				var w = $('#'+GSConst.GSWindow+info.idElem);
				Utility.removeAllChilds(w[0]);
				$('<div><input type="text" name="expfen" value="'+info.fens[info.iFen]+'" /></div>').appendTo(w);
			});
		$('#'+GSConst.GSImpFen+info.idElem)
			.click (function() {
				// Rimuovo tutto quello che c'era in precedenza
				var w = $('#'+GSConst.GSWindow+info.idElem);
				Utility.removeAllChilds(w[0]);
				
				var $button = $('<input type="button" name="imp" value="Import">');
				var $field = $('<input type="text" name="impfen">');
				var $input = $('<div></div>').append($field).append($button);
				$input.appendTo(w);
				
				$button.click(function () {
					var t = $field.attr('value');
					
					GSElements.reset(info);
					
					info.fen = t;
					GSElements.setFirstFen(info); 
					
					var objFen = new GSlib.GSFen();
					objFen.analyze(t);
					
					GSElements.chessboard.updateBoard(info);
					GSElements.refreshMove(info);
				});
			});
		
		$('#'+GSConst.GSImpPgn+info.idElem)
			.click (function() {
				// Rimuovo tutto quello che c'era in precedenza
				var w = $('#'+GSConst.GSWindow+info.idElem);
				Utility.removeAllChilds(w[0]);
				
				var $button = $('<div><input type="button" name="imp" value="Import"></div>');
				var $field = $('<div><textarea name="pgn" rows="10" cols="30"></textarea></div>');
				var $input = $('<div></div>').append($field).append($button);
				$input.appendTo(w);
				
				$button.click(function () {
					info.pgnText = $('#'+GSConst.GSWindow+info.idElem+' textarea:first').val();
					
					GSElements.reset(info);
					GSElements.pgnAnalyze(info);
					
					GSElements.chessboard.updateBoard(info);
					GSElements.refreshMove(info);
				});
			});
		$('#'+GSConst.GSExpPgn+info.idElem)
			.click (function() {
				// Rimuovo tutto quello che c'era in precedenza
				var w = $('#'+GSConst.GSWindow+info.idElem);
				Utility.removeAllChilds(w[0]);
				
				var pgn = '';
				var len = info.moves.length;
				for (var i=0; i<len; i++) {
					if (i%2 == 0) pgn = ' ' + pgn + (i/2 + 1) + '. ';
					pgn = pgn + info.moves[i] + ' ';
				}
				$('<div><textarea name="pgn" rows="10" cols="30">' + $.trim(pgn) + '</textarea></div>').appendTo(w);
			});
	},
	
	promotionPanel: function (info) {
		var table = Doc.cE('table');		
		var tbody = Doc.cE('tbody');	// per IE
		
		var cap = Doc.cE('caption');
		cap.appendChild(document.createTextNode('Promotion'));
		
		// Sintassi obbligatoria per IE
		table.appendChild(cap);
		table.appendChild(Doc.cE('thead'));
		table.appendChild(Doc.cE('tfoot'));
		table.appendChild(tbody);
		
		var col = (info.who == 'w') ? 'b' : 'n';
		
		$(tbody).append('<tr><th><img src="' + GSConst.pgn + 'D' + col + '.gif" alt="Q"></th><td> - Queen</td></tr>');
		$(tbody).append('<tr><th><img src="' + GSConst.pgn + 'T' + col + '.gif" alt="R"></th><td> - Rook</td></tr>');
		$(tbody).append('<tr><th><img src="' + GSConst.pgn + 'A' + col + '.gif" alt="B"></th><td> - Bishop</td></tr>');
		$(tbody).append('<tr><th><img src="' + GSConst.pgn + 'C' + col + '.gif" alt="N"></th><td> - Knight</td></tr>');
		
		var p1 = $('<div id="pawnLayout"></div>').append(table);
		var obj = $('<div id="pawnPromotion"></div>').append(p1);
		return obj[0];
	},
	
	listenerPromotionPanel: function (info) {
		$('#pawnPromotion img').click(function () {
			$('#pawnPromotion').remove();
			GSElements.playMove(info, $(this).attr('alt'));
		});
	},
	
	/**
		TODO: non è possibile che debba ripetere due volte il codice
	*/
	pgnAnalyze: function (info) {
		var k;
		
		// Analizzo il PGN fornito come input per elaborarlo
		var pgn = new Pgn(info.pgnText);
		if (pgn.props['FEN']) info.fen = pgn.props['FEN'];
		if (pgn.props['Variant']) info.variant = pgn.props['Variant'];
		GSElements.setFirstFen(info);
		
		var len = pgn.moves.length;
		for (var i=0; i<len; i++) {
			// Percorro ogni mossa
			
			if (pgn.moves[i].white != null) {
				var objFen = new GSlib.GSFen();
				objFen.analyze(info.fens[info.iFen]);
				
				var sMove = GSlib.GSMoveConverter(objFen, pgn.moves[i].white, info.variant);
				
				// Controllo se la mossa prevede una promozione
				var prom = pgn.moves[i].white.match(/=[QRBN]/);
				if (prom != null) prom = prom.toString().charAt(1);
				
				var msg = new GSlib.GSMoveMessage(info.fens[info.iFen], sMove, prom, info.variant);
				var mMan = new GSlib.GSMoveManager(msg);
				var r = mMan.play();
				/* DEBUG */ if (r === false) alert(mMan.log.get());
				
				GSElements.addMove(info, r.strFen, pgn.moves[i].white, r.msg);
			}
			
			if (pgn.moves[i].black != null) {
				var objFen = new GSlib.GSFen();
				objFen.analyze(info.fens[info.iFen]);
				
				var sMove = GSlib.GSMoveConverter(objFen, pgn.moves[i].black, info.variant);
				
				// Controllo se la mossa prevede una promozione
				var prom = pgn.moves[i].black.match(/=[QRBN]/);
				if (prom != null) prom = prom.toString().charAt(1);
				
				var msg = new GSlib.GSMoveMessage(info.fens[info.iFen], sMove, prom, info.variant);
				var mMan = new GSlib.GSMoveManager(msg);
				var r = mMan.play();
				/* DEBUG */ if (r === false) alert(mMan.log.get());
				
				GSElements.addMove(info, r.strFen, pgn.moves[i].black, r.msg);
			}
		}
		
		info.iFen = 0;
	}
};

// ************************************
// Modalità specifiche della scacchiera
// ************************************

// -----------------------------------------

function GSShowGame(info) {
	this.info = info;
	
	this.init = function() {
		GSElements.pgnAnalyze(this.info);
		
		// Creo il pannello delle mosse
		if (info.showMoves === true) {
			var mPanel = GSElements.createMovePanel(this.info);
			this.info.elem.appendChild(mPanel);
			GSElements.listenerMove(this.info);
		}
	
		// Creo la scacchiera
		var table = GSElements.createTableBoard(this.info);
		this.info.elem.appendChild(table);
		
		// Creo Le frecce
		if (info.arrow === true) {
			var arrow = GSElements.createArrowPanel(this.info);
			this.info.elem.appendChild(arrow);
		}
		
		// Creo le opzioni
		var opt = GSElements.createOptionPanel(this.info);
		this.info.elem.appendChild(opt);
		GSElements.listenerOptionPanel(this.info);
		
		// Imposto la scacchiera nella posizione iniziale
		GSElements.chessboard.updateBoard(this.info);
		GSElements.updateMove(this.info);
	}
}

// -------------------------------------------------

function GSAnalysis (info) {
	this.info = info;
	
	this.init = function () {
		GSElements.pgnAnalyze(this.info);
	
		if (info.showMoves === true) {
			var mPanel = GSElements.createMovePanel(this.info);
			this.info.elem.appendChild(mPanel);
			GSElements.listenerMove(this.info);
		}
	
		// Creo la scacchiera
		var table = GSElements.createTableBoard(this.info);
		this.info.elem.appendChild(table);
		GSElements.listenerTableBoard(this.info);
		
		// Creo Le frecce
		if (info.arrow === true) {
			var arrow = GSElements.createArrowPanel(this.info);
			this.info.elem.appendChild(arrow);
		}
		
		// Creo le opzioni
		var opt = GSElements.createOptionPanel(this.info);
		this.info.elem.appendChild(opt);
		GSElements.listenerOptionPanel(this.info);
		
		// Imposto la scacchiera nella posizione iniziale
		GSElements.chessboard.updateBoard(this.info);
		GSElements.updateMove(this.info);
	}
}

function GSEgame (info) {
	this.info = info;
	
	this.init = function () {
		//this.info.fens.push(this.info.fen);
		GSElements.pgnAnalyze(this.info);
		
		// Creo il pannello delle mosse
		if (info.showMoves === true) {
			var mPanel = GSElements.createMovePanel(this.info);
			this.info.elem.appendChild(mPanel);
			GSElements.listenerMove(this.info);
		}
	
		// Creo la scacchiera
		var table = GSElements.createTableBoard(this.info);
		this.info.elem.appendChild(table);
		GSElements.listenerTableBoard(this.info);
		
		// Creo Le frecce
		if (info.arrow === true) {
			var arrow = GSElements.createArrowPanel(this.info);
			this.info.elem.appendChild(arrow);
		}
		
		$('<div id="'+GSConst.GSLoading+info.idElem+'" class="' + GSConst.GSLoading + '"></div>').appendTo(this.info.elem);
		
		// Creo le opzioni
		var opt = GSElements.createOptionPanel(this.info);
		this.info.elem.appendChild(opt);
		GSElements.listenerOptionPanel(this.info);
		
		this.info.iFen = this.info.fens.length-1;
		
		if (info.doReverse == true) {
			if (info.rotWhite === true) info.rotWhite = false;
			else info.rotWhite = true;
			GSElements.chessboard.rotateCoord(info);
		}
		
		// Imposto la scacchiera nella posizione iniziale
		GSElements.chessboard.updateBoard(this.info);
		GSElements.updateMove(this.info);
	}
}
