/* 
 * cone.app main JS
 * 
 * Requires:
 *     bdajax
 *     jquery ui autocomplete
 */

if (typeof(window['yafowil']) == "undefined") yafowil = {};

(function($) {

    $(document).ready(function() {
        
        // personaltools
        $('#personaltools').dropdownmenu({
            menu: '.dropdown_items',
            trigger: '.currentuser a'
        });
        
        // initial binding
        cone.key_binder();
        cone.livesearchbinder();
        cone.tabsbinder();
        cone.dropdownmenubinder();
        cone.transitionmenubinder();
        cone.tabletoolbarbinder();
        cone.sharingbinder();
        cone.selectable.binder();
        cone.copysupportbinder();
        yafowil.referencebrowser.browser_binder();
        
        // add binders to bdajax binding callbacks
        $.extend(bdajax.binders, {
            tabsbinder: cone.tabsbinder,
            dropdownmenubinder: cone.dropdownmenubinder,
            transitionmenubinder: cone.transitionmenubinder,
            tabletoolbarbinder: cone.tabletoolbarbinder,
            sharingbinder: cone.sharingbinder,
            selectablebinder: cone.selectable.binder,
            copysupportbinder: cone.copysupportbinder,
            refbrowser_browser_binder: yafowil.referencebrowser.browser_binder,
            refbrowser_add_reference_binder:
                yafowil.referencebrowser.add_reference_binder,
            refbrowser_remove_reference_binder:
                yafowil.referencebrowser.remove_reference_binder
        });
    });
    
    cone = {
            
        // object to store global flags
        flags: {},
                
        // keyboard control keys status
        keys: {},
        
        // keydown / keyup binder for shift and ctrl keys
        key_binder: function() {
            $(document).bind('keydown', function(event) {
                switch (event.keyCode || event.which) {
                    case 16:
                        cone.keys.shift_down = true;
                        break;
                    case 17:
                        cone.keys.ctrl_down = true;
                        break;
                }
            });
            $(document).bind('keyup', function(event) {
                switch (event.keyCode || event.which) {
                    case 16:
                        cone.keys.shift_down = false;
                           break;
                    case 17:
                        cone.keys.ctrl_down = false;
                        break;
                }
            });
        },
        
        livesearchbinder: function(context) {
            $('input#search-text', context).autocomplete({
                source: 'livesearch',
                minLength: 3,
                select: function(event, ui) {
                    $('input#search-text').val('');
                    bdajax.action({
                        name: 'content',
                        selector: '#content',
                        mode: 'inner',
                        url: ui.item.target,
                        params: {}
                    });
                    bdajax.trigger('contextchanged',
                                   '.contextsensitiv',
                                   ui.item.target);
                    return false;
                }
            });
        },
        
        tabsbinder: function(context) {
            // normal tabs
            $('ul.tabs', context).tabs('div.tabpanes > div');
            // ajax tabs
            $('ul.ajaxtabs', context).tabs('div.ajaxtabpanes > div');
            $('ul.ajaxtabs li a', context).bind('click', function(event) {
                event.preventDefault();
                var elem = $(this);
                var target = bdajax.parsetarget(elem.attr('ajax:target'));
                bdajax.request({
                    url: target.url,
                    params: target.params,
                    success: function(data, status, request) {
                        var container = elem.parents('.ajaxtabs').parent();
                        $('.ajaxtabpane', container)
                            .html(data).css('display', 'block').bdajax();
                    }
                });
            }).first().trigger('click');
        },
        
        dropdownmenubinder: function(context) {
            $('.dropdown', context).dropdownmenu();
        },
        
        transitionmenubinder: function(context) {
            $('.transitions_dropdown', context).dropdownmenu({
                menu: '.dropdown_items',
                trigger: '.state a'
            });
        },
        
        tabletoolbarbinder: function(context) {
            var selection = $('.pretty_table_length select', context);
            selection.unbind('change').bind('change', function(event) {
                var option = $('option:selected', $(this)).first();
                var size = option.text();
                var evt = selection.attr('ajax:event').split(':');
                var target = selection.attr('ajax:target') + '&size=' + size;
                bdajax.trigger(evt[0], evt[1], target);
            });
            var trigger_search = function(input) {
                var term = input.attr('value');
                var evt = input.attr('ajax:event').split(':');
                var target = input.attr('ajax:target') + '&term=' + term;
                bdajax.trigger(evt[0], evt[1], target);
            };
            var searchfield = $('.pretty_table_filter input', context);
            searchfield.unbind('keypress').bind('keypress', function(event) {
                if (event.keyCode == 13) {
                    event.preventDefault();
                }
            });
            searchfield.unbind('keyup').bind('keyup', function(event) {
                if (event.keyCode == 13) {
                    event.preventDefault();
                    trigger_search($(this));
                }
            });
            searchfield.unbind('change').bind('change', function(event) {
                event.preventDefault();
                trigger_search($(this));
            });
        },
        
        sharingbinder: function(context) {
            var checkboxes = $('input.add_remove_role_for_principal', context);
            checkboxes.unbind('change').bind('change', function(event) {
                event.preventDefault();
                var checkbox = $(this);
                var action;
                if (this.checked) {
                    action = 'add_principal_role';
                } else {
                    action = 'remove_principal_role';
                }
                var url = checkbox.parent().attr('ajax:target');
                var params = {
                    id: checkbox.attr('name'),
                    role: checkbox.attr('value')
                };
                bdajax.action({
                    name: action,
                    mode: 'NONE',
                    selector: 'NONE',
                    url: url,
                    params: params
                });
            });
        },
        
        copysupportbinder: function(context) {
            var cut_cookie = 'cone.app.copysupport.cut';
            var copy_cookie = 'cone.app.copysupport.copy';
            var write_selected_to_cookie = function(name) {
                var selected = $(cone.selectable.selected);
                var ids = new Array();
                selected.each(function() {
                    ids.push($(this).attr('ajax:target'));
                });
                var cookie = ids.join('::');
                createCookie(name, cookie);
                if (cookie.length) {
                    return true;
                }
                return false;
            };
            $('a.cut16_16', context).unbind('click').bind('click',
                                                          function(event) {
                event.preventDefault();
                createCookie(copy_cookie, '', 0);
                var selected_exist = 
                    write_selected_to_cookie(cut_cookie);
                if (selected_exist) {
                    $('a.paste16_16').removeClass('disabled');
                }
                var selectable = $('.selectable');
                selectable.removeClass('copysupport_cut');
                var selected = $(cone.selectable.selected);
                selected.each(function() {
                    elem = $(this);
                    elem.addClass('copysupport_cut');
                });
                cone.selectable.reset();
            });
            $('a.copy16_16', context).unbind('click').bind('click',
                                                           function(event) {
                event.preventDefault();
                createCookie(cut_cookie, '', 0);
                var selected_exist = 
                    write_selected_to_cookie(copy_cookie);
                if (selected_exist) {
                    $('a.paste16_16').removeClass('disabled');
                }
                var selectable = $('.selectable');
                selectable.removeClass('copysupport_cut');
                cone.selectable.reset();
            });
            $('a.paste16_16', context).unbind('click').bind('click',
                                                            function(event) {
                event.preventDefault();
                var elem = $(this);
                if (elem.hasClass('disabled')) {
                    return;
                }
                var target = bdajax.parsetarget(elem.attr('ajax:target'));
                bdajax.action({
                    name: 'paste',
                    mode: 'NONE',
                    selector: 'NONE',
                    url: target.url,
                    params: target.params
                });
            });
        }
    }
    
    /* 
     * Dropdown menu
     * =============
     * 
     * Markup
     * ------
     * 
     *     <div class="dropdown">
     *       <div class="icon">
     *         <a href="http://example.com">&nbsp;</a>
     *       </div>
     *       <ul class="dropdown_items" style="display:none;">
     *         <li>
     *           <a href="http://example.com/whatever">
     *             Item title
     *           </a>
     *         </li>
     *       </ul>
     *     </div>
     * 
     * Script
     * ------
     * 
     *     $('.dropdown').dropdownmenu({
     *         menu: '.dropdown_items',
     *         trigger: '.icon a'
     *     });
     */
    $.fn.dropdownmenu = function (options) {
        var trigger = options ? (options.trigger ? options.trigger : '.icon a')
                              : '.icon a';
        var menu = options ? (options.menu ? options.menu : '.dropdown_items')
                           : '.dropdown_items';
        this.unbind('click');
        $(trigger, this).bind('click', function(event) {
            event.preventDefault();
            var container = $(menu, $(this).parent().parent());
            $(document).unbind('mousedown')
                       .bind('mousedown', function(event) {
                if ($(event.target).parents(menu + ':first').length) {
                    return true;
                }
                container.css('display', 'none');
            });
            container.css('display', 'block');
        });
        return this;
    }
    
    /*
     * Selectable Items
     * ================
     * 
     * Markup
     * ------
     * 
     *     <div>
     *       <div class="selectable">selectable 1</div>
     *       <div class="selectable">selectable 2</div>
     *     </div>
     * 
     * Script
     * ------
     * 
     *     $('div.selectable').selectable();
     */
    $.fn.selectable = function() {
        this.unbind('click').bind('click', function(event) {
            event.preventDefault();
            $(document).unbind('mousedown')
                       .bind('mousedown', function(event) {
                var elem = $(event.target);
                // XXX: currently static selector
                if (elem.parents('.selectable').length) {
                    return true;
                }
                $('.selectable').removeClass('selected');
                $(document).unbind('mousedown');
                return false;
            });
            var elem = $(event.currentTarget);
            var container = elem.parent();
            if (!cone.keys.ctrl_down && !cone.keys.shift_down) {
                container.children().removeClass('selected');
                elem.addClass('selected');
                cone.selectable.reset();
                cone.selectable.add(event.currentTarget);
            } else {
                if (cone.keys.ctrl_down) {
                    elem.toggleClass('selected');
                    if (elem.hasClass('selected')) {
                        cone.selectable.add(event.currentTarget);
                    } else {
                        cone.selectable.remove(event.currentTarget);
                    }
                }
                if (cone.keys.shift_down) {
                    var selected = container.children('.selected');
                    // get nearest next selected item, disable others
                    var current_index = elem.index();
                    // -1 means no other selected item
                    var nearest = -1;
                    var selected_index, selected_elem;
                    $(selected).each(function() {
                        selected_elem = $(this);
                        selected_index = selected_elem.index();
                        if (nearest == -1) {
                            nearest = selected_index;
                        } else if (current_index > selected_index) {
                            if (cone.flags.select_direction > 0) {
                                if (selected_index < nearest) {
                                    nearest = selected_index;
                                }
                            } else {
                                if (selected_index > nearest) {
                                    nearest = selected_index;
                                }
                            }
                        } else if (current_index < selected_index) {
                            if (selected_index < nearest) {
                                nearest = selected_index;
                            }
                        }
                    });
                    if (nearest == -1) {
                        elem.addClass('selected');
                        cone.selectable.add(event.currentTarget);
                    } else {
                        container.children().removeClass('selected');
                        var start, end;
                        if (current_index < nearest) {
                            cone.flags.select_direction = -1;
                            start = current_index;
                            end = nearest;
                        } else {
                            cone.flags.select_direction = 1;
                            start = nearest;
                            end = current_index;
                        }
                        cone.selectable.reset();
                        container.children()
                                 .slice(start, end + 1)
                                 .addClass('selected')
                                 .each(function() {
                                     cone.selectable.add(this);
                                 });
                    }
                }
            }
        });
        return this;
    }
    
    $.extend(cone, {
        
        selectable: {
            
            // current selected dom elements
            selected: [],
            
            // reset
            reset: function() {
                cone.selectable.selected = [];
            },
            
            // add element to selected
            add: function(elem) {
                cone.selectable.remove(elem);
                cone.selectable.selected.push(elem);
            },
            
            // remove element from selected
            remove: function(elem) {
                var reduced = $.grep(cone.selectable.selected,
                                     function(item, index) {
                    return item !== elem;
                });
                cone.selectable.selected = reduced;
            },
            
            binder: function(context) {
                $('table tr.selectable', context).selectable();
            }
        }
    });
    
    /*
     * Reference Browser
     * =================
     * 
     * Markup
     * ------
     * 
     *     <input type="text" name="foo" class="referencebrowser" />
     *     <input type="hidden" name="foo.uid" value="" />
     * 
     * for single value reference or
     * 
     *     <select name="foo" class="referencebrowser" />
     * 
     * for multi valued reference.
     * 
     * Script
     * ------
     * 
     *     $('input.referencebrowser').referencebrowser();
     */
    $.fn.referencebrowser = function() {
        var icon = $('<a>&nbsp;</a>').attr('class', 'reference16_16');
        this.after(icon);
        icon = this.next();
        icon.unbind('click');
        icon.bind('click', function() {
            var elem = $(this);
            yafowil.referencebrowser.target = elem.prev().get(0);
            bdajax.overlay({
                action: 'referencebrowser',
                target: elem.parent().attr('ajax:target')
            });
        });
        return this;
    }
    
    // extend yafowil by reference browser widget.
    $.extend(yafowil, {
        
        referencebrowser: {
            
            target: null,
            
            overlay: function() {
                return $('#ajax-overlay').data('overlay');
            },
            
            browser_binder: function(context) {
                $('input.referencebrowser', context).referencebrowser();
                $('select.referencebrowser', context).referencebrowser();
            },
            
            add_reference_binder: function(context) {
                $('a.addreference').unbind('click')
                                   .bind('click', function(event) {
                    event.preventDefault();
                    yafowil.referencebrowser.addreference($(this));
                });
            },
            
            remove_reference_binder: function(context) {
                $('a.removereference').unbind('click')
                                      .bind('click', function(event) {
                    event.preventDefault();
                    yafowil.referencebrowser.removereference($(this));
                });
            },
            
            addreference: function(elem) {
                var target = $(this.target);
                var uid = elem.attr('id');
                uid = uid.substring(4, uid.length);
                var label = $('.reftitle', elem.parent()).html();
                if (this.singlevalue()) {
                    target.attr('value', label);
                    var sel = '[name="' + target.attr('name') + '.uid"]';
                    $(sel).attr('value', uid);
                    this._set_selected_on_ajax_target(target.parent(), [uid]);
                    this.overlay().close();
                    return;
                }
                if (this.multivalue()) {
                    if ($('[value="' + uid + '"]', target.parent()).length) {
                        return;
                    }
                    var option = $('<option></option>');
                    option.val(uid).html(label).attr('selected', 'selected');
                    target.append(option);
                }
                this._reset_selected(target);
                this._toggle_enabled(elem);
            },
            
            removereference: function(elem) {
                var target = $(this.target);
                var uid = elem.attr('id');
                uid = uid.substring(4, uid.length);
                if (this.singlevalue()) {
                    target.attr('value', '');
                    var sel = '[name="' + target.attr('name') + '.uid"]';
                    $(sel).attr('value', '');
                }
                if (this.multivalue()) {
                    var sel = '[value="' + uid + '"]';
                    if (!$(sel, target.parent()).length) {
                        return;
                    }
                    $(sel, target).remove();
                }
                this._reset_selected(target);
                this._toggle_enabled(elem);
            },
            
            singlevalue: function() {
                return this.target.tagName == 'INPUT';
            },
            
            multivalue: function() {
                return this.target.tagName == 'SELECT';
            },
            
            _toggle_enabled: function(elem) {
                $('a', elem.parent()).toggleClass('disabled');
            },
            
            _reset_selected: function(elem) {
                var selected = new Array();
                if (this.singlevalue()) {
                    selected.push(elem.attr('value'));
                }
                if (this.multivalue()) {
                    $('[selected=selected]', elem).each(function() {
                        selected.push($(this).attr('value'));
                    });
                }
                this._set_selected_on_ajax_target(elem.parent(), selected);
                var overlay = this.overlay().getOverlay();
                var rb;
                $('div.referencebrowser a', overlay).each(function() {
                    var link = $(this);
                    if (link.attr('ajax:target')) {
                        rb = yafowil.referencebrowser;
                        rb._set_selected_on_ajax_target(link, selected);
                    }
                });
            },
            
            _set_selected_on_ajax_target: function(elem, selected) {
                var target = bdajax.parsetarget(elem.attr('ajax:target'));
                target.params.selected = selected.join(',');
                var query = new Array();
                for (var name in target.params) {
                    query.push(name + '=' + target.params[name]);
                }
                elem.attr('ajax:target', target.url + '?' + query.join('&'));
            }
        }
    });

})(jQuery);