/**
 * Copyright 2009, OpenScriptures.org
 * GPL 3 License: http://www.gnu.org/licenses/gpl.html
 * $Id: main.js 167 2009-03-03 16:53:03Z WestonRuter@gmail.com $
 */

$(function(){
	var $lists = $('#delList, #insList');
	
	//Disable the submit button if one of the lists is empty or if there are some checkboxes that aren't checked
	function checkFormState(){
		if($lists.filter(':empty').length || $lists.filter(':has(:checked)').length < 2){
			$('form button').attr('disabled', 'disabled'); //.attr('title', 'There must be at least one manuscript in both the insertion list and the deletion list.');
			return false;
		}
		else {
			$('form button').removeAttr('disabled'); //.removeAttr('title');
			return true;
		}
	}

	//When clicking the introduction link, add the target class to make it appear
	$('#introduction p:first-child a').click(function(e){
		$('#introduction').addClass('target');
		$(window).resize(); //re-calculate the position of the fixed headers
		e.preventDefault();
	});
	$('legend > a').click(function(e){
		$(this).parent().text($(this).text());
		$('#configuration').removeClass('collapsed');
		$(window).resize(); //re-calculate the position of the fixed headers
		$('#passage').select();
		e.preventDefault();
	}).focus();
	
	//Before submitting the form, check first to see if it is valid
	$('form:first').submit(function(e){
		if(!checkFormState()){
			e.preventDefault();
			return;
		}
		$('form button').text('Please wait... request may take a few seconds')
		                .attr('disabled', 'disabled')
						.addClass('working')
						.blur();
		//registerManuscriptOrder();
	});
	
	function makeManuscriptsRearrangeable(){
	
		//Whenever a checkbox is clicked, re-check the form state
		$lists.find('li input[type=checkbox]').click(function(){
			checkFormState();
		}).removeAttr('disabled');
	
		//Make each of the two lists sortable, that is, re-orderable
		var dropDest = null;
		$lists.sortable({
			axis: "y",
			cursor: "move",
			stop:function(ev, ui){
				if(dropDest){
					//Toggle the name according to the new container
					var checkbox = ui.item.find('input[type=checkbox]');
					checkbox.attr('name', (checkbox.attr('name') == 'del[]' ? 'ins[]' : 'del[]'))
					
					//Move the list item
					$(dropDest).append(ui.item);
					
					//Update the OL start for the second list
					$('#delList').attr('start', $('#insList li').length+1);
					
					//End dropping
					dropDest = null;
					checkFormState();
				}
			}
		});
		
		//Prevent clicking on label or checkbox from initiating sortable
		$lists.find('label, input').mousedown(function(e){
			e.stopPropagation();
		});
		
		//Allow items in either list to be placed in the other
		var onDrop = function(ev, ui){
			dropDest = ev.target;
			checkFormState();
		};
		$('#insList').droppable({
			accept:'#delList li',
			hoverClass:'droppable-hover',
			//activeClass:'droppable-active',
			drop:onDrop
		});
		$('#delList').droppable({
			accept:'#insList li',
			hoverClass:'droppable-hover',
			//activeClass:'droppable-active',
			drop:onDrop
		});
	}
	
	//If request wasn't using default MSS, then immediately make the MSS rearrangeable
	if(!$('#use-default-mss').length){ //[checked]
		makeManuscriptsRearrangeable();
	}
	//Otherwise, only make them arrangeable when the use-default-mss checkbox is checked
	else {
		//Make sure that all MSS checked and disabled
		$lists.find('li input[type=checkbox]')
			.attr('checked', 'checked')
			.attr("disabled","disabled");
		
		//When clicking the checkbox, delete this form control, make sure it is enabled and checked
		$('#use-default-mss')
			.click(function(){
				this.disabled = true;
				if(!this.checked){
					$(this).closest('p').hide('slow', function(){
						$(this).remove();
					});
					makeManuscriptsRearrangeable();
				}
			})
			.removeAttr('disabled')[0].checked = true;
	}

	/** Allow conventional passages to be used instead of osisRefs */
	//if(window.parseReference){
	//	$('#osisref').parent().find('label').text('Passage: ');
	//	$('#osisref + samp').text('e.g. John 3:16, Rom 5:5-8, Mt 1-2');
	//	$('#osisref').removeAttr('name');
	//	$('form:first')
	//		.append('<input type="hidden" id="bg-osisref" name="osisref" />')
	//		.submit(function(e){
	//			$('#bg-osisref').val( parseReference($('#osisref').val()) );
	//		});
	//}
	
	
	// reinstate the user's order upon last form submission
	//restoreManuscriptOrder();
	
	//TEMP: Make sure that only two manuscripts are selected
	
	//var allChecked = $('form ol input:checked').get();
	//while(allChecked.length > 2){
	//	allChecked[0].checked = false;
	//	allChecked.shift();
	//}
	//$('form ol input[type=checkbox]').click(function(e){
	//	if(this.checked){
	//		while(allChecked.length >= 2){
	//			allChecked[0].checked = false;
	//			allChecked.shift();
	//		}
	//		allChecked.push(this);
	//	}
	//	else {
	//		var that = this;
	//		allChecked = $(allChecked).filter(function(){
	//			return this != that;
	//		}).get();
	//	}
	//});
	
	var isParallel = !!$('#parallel').length;
	var isUnified = !!$('#unified').length;
	
	//Undo what was done with makeHeadersFixed()
	var allowFixedHeaders = true;//!(/MSIE [1-7]\b/.test(navigator.userAgent)); //.indexOf('MSIE') == -1);
	var $header = $('#parallel thead, #unified header');
	window.removeFixedHeaders = function removeFixedHeaders(persist){
		if(persist)
			allowFixedHeaders = false;
		
		//For parallel view
		if(isParallel){
			$header.find('h2').each(function(){
				$(this).closest('th').css('height', 'auto');
				$(this).css('height','auto');
			});
			$header.removeClass('fixed');
		}
		
		//For unified view
		if(isUnified){
			$('#unified').each(function(){
				$(this).css('paddingTop', 0);
			});
			$header.removeClass('fixed');
		}
	}
	
	window.makeHeadersFixed = function makeHeadersFixed(force){
		if(force)
			allowFixedHeaders = true;
		if(!allowFixedHeaders || $header.hasClass('fixed'))
			return;
		//removeFixedHeaders();
		
		//Set the headers for the parallel view
		if(isParallel){
			var maxHeadHeight = 0;
			$header.find('h2').each(function(){
				maxHeadHeight = Math.max(maxHeadHeight, this.parentNode.offsetHeight);
			}).each(function(){
				$(this).css('height', maxHeadHeight); //Set the exact widths of the h2s so that when fixed position they'll remain the proper width
				$(this).closest('th').css('height', maxHeadHeight); //Persist thead height
			});
			$header.addClass('fixed');
		}
		
		//Set the headers for the unified view
		if(isUnified){
			$('#unified').css('paddingTop', $header[0].offsetHeight);
			$header.addClass('fixed');
		}
	}
	
	//Store the offset from the top of the page to the content, and whenever the page is resized, recalculate
	var contentOffsetTop = $('#parallel, #unified').offset().top;
	$(window).resize(function(){
		contentOffsetTop = $('#parallel, #unified').offset().top;
		removeFixedHeaders();
		$(window).scroll();
	});
	
	//When scrolling down past the beginning of the table header, then make the thead.fixed
	if($('#parallel, #unified').length){
		$(window).scroll(function(e){
			if($(document).scrollTop() > contentOffsetTop)
				makeHeadersFixed();
			else
				removeFixedHeaders();
		}).scroll();
	}
	
	
	
	
	
	
	/**
	 * Find the transposed words
	 * In the unified view and in within each side of the parallel view, find potentially transposed words.
	 */
	var transposedLookahead = 10;
	
	$('#unified p *[id]:not(span), #parallel p *[id]:not(span)').each(function(){
		var thisToken = this;
		var nextToken = $(thisToken).next()[0]; //next() instead of nextAll('[id]:first') for performance reasons
		var lookaheadRemaining = transposedLookahead;
		while(nextToken && lookaheadRemaining > 0){
			if(nextToken.id){
				//The following token can be determined to be the transposition of the first if it doesn't have the same node name (i.e. a transposition pair
				//  may be an INS and DEL, or INS and B, but not INS and INS), and if it not a regular word (a SPAN), and if it has the same normalized value
				if(nextToken.nodeName.toLowerCase() != 'span' &&
				   nextToken.nodeName != thisToken.nodeName &&
				   tokenInfo[thisToken.id].u/*normalizedToken*/ == tokenInfo[nextToken.id].u)
				{
					//Mark thisToken as being transposed
					if(!tokenInfo[thisToken.id].inlineTranspositions)
						tokenInfo[thisToken.id].inlineTranspositions = [];
					tokenInfo[thisToken.id].inlineTranspositions.push(nextToken);
					
					//Mark nextToken as being transposed
					if(!tokenInfo[nextToken.id].inlineTranspositions)
						tokenInfo[nextToken.id].inlineTranspositions = [];
					tokenInfo[nextToken.id].inlineTranspositions.push(thisToken);
					
					if(isUnified && $(thisToken).is('ins,del') && $(nextToken).is('ins,del')){
						$(thisToken).addClass('translateralTransposed');
						$(nextToken).addClass('translateralTransposed');
					}
					else {
						$(thisToken).addClass('transposed');
						$(nextToken).addClass('transposed');
					}
					
					break;
				}
				lookaheadRemaining--;
			}
			nextToken = $(nextToken).next()[0]
		}
	});
	
	/**
	 * For the parallel view, compare the tokens on either side to determine potential transpositions. For each suspect token
	 * check the subsequent transposedLookahead tokens to see if there is a match
	 **/
	var transposedLookbehind = 5;
	
	if(isParallel){
		
		
		/*var $insDiffTokens = */
		$('#parallel ins').each(function(){
			//var otherSideIdPrefix    = (this.id.substr(0,1)  == 'i' ? 'd'   : 'i'  );
			//var otherSideElementName = (otherSideIdPrefix    == 'i' ? 'del' : 'ins');
			var thisToken = this;
			
			//Find the closest previous token which corresponds to a token on the other side; keep track of how far back the
			//  matched token was, so that we can make sure that we look ahead from the matched word (maxBacktrackPos + transposedLookahead) places
			var id;
			var backtrackPos = 0, maxBacktrackPos = 0;
			var $prevToken = $(thisToken).prev();
			var $correspondingDelToken, $delToken;
			while($prevToken.length && backtrackPos < transposedLookbehind){
				//If the previous element has an id, and if it is not an INS element
				if((id = $prevToken.attr('id')) && $prevToken[0].nodeName != thisToken.nodeName){
					//Check to see if there is a corresponding UMS token on the other side
					var $delToken = $('#d' + id.substr(1)); //both sides have ids consisting of (d|i) + umsToken
					if($delToken.length){
						//If there is a corresponding token, save it as the corresponding token on the del side
						$correspondingDelToken = $delToken;
						maxBacktrackPos = backtrackPos;
					}
					//backtrackCount < transposedLookbehind && 
				}
				backtrackPos++;
				$prevToken = $prevToken.prev();
			}
			
			//Now walk the tree inspecting all corresponding elements to see if they match
			if($correspondingDelToken && $correspondingDelToken.length){
				var nextToken = $correspondingDelToken[0]; //next() instead of nextAll('[id]:first') for performance reasons
				var lookaheadRemaining = maxBacktrackPos + transposedLookahead;
				
				while(nextToken && lookaheadRemaining > 0){
					if(nextToken.id){
						//The following token can be determined to be the transposition of the INS if is a DEL and if it has the same normalized value
						if(nextToken.nodeName.toLowerCase() == 'del' &&
						   tokenInfo[thisToken.id].u/*normalizedToken*/ == tokenInfo[nextToken.id].u)
						{
							//Mark thisToken as being transposed
							if(!tokenInfo[thisToken.id].translateralTranspositions)
								tokenInfo[thisToken.id].translateralTranspositions = [];
							tokenInfo[thisToken.id].translateralTranspositions.push(nextToken);
							$(thisToken).addClass('translateralTransposed');
							
							//Mark nextToken as being transposed
							if(!tokenInfo[nextToken.id].translateralTranspositions)
								tokenInfo[nextToken.id].translateralTranspositions = [];
							tokenInfo[nextToken.id].translateralTranspositions.push(thisToken);
							$(nextToken).addClass('translateralTransposed');
							
							break;
						}
						lookaheadRemaining--;
					}
					nextToken = $(nextToken).next()[0]
				}
			}
			
		});
	}
	
	//Highlight the corresponding equivalent tokens between the two manuscripts
	//$($('#parallel').length ? '#parallel p span, #parallel p del, #parallel p ins' : '#unified  p span, #unified  p del, #unified  p ins')
	$($('#parallel').length ? '#parallel p *[id]' : '#unified  p *[id]') 
		.live('mouseover', function(e){
			//Stop if already highlighted (prevents infinite recursion)
			if($(this).hasClass('highlight'))
				return;
			$(this).addClass('highlight');
			
			//Highlight equivalent words
			if(this.id.substr(0,1) != 't'){
				var otherId = (this.id.substr(0, 1) == 'i' ? 'd' : 'i') + this.id.substr(1);
				$('#' + otherId).mouseover();
			}
			
			//Highlight inline transposed words
			if(tokenInfo[this.id].inlineTranspositions){
				$(tokenInfo[this.id].inlineTranspositions).each(function(){
					//$(this).mouseover(); //Don't do this because it will also highlight the token's works
					$(this).addClass('transposedHighlight');
				});
			}
			
			//Highlight translateral transposed words (first in INS side, second in DEL side)
			if(tokenInfo[this.id].translateralTranspositions){
				$(tokenInfo[this.id].translateralTranspositions).each(function(){
					$(this).mouseover();
				});
			}
			
			//Highlight the titles of this unique word's work 
			if(tokenInfo[this.id] && tokenInfo[this.id].w){
				$(tokenInfo[this.id].w).each(function(){
					$('#name' + this).addClass('highlight');
				});
			}
			
			//Gather token parsings for display
			if(window.tokenInfo[this.id] && !window.tokenInfo[this.id].p){
				console.warn(this, window.tokenInfo[this.id])
				return;
			}
			if(!this.title && window.tokenInfo[this.id] && tokenInfo[this.id].p.length){
				var parsingParts = [];
				var strongsObtained = {};
				$(tokenInfo[this.id].p).each(function(){
					var parse = [];
					if(this.p/*parse*/)
						parse.push(this.p);
					if(this.l/*lemma*/)
						parse.push(this.l);
					if(this.s/*strongs*/){
						if(!window.strongsGreekDictionary){
							parse.push(this.s); //just include the strong's numbers if definitions aren't available
						}
						else {
							$(this.s.split(/;/)).each(function(){
								if(strongsObtained[this])
									return;
								parse.push(this);
								var entry = strongsGreekDictionary[this];
								if(entry){
									parse.push(' ' + entry.lemma);
									if(entry.strongs_def)
										parse.push(' ' + entry.strongs_def);
									if(entry.kjv_def)
										parse.push(' ' + entry.kjv_def);
									if(entry.derivation)
										parse.push(' ' + entry.derivation);
								}
								strongsObtained[this] = true;
							});
						}
						//parse.push(this.strongs);
					}
					parsingParts.push(parse.join(' '));
				});
				
				this.title = parsingParts.join('; ');
			}
		})
		.live('mouseout', function(){
			//Stop if already highlighted (prevents infinite recursion)
			if(!$(this).hasClass('highlight'))
				return;
			$(this).removeClass('highlight');
			
			//Un-highlight equivalent words
			if(this.id.substr(0,1) != 't'){
				var otherId = (this.id.substr(0, 1) == 'i' ? 'd' : 'i') + this.id.substr(1);
				$('#' + otherId).mouseout();
			}
			
			//Unhighlight inline transposed words
			if(tokenInfo[this.id].inlineTranspositions){
				$(tokenInfo[this.id].inlineTranspositions).each(function(){
					//$(this).mouseout();
					$(this).removeClass('transposedHighlight');
				});
			}
			
			//Highlight translateral transposed words (first in INS side, second in DEL side)
			if(tokenInfo[this.id].translateralTranspositions){
				$(tokenInfo[this.id].translateralTranspositions).each(function(){
					$(this).mouseout();
				});
			}
			
			//Un-highlight the titles of this unique word's work 
			if(tokenInfo[this.id] && tokenInfo[this.id].w){
				$(tokenInfo[this.id].w).each(function(){
					$('#name' + this).removeClass('highlight');
				});
			}
		});
	
	$(document.documentElement).addClass('loaded');
	$('#loadingNotice').attr('hidden', 'hidden');
	checkFormState();
});



////Persistant list code from Sortable Lists Using jQuery UI <http://www.shopdev.co.uk/blog/sortable-lists-using-jquery-ui/>
//var $manuscriptOL;
//var manuscriptListSelector = "form ol";
//var manuscriptOrderCookieName = "manuscriptOrder";
//
//// write the list order to a cookie
//function registerManuscriptOrder() {
//	$.cookie(manuscriptOrderCookieName, $manuscriptOL.sortable("toArray"), { expires: 7, path: "/" });
//}
//
//// restore the list order from a cookie
//function restoreManuscriptOrder() {
//	var list = $manuscriptOL;
//	if (list == null) return;
//	
//	// fetch the cookie value (saved order)
//	var cookie = $.cookie(manuscriptOrderCookieName);
//	if (!cookie) return;
//	
//	// make array from saved order
//	var IDs = cookie.split(",");
//	
//	// fetch current order
//	var items = list.sortable("toArray");
//	
//	// make array from current order
//	var rebuild = new Array();
//	for ( var v=0, len=items.length; v<len; v++ ){
//		rebuild[items[v]] = items[v];
//	}
//	
//	for (var i = 0, n = IDs.length; i < n; i++) {
//		
//		// item id from saved order
//		var itemID = IDs[i];
//		
//		if (itemID in rebuild) {
//		
//			// select item id from current order
//			var item = rebuild[itemID];
//			
//			// select the item according to current order
//			var child = $manuscriptOL.children("#" + item);
//			
//			// select the item according to the saved order
//			var savedOrd = $manuscriptOL.children("#" + itemID);
//			
//			// remove all the items
//			child.remove();
//			
//			// add the items in turn according to saved order
//			// we need to filter here since the "ui-sortable"
//			// class is applied to all ul elements and we
//			// only want the very first!  You can modify this
//			// to support multiple lists - not tested!
//			$manuscriptOL.filter(":first").append(savedOrd);
//		}
//	}
//}
