var oFCKeditor;
var oMonitor = new Object;
var ajax_timeoutid;


$(document).ready(function(){
    //------------------------------- forms --------------------------------------------
    //extended form attributes: child SPANs have details of the extended attibutes
    $(".extended_attributes.xinput").each(function(){
	    var input    = $(this).find(":input");

        //field selection on submit (ajax only and thus usually only admin screens)
	    var fields   = $(this).find("span.fields");
	    if (fields.length) {
	        input.click(function(){
                $("form *").attr("disabled", true);
                $("form *[name='" + fields.text() + "']").removeAttr("disabled");
            });
        }
    	
	    //default (disappears on focus etc.)
	    var xdefault = $(this).find("span.default");
	    if (xdefault.length && xdefault.text() != '') {
		    input.focus(function(){if ($(this).val() == xdefault.text()) $(this).val('');});
		    input.blur( function(){if ($(this).val() == '') $(this).val(xdefault.text());});
		    input.each( function(){if ($(this).val() == '') $(this).val(xdefault.text());});
	    }
	    
	    //auto form action switching (ajax only and thus usually only admin screens)
	    var action   = $(this).find("span.action");
	    if (action.length) {
	        input.click(function(){$(this.form).attr("action", action.text());});
	    }
    });
    
  	$(".noautocomplete").attr("autocomplete", "off");
  	var jFirstInput = $(":input:enabled:not(:hidden)");
  	if (jFirstInput.length) jFirstInput[0].focus(); //crashes IE if focus not possible

    $("form").submit(function(){
        var errors = '';
        $(this).find(".extended_attributes.xinput").each(function(){
            //objects
	        var input            = $(this).find(":input");
	        var required         = $(this).find("span.required");
	        var validation_error = $(this).find("span.validation_error");
	        var xdefault         = $(this).find("span.default");

            //clear hints (default)
            if (xdefault.length && !input.hasClass("keep") && input.val() == xdefault.text()) input.val('');
	        
            //validation
	        if (required.length) {
	            var required_text         = required.text();
                if (required_text == '') required_text = '.+';
                var regexp                = new RegExp(required_text);
                var value_text            = input.val();
                var name_text             = input.attr("name");
                var type_text             = input.attr("type");
                var validation_error_text = validation_error.text();
                if (validation_error_text == '') validation_error_text = name_text + ' is invalid (' + required_text + ')';
                if (type_text == "checkbox") value_text = (input.attr("checked") ? value_text : "off");
                //alert(name + '=' + value);
                if (!value_text.match(regexp)) errors += 'o - ' + validation_error_text + '\n';
            }
        });
        if (window.customsubmit) errors += customsubmit();
        if (errors != '') alert('There are errors in your form:\n' + errors);
        return (errors == '');
    });

    //misc classes
    $(".backlink").attr("href", "backlink:").click(function(){history.go(-1);return false;});

    //standard jquery elements (check for existence first)
    if ($(".ui-slider-1").slider)    $(".ui-slider-1").slider({min:-2, max:2, steps:5});
    if ($("ul.nodrag").sortable) {
        $("ul.nodrag").sortable({axis:'y', opacity:0.7, revert:true, placeholder:'placeholder', start:sortstart, stop:resorted})
        $("ul.nodrag").addClass('candrag')    //apply draggable classes
                      .removeClass('nodrag'); //remove can't drag classes
    }
    if ($(".notabs").tabs) {
        $(".notabs").tabs()
        .addClass('aretabs')    //apply tab ok classes
        .removeClass('notabs'); //remove tab failed classes
    }
    if ($(".datepicker").datepicker) {
        $(".datepicker").datepicker({dateFormat: 'dd/M/yy'});
    }
    
    //run iframe src after document load so that the browser does not hang at document load
    $("iframe.delayedload").each(function(){
        if ($(this).attr("id")) $(this).attr("src", $(this).attr("id"));
    });
    $("form.ajax").submit(ajaxform).ajaxError(ajaxformerror);
    $(".ajax_hide").hide();
    $(".ajax_remove").remove();
    $(".ajax_show").show();   //display:none; by default
    $(".ajax_autosubmit").change(function(){$(this.form).submit();});
    
    //value change monitor - used for typeahead amoungst other things
    $(".ajax_monitor").each(addMonitor);

    //HTML editors (max 1 per screen at mo)
    $(".HTMLEditor").each(function(){
        var fck                                   = new FCKeditor(this.name);
        var fckcss                                = ['/' + siteroot + '/includes/header.css', '/' + siteroot + '/includes/widgets.css'];
        if ($(this).attr("fckcss"))    fckcss.push( '/' + siteroot + '/' + $(this).attr("fckcss"));
        if ($(this).attr("fckheight")) fck.Height = $(this).attr("fckheight");
        if ($(this).attr("fckwidth"))  fck.Width  = $(this).attr("fckwidth");
        fck.Config["EditorAreaCSS"]               = fckcss;
        fck.Config["CustomConfigurationsPath"]    = '/' + siteroot + '/includes/FCKconfig.js';
        fck.BasePath                              = "/includes/fckeditor/";
        fck.ReplaceTextarea();
    });
    if ($(".dialog").dialog) $(".dialog").dialog({autoOpen:false, modal:true, height:400, width:300});
    
    //Quick tips - disable and links and show the first .quicktip instead
    $(".quicklink")
        .attr("href", "#")
        .attr("title", "")
        .addClass("quicklink_linked")
        .click(function(e){
            $(this).find(".quicktip").show("slow");
            e.stopPropagation();
            e.preventDefault();
        })
        .mouseover(function(e){
            e.stopPropagation();
        });
    $(document).mouseover(function(){$(".quicktip").hide("slow");});
    $(document).click(function(){$(".typeahead ul").hide("slow");});
});

//------------------------------- misc sys funcs --------------------------------------------
//FireBug console
function cdebug(s)    {if (window.console && window.console.debug   ) return window.console.debug.apply(   window.console, arguments);}
function cinfo(s)     {if (window.console && window.console.info    ) return window.console.info.apply(    window.console, arguments);}
function cwarn(s)     {if (window.console && window.console.warn    ) return window.console.warn.apply(    window.console, arguments);}
function cerror(s)    {if (window.console && window.console.error   ) return window.console.error.apply(   window.console, arguments);}
function cgroup(s)    {if (window.console && window.console.group   ) return window.console.group.apply(   window.console, arguments);}
function cgroupend(s) {if (window.console && window.console.groupEnd) return window.console.groupEnd.apply(window.console, arguments);}

//------------------------------- formatting funcs --------------------------------------------
function format_distance(distance) {
    return parseInt(distance / 100)/10 + ' km';
}

//------------------------------- ordering funcs --------------------------------------------
function order_distance(i1, i2) {return i1.distance - i2.distance;}
function order_title(i1, i2)    {return i1.title.toLowerCase() > i2.title.toLowerCase();}

//------------------------------- monitor --------------------------------------------
function addMonitor() {
    //check for the change function
    var monitor = this;
    var i = 0, func, classes = $(this).attr("class").split(' ');
    while (i < classes.length && classes[i].substr(0,7) != 'ajax_f_') i++;
    if (i < classes.length) {
        this.func = window[classes[i]];
        $(this).find(":input").each(function(){addMonitorValue(this, monitor);}); //store intial values
        $(this).keyup(monitorChange) //typing
            //.change(monitorChange)   //details in 1 input changed
            .mouseup(monitorChange); //a paste or sumink
    } else alert('no monitor function!');
}
function addMonitorValue(input, monitor) {
    //store the current value (ignoring defaults)
    var inputdefault = $(input).parent(".extended_attributes.xinput").find("span.default").text();
    var name         = $(input).attr("name");
    var inputval     = $(input).val();
    if (inputval == inputdefault) inputval = '';
    oMonitor[name]   = inputval;
}
function monitorChange() {
    var monitor = this;
    $(this).find(":input").each(function(){monitorCompareValue(this, monitor);}); 
}
function monitorCompareValue(input, monitor) {
    //compare values, this = each :input
    //monitor = the span class="ajax_monitor"
    var inputdefault = $(input).parent(".extended_attributes.xinput").find("span.default").text();
    var name         = $(input).attr("name");
    var inputval     = $(input).val();
    var inputold     = oMonitor[name];
    if (inputval == inputdefault) inputval = '';
    
    if (inputval != inputold) {
        oMonitor[name] = inputval;
        //restart timer
        if (ajax_timeoutid) clearTimeout(ajax_timeoutid);
        if (monitor.func) {
            $(input).addClass('monitor_wait');
            ajax_timeoutid = setTimeout(function(){
                $(input).removeClass('monitor_wait');
                monitor.func(monitor, input, inputval);
            }, 1000); //1 second delay
        } else alert('no monitor function!');
    }
}

//------------------------------- ajax forms --------------------------------------------
function ajaxformerror(e, request, ajaxOptions, thrownError) {
    alert('ajaxerror:\nerror:[' + e + ']\nrequest:[' + request + ']\noptions:[' + ajaxOptions + ']\nthrown:[' + thrownError + ']');
}
function ajaxform(e) {
    var jForm     = $(this);
    var jSubmit   = $(e.target);
    var subname   = jSubmit.attr("name");
    var subval    = jSubmit.attr("value");
    var classes   = jForm.attr("class").split(' ');
    var i         = 0;
    var debugajax = false, classname, funcname, func;
    var jsonurl   = '/api' + jForm.attr("action") + '.ajaxForm'; //run the json version so we can get a validation response
    
    //find the function to run on return
    for (var i = 0; i < classes.length; i++) {
        classname = classes[i];
        if (classname.substr(0,7) == 'ajax_f_') {
            funcname = classname;
            func     = window[funcname];
            if (!func) alert('[' + funcname + '] does not exist!'); //required (must always be a response!)
        }
        if (classname.substr(0,10) == 'ajax_debug') debugajax = true;
    }

    //serialisation + submit button
    var formdata = jForm.serialize();
    if (formdata.length) formdata += '&';
    formdata += (subname?subname:'submit') + '=' + (subval?subval:'submitted');
    
    //debug
    if (debugajax) alert('ajax_debug request:\nFUNC:' + funcname + '\nURL:' + jsonurl + '\nFORM:' + formdata);

    //run ajax
    $.post(
        jsonurl, //must be in non-absolute jForm, e.g. /api/business/account/getphotos.ajaxjForm
        formdata, 
        function(data, status) {if (ajax_valid(data, status, debugajax)) func(jForm, data, status, debugajax);} //closure
        ,"json"
    );
    return false;
}

function ajax_valid(data, status, debugajax) {
    //convert text to JSON object
    if (debugajax) alert('ajax_debug response:\nDATA:\n' + data + '\nTYPE:' + typeof data);
    var jsonobj;
    try {jsonobj = eval(data);}
    catch (e) {
        //JSON object not well formed: hard system error!
        alert('AJAX response badly formed!\n' + e + '\n' + data);
        return false;
    }
    //JSON object reply well-formed, check details
    var ok = (jsonobj.status == 'ok');
    if (!ok) {
        var validation_errors = "There were validation errors submitting your form\n";
        for (i in jsonobj.validation_errors) validation_errors += "o - " + jsonobj.validation_errors[i] + "\n";
        alert(validation_errors);
    }
    return ok;
}

//common ajax reply functions
function ajax_f_debug(form, data, status) {
    alert('response:\nSTATUS:' + status + '\nDATA:\n' + data.toString(2));
}
function ajax_f_refresh(form) {
    document.location = document.location;
}
function ajax_f_removeAncestorLI(form) {
    form.parents("li").hide("slow");
}
function ajax_f_disablesubmit(form) {
    $(form).find("input[type=submit]").attr("disabled", true);
}
function ajax_f_typeahead(form, input, inputval) {
    //something has changed on a monitored input
    //run a standard ajax function to get the list of typeahead options
    if (inputval.length > 2) {
        $(input).addClass('typeahead_getdata');
        //run ajax
        var typeaheadfile = '/api/typeahead/' + $(input).attr("name") + '.ajaxform';
        $.post(
            typeaheadfile,
            $(form).serialize(), 
            function(data, status) {
                $(input).removeClass('typeahead_getdata');
                if (ajax_valid(data, status)) ajax_typeahead(form, input, inputval, data, status);
            },
            "json"
        );
    }
}

//misc ajax helpers
function ajax_typeahead(form, input, inputval, data, status) {
    var option, options = data.procxml.root.options;
    var typeahead_name  = 'typeahead_' + $(input).attr("name");
    var typeahead_div   = $('#' + typeahead_name);
    var typeahead_ul;
    
    //find or create the holding div
    if (typeahead_div.length) {
        //found it
        typeahead_ul = typeahead_div.find("ul");
        typeahead_ul.empty();
    } else {
        //create it
        $(input).wrap('<div id="' + typeahead_name + '" class="typeahead"></div>');
        $(input).after('<ul></ul>');
        typeahead_div   = $('#' + typeahead_name);
        typeahead_ul    = typeahead_div.find("ul");
        typeahead_ul.click(function(event){typeahead_select(typeahead_ul, form, input, event);});
        typeahead_ul.mouseover(function(event){typeahead_mouseover(typeahead_ul, form, input, event);});
        typeahead_div.keydown(function(event){typeahead_keydown(typeahead_ul, form, input, event);}); //to act before the form is submitted
    }
    
    //create options
    var html                        = '';
    var typeahead_custom_optionhtml = window[typeahead_name + '_optionhtml'];
    for (i in options) {
        option = options[i];
        if (typeahead_custom_optionhtml) html += typeahead_custom_optionhtml(option, i);
        else html += '<li>' + option + '</li>';
    }
    if (!html) html = '<li><span class="nooptions">no options found</span></li>';
    typeahead_ul.html(html);
    typeahead_ul.hide();
    typeahead_ul.slideDown("fast");
    $(input).focus();
}
function typeahead_select(typeahead_ul, form, input, event) {
    var target  = $(event.target);
    if (target.is("li")) {
        $(input).val(target.text());
        $(form).submit();
    }
}
function typeahead_mouseover(typeahead_ul, form, input, event) {
    var target  = $(event.target);
    var selected = typeahead_ul.find("li.selected");
    if (target.is("li")) {
        selected.removeClass("selected");
        target.addClass("selected");
    }
}
function typeahead_keydown(typeahead_ul, form, input, event) {
    var selected = typeahead_ul.find("li.selected");
    selected.removeClass("selected");
    switch (event.keyCode) {
        case 40: {//KEY_DOWN
            if (!selected.length) selected = typeahead_ul.children(":first");
            else selected = selected.next();
            break;
        }
        case 38: {//KEY_UP
            if (!selected.length) selected = typeahead_ul.children(":last");
            else selected = selected.prev();
            break;
        }
        case 13: {//KEY_ENTER
            if (selected.length) {
                $(input).val(selected.text());
                $(form).submit();
            }
            break;
        }
    }
    selected.addClass("selected");
    return false;
}

/*
Object.prototype.toString = function toString(level) {
    var item, datastring = '';
    if (!level) level = 0;
    var pad = '                                     '.substring(0, level*2);
    for (i in this) {
        item        = this[i];
        datastring += pad + i + ': ';
        if (item instanceof Object) datastring += '{\n' + item.toString(level + 1) + pad + '}\n';
        else datastring += item + '\n';
    }
    return datastring;
}
*/

var gScrolling = false;
function scrollIntoView(container, selector) {
    if (!gScrolling) {
        var currentScrollTop    = container.scrollTop();
        var containerTop        = container.offset().top;
        var containerHeight     = container.height();
        var targetScrollTop     = selector.offset().top                     - containerTop + currentScrollTop;
        var targetScrollBottom  = selector.offset().top + selector.height() - containerTop + currentScrollTop;
        if (targetScrollTop < currentScrollTop || targetScrollBottom > containerHeight + currentScrollTop) {
            gScrolling = true;
            container.animate({scrollTop: targetScrollTop}, 500, function(){gScrolling = false;});
        }
    }
}

//sorting functions
function sortstart(e, ui) {
    ui.item.parent().parent().addClass('sort-active');
    $(document.body).addClass('sort-inactive');
    return true;
}
function resorted(e, ui) {
    ui.item.parent().parent().removeClass('sort-active');
    //ui.item.animate({backgroundColor:'#000000'}, 1000);
    $(document.body).removeClass('sort-inactive');
    return true;
}

function FCKeditor_OnComplete(editorInstance) {
    oFCKeditor = editorInstance;
}


