(function() {

// From jQuery.
// A simple way to check for HTML strings or ID strings
// (both of which we optimize for)
var quickExpr = /^[^<]*(<(.|\s)+>)[^>]*$|^#(\w+)$/,

// Is it a simple selector
    isSimple = /^.[^:#\[\.]*$/,

// IsPHPArray
    phpVariable = /([^\[\]]*)(\[.*\])*/;

var objectCache = [];
var elementCache = [];

var jQuery = window.jQuery;

var _maxZ = 1000;
var _nextId = 0;
var dropArray = {};

var Shout = window.Shout = function(selector)
{
    return new Shout.fn.init(selector);
};

Shout.fn = Shout.prototype = {
    nextId: function()
    {
        return 'Shout-Gen-' + _nextId++;
    },
    init: function(selector) {

        if(!selector)
        {
            return this;
        }
        else if(selector && selector.nodeEl)
        {
            return selector;
        }
        else if ( typeof selector == "string" )
        {
            // Use jquery expression to determine if we've got
            // and id string.

            var match = quickExpr.exec( selector );

            if(match && match[3] !== undefined)
            {
                if(objectCache[match[3]])
                {
                    return objectCache[match[3]];
                }
                else
                {
                    objectCache[match[3]] = this;
                }
            }
            this.nodeEl = jQuery(selector);
        }
        else if(selector)
        {
            this.nodeEl = jQuery(selector);
        }
        else
        {

        }

        this.attachParams = null;
        this.inherittedMove = false;
        this.shoutId = '';
        this.attachments = [];
        this.constraints = {};

        this.dragProxy = null;
        this.dropProxy = null;

        this.shoutId = this.nextId();

        this.nodeEl.data('shoutObj',this);

        return this;

    }
};

// Give the init function the Shout prototype

Shout.fn.init.prototype = Shout.fn;

jQuery.extend(Shout, {

    configure: function(params)
    {
        this.configuration = params;
    },

    objSerialize: function(fields)
    {
        var returnObj = {};

        jQuery.each(jQuery(fields),function()
        {
            var field = jQuery(this);
            returnObj[field.attr('name')] = field.val();
        });

        return returnObj;
    },

    loadFields: function(region,dataArray,prefix)
    {
        var params = [];

        if(dataArray)
        {
            jQuery.each(dataArray, function(e,obj) {
                jQuery.each(obj, function(j, data)
                {
                    var match = phpVariable.exec(j);
                    if(match[2])
                    {
                        var str = '['+e+']';

                        if(match[1])
                        {
                            str += '['+match[1]+']';
                        }

                        str += ''+match[2]+'='+data;

                        params.push(str);
                    }
                    else
                    {
                        params.push('['+e+']['+j+']='+data);
                    }
                });
            });
        }

        jQuery.each(params,function(i)
        {

            region.find('[name='+prefix+i+']').val(this);
        });
    },

    flattenFields: function(data, prefix,depth)
    {
        if(!prefix)
        {
            prefix = '';
        }

        if(!depth)
        {
            depth = 1;
        }

        var returnFields = {};

        var additionalFields = {};

        if(jQuery.isArray(data) || typeof data == 'object')
        {
            jQuery.each(data,function(i, obj)
            {
                if(jQuery.isFunction(obj))
                {
                    return true;
                }

                if(obj && ( jQuery.isArray(obj) || typeof obj  == 'object') )
                {
                    if(depth > 0)
                    {
                        name = prefix + '[' + i + ']';
                    }
                    else
                    {
                        name = prefix + i;
                    }

                    jQuery.extend(additionalFields, Shout.flattenFields(obj,name,depth+1) );
                }
                else
                {
                    if(depth > 0)
                    {
                        name = prefix + '[' + i + ']';
                    }
                    else
                    {
                        name = prefix + i;
                    }

                    returnFields[name] = obj;
                }
            });
        }
        else
        {
            return data;
        }

        jQuery.extend(returnFields,additionalFields);

        return returnFields;
    },

    phpSerialize: function(dataArray)
    {
        var params = [];


        if(dataArray.length)
        {
            jQuery.each(dataArray, function(e,obj) {
                jQuery.each(obj, function(j, data)
                {
                    var match = phpVariable.exec(j);
                    if(match[2])
                    {
                        var str = 'actions['+e+']';

                        if(match[1])
                        {
                            str += '['+match[1]+']';
                        }

                        str += ''+match[2]+'='+data;

                        params.push(str);
                    }
                    else
                    {
                        params.push('actions['+e+']['+j+']='+data);
                    }
                });
            });
        }

        return params.join('&');
    },

    drawInfoItem: function(content)
    {
        var list = [];
        if(jQuery.isArray(content))
        {
            jQuery.each(content,function()
            {
                list.push('<li class = "ui-state-info ui-corner-all"><span class = "ui-icon ui-icon-lightbulb"></span><span class="sui-content-text">'+this+'</span></li>');
            });
        }
        else
        {
            list.push('<li class = "ui-state-info ui-corner-all"><span class = "ui-icon ui-icon-lightbulb"></span><span class="sui-content-text">'+content+'</span></li>');
        }

        return jQuery(list.join(''));
    },

    drawInfo: function(content)
    {
        return jQuery('<div class = "sui-info"></div>').append(jQuery(this.drawInfoItem(content)).wrap('<ul></ul>'));
    },

    drawSummaryItem: function(content)
    {
        var list = [];
        if(jQuery.isArray(content))
        {
            jQuery.each(content,function()
            {
                list.push('<li><input readonly disabled class="sui-summary-content" value = "'+this+'"></span></li>');
            });
        }
        else
        {
            list.push('<li><input readonly disabled class="sui-summary-content" value = "'+content+'"></span></li>');
        }

        return jQuery(list.join(''));
    },

    drawErrorItem: function(content)
    {
        var list = [];
        if(jQuery.isArray(content))
        {
            jQuery.each(content,function()
            {
                list.push('<li class = "ui-state-error ui-corner-all"><span class = "ui-icon ui-icon-info"></span><span class="sui-content-text">'+this+'</span></li>');
            });
        }
        else
        {
            list.push('<li class = "ui-state-error ui-corner-all"><span class = "ui-icon ui-icon-info"></span><span class="sui-content-text">'+content+'</span></li>');
        }

        return jQuery(list.join(''));
    },

    pathToId: function(path)
    {
        var pathElements = path.split('/');

        return pathElements.join('-');
    },

    pathToName: function(path)
    {
        var pathElements = path.split('/');

        var elementString = '';

        jQuery.each(pathElements,function()
        {
            if(elementString.length == 0)
            {
                elementString = this;
            }
            else
            {
                elementString += '['+this+']';
            }
        });

        return elementString;
    },

    parseCommonParams: function(params)
    {
        if(!params)
        {
            params = {};
            return params;
        }

        results = {};

        if(params.value)
        {
            results.value = "value = \""+params.value+"\"";
        }
        else
        {
            results.value = "";
        }

        if(params.reset != undefined && params.reset == false)
        {
            results.reset = "";
        }

        if(params.css)
        {
            results.css = params.css;
        }
        else
        {
            results.css = '';
        }

        if(params.type)
        {
            results.type = 'type = "'+params.type+'" ';
        }
        else
        {
            results.type = '';
        }

        if(params.style)
        {
            results.style = 'style = "'+params.style+'" ';
        }
        else
        {
            results.style = '';
        }

        if(params.multiple)
        {
            results.multiple = 'multiple';
        }
        else
        {
            results.multiple = '';
        }

        if(params.selected)
        {
            results.selected = 'selected';
        }
        else
        {
            results.selected = '';
        }

        if(params.checked)
        {
            results.checked = 'checked';
        }
        else
        {
            results.checked = '';
        }

        if(params.icon)
        {
            results.icon = '<span class = "sui-icon '+params.icon+'"></span>';
        }
        else
        {
            results.icon = '';
        }


        if(params.href)
        {
            results.href = "href = \""+params.href+"\"";
        }

        if(params.target)
        {
            results.target = "target = \""+params.target+"\"";
        }

        if(params.title)
        {
            results.title = "title = \""+params.title+"\"";
        }

        return results;
    },

    drawButton: function(path, label, fieldIconClass, params)
    {
        var fieldId = this.pathToId(path);
        var fieldName = this.pathToName(path);

        var pp = this.parseCommonParams(params);

        if(params && params.type)
        {
            pp.type = 'hidden';
        }
        else if(params && params.type == 'submit')
        {
            // Well, we could be using buttons but IE 7 renders them incorrectly,
            // depriving us of a semantically useful element.
            var hackScript   = 'onclick = "jQuery(this).next(\'input\').click();"';
            pp.type   = 'submit';
        }
        else
        {
            pp.type = 'hidden';
        }

        if(params && params.type == 'submit')
        {
            pp.name = 'name = "'+fieldName+'"';
        }
        else
        {
            pp.name = '';
        }

        if(params && params.click)
        {
            jQuery('#'+fieldId).click(pp.click);
        }

        var HTML = '\
        <div class = "sui-control sui-control-button">\
            <a id = "'+fieldId+'" class = "ui-state-default ui-corner-all sui-button '+pp.css+'"\
            '+pp.style+'  '+pp.href+' '+pp.title+' '+pp.target+'>\
        ';

        if(fieldIconClass.length)
        {
            HTML += '\
                <span class = "ui-icon '+fieldIconClass+'"></span>\
            ';
        }

        if(label.length)
        {
            HTML += '\
                <span class = "sui-button-label">'+label+'</span>\
            ';
        }

        HTML += '\
            </a>\
            <input type="'+pp.type+'" '+pp.name+' '+pp.value+' style = "display:none" />\
        </div>';

        return HTML;
    },

    addHeaderButton: function(element, icon, callback)
    {
        //jQuery(element).find('ui-dialog')
    },

    multiPaste: function(content, pasteElement, parentSelector, rowSelector, columnSelector)
    {
        var rowDelimeter = '\n';
        var columnDelimeter = '\t';

        var columnQuery = '.sui-form-field input[type!=hidden], .sui-form-field textarea';
        var rowQuery = '.sui-tree-node';
        var parentQuery = '.sui-tree-root ul > .sui-tree-node';

        var rows = content.split(rowDelimeter);

        var resultObj = {};

        jQuery.each(rows,function(i)
        {
            resultObj[i] = {};
            resultObj[i] = this.split(columnDelimeter);
        });

        var rowIndex = 0;

        var $parent = jQuery(parentSelector);

        // In case we're not in the top right corner of a 2d array of input boxes, we offset the pasting from the cursor position.
        var rowOffset = -1;
        var columnOffset = -1;

        $parent.find(rowSelector).each(function(index)
        {
            var $currentRow = jQuery(this);

            if( ( columnOffset = $currentRow.find(columnSelector).index(pasteElement)  ) >= 0 )
            {
                rowOffset = index;

                return false;
            }

        });

        var $rows = null;

        if(rowOffset != -1)
        {
            $rows = jQuery(parentSelector).find(rowSelector).slice(rowOffset);
        }
        else
        {
            $rows = jQuery(parentSelector).find(rowSelector);
        }

        $rows.each(function()
        {
            var columnIndex = 0;
            var $columns = null;

            if(columnOffset != -1)
            {
                $columns = jQuery(this).find(columnSelector).slice(columnOffset);
            }
            else
            {
                $columns = jQuery(this).find(columnSelector);
            }

            $columns.each(function()
            {
                if(!resultObj[rowIndex])
                {
                    return false;
                }
                else if(resultObj[rowIndex] == 'undefined')
                {
                    return false;
                }

                jQuery(this).val(resultObj[rowIndex][columnIndex]);

                if(columnIndex > resultObj[rowIndex].length)
                {
                    return false;
                }

                columnIndex++;
            });

            rowIndex++;
        });
    },

    toggleCollapse: function($el)
    {
        var $el = jQuery($el);

        if($el.hasClass('sui-expanded'))
        {
            Shout.collapse($el);
            return false;
        }
        else if($el.hasClass('sui-collapsed'))
        {
            Shout.expand($el);
            return true;
        }
    },

    collapse: function($el)
    {
        var $el = jQuery($el);
        $el.removeClass('sui-expanded').addClass('sui-collapsed');
        $el.find(' > .sui-fieldset').hide();
        $el.find(' > .sui-toggle-icon').addClass('ui-icon-triangle-1-e').removeClass('ui-icon-triangle-1-se');

    },

    expand: function($el)
    {
        var $el = jQuery($el);
        $el.addClass('sui-expanded').removeClass('sui-collapsed');

        $el.find(' > .sui-fieldset').show();
        $el.find(' > .sui-toggle-icon').removeClass('ui-icon-triangle-1-e').addClass('ui-icon-triangle-1-se');
    }

});

})();

