(function(){

    IApp_Portlet = function( id, classname ){
        this.id = id;
        this.classname = classname;

        this.options = $.extend(this.options || {},{
            'selector' : 'div.portlet' + this.id,
            'instance' : {}
        });

        this.events = this.events || [];
        this.listen = this.listen || [];

        this._func = [];
        this._event = [];

        this._defaultCallback = function(){};

    }

    IApp_Portlet.prototype = {
        init : function(){

            var self = this;

            /** Set div property **/
            this.$div = $( this.options.selector );

            /** Register Portlet events **/
            for( var i = 0; i < this.events.length; i++ ){
                this.registerEvent(this.events[i]);
            }

            /** Register Portlet listeners **/
            for( var i = 0; i < this.listen.length; i++ ){
                if( typeof this.listen[i][0] != 'object' ){
                    this.listen[i][0] = IApp_Portlet_Factory.get( this.listen[i][0] );
                }
                this.listen[i][0].registerEventListener(this.listen[i][1], this.listen[i][2], this);
            }

            /** Add this to div **/
            if( this.$div.length ){
                this.div = this.$div.get(0);
                this.$div.get(0)._iapp_portlet = this;

                this.$div
                    .find('div.butt-portlet-config-disabled')
                    .removeClass('butt-portlet-config-disabled')
                    .click(function(){
                        self.configInstance();
                    });
                
                this.dispatchEvent('init');
            }
        },
        setOptions : function( options ){
            $.extend( this.options, options );
        },
        registerRemoteFunc : function (func, req, opt){

            var oFunc = { func_name: func, required: req, optional: opt };
            var self = this;

            if( typeof this._func[func] == 'undefined' ){
                this._func[func] = oFunc;
            }
        },
        
        ajaxErrorHandler: function (xhr) {
            // TODO: here a message should be shown explaining that an error has happened (most likely the session has expired)
            if (401 == xhr.status) {
            	
            	var href = xhr.getResponseHeader('X-Location') || location.href;
            	
                location.href = href;
                
                return true;
            }
            
            return false;
        },
        
        callRemoteFunc : function( func, options ){

            var self = this;

            if (!options) {
                options = {};
            }

            if (!options.url && this.options.instance.request_uri) {
                options.url = this.options.instance.request_uri;
            }

            var o = $.extend({
                data: [],
                layout: 'ajax',
                callback: this._defaultCallback,
                target: false,
                block: true,
                autoeval: true,
                cache: false,
                timeout: 20000,
                request_type: 'POST',
                mode: 'portlet',
                async: true,
                error: function (xhr) {
                	return self.ajaxErrorHandler(xhr);
                }
            }, options);

            if( typeof o.data == 'function' ){
                o.data = o.data();
            }else if( typeof o.data == 'string' && eval('typeof '+o.data) == 'function' ){
                o.data = eval(o.data)();
            }

            var self = this;

            /*if( typeof this._func[func] == 'undefined' ){
                return false;
            }*/

            if( aVars = self._checkVars( this.id, func, o.data ) ){
                self._ajax( aVars, o );
                return true;
            }

            return false;
        },

        globalEval : function( script ){
            jQuery.globalEval( script );
        },

        _evalDataScript : function( $script ){
            jQuery.globalEval( $script.html() );
            $script.remove();
        },

        evalDataScripts : function( data ){
            var self = this;
            $(data).filter('script').each(function(){
                self._evalDataScript( $(this) );
    		});
            $(data).find('script').each(function(){
                self._evalDataScript( $(this) );
    		});
        },

        registerEvent : function(){
            for( var i = 0; i < arguments.length; i++){
                var evt = arguments[i];
                var oEvt = { name: evt, listener: [], listener_obj: [] };

                var self = this;

                if( typeof this._event[evt] == 'undefined' )
                    this._event[evt] = oEvt;
            }
        },
        registerEventListener : function( evt, callback, obj ){

            var self = obj || this;

            if( typeof this._event[evt] == 'undefined'){
                this.registerEvent(evt);
            }

            var needAdd = true;
            var this_ = this;
            if( $.inArray( callback, this._event[evt].listener ) >= 0 ){
                $.each( this._event[evt].listener, function(ind){
                    if( this_._event[evt].listener[ind] == callback && this_._event[evt].listener_obj[ind] == self ){
                        needAdd = false;
                    }
                });
            }

            if( needAdd ){
                this._event[evt].listener.push( callback );
                this._event[evt].listener_obj.push( self );
            }
        },
        unregisterEventListener : function( evt, callback, obj ){

            if( typeof this._event[evt] != 'undefined' ){
                var j = 0;
                $.each( this._event[evt].listener, function(){
                    if( this == callback ){
                        if( typeof obj == 'undefined' || this._event[evt].listener_obj[j] == obj ){
                            this._event[evt].listener.splice( j, 1 );
                        }
                    }
                    j++;
                });
            }
        },
        dispatchEvent : function( evt ){
            var self = this;

            var args = new Array();
            for( var i = 1; i < arguments.length; i++)
                args.push( arguments[i] );

            if( typeof this._event[evt] != 'undefined' ){
                for( var i = 0; i < this._event[evt].listener.length; i++ ){
                    if( typeof this._event[evt].listener[i] == 'function' ){
                        this._event[evt].listener[i].apply( this._event[evt].listener_obj[i], args );
                    }
                }
            }
        },
        configInstance : function(options){
            var data = typeof options != 'undefined' ? [ JSON.stringify( options ) ] : [];
            this.callRemoteFunc('portletConfig',{ data: data, block: this.$div });
        },
        _checkVars : function( id, func, data ){
            /*if( oFunc.required > 0 && (typeof data != 'object' || data.length < oFunc.required ) ){
                return false;
            }*/

            var vars = new Array( id, func );
            var i = 0;
            while( data.length > i ){//(i < oFunc.required + oFunc.optional) && (i < data.length) ){
                vars.push( data[i] );
                i++;
            }

            return vars;
        },
        _ajax : function( aVars, oOpt ){

            var self = this;

            //var data_type = 'ajax';
            var data_type = ( oOpt.layout == 'json' ? 'json' : 'ajax' );

            if( oOpt.block ){
                if( typeof oOpt.block != 'boolean' ){
                    $(oOpt.block).blockUI();
                }else if( oOpt.target ){
                    $(oOpt.target).blockUI();
                }
            }
            var settings = {
                cache: oOpt.cache,
                data: { 'mode': oOpt.mode, 'layout': oOpt.layout, 'data[]': aVars },
                dataType: data_type,
                success: this._ajax_callback( oOpt ),
                timeout: oOpt.timeout,
                type: oOpt.request_type,
                async: oOpt.async,
                error: function(){
                    if( typeof oOpt.error == 'function' ){
                        oOpt.error.apply( self, arguments );
                    }else if( typeof oOpt.error == 'string' && typeof self[ oOpt.error ] == 'function' ){
                        self[ oOpt.error ].apply( self, arguments );
                    }

                    if(  oOpt.block ){
                        if( typeof  oOpt.block != 'boolean' ){
                            $( oOpt.block ).unblockUI();
                        }else if( oOpt.target ){
                            $( oOpt.target ).unblockUI();
                        }
                    }
                },
                beforeSend: function(xhr) {
                    if (typeof oOpt.headers == 'object') {
                        for (var key in oOpt.headers) {
                            xhr.setRequestHeader(key, oOpt.headers[key]);
                        }
                    }   
                }       
            };
            
            if (oOpt.url) {
                settings.url = oOpt.url;
            }
            

            $.ajax(settings);
        },
        _ajax_callback : function( oOpt ){

            var self = this;
            var o = oOpt;

            return function( data ){
                var $data = $('<div />');// + data + '</div>');
                $data.get(0).innerHTML = data;

                /** Process CSS **/
                $( 'link[type="text/css"]', $data ).each(function(){
                    if( $('head link[type="text/css"][href="'+$(this).attr('href')+'"]').length ){
                        $(this).remove();
                    }else{
                        $('head').append( $(this) );
                    }
                });

                if( o.target ){
                    $(o.target).each(function(){
                        this.innerHTML = $data.get(0).innerHTML;
                    })
                    //$(o.target).html( $data.html() );
                }//else

                if( o.autoeval ){
                    if( $.browser.msie ){
                    	if(data.length) {
                    		self.evalDataScripts(data);
                    	}
                    }else{
                        self.evalDataScripts($data)
                    }
                }

                if( o.block ){
                    if( typeof o.block != 'boolean' ){
                        $(o.block).unblockUI();
                    }else if( o.target ){
                        $(o.target).unblockUI();
                    }
                }
//alert(data);
                /*if( oOpt.layout == 'json' ) {
                	jQuery.globalEval('var json_data = ' + data);
                	data = json_data;
                }*/

                if( typeof o.callback == 'function' ){
                    o.callback( data );
                } else if( typeof o.callback == 'string' ) {
                    jQuery.globalEval(o.callback + '(data);');
                }
            };
        },

        isAlive : function() {
        	return this.$div && this.$div.parent().length;
        }
    }

    /**
    * jQuery Plugin for Portlet JS Object
    *
    * @example $('a.link').portlet()
    * @return false|IApp_Portlet
    **/
    $.extend( $.fn, {
        portlet : function(){
            if( this.length == 1 && this.is('.widget-portlet') && typeof this.get(0)._iapp_portlet == 'object' ){
                return this.get(0)._iapp_portlet;
            }

            /** There are situations when there are more than 1 parent found
             * @author y.ksenevich
             */
            if( this.parents('.widget-portlet').length ){
                if( typeof this.parents('.widget-portlet').get(0)._iapp_portlet == 'object' ){
                    return this.parents('.widget-portlet').get(0)._iapp_portlet;
                }else{
                    var classname = '';
                    var id = [];
                    if( (classname = this.parents('.widget-portlet').attr('class')) && (id = classname.match(/portlet([0-9]+)/)) && (id.length > 1) ){
                        return IApp_Portlet_Factory.get(parseInt(id[1]));
                    }
                }
            }

            return false;
        }
    });

    /*$(function(){

        $('div.widget-portlet').find('div.butt-portlet-config-disabled')
            .removeClass('butt-portlet-config-disabled')
            .click(function(){
                try {
                    $(this).portlet().configInstance();
                    }
                catch (e) {}
            })

    });*/

})(jQuery);
