/*
# $Id: gi.WidgetModule.js 178 2010-04-15 16:30:15Z john $
#
# Requires:
# jQuery, jQuery JSON plugin
*/

if(!self.gi) {
	gi = {};
}

gi.WidgetModule = {

	/*
	# @variable object config
	#
	# Configuration settings.
	# string controllerUrl	= Absolute URL to controlller that handles AJAX calls
	*/
	config: {
		containerId: 'widget-columns',
		numColumns: 1,
		controllerUrl: '/widget',

		/* Settings required by the "widgets" UI handlers */
		columnSelector: '.widget-column',
        widgetSelector: '.widget',
        handleSelector: '.widget-head',
        contentSelector: '.widget-content'
	},

	/*
	# @variable bool ready
	#
	# Used internally, this indicates when the system is ready to run.
	*/
	ready: false,

	/*
	# @function void init( object config )
	# config		= Config (overrides defaults in gi.WidgetModule.settings)
	#
	# Initialise the UI.
	*/
	init: function(config) {

		// Overwrite config defaults with custom settings
		this.config = $.extend({}, this.config, config);
		
		// Determine the no. columns used which is required to set each widget's
		// "position" element correctly.
		this.config.numColumns = $(this.config.columnSelector).length;

		// Start the UI handling routines
		widgets.settings = $.extend({}, widgets.settings, {
			columns: this.config.columnSelector,
			widgetSelector: this.config.widgetSelector,
			handleSelector: this.config.handleSelector,
			contentSelector: this.config.contentSelector
		});
		widgets.init();
		
		// Set the initial collapsed state of all widgets
		var columns = $(this.config.columnSelector);
		for(var col=0; col<columns.length; col++) {
			var configs = $(columns[col]).find(this.config.widgetSelector+' input[rel="widgetconfig"]');
			for(var wc=0; wc<configs.length; wc++) {
				var handle = $(configs[wc]).parents(this.config.widgetSelector).find(this.config.handleSelector+' a.collapse');
				var widgetConfig = $.evalJSON(configs[wc].value);
				if(widgetConfig.collapsed && widgetConfig.collapsed==1) {
					handle.trigger('click');
				}
			}
		}

		// Tell the system we're ready
		this.ready = true;
	},

	/*
	# @function void updatePositions()
	#
	# Updates the "position" and "collapsed" attributes of all widgets in the UI.
	# This is usually called after widgets have been moved around.
	*/
	updatePositions: function() {
		var undefined;
		var columns = $(this.config.columnSelector);
		for(var col=0; col<columns.length; col++) {
			var configs = $(columns[col]).find(this.config.widgetSelector+' input[rel="widgetconfig"]');
			for(var wc=0; wc<configs.length; wc++) {
				var widgetContent = $(configs[wc]).parents(this.config.widgetSelector).find(this.config.contentSelector);
				var widgetConfig = $.evalJSON(configs[wc].value);
				var isCollapsed = widgetContent.attr('iscollapsed');
				widgetConfig.position = wc*this.config.numColumns + col;
				widgetConfig.collapsed = isCollapsed===undefined ? 0 : isCollapsed;
				configs[wc].value = $.toJSON(widgetConfig);
			}
		}
	},

	/*
	# @function void saveConfig()
	#
	# Sends all the hidden config settings from each widget to the server for
	# saving.
	#
	# The server script must accept a single $_POST parameters called "widgets"
	# which contains a JSON'ed string of all widget data pulled from the UI.
	#
	# The response from the server must be one of:
	#	OK		= for a successful save
	#	FAIL	= For a failed save
	*/
	saveConfig: function() {

		// Build a structure containing all widget config
		var widgets = [];
		var columns = $(this.config.columnSelector);
		for(var col=0; col<columns.length; col++) {
			var configs = $(columns[col]).find(this.config.widgetSelector+' input[rel="widgetconfig"]');
			for(var wc=0; wc<configs.length; wc++) {
				widgets.push($.evalJSON(configs[wc].value));
			}
		}

		// Send data to server
		$.post(this.config.controllerUrl+'/save-user-config', {widgets:$.toJSON(widgets)}, function(response, state) {
			if(response!='OK') {
				alert('Save failed');
			}
		});
	},

	/*
	# @function void doAjax( object widgetConfig, object params, Function callback )
	# widgetConfig	= Widget config
	# params		= Custom parameters to pass through to
	# callback		= Function executed upon response from server
	#
	# Send an AJAX request through the WidgetController::ajaxProxy() method.
	*/
	doAjax: function(widgetConfig, params, callback) {
		params = params!==null ? params : {};
		$.post(this.config.controllerUrl+'/ajax-proxy', $.extend({}, params, {_wconfig:$.toJSON(widgetConfig)}), callback);
	}
};

/*
# Widgets UI handling, provided by third party.
*/
var widgets = {

    jQuery : $,

    settings : {
        columns : '.widget-column',
        widgetSelector: '.widget',
        handleSelector: '.widget-head',
        contentSelector: '.widget-content',
        widgetDefault : {
            movable: true,
            removable: true,
            collapsible: true,
            editable: false		/* All editing routines will be handled by the widget itself */
        }

		/* this is how to apply settings per-widget ...
        ,widgetIndividual : {
            intro : {
                movable: false,
                removable: false,
                collapsible: false,
                editable: false
            }
        }*/
    },

    init : function () {
        this.addWidgetControls();
        this.makeSortable();
    },

    getWidgetSettings : function (id) {
        var $ = this.jQuery,
            settings = this.settings;
        return (id&&settings.widgetIndividual[id]) ? $.extend({},settings.widgetDefault,settings.widgetIndividual[id]) : settings.widgetDefault;
    },

    addWidgetControls : function () {
        var widgets = this,
            $ = this.jQuery,
            settings = this.settings;

        $(settings.widgetSelector, $(settings.columns)).each(function () {
            var thisWidgetSettings = widgets.getWidgetSettings(this.id);
            if (thisWidgetSettings.removable) {
                $('<a href="#" class="remove">CLOSE</a>').mousedown(function (e) {
                    e.stopPropagation();
                }).click(function () {
                    if(confirm('This widget will be removed, ok?')) {
                        $(this).parents(settings.widgetSelector).animate({
                            opacity: 0
                        },function () {
                            $(this).wrap('<div/>').parent().slideUp(function () {
                                $(this).remove();
								gi.WidgetModule.updatePositions();
								gi.WidgetModule.saveConfig();
                            });
                        });
                    }
                    return false;
                }).appendTo($(settings.handleSelector, this));
            }

            if (thisWidgetSettings.editable) {
                $('<a href="#" class="edit round-med">EDIT</a>').mousedown(function (e) {
                    e.stopPropagation();
                }).toggle(function () {
                    $(this).addClass('active')
                        .parents(settings.widgetSelector)
                            .find('.edit-box').show().find('input').focus();
                    return false;
                },function () {
                    $(this).css({backgroundPosition: '', width: ''})
                        .parents(settings.widgetSelector)
                            .find('.edit-box').hide();
                    return false;
                }).appendTo($(settings.handleSelector,this));
                $('<div class="edit-box" style="display:none;"/>')
                    .append('<ul><li class="item"><label>Change the title?</label><input value="' + $('h3',this).text() + '"/></li>')
                    .append((function(){
                        var colorList = '<li class="item"><label>Available colors:</label><ul class="colors">';
                        $(thisWidgetSettings.colorClasses).each(function () {
                            colorList += '<li class="' + this + '"/>';
                        });
                        return colorList + '</ul>';
                    })())
                    .append('</ul>')
                    .insertAfter($(settings.handleSelector,this));
            }

            if (thisWidgetSettings.collapsible) {
                $('<a href="#" class="collapse">COLLAPSE</a>').mousedown(function (e) {
                    e.stopPropagation();
                }).toggle(function () {
                    
                    //
                    var intHorizPos = '0';
                    //
                    if($(this).parent().parent().is('.news-widget'))
                    {
                    	intHorizPos = '-60px';
                    }
                    if($(this).parent().parent().is('.events-widget'))
                    {
                    	intHorizPos = '-30px';
                    }
                    if($(this).parent().parent().is('.marketplace-widget'))
                    {
                    	intHorizPos = '-90px';
                    }
                    
                    $(this).css({backgroundPosition: '0 '+intHorizPos })
                        .parents(settings.widgetSelector)
                            .find(settings.contentSelector).attr('iscollapsed', 1).slideUp();
					if(gi.WidgetModule.ready) {
						gi.WidgetModule.updatePositions();
						gi.WidgetModule.saveConfig();
					}
                    return false;
                },function () {
                    
                    //
                    var intHorizPos = '0';
                    //
                    if($(this).parent().parent().is('.news-widget'))
                    {
                    	intHorizPos = '-60px';
                    }
                    if($(this).parent().parent().is('.events-widget'))
                    {
                    	intHorizPos = '-30px';
                    }
                    if($(this).parent().parent().is('.marketplace-widget'))
                    {
                    	intHorizPos = '-90px';
                    }
                    
                    $(this).css({backgroundPosition: '-30px '+intHorizPos })
                        .parents(settings.widgetSelector)
                            .find(settings.contentSelector).attr('iscollapsed', 0).slideDown();
					if(gi.WidgetModule.ready) {
						gi.WidgetModule.updatePositions();
						gi.WidgetModule.saveConfig();
					}
                    return false;
                }).prependTo($(settings.handleSelector,this));
            }
        });

        $('.edit-box').each(function () {
            $('input',this).keyup(function () {
                $(this).parents(settings.widgetSelector).find('h3').text( $(this).val().length>18 ? $(this).val().substr(0,18)+'...' : $(this).val() );
            });
            $('ul.colors li',this).click(function () {

                var colorStylePattern = /\bcolor-[\w]{1,}\b/,
                    thisWidgetColorClass = $(this).parents(settings.widgetSelector).attr('class').match(colorStylePattern)
                if (thisWidgetColorClass) {
                    $(this).parents(settings.widgetSelector)
                        .removeClass(thisWidgetColorClass[0])
                        .addClass($(this).attr('class').match(colorStylePattern)[0]);
                }
                return false;

            });
        });

    },

    attachStylesheet : function (href) {
        var $ = this.jQuery;
        return $('<link href="' + href + '" rel="stylesheet" type="text/css" />').appendTo('head');
    },

    makeSortable : function () {
        var widgets = this,    
            $ = this.jQuery,
            settings = this.settings,
            $sortableItems = (function () {
                var notSortable = '';
                $(settings.widgetSelector,$(settings.columns)).each(function (i) {
                    if (!widgets.getWidgetSettings(this.id).movable) {
                        if(!this.id) {
                            this.id = 'widget-no-id-' + i;
                        }
                        notSortable += '#' + this.id + ',';
                    }
                });
                // not:() seems to be breaking later versions of jquery...
                // return $('> li:not(' + notSortable + ')', settings.columns);
                return $('> li',settings.columns );
            })();
		
        $sortableItems.find(settings.handleSelector).css({
            cursor: 'move'
        }).mousedown(function (e) {
            $sortableItems.css({width:''});
            $(this).parent().css({
                width: $(this).parent().width() + 'px'
            });
        }).mouseup(function () {
            if(!$(this).parent().hasClass('dragging')) {
                $(this).parent().css({width:''});
            } else {
                $(settings.columns).sortable('disable');
            }
        });

        $(settings.columns).sortable({
            items: $sortableItems,
            connectWith: $(settings.columns),
            handle: settings.handleSelector,
            placeholder: 'widget-placeholder',
            forcePlaceholderSize: true,
            revert: 300,
            delay: 100,
            opacity: 0.8,
            containment: 'document',
            start: function (e,ui) {
                $(ui.helper).addClass('dragging');
            },
            stop: function (e,ui) {
                $(ui.item).css({width:''}).removeClass('dragging');
                $(settings.columns).sortable('enable');
				gi.WidgetModule.updatePositions();
				gi.WidgetModule.saveConfig();
            },
			over: function(e,ui) {
				//console.debug(ui);
				$(ui.placeholder).css('height',$(ui.item).height());
			}
        });
    }

};
