var tick_select_boxes = {
  '.select:click': function(element) {
    boxes = $$('.select_tick_boxes input')
    tick = true;

    boxes.each( function(input) {
      if(input.checked) {
        tick = false;
      }
    });

    // untick if there's already a ticked box
    boxes.each( function(input) {
      input.checked = tick;
    });
  }
}

// tick parent {{{1
//
// naming convention:
//
// make a div with class="dependency_tree" and nested dl
var tick_parent = {
	'.dependency_tree label input:click': function(element) {
        parts = element.id.split(']');
        
        start_of_id = parts[0] + ']' + parts[1] + ']';

        $$('.dependency_tree input').each( function(input) {
            if ((input.id.indexOf(start_of_id) == 0) && element.checked && input.id.length < element.id.length) {
                input.checked = true;
            }
        });
	}
}

// auto-focus (and select) errors {{{1
//
// naming convention:
// 
// * errors must use the class .fieldWithErrors (Rails' default)
var auto_focus_errors = {
    '.fieldWithErrors': function(element) {
        $$('.fieldWithErrors')[0].focus();
        $$('.fieldWithErrors')[0].select();
    }
}

// auto-submit selects {{{1
// 
// naming convention:
// 
// * give your select a class of 'auto_submit' and it will... automatically submit

var auto_submit = {
    'select.auto_submit:change': function(element, event) {
        element.form.submit();
    }
}

// select_swap_optgroups: select boxes that copy from one to another NOW WITH OPTGROUPS! {{{1

// naming conventions:
//
// * selects must have ids 'from_xxx' and 'to_xxx'
// * buttons must have ids 'add_xxx' and 'remove_xxx'
// * buttons must have classes 'link_add' and 'link_remove'
// * form must have class 'select_swap' if you want to submit
//   the unselected items in the destination box
// * optgroup names MUST BE UNIQUE!

if ($$('.select_swap_optgroups'))
var select_swap_optgroups = {
    // form submitting
    // select all of the to-boxes options before submitting to server
    'form.select_swap_optgroups:submit': function(element, event) {
        var boxes = element.getElementsByTagName('select');
        boxes = $A(boxes);

        // get all 'to' boxes
        var to_boxes = boxes.findAll(function(opt){
                return opt.id.indexOf('to_') == 0;
                });

        // select all of the 'to' boxes' options
        to_boxes.each(function(box){
                options = getOptions(box);
                var i = 0;
                options.each(function(opt){
                    box.options[i].selected = true;
                    i++;
                    });
                });
    },

    // adding
    '.link_add:click': function(element, event) {

        // substring gets everything after 'add_'
        var name = element.id.substring(4);

        var to_box = $('to_' + name);
        var from_box = $('from_' + name);

        moveOptionsBetweenOptGroups(from_box, to_box); 

        Event.stop(event);
    },

    // removing
    '.link_remove:click': function(element, event) {

        // substring gets everything after 'remove_'
        var name = element.id.substring(7);

        // to and from are reverse for removing
        var to_box = $('from_' + name);
        var from_box = $('to_' + name);

        moveOptionsBetweenOptGroups(from_box, to_box); 

        Event.stop(event);
    }
}

// select_swap: select boxes that copy from one to another {{{1

// naming conventions:
//
// * selects must have ids 'from_xxx' and 'to_xxx'
// * buttons must have ids 'add_xxx' and 'remove_xxx'
// * buttons must have classes 'link_add' and 'link_remove'
// * form must have class 'select_swap' if you want to submit
//   the unselected items in the destination box

var select_swap = {
    // form submitting
    // select all of the to-boxes options before submitting to server
    'form.select_swap:submit': function(element, event) {
        var boxes = element.getElementsByTagName('select');
        boxes = $A(boxes);

        // get all 'to' boxes
        var to_boxes = boxes.findAll(function(opt){
                return opt.id.indexOf('to_') == 0;
                });

        // select all of the 'to' boxes' options
        to_boxes.each(function(box){
                options = getOptions(box);
                var i = 0;
                options.each(function(opt){
                    box.options[i].selected = true;
                    i++;
                    });
                });
    },

    // adding
    '.link_add:click': function(element, event) {

        // substring gets everything after 'add_'
        var name = element.id.substring(4);

        var to_box = $('to_' + name);
        var from_box = $('from_' + name);

        moveOptions(from_box, to_box); 

        Event.stop(event);
    },

    // removing
    '.link_remove:click': function(element, event) {

        // substring gets everything after 'remove_'
        var name = element.id.substring(7);

        // to and from are reverse for removing
        var to_box = $('from_' + name);
        var from_box = $('to_' + name);

        moveOptions(from_box, to_box); 

        Event.stop(event);
    }
}

// return options of an element as an array {{{1
function getOptions(el){
    el_options = el.getElementsByTagName('option');
    return $A(el_options);
}

// return optgroups of a select as an array {{{1
function getOptGroups(el){
    el_optgroups = el.getElementsByTagName('optgroup');
    return $A(el_optgroups);
}

// moves selected options from one select box to another {{{1
function moveOptions(from_box, to_box) {
    var to_options = getOptions(to_box);
    var from_options = getOptions(from_box);

    // get selected options
    var selected = from_options.findAll(function(opt){
            return opt.selected;
            });

    // add the options to the destination
    // note we don't use to_options as that is an array
    selected.each(function(opt){
            to_box.options.add(opt);
            });
}

function getOptGroupByLabel(element, lbl) {
    ogs = element.getElementsByTagName('optgroup');

    for(i=0,n=ogs.length;i<n;i++){
        if (ogs[i].label == lbl)
            return ogs[i];
    }
    return false;
}

// moves selected options from one select's optgroup to another select's optgroup with the same name {{{1
function moveOptionsBetweenOptGroups(from_box, to_box) {
    var to_optgroups = getOptGroups(to_box);
    var from_optgroups = getOptGroups(from_box);

    var ar_opts = new Array();
    var opts;

    // store whether this is an exclusive_names box, which should remove optgroups when only one item is transferred
    var exclusive = from_box.parentNode.parentNode.parentNode.hasClassName('exclusive_names');

    // loop thru each 'from' optgroup
    from_optgroups.each( function(from_og) {
        from_opts = getOptions(from_og);

        /* loop thru each 'from' option */
        from_opts.each( function(from_o) {

            if (from_o.selected) {

                /* find 'real' optgroup by label */
                found_og = getOptGroupByLabel(to_box, from_og.label);

                if (found_og) {
                    /* if it was found, append! */
                    found_og.appendChild(from_o); 

                } else {
                    /* otherwise make it and add */
                    new_og = document.createElement('optgroup');
                    new_og.label = from_og.label;
                    to_box.appendChild(new_og);
                    new_og.appendChild(from_o);
                }
            }

            /* if the from optgroup is now empty delete it */
            /* can't seem to get exclusive_names - only stuff to delete - it claims there is no element */
            if (from_og.getElementsByTagName('option').length < 1) {
                Element.remove(from_og);
            }
        });
    });
}
