/*
 * Main JS file for courtside. Should probably be renamed courtside.js.
 *
 * jQuery 1.3.2.
 *
 */

if (window['loadFirebugConsole']) {
    window.loadFirebugConsole();
}

jQuery.fn.extend({
    /* Add a traversing extension to get the labels of the fields in a
     jQ object. */
    label: function() {
        return $(this.map(function() {
            var field = $(this); var label;
            var id = field.attr("id");
            label = $("label[for="+id+"]")[0];
            return label;
        }));},
    default_value: function(value) {
        if(this.val()==""){
            this.closest("form").bind("submit pre-ajax-submit", remove_default_values_callback);
            return this.addClass("default-value").focus(default_value_callback)
                .val(value);

        }else{
            return this;
        }
        },

    log: function() {
        log(this);
        return this;
        },

    scroll_to: function() {
        $("html,body").scrollTop(this.offset().top);
        return this;
    },
    _cs_datepicker: function() {
        return this.datepicker({
            buttonImage: "http://getcourtside.com/static/lib/famfamfam/silk/icons/calendar.png",
            showOn: "both", dateFormat: "yy-mm-dd"});
    },
    hasAttr: function(name) {
        return this.attr(name) !== undefined
    }
});

var csutil = {
    /* Variations on a theme. TODO: can this be generalized at all?
     * I'm not sure it can, what with all the magic arguments
     * stuff. */

    defer: function(){
        var orig_arguments = Array.prototype.slice.call(arguments);
        var orig_this = this;
        return csutil.defer0([orig_arguments]);
    },
    /* Passed a list of lists, each of which consists of a function
     * and any number of arguments, returns a callable that, when
     * called, calls each function with its associated arguments. */
    defer0: function(){
        var func_specs = Array.prototype.slice.call(arguments);
        var orig_this = this;
        return function(){
            $.each(func_specs, function(ii, func_and_args){
                var func = func_and_args[0];
                var args = func_and_args.slice(1);
                func.apply(orig_this, args);
            });
        }
    },
    /* Passed a list of lists, each of which consists of string name
     * of a function and any number of arguments, returns a callable
     * that, when called, evaluates the function string, then calls it
     * with its associated arguments. */
    defer1: function(){
        var func_specs = Array.prototype.slice.call(arguments);
        var orig_this = this;
        return function(){
            $.each(func_specs, function(ii, func_and_args){
                var func = eval(func_and_args[0]);
                var args = func_and_args.slice(1);
                func.apply(orig_this, args);
            });
        }
    },
    /* Functions which emulate python behavior or libs */
    py: {
        int: function(value){
            return parseInt(value, 10);
        },
        str: {
            startswith: function(match_string, start_string){
                return match_string.substr(0, start_string.length) == start_string;
            }
        }
        
    },
    ajax: {
        get_params: function(obj){
            var params = eval("(" + ($(obj).attr("data-params")||'{}') + ")");
            log(params)
            log(params)
            $(obj).each(function(){
                $.each(this.attributes, function(i, attr){
                    if(csutil.py.str.startswith(attr.name, "data-param-")){
                        params[attr.name.substr("data-param-".length)] = attr.value;
                    }
                });
            });
            log(params)
            return params;
        }
    },
    callbacks: {
        make_attr_evaler: function(attr){
            return function(){$.proxy(function(){eval($(this).attr(attr));}, this)();}
        }
    }
}

/* TODO: Kill this when jscal is totally excised */
if (typeof on_calendar_update == "undefined"){
    on_calendar_update = function(){};
}

/* Onready function. */
$(function(){
    bindMessageClosers();
    bind_backboard();
    bind_gameplan_wizard();
    bind_check_all();
    init_tinymce()
    $(".scorecard input[type=text]").attr("autocomplete", "off");
    $("#tabnav-flair").click(function(){
        $.post(root_ajax_url, {"action": "get-ajax-dialog", "name": "tabnav-flair"}, function(html){
            $("#ajax-dialog").html(html).removeClass("display-none").dialog({width: 600, height: 400}).dialog("open")
        })
        return false;
    })
    $(".scroller-wrapper").each(_setup_scroller);

    var timerid;
    $("li.help").click(show_or_hide_inline_help);
    var payment_fields_callback = function(){
        var payment_fields = $(this).closest("form").find(".field-registration_price,.field-payment_policy,.field-price");
        if(this.checked){
            payment_fields.show();
        }else{
            payment_fields.hide();
        }
    };
    $("#id_paid_event,#id_paid_round_robin").change(payment_fields_callback)
        .click(payment_fields_callback).change();

    init_html(document)
    $(".ajax-action").live("click", _ajax_action_callback);
    $("[data-live-click]").live("click", csutil.callbacks.make_attr_evaler("data-live-click"));
    $("[data-live-mouseenter]").live("mouseenter", csutil.callbacks.make_attr_evaler("data-live-mouseenter"));
    $("[data-live-mouseleave]").live("mouseleave", csutil.callbacks.make_attr_evaler("data-live-mouseleave"));

    $(".ajax-submit").live("click", _ajax_submit_callback);

    $(".switcher-chooser").bind("switch", function(){
        var target = $(this).attr("data-target");
        $(this).addClass("selected").siblings(".switcher-chooser").removeClass("selected");
        $(target).removeClass("display-none").siblings(".switcher-target").addClass("display-none");
    }).filter(".switcher-chooser-first").trigger('switch')
        .end().live("click", function(){$(this).trigger("switch")});

});

function init_html(node){
    log("init_html(" + node + ")");
    log(node);
    $(".noselect,.disable-selection", node).disableSelection();
    $("input,select,textarea", node).focus(function(){
        $(this).addClass("has-been-focused");});
    $("[data-default-value]", node).each(function(){
        $(this).default_value($(this).attr("data-default-value"));
    });
    $(".searchbox input.searchfield", node).each(_searchbox);
    $(".searchbox2", node).log().each(_searchbox2);
    $(".js-adjust-height", node).bind("adjust-height", _adjust_height_callback).trigger("adjust-height");
    $(".jqui-button0", node).button();
    $(".datepicker", node)._cs_datepicker();

    /* I'm kind of shocked this works. */
    if(typeof tinyMCE != "undefined"){
        $("textarea.editor", node).each(function(){
            var id = $(this).attr("id");
            tinyMCE.execCommand("mceRemoveControl", false, id);
            tinyMCE.execCommand("mceAddControl", false, id);
            $("#" + id + "_parent").show();
        });
    }

    $(".ajax-dialog-opener", node).each(_ajax_dialog_setup);
    bindTimePicker(node);
    $(".ajax-form").bind("pre-ajax-submit", csutil.callbacks.make_attr_evaler("data-pre-ajax-submit"));
    $(".subnav0", node).each(_setup_subnav0)
}

/* AJAX start/stop callbacks */
function showSpinner() { $('#spinner').css("visibility", "visible"); }
function hideSpinner() { $('#spinner').css("visibility", "hidden"); }

function hideMessage(){
    /* The callback method to close a message */
    $(this).parents(".message").slideUp();
}

var flash_tmpl = '<div class="message">'
          + '<div class="message-content">'
          + '{content}'
          + '</div>'
          + '<div class="closer">'
          + '<span class="link">[x]</span>'
          + '</div>'
    + '</div>';
function addFlash(flash){
    $("#alerts").append($.format(flash_tmpl, {content:flash}));
    bindMessageClosers();
}

function bindMessageClosers(){
    /* Bind the buttons that close messages to a function that closes
     them. */
    $(".closer").click(hideMessage);
}

var timepicker_opts = {
    normal: {
        startTime: new Date(0, 0, 0, 7, 0, 0),
        endTime: new Date(0, 0, 0, 21, 0, 0),
	show24Hours: false
    },
    "24h": {
        startTime: new Date(0, 0, 0, 0, 0, 0),
        endTime: new Date(0, 0, 0, 23, 0, 0),
	show24Hours: false
    }
};

function bindTimePicker(node){
    var timepicker_input = $(".timepicker > input", node);
    if(typeof timepicker_input.timePicker=="undefined"){log("timepicker not found.");}else{
        $(".timepicker > input:not(.24h)", node).timePicker(timepicker_opts.normal);
        $(".timepicker > input.24h", node).timePicker(timepicker_opts["24h"]);
    }

}

function log(expr){
    /* Production-safe console.log - won't break non-Firebug browsers */
    if(typeof console=="undefined"){
        return;
    }

    if(console&&console.log){
        console.log(expr);
    }
}

function assert(expr){
    /* Log an error (for me) if the passed expression is false. */
    if(!expr){
        log("Failed: "+expr);
    }
}

function disable(){
    // A callback for disabling forms.
    return false;
}

function club_address_switcher(){
    $(".pro-info .addresses div").addClass("display-none");
    $(".pro-info .pro-courts .link").click(address_switcher_callback).eq(0).click();
}

function address_switcher_callback(){
    var addy=$(this).addClass("selected").siblings().removeClass("selected").attr("number");
    $(".pro-info .addresses div").addClass("display-none");
    $(".pro-info .addresses div[address="+addy+"]").removeClass("display-none");
}

/** Functions for accounts.fields.UserSearchWidget **/

// TODO: this hits the server way too much.      add a timeout or something.
function user_search_widget_search(id, max_choices)
{
    function user_search_widget_toggle()
    {
        $('#' + id).toggle();
    }

    function user_search_widget_name_click(item)
    {
        var value = $('#real-' + id).val();
        if (value == '')
            value = [];
        else
            value = value.split(',');

        if (jQuery.inArray(item.id, value) == -1)
        {
            var dispitem = $('<span id="disp-item-' + id + '-' + item.id +'">' +
                             item.name +
                             '</span>');
            var link = $('<a>x</a> ');
            dispitem.addClass('usersearchbox-dispitem');
            link.click(function () {
                           user_search_widget_name_remove(id, item.id, max_choices);
                       });
            dispitem.prepend(link);
            $('#display-' + id).append(dispitem);

            value.push(item.id);
            if (max_choices != -1 && value.length >= max_choices)
            {
                $('#' + id).hide(); // hide the search box
            }
            $('#real-' + id).val(value.join(','));
            var searchbox = $('#q-' + id);
            searchbox.val(''); // empty search box
            searchbox.focus(); // focus to search box
            $('#results-' + id).empty(); // empty result list
        }
    }

    function user_search_widget_receive(json)
    {
        output.empty();
        $('#spinner-' + id).css("visibility", "hidden");
        $.each(json, function(i, item)
               {
                   var link = $('<a>' + item.name + '</a>');
                   link.click(function() { user_search_widget_name_click(item); });
                   $('<li/>').append(link).appendTo(output);
               });
    }

    var output = $('#results-' + id);
    var queryval = $('#q-' + id).val();
    if (queryval == "")
    {
        output.empty();
        return;
    }
    $('#spinner-' + id).css("visibility", "visible");;
    $.getJSON(
        script_name + 'search/members/ajax/',
        { name: queryval },
        user_search_widget_receive
    );
}

function user_search_widget_name_remove(id, itemid, max_choices)
{
    var value = $('#real-' + id).val().split(',');

    $('#disp-item-' + id + '-' + itemid).remove();

    value = jQuery.grep(value,
        function(a){ return a != itemid; });

    $('#real-' + id).val(value.join(','));

    if (value.length < max_choices)
    {
        $('#' + id).show(); // show the search box
    }
}

function clear_searchbox_focus(id)
{
    var searchbox = $('#' + id);
    if (searchbox.val() == "Search..."||searchbox.val() == "Last Name...")
    {
        searchbox.val('');
    } else {
	searchbox.select();
    }
    searchbox.removeClass('dimmed');
}

function clear_searchbox_blur(id)
{
    var searchbox = $('#' + id);
    if (searchbox.val() == "")
        searchbox.val('Search...');
    if (searchbox.val() == "Search..."||searchbox.val() == "Last Name...")
        searchbox.addClass('dimmed');
}

/** End functions for UserSearchWidget **/

function clear_invite_input_focus()
{
    var input = $("#invite-email-input")
    if(input.val() == "Enter Email..."){
        input.val("")
    }
    input.removeClass("dimmed")
}

function clear_invite_input_blur()
{
    var input = $("#invite-email-input")
    if(input.val() == ""){
	input.val("Enter Email...")
	input.addClass("dimmed")
    }
}

inline_help_shown = false;
function show_or_hide_inline_help(){
    if(inline_help_shown){
        $("div.inline-help").addClass("display-none");
        inline_help_shown = false;
    }else{
        $("div.inline-help").removeClass("display-none");
        inline_help_shown = true;
    }
}

function _clean_query(query){
    if(query == 'Search...' || query == 'Last Name...'){
	return '';
    }
    return query;
}

ajax_urls = {
    player: "search/members/ajax/?result_type=non-pros&",
    user: "search/members/ajax/?result_type=all&",
    pro: "search/members/ajax/?result_type=pros&",
    account: "search/members/ajax/?result_type=all&",
    club: "search/clubs/ajax/?",
    "user-noclub": "search/members/ajax/?result_type=all&",
    "user-draggable": "search/members/ajax/?result_type=all&"
};

searchresult_templates = {
    user: '<tr data-slug="{slug}" data-is-pro="{is_pro}">'
          + '<td class="main"><a href="{url}">{name}</a></td>'
          + '<td class="main">{home_club}</td>'
          + '<td><span class="button">{button_text}</span></td>'
        + '</tr>',
    club: '<tr data-slug="{slug}">'
          + '<td class="main"><a href="{url}">{name}</a></td>'
          + '<td><span class="button">{button_text}</span></td>'
        + '</tr>',
    "user-noclub": '<tr data-slug="{slug}" data-is-pro="{is_pro}">'
          + '<td class="main"><a href="{url}">{name}</a></td>'
          + '<td><span class="button">{button_text}</span></td>'
        + '</tr>',
    "user-draggable": '<div data-slug="{slug}" data-is-pro="{is_pro}" class="result">{name}</div>'
};
searchresult_templates["pro"] = searchresult_templates["user"];
searchresult_templates["account"] = searchresult_templates["user"];


function _searchbox(){
    var counter = 0;
    var searchbox = $(this);
    var clear_focus = function(){
        if (searchbox.val() == "Search..." || searchbox.val() == "Last Name..."){
            searchbox.val('');
        }
        searchbox.removeClass('dimmed');
    };

    searchbox.focus(clear_focus).blur(clear_focus);
    var search_type = searchbox.attr("data-search-type");
    var search_field = searchbox.attr("data-search-field");
    var button_text = searchbox.attr("data-button-text");
    var output_selector = searchbox.attr("data-output-selector");
    if(!output_selector) output_selector = ".results table";
    var onclick = searchbox.attr("data-onclick");
    if(!onclick) onclick=null;
    var params = searchbox.attr("data-search-params");
    if(!params) params='';
    var results_callback = searchbox.attr("data-results-callback");
    if(!results_callback) results_callback = null;
    var output = searchbox.parents(".searchbox").find(output_selector);
    var template = searchresult_templates[search_type];
    var search_func = function(){
        counter++;
        var local_counter = counter;
        var _callback = function(json){
            if(counter!=local_counter){
                return;
            }
            output.empty();
            $('#spinner').css("visibility", "hidden");
            $.each(json, function(i, context) {
                context["button_text"] = button_text;
                output.append($.format(template, context));
            });
            if(onclick) output.find("span.button").click(eval(onclick));
            if(results_callback) eval(results_callback)(output);
        };

        var value = _clean_query(searchbox.val());
        if (value == ""){
            output.empty();
        } else {
            $('#spinner').css("visibility", "visible");
            var data = {};
            data[search_field] = value;
            var url = script_name + ajax_urls[search_type];
            $.getJSON(url + params, data, _callback);
        }

    };
    searchbox.keyup(search_func);
}


function _searchbox2(){
    var $searchbox = $(this);
    $searchbox.data("counter", 0);
    var url = $searchbox.attr("data-search-url");
    var output_selector = $searchbox.attr("data-output-selector");
    if(!output_selector) output_selector = ".results";

    var output_callback = $searchbox.attr("data-output-callback");
    if(!output_callback) output_callback=null; else output_callback=eval(output_callback);

    var input_selector = $searchbox.attr("data-input-selector");
    if(!input_selector) input_selector='input.searchbox2-input';

    var params_data = $searchbox.attr("data-params");
    if(!params_data) params_data='{}';
    var params = eval("(" + params_data + ")");

    var $output = $searchbox.find(output_selector);
    var $input = $searchbox.find(input_selector);
    var search_func = function(){
        $searchbox.data("counter", $searchbox.data("counter") + 1);
        var local_counter = $searchbox.data("counter");
        var _callback = function(data){
            if($searchbox.data("counter")!=local_counter){
                return;
            }
            $output.empty().html(data);
            init_html($output);
            if(output_callback){output_callback(data);};
        };

        var value = $input.val();
        if (value == ""){
            $output.empty();
        } else {
            var data = {text: value};
            for (var attr in params){
                if(params.hasOwnProperty(attr)){
                    data[attr] = params[attr];
                }
            }
            $.get(url, data, _callback);
        }

    };
    $searchbox.find(input_selector).keyup(search_func);
}

function make_replacer(selector, callback){
    /* Return a function usable as an AJAX callback which replaces the
     selected elements with the HTML passed to the callback */
    return function(data){
        $(selector).html(data);
        if(callback){
            callback();
        }
    };
};

function make_replacer_init(selector, callback){
    /* Return a function usable as an AJAX callback which replaces the
     selected elements with the HTML passed to the callback */
    return function(data){
        $(selector).html(data);
        init_html($(selector));
        if(callback){
            callback();
        }
    };
};

function gameplan_wizard_callback(){
    var slug = $(this).parents("tr").attr("data-slug");
    var callback_url =  $(".wizard").attr("data-callback-url");
    var data = {};
    data["user-slug"] = slug;
    $.post(callback_url, data, make_replacer("#invitations"));
    $(".wizard .searchfield").val("").focus();
}

function gameplan_wizard_remove_callback(){
    var slug = $(this).parents("tr").attr("data-slug");
    var callback_url =  $(".wizard").attr("data-callback-url");
    var data = {};
    data["remove-user"] = slug;
    $.post(callback_url, data, make_replacer("#invitations"));
}

function gameplan_create_single_invite_callback(){
    var $tr = $(this).parents("tr");
    var slug = $tr.attr("data-slug");
    $(this).parents("form").append(
        '<input type="hidden" '
            + 'name="invite" '
            + 'value="' + slug + '"/>');
    $("table.invitations tbody").find("tr[data-slug=" + slug + "]").remove().end().append(
        '<tr data-slug="' + slug + '"><td>' + $tr.find("td:eq(0)").text() + "</td>" +
        '<td><span class="link invitation-remover">&otimes;</span></td></tr>');
    $(".results table").empty();
    $(".searchfield").scroll_to().val("").focus();
}
var gameplan_create_multi_invite_callback = gameplan_create_single_invite_callback;

function gameplan_single_dashboard_invite_callback(){
    var $tr = $(this).parents("tr");
    var slug = $tr.attr("data-slug");
    $(this).parents("form").append(
        '<input type="hidden" '
            + 'name="invite" '
            + 'value="' + slug + '"/>');
    $("table.invitations tbody").find("tr[data-slug=" + slug + "]").remove().end().append(
        '<tr data-slug="' + slug + '"><td>' + $tr.find("td:eq(0)").text() + "</td>" +
        '<td>Not yet sent</td><td>Not yet sent</td>' +
        '<td><span class="link invitation-remover">&otimes;</span></td></tr>');
}

function gameplan_single_inline_invite_callback(){
    var $tr = $(this).parents("tr");
    var slug = $tr.attr("data-slug");
    $(this).parents("form").append(
        '<input type="hidden" '
            + 'name="invite" '
            + 'value="' + slug + '"/>');
    $("table.invitations tbody").find("tr[data-slug=" + slug + "]").remove().end().append(
        '<tr data-slug="' + slug + '"><td>' + $tr.find("td:eq(0)").text() + "</td>" +
        '<td>Not yet sent</td>' +
        '<td><span class="link invitation-remover">&otimes;</span></td></tr>');
    $(".results table").empty();
    $(".searchfield").scroll_to().val("").focus();
}

function gameplan_invitation_remover_callback(){
    var $tr = $(this).parents("tr");
    var slug = $tr.attr("data-slug");
    $(this).parents("tbody").find("tr[data-slug=" + slug + "]").remove();
    $tr.remove();
    $("input[value=" + slug + "]").remove();
}


function bind_backboard(){
    $(".backboard").each(function(){
        var content_type = $(this).attr("data-content-type");
        var object_id = $(this).attr("data-object-id");
        var backboard = $(this);
        backboard.find(".backboard-submit").click(function(){
            var data = {};
            /* TODO: hardcoded */
            data["content_type"] = content_type;
            data["object_id"] = object_id;
            data["message"] = backboard.find(".backboard-message-content").val();
            $.post("/backboard/post/", data, function(data){
                backboard.find(".backboard-messages").html(data);
                backboard.find(".backboard-message-content").val("");
                bind_backboard_actions();
            });
            return false;
            });
        var get_data = {};
        get_data["content_type"] = content_type;
        get_data["object_id"] = object_id;

    });
    bind_backboard_actions();
}

function bind_backboard_actions(){
    $(".backboard-message-actions .delete-x").click(backboard_delete_callback);
}

function backboard_delete_callback(){
    var message = $(this).parents(".backboard-message-container");
    var backboard = message.parents(".backboard");
    var url = backboard.attr("data-action-url");
    var data = {
        message_id: message.attr("data-message-id"),
        action: "delete"
    };
    $.get(url, data, function(){message.hide(); });
}


function input_callback(){
    var name_node = $(".wizard .name,.dashboard .name");
    var input = name_node.find("input");
    var new_html = '<span class="inline-editable"><span class="content-value">' + input.val() + '</span> - <span class="link">edit</span></span>';
    var hidden_input = '<input type="hidden" name="name" value="' + input.val() + '"/>';
    input.replaceWith(new_html);
    name_node.find("input").remove();
    var span_node = name_node.find("span.inline-editable");
    span_node.append(hidden_input);
    name_node.find(".link").click(function(){span_callback();});
}


function span_callback(){
    var name_node = $(".wizard .name,.dashboard .name");
    var span = name_node.find("span.inline-editable");
    var input_html = '<input type="text" maxlength="64" value="" name="name" id="id_name"/>';
    var static_value = span.find(".content-value").text();
    span.replaceWith(input_html);
    name_node.find("span.inline-editable").remove();
    var input = name_node.find("input");
    input.val(static_value).blur(function(){input_callback();});
}


function bind_gameplan_wizard(){
    $(".step3 .dates tbody tr").hide();
    $("tr.errors").show();
    $(".wizard .name,.dashboard .name").each(function(){
        var input_node = $(this).find("input");
        input_callback();
    });
    $(".calendars tr td").click(function(){
        $(".dates tbody").css("visibility", "visible");
        var date_string = $(this).attr("data-date");
        var node = $(".dates tbody tr[taken!=taken] td:eq(0) input").eq(0);
        node.parents("tr").attr("taken", "taken").show();
        node.val(date_string);
    });
    $(".col-rotations input").val("1");

}


function networks_friend_callback(){
    var slug = $(this).parents("tr").attr("data-slug");
    var callback_url =  $(this).parents(".searchbox").attr("data-callback-url");
    data = {};
    data["friend-slug"] = slug;
    if(!$.browser.msie){
        $.post(callback_url, data, make_replacer("#players-groups table.items", bind_check_all));
    }else{
    $.post(callback_url, data, function(data){
               $("#players-groups").html(data);
               bind_check_all();
           });
    }
    $(".searchfield").val("").focus();
}


function networks_pro_callback(){
    var slug = $(this).parents("tr").attr("data-slug");
    var callback_url =  $(this).parents(".searchbox").attr("data-callback-url");
    var data = {};
    data["pro-slug"] = slug;
    if(!$.browser.msie){
        $.post(callback_url, data, make_replacer("#players-groups table.items", bind_check_all));
    }else{
        $.post(callback_url, data, function(data){
               $("#players-groups").html(data);
               bind_check_all();
           });
    }
    $(".searchfield").val("").focus();
}


function add_club_callback(){
    var slug = $(this).parents("tr").attr("data-slug");
    var callback_url =  $(this).parents(".searchbox").attr("data-callback-url");
    var data = {};
    data["add-club"] = slug;
    if(!$.browser.msie){
        $.post(callback_url, data, make_replacer("#auxiliary-clubs table.items", bind_check_all));
    }else{
    $.post(callback_url, data, function(data){
               $("#auxiliary-clubs").html(data);
               bind_check_all();
           });
    }
    $(".searchfield").val("").focus();
}

function check_all_callback(){
    // The checkbox in the table header, determining what all the others do
    var toggler = $(this);
    var checked = this.checked;
    toggler.parents("table").find(":checkbox").each(function(){
         this.checked = checked;
    });
}


function bind_check_all(){
}

function queryParameters(query) {
    var keyValuePairs = query.split(/[&?]/g);
    var params = {};
    for (var i = 0, n = keyValuePairs.length; i < n; ++i) {
        var m = keyValuePairs[i].match(/^([^=]+)(?:=([\s\S]*))?/);
        if (m) {
            var key = decodeURIComponent(m[1]);
            (params[key] || (params[key] = [])).push(decodeURIComponent(m[2]));
        }
    }
    return params;
}

function default_value_callback(){
    $(this).removeClass("default-value").val("").unbind("focus", default_value_callback);
}
function remove_default_values_callback(){
    $(this).find(".default-value").each(function(){$(this).val("")});
    return true;
}

function reload(){
    log("reloading");
    window.location.reload();
}

function get_date(str) {
    var bits = str.split("/");
    var day = Number(bits[1]);
    var month = Number(bits[0]) - 1;
    var year = Number(bits[2]);
    var d = new Date();
    d.setFullYear(year);
    d.setMonth(month);
    d.setDate(day);
    d.setSeconds(0);
    d.setMilliseconds(0);
    return d;
}

function init_tinymce(){
    if(typeof tinyMCE != "undefined"){
        tinyMCE.init({
            mode : "none",
            theme : "advanced",
            plugins : "advhr,advlink,style",
            theme_advanced_layout_manager : "SimpleLayout",
            theme_advanced_disable: "hr,",
            theme_advanced_buttons1: "justifyleft,"
                + "justifycenter,"
                + "justifyright,"
                + "justifyfull,"
                + "separator,"
                + "removeformat,"
                + "separator,"
                + "bold,"
                + "underline,"
                + "italic,"
                + "separator,"
                + "link,"
                + "separator,"
                + "bullist,"
                + "numlist,"
                + "fontsizeselect,",
            theme_advanced_buttons2: "",
            theme_advanced_buttons3: "",
            theme_advanced_toolbar_location : "top",
            theme_advanced_toolbar_align : "left"});

    }
}

function _setup_scroller(){
    var $scroller_wrapper = $(this);
    $scroller_wrapper.find(".scroll-handle-right").click(_scroller_right_click);
    $scroller_wrapper.find(".scroll-handle-left").click(_scroller_left_click);
}

function _scroller_right_click(){
    var $scroller_wrapper = $(this).parents(".scroller-wrapper")
    var $non_offscreen = $scroller_wrapper.find(".scroller-item:not(.scroller-offscreen)")
    var $last = $non_offscreen.last();
    var last_pos = $last.position()
    var wrapper_pos = $scroller_wrapper.find(".wrapper").position();
    var scroller_width = $scroller_wrapper.innerWidth() - ($last.width() / 2);
    if((last_pos.left + wrapper_pos.left) < scroller_width){return;}
    if($non_offscreen.length<3){return}
    var width = $non_offscreen.eq(0).addClass("scroller-offscreen").outerWidth();
    $scroller_wrapper.find(".wrapper").animate({left:'-='+ width},200, 'linear');
}

function _scroller_left_click(){
    var $scroller_wrapper = $(this).parents(".scroller-wrapper")
    var width = $scroller_wrapper.find(".scroller-offscreen:last").removeClass("scroller-offscreen").outerWidth();
    $scroller_wrapper.find(".wrapper").animate({left: '+='+ width},200, 'linear');
}

function _ajax_action_callback(){
    var pre_callback = $(this).attr("data-ajax-action-pre");
    log(pre_callback);
    if(pre_callback){eval(pre_callback);}
    var action = $(this).attr("data-action");
    var extra = $(this).attr("data-extra-data");
    var url_var = $(this).attr("data-url-var")||"root_ajax_url";
    var url = eval(url_var);

    var params = csutil.ajax.get_params(this);
    params.action = action
    params.extra = extra
    $.post(url, params, _make_ajax_action_callback(this))
}

function _make_ajax_action_callback(node){
    var $node = $(node);
    var callbacks = [];
    if($node.hasAttr("data-onclick")){
        callbacks.push($node.attr("data-onclick"));
    }
    if($node.hasAttr("data-callback")){
        callbacks.push($node.attr("data-callback"));
    }
    return function(data){
        $.each(callbacks, function(ii, sub_callback){
            log("sub_callback" + sub_callback);
            eval(sub_callback)(data);
        });
    }
}

function _toggle_userclubrels(){
    $("#user-subclubrels").toggleClass("display-none")
}
function _toggle_usercommrels(){
    $("#user-subcommrels").toggleClass("display-none")
}


function _ajax_submit_callback(){
    var $this = $(this);
    var extra = $this.attr("data-extra-data");
    var $form = $this.closest(".ajax-form");
    $form.trigger("pre-ajax-submit");
    var submit_value = $this.attr("data-submit-value")||"";
    var action = $form.attr("data-action")
    var url_var = $form.attr("data-url-var")||"root_ajax_url";
    var data = $form.serialize();
    data += "&action=" + action;
    data += "&submit-value=" + submit_value;
    if(extra){
        data += "&extra=" + extra;
    }
    var url = eval(url_var);
    $.post(url, data, _make_ajax_action_callback($form));
}

function _adjust_height_callback(){
    var target_selector = $(this).attr("data-height-target");
    var new_height = $(target_selector).height();
    log(new_height);
    $(this).css("height", new_height);
}

function child_account_change(){
    if($(this).val()==""){return;}
    else{
    }
}
function _ajax_dialog_setup(){
    var dialog_name = $(this).attr("data-dialog-name");
    var extra_data = $(this).attr("data-extra-data");
    var dialog_width = parseInt($(this).attr("data-dialog-width")||"800", 10);
    var dialog_height = parseInt($(this).attr("data-dialog-height")||"600", 10);
    var dialog_title = $(this).attr("data-dialog-title")||"Courtside";
    var dialog_url = $(this).attr("data-url-var")||"homecourt_ajax_url";

    $(this).click(function(){
        url = eval(dialog_url);        
        $.post(url, {"action": "get-ajax-dialog", "dialog-name": dialog_name, "extra": extra_data}, function(data){
            $("#ajax-dialog").html(data).dialog({modal: true})
                .dialog("option", "width", dialog_width)
                .dialog("option", "title", dialog_title)
                .dialog("option", "height", dialog_height).dialog("open");
            $("#ajax-dialog").find(".timepicker").timePicker({
                startTime: new Date(0, 0, 0, 0, 0, 0),
                endTime: new Date(0, 0, 0, 23, 0, 0),
                show24Hours: false
            })

            $("#ajax-dialog").bind("dialogclose", function(event, ui){

    if(typeof tinyMCE != "undefined"){
            $(this).find("textarea.editor").each(function(){
                var id = $(this).attr("id");
                tinyMCE.execCommand("mceRemoveControl", false, id);
            });
    }


            });
            init_html($("#ajax-dialog"));
        });
    });
}


function _setup_subnav0(){
    var $this = $(this);
    var $container = $this.parents(".has-subnav0");
    $container.css("position", "relative");
    $this.css({position: "absolute", top: $container.outerHeight(), left: 0});
    $container.bind("mouseenter", function(){$this.removeClass("display-none");});
    $container.bind("mouseleave", function(){$this.addClass("display-none");});
}
