/*
	Yacpdb frontend Copyright 2008 
	Author: Dmitri Turevski <dmitri.turevski@gmail.com>
	
	This program is distributed under the terms of the GNU General Public License
	
	This program is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.
	
	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.
	
	You should have received a copy of the GNU General Public License
	along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

/**************************************
	Chess
***************************************/

function Board() {

	this.add = function(name, at, specs) {
		if( (at > 63) || (at < 0) ) {
		    return;
		}
		if(this.board[at].name != '')
		    this.drop(at);
		if(this.head != -1)
		    this.board[this.head].prev = at;
		this.board[at] = { 'prev':-1, 'next':this.head, 'name':name, 'specs':specs };
		this.head = at
	}

	this.drop = function(at) {
		if( (at > 63) || (at < 0) ) {
		    return;
		}
		if(this.board[at].prev != -1)
		    this.board[this.board[at].prev].next = this.board[at].next;
		if(this.board[at].next != -1)
		    this.board[this.board[at].next].prev = this.board[at].prev;
		if(at == this.head)
		    this.head = this.board[at].next;
		this.board[at] = { 'prev':-1, 'next':-1, 'name':'', 'specs':[] };
	}

	this.clear = function() {
		this.head = -1;
		this.board = new Array(64);
		for(i = 0; i < 64; i++) {
			this.board[i] = { 'prev':-1, 'next':-1, 'name':'', 'specs':[] };
		}
	}

	this.toFen = function() {
		var fen = ''; var blanks = 0;
		for(var i = 0; i < 64; i++) {
			if( (i > 0) && (i % 8 == 0) ) {
				if(blanks > 0) 
					fen += blanks;
				fen += '/';
				blanks = 0;
			}
			if(this.board[i].name != '') {
				if(blanks > 0) 
					fen += blanks;
				if(this.board[i].name.length ==1)
					fen += this.board[i].name;
				else
					fen += '(' + this.board[i].name + ')';
				blanks = 0;
			} else {
				blanks++;
			}
		}
		if(blanks > 0) 
			fen += blanks;
		return fen;
	}

	this.fromFen = function(fen) {
		this.clear()
		var i = 0;
		var j = 0;
		while((j < 64) && (i < fen.length)) {
			if("12345678".indexOf(fen.charAt(i)) != -1) {
				j = j + parseInt(fen.charAt(i))
				i = i + 1
			} else if('(' == fen.charAt(i)) {
				idx = fen.indexOf(')', i);
				if(idx != -1) {
					this.add(fen.substring(i+1, idx), j, [])         
					j = j + 1
					i = idx + 1
				} else {
					i = i + 1
				}
			} else if('/' == fen.charAt(i)) {
				i = i + 1
			} else {
				this.add(fen.charAt(i), j, [])           
				j = j + 1;
				i = i + 1;
			}
		}
	}

	this.toGc = function(withHandlers, disambiguations) {
		var retval = '';
		for(var i = 0; i < 8; i++) {
			for(var j = 0; j < 8; j++) {
				var k = i*8 + j
				if(withHandlers)
					retval += '<a id="s' + k + '">'
				retval += xfen2spritedecl(this.board[k].name, (i+j)%2)
				if(withHandlers)
					retval += '</a>';
			}
			retval += '<div style="clear:both;"></div>'
		}
		return retval;
	}


	this.toMerida = function(withHandlers) {
		var merida = '';
		for(var i = 0; i < 8; i++) {
			for(var j = 0; j < 8; j++) {
				var k = i*8 + j
				if(withHandlers)
					merida += '<a id="s' + k + '">';
				/* ttf version				
				merida += (this.board[k].name == '') ? MBLANKS.charAt((i + j)%2) :
					MPIECES[(i + j)%2].charAt(PIECES.indexOf(this.board[k].name));
				*/
				var cl = (this.board[k].name == '') ? MBLANKS.charAt((i + j + 1)%2) :
					MPIECES[(i + j)%2].charAt(PIECES.indexOf(this.board[k].name));
				merida += '<div class="cp cp' + cl + '"></div>'			
				if(withHandlers)
					merida += '</a>';
			}
			/* ttf version				
			merida += "<br/>";
			*/
			merida += '<div style="clear:both;"></div>'
		}
		return merida;
	}
	
	this.piecesCount = function() {
		var b = 0
		var w = 0
		var n = 0
		var p = this.head
		while(p != -1) {
			if(-1 != this.board[p].name.indexOf('!'))
				n++
			else if(this.board[p].name == this.board[p].name.toLowerCase())
				b++
			else
				w++
			p = this.board[p].next
		}
				
		pcs =  w + '+' + b
		if(n > 0) pcs = pcs + '+' + n
		return pcs
	}

	this.packFairySpecs = function() {
		r = []
		var p = this.head
		while(p != -1) {
			if(this.board[p].specs.length > 0) {
				r.push(p + ':' + this.board[p].specs.join(';'))
			}
			p = this.board[p].next
		}
		return r.join("\n")
	}

	this.clear();
}



function xfen2spritedecl(xfen, color) {
	if('' == xfen) {
		return '<div class="cp ' + ['cpEQ', 'cpFQ'][color] + '"></div>'
	}

	sprite = {}
	matches = xfen.match(/^(B?)(!?)([kqrbsnpeaofwdx])([1-7])?$/i)
	if(matches) {
		sprite = {'glyph':matches[3].toLowerCase(), 'rot':matches[4], 'border':(matches[1] != '')}

		if(matches[2] != '') sprite.color = 'neutral'
		else if(sprite.glyph == matches[3]) sprite.color = 'black'
		else sprite.color = 'white' 

		if(!sprite.rot) sprite.rot = 0;

	} else {
		sprite = {'glyph':'x', 'rot':0, 'color':'white', 'border':false}
	}
	if(sprite.glyph == 'x') sprite.color = 'white';

	rot4 = 'kqrbsnp'
	rot2 = 'e'
	rot1 = 'aofwd'

	baseGlyphs = { 
			'k':[[0,0], [0,17]],
			'q':[[0,2], [0,18]],
			'r':[[0,4], [0,19]],
			'b':[[0,6], [0,20]],
			's':[[0,8], [0,21]],
			'n':[[0,8], [0,21]],
			'p':[[0,10], [0,22]],
			'e':[[0,14], [0,16]],
			'a':[[4,15], [4,15]],
			'o':[[0,15], [6,13]],
			'f':[[0,12], [0,12]],
			'w':[[4,12], [4,12]],
			'd':[[0,13], [0,13]],
			'x':[[4,13], [4,13]] }
	s = 0

	// color modifiers
	if(sprite.color == 'neutral') {
		s = baseGlyphs[sprite.glyph][1][0] + 8*baseGlyphs[sprite.glyph][1][1]
	} else if((sprite.color == 'white')) {
		s = baseGlyphs[sprite.glyph][0][0] + 8*baseGlyphs[sprite.glyph][0][1]
	} else {
		s = baseGlyphs[sprite.glyph][0][0] + 8*baseGlyphs[sprite.glyph][0][1] + 2
	}

	// rotation modifiers
	if(sprite.rot > 3) { // 45 deg are not yet supported
		sprite.rot = sprite.rot % 4
		if(0 == sprite.rot) sprite.rot = 1
	}
	if(-1 != rot4.indexOf(sprite.glyph)) {
		if(sprite.color == 'neutral') {
			s += 2*sprite.rot
		} else {
			s += 4*sprite.rot
		}
	} else if(-1 != rot2.indexOf(sprite.glyph)) {
		if(sprite.color == 'neutral') {
			s += 2*(sprite.rot % 2)
		} else {
			s += 4*(sprite.rot % 2)
		}
	} // and rot1 cant be rotated

	// bg modifier
	s += color

	ABC = 'ABCDEFGHIJKLMNOPQRSTUVW'
	spriteHtml = '<div class="cp cp' + ABC.charAt(s % 8) + ABC.charAt(s / 8) + '">'

	// boxed
	if(sprite.border) spriteHtml += '<div class="boxed"></div>'

	return spriteHtml + '</div>'

}

function getCurrentSpecs() {
	var specs = []
	for(spec in FAIRYSPECS) {
		if(document.getElementById('spec' + spec).checked) specs.push(spec)
	}
	return specs
}

function getCurrentPiece() {
	var p = selectedPiece.charAt(1)
	if(selectedPiece.charAt(0) == 'n') p = '!' + p
	else if(selectedPiece.charAt(0) == 'b') p = p.toLowerCase()
	else p = p.toUpperCase()
	
	if(getCurrentSpecs().length > 0) p = 'b' + p
	p = p + selectedRotation

	return p
}

function updatePickerPreview() {
	document.getElementById('pickerPreview').innerHTML = xfen2spritedecl(getCurrentPiece(), 0) + '<div style="clear:both;"></div>'
}

/**************************************
	DOM
***************************************/


function createWidget() {
	var e = document.getElementById('widget');
	e.innerHTML = board.toGc(true, []); // global var boarvar d
	for(i = 0; i < 64; i++) {
		e = document.getElementById('s' + i);
		e.onclick = function() {
			var at = parseInt(this.id.slice(1));
			var bg = ((at % 8) + Math.floor(at/8)) % 2;
			curPiece = getCurrentPiece()
			if(board.board[at].name == curPiece) {
				board.drop(at);
				this.innerHTML = xfen2spritedecl('', bg)
			} else {
				board.add(curPiece, at, getCurrentSpecs());
				this.innerHTML = xfen2spritedecl(curPiece, bg)		
			}
			document.getElementById('fen').value = board.toFen();
			updatePcsCount()
			return false;			
		}
	}
	var buttons = [	'bwk', 'bbk', 'bnk',
			'bwq', 'bbq', 'bnq',
			'bwr', 'bbr', 'bnr',
			'bwb', 'bbb', 'bnb',
			'bwn', 'bbn', 'bnn',
			'bwp', 'bbp', 'bnp',
			'bwe', 'bbe', 'bne',
			'bwo', 'bbo', 'bno',
			'bwf', 'bbf',
			'bwa', 'bba'	]
	for(var i = 0; i < buttons.length; i++) {
		e = document.getElementById(buttons[i]);
		e.style.border = (buttons[i].slice(1) == selectedPiece)?
			'1px solid highlight': '1px solid white';
		e.onclick = function() {
			document.getElementById('b' + selectedPiece).style.border = '1px solid white';
			selectedPiece = this.id.slice(1);
			this.style.border = '1px solid highlight';
			updatePickerPreview();
			return false;			
		}
	}
	document.getElementById('fen').value = board.toFen();
	updatePcsCount();
}

function init() {
	createWidget();
	if(!document.location.hash) {
		showItem('SearchHelp');
	}
	setInterval('trackHistory()', 200);
	//loadStipulations();
}

function createHtml(problem) {
	if(problem.author == '')
		problem.author = '&nbsp;'

	var source_extended = problem.source
	if(problem.date) {
		if(/[a-z0-9]$/i.test(source_extended)) source_extended += ', ' + problem.date;
		else source_extended += ' ' + problem.date;
	}
	if(problem['source-id']) {
		source_extended += source_extended? ' (' + problem['source-id'] + ')':
			'(' + problem['source-id'] + ')';
	}
	if(problem.distinction) {
		source_extended += source_extended? '<br/>' +
			problem.distinction: problem.distinction;
	}
	source_extended = source_extended.replace(/([0-9])((st)|(nd)|(rd)|(th))/i, '$1<sup>$2</sup>')
	if(source_extended == '')
		source_extended = '&nbsp;' 
	var html = '<div class="problem">';
	html += '<h2><a target="_blank" href="?id=' + problem.id + '">' + problem.id + '</a>. ' + problem.author + '</h2>';
	html += source_extended;
	auxBoard.fromFen(problem.fen);
	html += '<div class="pWrapper"><table><tr><td class="bordered" colspan="3">' + auxBoard.toGc(false, []) +
		'</td></tr><tr><td colspan="3"><input class="feninp" value="' + problem.fen +
		'"/></td></tr><tr><td valign="top" align="left">';
	html += problem.stipulation + '</td>';
	extra = '';
	if(problem.options != '') {
		extra = problem.options + '<br/>';
	}
	if(problem.twins.length != 0) {
		for(var i = 0; i < problem.twins.length; i++) {
			extra += problem.twins[i].twin_id + ') ' + problem.twins[i].display + '<br/>';
		}
	}
	if(extra == '') {
		extra = '&nbsp;';
	}
	html += '<td align="center">' + extra + '</td>';
	html += '<td valign="top" align="right">' + auxBoard.piecesCount() + '</td></tr></table></div>';
	html += '</div>';
	return html;
}

function createPagesLinks(pageSize, totalMatches) {
	var html = '<div style="clear:both">';
	
	var totalPages = Math.floor(totalMatches/pageSize);
	if((totalMatches == 0) || (totalMatches % pageSize != 0))
		totalPages++;

	if(curPage > 1) { // curPage is a global var
		html += createPageLink(1, '&lt;&lt;');	
	}
	if(curPage > 2) {
		html += createPageLink(curPage - 1, '&lt;');	
	}
	html += "Showing page <strong>" + curPage + '</strong> of <strong>' + totalPages + '</strong> ';
	if(curPage < totalPages - 1) {
		html += createPageLink(curPage + 1, '&gt;');	
	}
	if(curPage < totalPages) {
		html += createPageLink(totalPages, '&gt;&gt;');	
	}
	
	html += '</div>';
	return html;
}

function createPageLink(pageNo, caption) {
//	return '<a href="#" class="navLink" onClick="return gotoSearchPage(' + pageNo + ')">' + caption + '</a>&nbsp;';
	return '<input type="button" onClick="return gotoSearchPage(' + pageNo + ')" value="' + caption + '">&nbsp;';
}

function onFenChange() {
	board.fromFen(document.getElementById('fen').value);
	createWidget();
}

function resetForm() {
	document.getElementById('stipulation').value = '';
	document.getElementById('author').value = '';
	document.getElementById('source').value = '';
	document.getElementById('material').checked = false;
	document.getElementById('pieces_lo').value = '';
	document.getElementById('pieces_hi').value = '';
	document.getElementById('date_lo').value = '';
	document.getElementById('date_hi').value = '';
	for(id in keywords_reversed)
		document.getElementById('keyword' + id).checked = false;
	document.getElementById('keywordsList').innerHTML = 'None';
}

function showItem(name) {
	var tabs = {'About':'', 'Results':'', 'SearchSplash':'', 'Tch':'', 'Download':'', 'SearchHelp':'', 'Wiki':'', 'RecentChanges':''};
	if(!(name in tabs)) {
		name = 'SearchHelp';
	}	
	for(tab in tabs) {
		document.getElementById('content' + tab).style.display = (tab == name)? 'block': 'none';
		menuItem = document.getElementById('menu' + tab)
		if(menuItem) {
			menuItem.className = (tab == name)? 'menuItemSelected': 'menuItemDeselected';
		}
	}
	document.location.hash = '#' + name;
	curHash = document.location.hash;

	document.getElementById('piecePicker').style.visibility = 'hidden';

	return false;
}

function trackHistory() {
	if(curHash != document.location.hash) {
		showItem(document.location.hash.substring(1, document.location.hash.length));
	}
}

function toggleKeywords() {
	ss = document.getElementById('keywords').style;
	if(ss.visibility == 'visible') {
		ss.visibility = 'hidden';
		ss.display = 'none';
		updateKeywordsList();
	} else {
		ss.display = 'block';
		ss.visibility = 'visible';
	}
}

function updateKeywordsList() {
	selected = Array();
	for(id in keywords_reversed) {
		if(document.getElementById('keyword' + id).checked) {
			selected.push(keywords_reversed[id]);
		}
	}
	document.getElementById('keywordsList').innerHTML = 
		(selected.length == 0) ? 'None': selected.join(', ');
}

function showTchInfo(tch_info) {
	var html = '';
	if(tch_info) {
		html += "<strong>Solution:</strong>\n";
	} else {
		return;
	}
	html += tch_info['solution_vt']? tch_info['solution_vt'] : '';
	num_tries_skipped = getSubstrCount(tch_info['solution_vut'], '??');
	if(num_tries_skipped > 0) {
		html += '<a href="#" onclick="toggleDiv(\'vut\'); return false;">';
		html += num_tries_skipped + ' ' + ((num_tries_skipped == 1)? 'try': 'tries') + ' skipped</a>';
		html += '<div id="vut">' + tch_info['solution_vut'] + "</div>\n\n"
	}
	html += tch_info['solution_k']? tch_info['solution_k'] : '';
	if(tch_info['keywords'].length) {
		html += "\n\n<strong>Keywords:</strong>\n";
		for(i in tch_info['keywords']) {
			html += '&middot;&nbsp;' + tch_info['keywords'][i] + "\n";
		}
	}
	document.write(html);
}

function toggleDiv(id) {
	ss = document.getElementById(id).style;
	if(ss.visibility == 'visible') {
		ss.visibility = 'hidden';
		ss.display = 'none';
	} else {
		ss.display = 'block';
		ss.visibility = 'visible';
	}
}

function selectStipulation(str) {
	document.getElementById('stipulation').value = str;
	toggleDiv('stipulations');
	return false;
}

function identLeft(text) {
	lines = text.split("\n");
	for(i = 0; i < lines.length; i++) 
		lines[i] = stripWs(stripWs(lines[i]));
	return lines.join("\n");
}

function stripWs(line) {
	if((line.length > 0) && (' ' == line[0]))
		return line.substr(1);
	return line;
}

function identRight(text) {
	lines = text.split("\n");
	for(i = 0; i < lines.length; i++) 
		lines[i] = '  ' + lines[i];
	return lines.join("\n");
}

function identSelection(dir) {
	el = document.getElementById('yamlText');
	el.focus();
	var identFunc;
	if(dir > 0)
		identFunc = identRight;
	else
		identFunc = identLeft;
	
	if(document.selection) {
		var s = document.selection.createRange(); 
		if(s.text)
		{
			var idented = identFunc(s.text);
			var len_diff = idented.length - s.text.length;
			s.text = identFunc(s.text);
			range = s.createRange();
			range.moveEnd("character", len_diff);
			s.select();
		}
	}
	else if(typeof(el.selectionStart)=="number") {
		var s = el.selectionStart;
		var e = el.selectionEnd;
		if (s != e) {
			var idented = identFunc(el.value.substr(s, e - s));
			el.value = el.value.substr(0, s) + idented + el.value.substr(e);
			el.setSelectionRange(s, s + idented.length);
		}
	}
}

function insertAtCursor(text) {

	el = document.getElementById('yamlText');
	//IE
	if (document.selection) {
		el.focus();
		sel = document.selection.createRange();
		sel.text = text;
	}
	//MOZILLA
	else if (el.selectionStart || el.selectionStart == '0') {
		var startPos = el.selectionStart;
		var endPos = el.selectionEnd;
		el.value = el.value.substring(0, startPos) + text
			+ el.value.substring(endPos, el.value.length);
	} else {
		el.value += myValue;
	}
	myMenu.hide()
}

/**************************************
	AJAX 
***************************************/
function loadStipulations() {
	document.getElementById('stipulation').options[0].text = "loading ...";
	agent.call('', 'ajax_get_stipulations', 'loadStipulationsCallback');
}

function loadStipulationsCallback(stipulations) {	
	var e = document.getElementById('stipulation');
	e.options[0].text = '';
	for(var i = 0; i < stipulations.length; i++) {
		e.options[e.options.length] = new Option(stipulations[i].stipulation + ' (' + stipulations[i].cnt + ' problems)',
			stipulations[i].stipulation);
	}
	document.getElementById('btnSearch').disabled = false;

}

function gotoSearchPage(page) {
	curPage = page;
	document.getElementById('btnSearch').disabled = true;
	showItem('SearchSplash');
	var stipulation 		= document.getElementById('stipulation');
	var author 				= document.getElementById('author');
	var source 				= document.getElementById('source');
	var date_lo 			= document.getElementById('date_lo');
	var date_hi 			= document.getElementById('date_hi');
	var fen 				= document.getElementById('fen');
	var material 			= document.getElementById('material');
	var pieces_lo 			= document.getElementById('pieces_lo');
	var pieces_hi 			= document.getElementById('pieces_hi');
	var keywords_id 		= Array();
	for(id in keywords_reversed) {
		if(document.getElementById('keyword' + id).checked) {
			keywords_id.push(id);
		}
	}

	stipHack = stipulation.value.replace('+', 'plussign')

	agent.call('', 'ajax_search', 'gotoSearchPageCallback',
		stipHack,
		author.value,
		source.value,
		fen.value,
		date_lo.value,
		date_hi.value,
		material.checked? 1: 0,
		pieces_lo.value,
		pieces_hi.value,
		keywords_id,
		page
	);
	return false;
}
function gotoSearchPageCallback(results) {
	var html = ''; 
	html += '<h2>' + results[0] + ' match(es)</h2>';
	pagesLinks = createPagesLinks(pageSize, results[0]);
	html += pagesLinks;
	var brd = new Board();
	for(var i = 0; i < results[1].length; i++) {
		html += createHtml(results[1][i]);
	}
	if(results[1].length > 0) {
		html += pagesLinks;
	}
	document.getElementById('contentResults').innerHTML = html;
	showItem('Results');
	document.getElementById('btnSearch').disabled = false;
	
}


function updatePcsCount() {
	e = document.getElementById('pcsCount')
	if(e) e.innerHTML = board.piecesCount();
}

/**************************************
	globals
***************************************/
function getSubstrCount(haystack, needle) {
	var c = 0;
	for (var i = 0; i < haystack.length; i++) {
		if (needle == haystack.substr(i, needle.length))
			c++;
	}
	return c;
}



var board 			= new Board();
var auxBoard 		= new Board();
var selectedPiece 	= 'bk';
var selectedRotation 	= '';

var PIECES			= 'KkQqRrBbNnPp';
//var MPIECES 		= new Array('KLQWRTBVNMPO', 'klqwrtbvnmpo');
var MPIECES 		= new Array('ACDEFGHIJSUZ', 'klqwrtbvnmpo');
var map 			= 'AkDqFrHbJnUp';
//var MBLANKS 		= "+ ";
//var MBLANKS 		= "+*";
var MBLANKS 		= "XY";
var curPage 		= 1;
var pageSize		= 10;
var curHash		= '';

