$(function(){
    /*
     * A simple cloud jquery widget.
     * Special attributes:
     * cloudSelection = a selector to find the input element to hold the selected items.
     * masterCloud = a selector to find the masterCloud that is then expected to have a cloudSelection attribute. ( saves having to keep slave clouds up to date with ids. )
     * 
     * each ui-selectee element:
     * 'cloudId' attribute that is the value saved as the key in the map stored in cloudSelection input element.
     * 'unselectedCssClass' / 'selectedCssClass' : optional class that is toggled in sync with the selection state. ( is this really needed? )
     * 
     */
    amplafi.cloud = {
        getMasterCloud : function getMasterCloud(target) {
            var masterCloudSelector = target.attr("masterCloud");
            var masterCloud;
            if ( masterCloudSelector ) {
                masterCloud = $(masterCloudSelector);
            } else {
                masterCloud = target;
            }
            return masterCloud;
        },
        getSelectedCloud: function getSelectedCloud(target) {
            var masterCloud = amplafi.cloud.getMasterCloud(target);
            var inputElementSelector = masterCloud.attr("cloudSelection");
            var inputElement = $(inputElementSelector);
            return inputElement;
        },
        getSelectionObject : function getSelectionObject(inputElement) {
            var inputElementVal = inputElement.val();
            var selected = $.parseJSON(inputElementVal);
            if ( selected == null) {
                selected = {};
            }
            return selected;
        },
        forceSelection : function(cloud) {
            var inputElement = amplafi.cloud.getSelectedCloud(cloud);
            var selected = amplafi.cloud.getSelectionObject(inputElement);
            // apply existing selection
            $(".ui-selectee", cloud).each(function(key, element){
                var cloudElement = $(element);
                var cloudId = cloudElement.attr("cloudId");
                if ( cloudId in selected ) {
                    cloudElement.addClass("ui-selected");
                } else {
                    cloudElement.removeClass("ui-selected");
                }
            });
            var reserialize = inputElement.val();
            var currentValue = cloud.prop("currentValue");   
            cloud.prop("currentValue", reserialize);
        },
        reserialize: function(selected, cloud) {
        	var inputElement = amplafi.cloud.getSelectedCloud(cloud);
        	var reserialize = $.toJSON(selected);
            var currentValue = cloud.prop("currentValue");
            cloud.prop("currentValue", reserialize);
            if ( reserialize != inputElement.val()) {
                inputElement.val(reserialize);   
                inputElement.change();
            }
        }
    };
    // a cloud is a selectable
    $(".cloud").live("selectablecreate", function(eventObject, ui){
        // on create make sure have a place to store selections
        // create hidden input if no master
        var target = $(eventObject.currentTarget);
        var cloud = target;

        amplafi.cloud.forceSelection(cloud);
        var inputElement = amplafi.cloud.getSelectedCloud(cloud);
        inputElement.change(function(eventObject){
            var target = $(eventObject.currentTarget);
            // sync with master
            var currentInputValue = target.val();
            var cloudValue = cloud.prop("currentValue");
            if ( currentInputValue != cloudValue) {
                // the selection was changed by another cloud or some external means.
                amplafi.cloud.forceSelection(cloud);
            }
        });
    });
    $(".cloud").live("selectableselected", function(eventObject, ui){
        var target = $(eventObject.currentTarget);
        var cloudElement = $(ui.selected);
        // cannot just rely on the normal classes as will be different?
        cloudElement.switchClass(cloudElement.attr("unselectedCssClass"), cloudElement.attr("selectedCssClass"));
        var cloudId = cloudElement.attr("cloudId");
        
        var inputElement = amplafi.cloud.getSelectedCloud(target);
        var inputElementVal = inputElement.val();
        var selected = $.parseJSON(inputElementVal);
        if ( selected == null) {
            selected = {};
        }
        selected[cloudId] = true;
        amplafi.cloud.reserialize(selected, target);
    });
    
    $(".cloud").live("selectableunselected", function(eventObject, ui){
        var target = $(eventObject.currentTarget);
        var cloudElement = $(ui.unselected);
        var inputElement = amplafi.cloud.getSelectedCloud(target);
        cloudElement.switchClass(cloudElement.attr("selectedCssClass"), cloudElement.attr("unselectedCssClass"));
        var inputElementVal = inputElement.val();
        var cloudId = cloudElement.attr("cloudId");
        var selected = $.parseJSON(inputElementVal);
        if ( selected == null) {
            selected = {};
        }
        delete selected[cloudId];
        amplafi.cloud.reserialize(selected, target);
    });
    $(".cloud").bind("mousedown", function(e) {
    	//HACK needed to emulate Ctrl key press to allow multiple selection by default.
    	//see http://stackoverflow.com/questions/4396042/implement-multiple-selects-with-jquery-ui-selectable
    	//also http://bugs.jqueryui.com/ticket/7769
    	e.metaKey = true;
    }).selectable();
});

