﻿if (!window.console)
	window.console = { log: function() { } };

if (!Array.indexOf) {
	Array.prototype.indexOf = function(obj) {
		for (var i = 0; i < this.length; i++) {
			if (this[i] == obj) {
				return i;
			}
		}
		return -1;
	}
}

$(document).ready(function() {

	bible = {};

	bible.Reader = {
		lang: 'G',

		dialog: null,

		init: function() {

			this.dialog = $('#dialog-container');
			this.dialogText = $('#dialog-text');
			this.dialogHeader = $('#dialog-header');

			// reference helper
			$('#reference').addClass('firstTime').click(function(e) { $(this).removeClass('firstTime'); });
			$('#go').click(function(e) { bible.Reader.getReference(); });


			// font choices

			// add options
			var options = '';
			for (var size = 8; size <= 38; size += 2) {
				options += '<option value="' + size + '">' + size + 'px</option>';
			}
			$('select.font-size').html(options);
			$('#font-size-hebrew').val(20);
			$('#font-size-greek').val(16);
			
			options='';
			for (var size = 100; size <= 500; size += 20) {
				options += '<option value="' + size + '">' + size + '%</option>';
			}
			$('select.font-lineheight').html(options);
			$('select.font-lineheight').val('200');
			
			// 
			

			$('head').append('<style id="injectedFontCss" type="text/css"></style>');
			this.updateFonts();
			$('.font-family').keyup(function(e) { bible.Reader.updateFonts(); });
			$('.font-size, .font-lineheight').change(function(e) { bible.Reader.updateFonts(); });

			// setup verse change		
			$('#reference').keyup(function(e) {
				if (e.keyCode == 13) {
					e.preventDefault();
					bible.Reader.getReference();
				}
			});

			// setup word count threshold
			$('#word-count-threshold, #show-parsing, #show-pos, #show-frequency').change(function(f) {
				bible.Reader.buildLexicalInfo();
			});

			// setup parts of speech
			$('select.pos-rule')
			.change(function(l) {
				bible.Reader.updateStyles();
			})
			.html('<option value="">--none--</option>'
					+ '<option value="c:#910000">Red</option>'
					+ '<option value="h:#ffcccc">Red (bg)</option>'
					+ '<option value="c:#ffcc33">Orange</option>'
					+ '<option value="h:#ffcc33">Orange (bg)</option>'
					+ '<option value="c:#eeee66">Yellow</option>'
					+ '<option value="h:#eeee66">Yellow (bg)</option>'
					+ '<option value="c:#319D2D">Green</option>'
					+ '<option value="h:#aaff55">Green (bg)</option>'
					+ '<option value="c:#0000ff">Blue</option>'
					+ '<option value="h:#55AAFF">Blue (bg)</option>'
					+ '<option value="c:#AA7FFF">Purple</option>'
					+ '<option value="h:#AA7FFF">Purple (bg)</option>'
					+ '<option value="u">Underline</option>'
					+ '<option value="b">Bold</option>'
					+ '<option value="i">Italic</option>'



					);

		},

		updateFonts: function() {
			var cssText =
				'span.gk { font-family: ' + $('#font-family-greek').val() + '; font-size: ' + $('#font-size-greek').val() + '; } div.greek { line-height: ' + $('#font-lineheight-greek').val() + '%;}' +
				'span.hb { font-family: ' + $('#font-family-hebrew').val() + '; font-size: ' + $('#font-size-hebrew').val() + ';} div.hebrew { line-height: ' + $('#font-lineheight-hebrew').val() + '%;}';

			console.log(cssText);
			if ($.browser.msie) {
				$('#injectedFontCss').remove();
				$('head').append('<style id="injectedFontCss" type="text/css">' + cssText + '</style>');
			} else {
				$('#injectedFontCss').html(cssText);
			}


		},

		wordOver: function(e) {
			if (!$('#show-popups').attr('checked'))
				return;

			// $(this).animate({backgroundColor: '#ffff00'}, 500);
			var o = $(this);
			o.css('color', '#666');


			var sn = o.attr('sn');
			if (!sn || parseInt(sn) < 1) return

			var pos = o.attr('pos')
			var inf = o.attr('inf');
			var d = bible.Reader.dialog;

			d.css('display', 'block');
			d.css('top', e.pageY + 5);
			d.css('left', e.pageX + 5);
			var dt = bible.Reader.dialogText;
			var dh = bible.Reader.dialogHeader;
			dh.html('');
			dt.html('loading...');

			//d.load('scraping/gbs/t-' + sn + '.html');
			//return;

			bible.Storage.getLexicalEntry(bible.Reader.lang + sn, function(data) {
				dh.html('<span class="lexical-form ' + ((bible.Reader.lang == 'G') ? 'gk' : 'hb') + '">' + data.LexicalForm + '</span> '
				+ '<span class="strongs">' + bible.Reader.lang + sn + '</span>');

				dt.html(
				'<span class="morphology">' + bible.Reader.getPartofSpeech(pos) + ', ' + bible.Reader.getMorphology(pos, inf) + '</span>'
				+ '<span class="gloss">usage: ' + data.KjvDefinition + '</span>'
				+ '<div class="outline-of-usage">' + data.OutlineOfUsage + '</dev>');
				/*
				var top = e.pageY+5;
				var left = e.pageX+5;
				var h = dt.height();
				var sTop = $(document).scrollTop();
				var vH= $(document).height();
	   
			console.log(top , h , vH);
	   
			if (top + h > vH) {
				top = (top + h) - vH;
				}
				
			d.css('top', top);
				d.css('left', left);
				*/
			});
		},

		wordOut: function(e) {
			bible.Reader.dialog.css('display', 'none');
			/*
			var o = $(this);
			var oOff = o.offset();
			var oW = o.width();
			var oH = o.height();	
		
		function mouseWithin(mX, mY, oX, oY, oW, oH) {
			console.log(mX, mY, oX, oY, oW, oH);
			console.log('-', (mX >= oX) , (mX <= oX + oW), (mY >= oY ), ( mY <= oY + oH) );
			
			return (mX >= oX && mX <= oX + oW &&
			mY >= oY && mY <= oY + oH );
			};
		
		setTimeout(function() {
			
			var dOff = bible.Reader.dialog.offset();
			var dW = bible.Reader.dialog.width();
			var dH = bible.Reader.dialog.height();
			
			if ( !(mouseWithin( e.pageX, e.pageY, oOff.left, oOff.top, oW, oH) || mouseWithin( e.pageX, e.pageY, dOff.left, dOff.top, dW, dH) ) ) {
			bible.Reader.dialog.css('display','none');	
			}			
			
		}, 250);
			*/

			// $(this).stop().css('background-color', '#ffffff');
			$(this).css('color', '');

		},




		getReference: function() {
			var ref = $('#reference').val();
			$('#bible-text').html('Loading...');
			$('#footnotes').html('');

			bible.Interface.getReference(ref, function(data) {
				bible.Storage.setRef(data.reference);
				$('#reference').val(data.reference);
				$('#bible-text').html(data.html);

				var book = parseInt(data.book);

				if (book > 0) {

					bible.Reader.lang = data.lang;

					// add verse hovers/highlight		
					//$('#bible-text span').hover(bible.Reader.wordOver, bible.Reader.wordOut);
					$('#bible-text span').mouseover(bible.Reader.wordOver);
					$('#bible-text span').mouseout(bible.Reader.wordOut);

					// text direction for greek and hebrew		
					if (bible.Reader.lang == 'H') {
						//if (book <= 39) { 
						$('#bible-text').removeClass('greek');
						$('#bible-text').addClass('hebrew');
						$('#bible-text').attr('dir','rtl');
					} else {
						$('#bible-text').removeClass('hebrew');
						$('#bible-text').addClass('greek');
						$('#bible-text').attr('dir','ltr');
					}

					bible.Reader.buildLexicalInfo();
				} else {
					$('#reference').val(ref);
					alert('Invalid reference. Try an alternate spelling.');
				}

			});
		},

		partsOfSpeech: {
			N: 'noun',
			A: 'adjective',
			T: 'article',
			V: 'verb',
			P: 'personal pronoun',
			R: 'relative pronoun',
			C: 'reciprocal pronoun',
			D: 'demonstrative pronoun',
			K: 'correlative pronoun',
			I: 'interrogative pronoun',
			X: 'indefinite pronoun',
			Q: 'correlative or interrogative pronoun',
			F: 'reflexive pronoun',
			S: 'possessive pronoun',
			ADV: 'adverb',
			CONJ: 'conjunction',
			COND: 'cond',
			PRT: 'particle',
			PREP: 'preposition',
			INJ: 'interjection',
			ARAM: 'aramaic',
			HEB: 'hebrew'
		},

		getPartofSpeech: function(pos) {
			var full = bible.Reader.partsOfSpeech[pos.toUpperCase()];

			return (full != null) ? full : '?';
		},

		nounCases: {
			'N': 'nominative',
			'V': 'vocative',
			'G': 'genitive',
			'D': 'dative',
			'A': 'accusative'
		},

		wordNumber: {
			'S': 'singular',
			'P': 'plural'
		},

		wordGender: {
			'M': 'masculine',
			'F': 'feminine',
			'N': 'neuter'
		},

		wordPerson: {
			'1': '1st',
			'2': '2nd',
			'3': '3rd'
		},

		verbTenses: {
			'P': 'present',
			'I': 'imperfect',
			'F': 'future',
			'2F': 'second future',
			'A': 'aorist',
			'2A': 'second aorist',
			'R': 'perfect',
			'2R': 'second perfect',
			'L': 'pluperfect',
			'2L': 'second pluperfect',
			'X': 'no tense stated'
		},

		verbVoices: {
			'A': 'active',
			'M': 'middle',
			'P': 'passive',
			'E': 'middle or passive',
			'D': 'middle deponent',
			'O': 'passive deponent',
			'N': 'middle or passive deponent',
			'Q': 'impersonal active',
			'X': 'no voice'
		},

		verbMoods: {
			'I': 'indicative',
			'S': 'subjunctive',
			'O': 'optative',
			'M': 'imperative',
			'N': 'infinitive',
			'P': 'participle',
			'R': 'imperative participle'
		},

		getMorphology: function(pos, info) {

			switch (pos.toUpperCase()) {
				case 'T':
				case 'N':
					var c = bible.Reader.nounCases[info.substring(0, 1)];
					var n = bible.Reader.wordNumber[info.substring(1, 2)];
					var g = bible.Reader.wordGender[info.substring(2, 3)];
					return c + ', ' + n + ', ' + ((g) ? g : '');
				case 'A':
					var c = bible.Reader.nounCases[info.substring(0, 1)];
					var n = bible.Reader.wordNumber[info.substring(1, 2)];
					return c + ', ' + n;
				case 'V':
					var t = '';
					var rem = ''
					if (info.substring(0, 1) == '2') {
						t = bible.Reader.verbTenses[info.substring(0, 2)];
						rem = info.substring(2);
					} else {
						t = bible.Reader.verbTenses[info.substring(0, 1)];
						rem = info.substring(1);
					}
					var v = bible.Reader.verbVoices[rem.substring(0, 1)];
					var m = bible.Reader.verbMoods[rem.substring(1, 2)];

					if (rem.length == 2) {
						return info + ': ' + t + ', ' + v + ', ' + m;
					} else if (rem.length == 5) {
						var p = bible.Reader.wordPerson[rem.substring(3, 4)];
						var n = bible.Reader.wordNumber[rem.substring(4, 5)];
						return t + ', ' + v + ', ' + m + ', ' + p + ', ' + n;

					} else if (rem.length == 6) {
						var c = bible.Reader.nounCases[rem.substring(3, 4)];
						var n = bible.Reader.wordNumber[rem.substring(4, 5)];
						var g = bible.Reader.wordGender[rem.substring(5, 6)];

						return t + ', ' + v + ', ' + m + ', ' + c + ', ' + n + ', ' + g;
					}

					//m = bible.Reader.verbMoods[info.substring(2+offset,3+offset)];



				default:
					return info;
			}
		},

		buildLexicalInfo: function() {
			var threshold = $('#word-count-threshold').val();

			// remove all words
			$('sup.def-up').remove();

			// show loading message
			$('#footnotes').html("Loading...");

			// add back to selected words
			if (threshold != '') {
				var lexicalList = [];

				var tn = parseInt(threshold);
				var index = 0;

				var showParsing = $('#show-parsing').attr('checked');
				var showFrequency = $('#show-frequency').attr('checked');

				// go through all the words, 
				// grab the ones we need to define
				var wordsNeedingWork = [];

				$('#bible-text span').each(function(f) {
					var word = $(this);

					// filter out verse numbers, articles, and prepositions
					if (!word.hasClass('v-num') && !word.hasClass('pos-t') && !word.hasClass('pos-prep')) {

						var counts = word.attr('wc').split('-');
						var tCount = parseInt(counts[0]);
						var bCount = parseInt(counts[1]);
						var strongsNum = word.attr('sn');

						// check frequency to see if we need to show this
						if ((isNaN(tCount) || tCount <= tn || threshold == 'all') && (parseInt(strongsNum) > 0)) {

							// if we are not showing parsing, check to see if the number can be re-used						

							var key = strongsNum;
							var number = 0;
							var skip = false;

							if (showParsing) {
								number = ++index;
							} else {

								number = lexicalList.indexOf(key);

								if (number != -1) {
									// this number already existed, so use one higher than the index,							
									number++;

									// but don't show the definition again
									skip = true;
								} else {
									// since this is new, we increase the index
									number = ++index;
									lexicalList.push(key);
									//list += '<li><a name="foot_' + number + '"></a>' + lex + ": " + kjv + '</li>';
								}
							}

							// create definition
							if (!skip) {

								var pos = word.attr('pos');
								var posInfo = word.attr('inf');

								wordsNeedingWork.push({
									number: number,
									//lex: lex,
									lex: '',
									strongsNum: strongsNum,
									tCount: tCount,
									bCount: bCount,
									pos: pos,
									posInfo: posInfo,
									englishGlosses: ''
								});


							}

							// create superscript number
							// could also use $.append, not sure which style looks better
							if (bible.Reader.lang == 'H')
								word.before('<sup class="def-up">' + number + '</sup>');
							else
								word.after('<sup class="def-up">' + number + '</sup>');
						}
					}
				});

				console.log('word length', wordsNeedingWork.length);


				// get all definitions from our database
				// when it calls back, draw the list
				bible.Storage.fillDefinitions(wordsNeedingWork, function(data) {

					var wordList = data;
					var showPartOfSpeech = $('#show-pos').attr('checked');
					var showParsing = $('#show-parsing').attr('checked');
					var showFrequency = $('#show-frequency').attr('checked');


					var list = '';
					for (var wi = 0; wi < wordList.length; wi++) {
						var wordData = wordList[wi];

						list += '<li>' + '<span class="' + ((bible.Reader.lang == 'G') ? 'gk' : 'hb') + '">' + wordData.lex + '</span>, ';

						if ((showPartOfSpeech || (showParsing && wordData.posInfo != ''))) {
							list += ' <span class="parsing-info">';
							if (showPartOfSpeech && showParsing)
								list += bible.Reader.getPartofSpeech(wordData.pos) + ((wordData.posInfo != '') ? ', ' + bible.Reader.getMorphology(wordData.pos, wordData.posInfo) : '');
							else if (showPartOfSpeech && !showParsing)
								list += bible.Reader.getPartofSpeech(wordData.pos);
							else if (!showPartOfSpeech && showParsing)
								list += bible.Reader.getMorphology(wordData.pos, wordData.posInfo);

							list += '</span>, ';
						}

						list += '' + wordData.englishGlosses +
						((showFrequency) ? ' (' + wordData.tCount + '-' + wordData.bCount + ')' : '') +
						'</li>';
					}

					$('#footnotes').html('<ol>' + list + '</ol>');

					// delete this info
					wordList = null;
					wordsNeedingWork = null;

				});
			}
		},

		updateStyles: function() {
			var styles = '';
			$('select.pos-rule').each(function(f) {
				var effect = $(this).val();
				if (effect != '') {
					var ef = effect.substring(0, 1);
					var css = '';
					switch (ef) {
						case 'h':
							css = 'background-color: ' + effect.substring(2) + ';';
							break;
						case 'c':
							css = 'color: ' + effect.substring(2) + ';';
							break;
						case 'b':
							css = 'font-weight: bold;';
							break;
						case 'u':
							css = 'text-decoration: underline;';
							break;
						case 'i':
							css = 'font-style: italic;';
							break;
					}


					styles += '.' + this.id + ' { ' + css + ' } ';
				}
			});

			try {
				$('#custom-styles').html(styles);
			} catch (ex) { }

		}
	}

	// STORAGE
	bible.Storage = {
		lexicon: null,

		init: function() {
			bible.Storage.settingsStore = new Persist.Store('settings');

			bible.Storage.lexiconStore = new Persist.Store('lexicon');

			// get lexicon
			bible.Storage.lexiconStore.get('lexicon', function(ok, data) {
				if (ok && data != null) {
					bible.Storage.lexicon = []; //eval("(" + data + ")");
				} else {
					bible.Storage.lexicon = [];
				}

				console.log('lexicon', ok, data);
			});
		},

		saveLexicon: function() {
			var x = jQuery.param(bible.Storage.lexicon)
			bible.Storage.lexiconStore.set('lexicon', x);
			console.log('lexicon store', bible.Storage.lexicon.length, bible.Storage.lexicon, x);
		},

		getLexicalEntry: function(sn, callback) {
			var entry = bible.Storage.lexicon[sn];

			if (entry != null) {
				callback(entry);
			} else {
				bible.Interface.getLexicalEntry(sn, function(data) {
					// store
					bible.Storage.lexicon[sn] = data;

					// send				
					callback(data);
				});
			}


		},

		getStrongs: function(word, callback) {
			// check store
			bible.Storage.strongsNumStore.get(word, function(ok, data) {
				// if in store, use it
				if (ok) {
					callback(data);
				} else {
					// else, pull it from ajax
					bible.Interface.getStrongs(word, function(data) {
						callback(data);
					});
				}
			});
		},

		deleteRef: function() {
			bible.Storage.settingsStore.remove('reference', function(ok, data) { });
		},

		setRef: function(value) {
			bible.Storage.settingsStore.set('reference', value);
		},

		getRef: function(callback) {
			bible.Storage.settingsStore.get('reference', function(ok, data) { callback(ok, data); });
		},

		fillDefinitions: function(wordList, callback) {

			// (1) get the list of words not in the database
			var undefinedWords = [];
			for (var i = 0; i < wordList.length; i++) {

				var lex = wordList[i].lex;
				var strongsNum = wordList[i].strongsNum;
				var key = (lex != '') ? lex : strongsNum;

				var definition = bible.Storage.lexicon[key];
				if (!definition || definition == null)
					undefinedWords.push(key);
			}

			console.log('word needing', undefinedWords.length, undefinedWords);

			// (4) fill the requested list
			function fillList() {
				// fill in this list
				for (var i = 0; i < wordList.length; i++) {

					//var lex = wordList[i].lex;
					var strongsNum = wordList[i].strongsNum;
					var key = bible.Reader.lang + strongsNum; //(lex != '') ? lex : strongsNum;			

					var definition = bible.Storage.lexicon[key];
					console.log('looking', key, definition);

					if (definition != null) {
						wordList[i].englishGlosses = definition.KjvDefinition;
						wordList[i].lex = definition.LexicalForm;
					} else {
						wordList[i].englishGlosses = '(not available)';
						wordList[i].lex = '?';
					}
				}

				// (5) run callback
				callback(wordList);
			}

			// (2) if we need words, get them via ajax
			if (undefinedWords.length > 0) {

				var wordQuery = undefinedWords.join(',');


				// grab all the words we need
				bible.Interface.getLexicalList(wordQuery, bible.Reader.lang, function(data) {

					// (3) fill the database with the ajax words
					for (var i = 0; i < data.length; i++) {
						var definition = data[i];
						var key = bible.Reader.lang + definition.StrongsNumber;
						console.log('storing', key, definition);
						bible.Storage.lexicon[key] = definition;
					}

					fillList();

					// store for next time
					bible.Storage.saveLexicon();

				});
			} else {
				fillList();
			}
		}
	};

	bible.Interface = {

		getLexicalList: function(words, lang, callback) {

			jQuery.get('ajax/get.ashx', { a: 'lexlist', d: words, l: lang }, function(data) {
				callback(data.list);
			}, 'json');

		},

		getLexicalEntry: function(word, callback) {

			jQuery.get('ajax/get.ashx', { a: 'lex', d: word }, function(data) {
				callback(data);
			}, 'json');

		},

		getReference: function(reference, callback) {

			jQuery.get('ajax/get.ashx', { a: 'ref', d: reference }, function(data) {
				callback(data);
			}, 'json');

		}

	};

	bible.utils = {
		serializeJSON: function(a) {
			var s = '';

			// Serialize the key/values
			for (var j in a)
			// If the value is an array then the key names need to be repeated
				if (a[j] && a[j].constructor == Array)
				jQuery.each(a[j], function() {
					s.push(encodeURIComponent(j) + "=" + encodeURIComponent(this));
				});
			else
				s.push(encodeURIComponent(j) + "=" + encodeURIComponent(jQuery.isFunction(a[j]) ? a[j]() : a[j]));

			// Return the resulting serialization
			return s.join("&").replace(/%20/g, "+");
		},

		deserializeJSON: function(s) {
			return eval("(" + s + ")");
		}
	}


	// START UP
	bible.Reader.init();
	bible.Storage.init();

	//  init refererence
	bible.Storage.getRef(function(ok, data) {

		var ref = (!ok || data == null || data.toString() == '' || data.toString().indexOf('Invalid') > -1) ? 'Rom 3:20-25' : data;
		$('#reference').val(ref);

		bible.Reader.getReference();

		// init styles	
		$('#pos-v').attr('selectedIndex', '2'); // verbs = red gb
		$('#pos-n').attr('selectedIndex', '7'); // nouns = green
		bible.Reader.updateStyles();

	});

});