Object.size = function(obj) {
    var size = 0, key;
    for (key in obj) {
        if (obj.hasOwnProperty(key)) size++;
    }
    return size;
};

Object.extend = function(destination, source) {
    for (var property in source) {
        if (source.hasOwnProperty(property)) {
            destination[property] = source[property];
        }
    }
    return destination;
};

(function () {
	"use strict";
	
	var focusElem;
	
	function insertAtCursorPos(addtext, fe) { //http://aktuell.de.selfhtml.org/artikel/javascript/bbcode/
		fe.focus();
		if (typeof document.selection !== 'undefined') { //IE, Opera
			var range = document.selection.createRange(), rangetext = range.text;
			range.text = addtext;
			if (navigator.appName !== "Opera") {
				range = document.selection.createRange();
				if (rangetext.length !==  0) {
					range.move('character', 1);
				}
				if (addtext === ' ()' || addtext === ' []' || addtext === ' {}' || addtext === ' <>') {
					range.move('character', -1);
				}
				range.select();
			}
		} else if (typeof fe.selectionStart !== 'undefined') {
			//Gecko-based
			var start = fe.selectionStart, end = fe.selectionEnd, selectedtext = fe.value.substring(start, end);
			fe.value = fe.value.substr(0, start) + addtext + fe.value.substr(end);
			if (addtext === ' ()' || addtext === ' []' || addtext === ' {}' || addtext === ' <>') {
				start = start - 1;
			}
			fe.selectionStart = start + addtext.length;
			fe.selectionEnd = start + addtext.length;
		} else { //others
			fe.value = fe.value + addtext;
		}
	}
	
	function insert(inChar) {
		if (focusElem) {
			insertAtCursorPos(inChar, focusElem);
		}
	}
	
	$(document).ready(function() {
		var SCRIPTURLPATH = foswiki.getPreference('SCRIPTURLPATH') + '/';
		var REST_RENDERPLUGIN_TEMPLATE = SCRIPTURLPATH + 'rest/RenderPlugin/template?name=' + foswiki.getPreference('WEB') + '.SongView;render=1;expand=';
	
		$(':input').focus(function () {
			focusElem = this;
		});

		$('form .dictionaryInsert').click(function () {
			insert(this.innerHTML);
			return false;
		});
		
		$("form :input[name='q']").livequery(function() {
			if ($(this).val() === '') {
				$(this).val('');
				$(this).focus();
			}
		});
		

		$('.pageId').livequery(function() {
			$(this).attr({size: $(this).val().length});
		});

		$('#editorSearchResults .itemcount').livequery(function() {
			var $el = $(this);
			var item = $el.attr('data-item');
			var type = $el.attr('data-type');
			var command = '%DICTIONARY_COMMAND{format="${thousands(\'${count}\')}" sqlQuery="SELECT COUNT(*) AS count FROM word WHERE ' + type + ' = \'' + item + '\'"}%';
			$el.addClass('loading');
			var loadItem = function() {
				$.ajax({
					url: SCRIPTURLPATH + 'rest/RenderPlugin/render?text=' + command,
					cache: true,
					async: true,
					processData: false,
					success: function(data, textStatus, XMLHttpRequest) {
						var number = data;
						if (isNaN(parseInt(data,10))) {
							number = 0;
						}
						$el.html(number);
						$el.removeClass('loading');
					}
				});
			};
			$.later(600, this, loadItem, {}, false);
		});
		
		var dialogActive = false;
		var preloadedEntries = {};
		var preloadedEntriesCurrentSet;
		var currentLoading;
		var currentLoadingTimer;
		var PRELOADING = 1;
		
		$('a.entry').livequery('click', function() {

			if (!dialogActive) {
				$('body').css({
					overflow:'hidden'
				});
				var w = $('.dictionaryPage').width();
				var maxH = w;
				var h = $(window).height() * .75;
				if (h > maxH) {
					h = maxH;
				}
				$('#dialogcontainer').dialog({
					bgiframe: false,
					height: h,
					width: w,
					draggable: false,
					resizable: false,
					position: 'center',
					title: undefined,
					modal: true,
					close: function(event, ui) {
						dialogActive = false;
						preloadedEntriesCurrentSet = {};
						currentLoading = undefined;
						if (currentLoadingTimer) {
							currentLoadingTimer.cancel();
						}
						$('body').css({
							overflow:'auto'
						});
						$(this).html('');
					}
				});
				dialogActive = true;
				preloadedEntriesCurrentSet = {};
				currentLoading = undefined;
			}
			if (currentLoadingTimer) {
				currentLoadingTimer.cancel();
			}
			
			$('#dialogcontainer').dialog().html('<div class=\'loading\'></div>');
			
			
			var createEntryCommand = function(word) {
				return escape('%DICTIONARY_COMMAND{format="$percntENTRY{topic=$quotWords.Word${id}$quot templateTopic=$quot%DICTIONARY_WEB%.EntryTemplate$quot <#if rowCount gt 1>number=$quot${rowNum}$quot</#if>}$percnt" noResultText="<h1 class=\'resultCount\'><em>Geen woorden gevonden voor <strong>') + word + escape('</strong></em></h1>" rowId="id" sqlQuery="SELECT id, findValue FROM word WHERE findValue LIKE \'') + word + escape('\' AND isValid = \'%URLPARAM{"valid" default="1"}%\' ORDER BY sortOrder"}%');
			};
			
			var $entry = $(this);
			var entries = $('a.entry');
			
			if (entries.length > 1) {
				var currentIdx = entries.index($entry);
				var isFirst = (currentIdx === 0);
				var isLast = (currentIdx === entries.length-1);
				var $prevEntryLink, $nextEntryLink;
				
				var buttons = [
					{
						text: "Vorige"
					},
					{
						text: "Volgende"
					}
				];
				
				if (!isFirst) {
					$prevEntryLink = $(entries[currentIdx-1]);
					buttons[0].click = function() {
						$prevEntryLink.click();
					};
				}
				if (!isLast) {
					$nextEntryLink = $(entries[currentIdx+1]);
					buttons[1].click = function() {
						$nextEntryLink.click();
					};
				}
	
				$('#dialogcontainer').dialog( 'option', 'buttons', buttons );		
				$(":button").attr('class', 'jqButton jqButtonSmall');
				
				if (isFirst) {
					$(":button:contains('Vorige')").attr('disabled', 'disabled').addClass( 'jqButtonDisabled' );
				}
				if (isLast) {
					$(":button:contains('Volgende')").attr('disabled', 'disabled').addClass( 'jqButtonDisabled' );
				}
			}
			
			var preload = function() {				
				if (dialogActive && entries.length > 1 && Object.size(preloadedEntriesCurrentSet) < entries.length) {
				
					var currentIdx, i;
					currentIdx = i = entries.index($entry);
					// forward
					for (i; i<entries.length; i=i+1) {
						var word = $(entries[i]).attr('data-internal-name');
						if (word !== undefined && preloadedEntriesCurrentSet[word] === undefined && preloadedEntries[word] === undefined && currentLoading !== word) {
							loadEntry(word, false);
							return;
						}
					}
				}
			};
			
			var handleContent = function(word, data, show) {
				preloadedEntriesCurrentSet[word] = data;
				preloadedEntries[word] = data;
				if (show) {
					$('#dialogcontainer').dialog().html('<div class=\'dictionaryPage\'>' + data + '</div>');
				}
				if (PRELOADING) {
					currentLoadingTimer = $.later(1000, this, preload, {}, false);
				}
			};
			
			var loadEntry = function(word, show) {
				if (preloadedEntries[word] !== undefined) {
					handleContent(word, preloadedEntries[word], show);
					return;
				}
				if (preloadedEntriesCurrentSet[word] !== undefined) {
					handleContent(word, preloadedEntriesCurrentSet[word], show);
					return;
				}
				var command = createEntryCommand(word);
				$.ajax({
					url: SCRIPTURLPATH + 'rest/RenderPlugin/render?text=' + command,
					cache: false,
					async: true,
					processData: false,
					success: function(data, textStatus, XMLHttpRequest) {
						handleContent(word, data, show);
					}
				});
				currentLoading = word;
			};
			
			var word = $(this).attr('data-internal-name');
			loadEntry(word, true);
			
			return false;
		});
		
		$('.ui-widget-overlay').livequery('click', function() {
			$('.ui-dialog-titlebar-close').trigger('click');
		});
		
	});
}());


/**
 * jQuery Later. Plugin for jQuery
 * Provides a setTimeout/setInterval wrapper
 *
 * Copyright 2010, Sudar Muthu (http://sudarmuthu.com)
 * Released under MIT
 * 
 */
(function($) {
    /**
     * Executes the supplied function in the context of the supplied
     * object 'when' milliseconds later.  Executes the function a
     * single time unless periodic is set to true.
     * 
     * Pretty much copied from http://developer.yahoo.com/yui/3/api/yui-later.js.html
     *
     * @method later
     * @for jQuery
     *
     * @param when {int} the number of milliseconds to wait until the fn
     * is executed.
     * @param o the context object.
     * @param fn {Function|String} the function to execute or the name of
     * the method in the 'o' object to execute.
     * @param data [Array] data that is provided to the function.  This accepts
     * either a single item or an array.  If an array is provided, the
     * function is executed with one parameter for each array item.  If
     * you need to pass a single array parameter, it needs to be wrapped in
     * an array [myarray].
     * @param periodic {boolean} if true, executes continuously at supplied
     * interval until canceled.
     * @return {object} a timer object. Call the cancel() method on this object to
     * stop the timer.
     */

   $.later = function(when, o, fn, data, periodic) {
        when = when || 0;
        o = o || {};
        var m=fn, d=$.makeArray(data), f, r;

        if (typeof fn === "string") {
            m = o[fn];
        }

        if (!m) {
        	// Throw an error about the method
            throw {
                name: 'TypeError',
                message: "The function is undefined."
            }
        }

        f = function() {
            m.apply(o, d);
        };

        r = (periodic) ? setInterval(f, when) : setTimeout(f, when);

        return {
            id: r,
            interval: periodic,
            cancel: function() {
                if (this.interval) {
                    clearInterval(r);
                } else {
                    clearTimeout(r);
                }
            }
        };
    };
 })(jQuery);
 
