/**
 * primitive inheritance
 *
 * @param {Object} parentCtor
 *
 * @TODO Move to library!
 */
Function.prototype.inherits = function(parentCtor) {
  function tempCtor() {};
  tempCtor.prototype = parentCtor.prototype;
  this.superClass_ = parentCtor.prototype;
  this.prototype = new tempCtor();
  this.prototype.constructor = this;
};

/**
 * @namespace gadgets
 */
var gadgets = gadgets || {};
/**
 * remoteServiceFactory
 *
 * @class returns service instances for any view
 * @name gadgets.remoteServiceFactory
 *
 */
gadgets.remoteServiceFactory = function () {

    /**
     * storage for the services
     *
     * @var object
     */
    var _serviceRegistry = {};

    /**
     * @var object
     */
    var _services = {};

    /**
     * Providing remote Services for the iframes
     * currently supported:
     *
     * requestNavigateTo
     * resize_iframe
     * set_title
     *
     */
    _services.basic = function(){
    };

    /**
     * Generating a url for another view of a Gadget
     *
     * @param {String} view
     * @return {String} url
     *
     */
    _services.basic.prototype._buildUrlForView = function (view, params, gadget) {
        var url;

        url = gadgets.baseUrl;

        var type = 'link';

        switch (view) {
            case 'profile'  :   if (gadgets.sandbox) {
                                    url += gadgets.sandbox.url.profile + gadget.aid + '/' + gadget.v;
                                }
                                else if (gadget.profileId) {
                                    url += '/Profile/' + gadget.profileId;
                                } else {
                                    return false;
                                }
                                break;
            case 'start'    :   return false;
                                break;
            case 'group'    :   if (gadgets.sandbox) {
                                    url += gadgets.sandbox.url.group + gadget.aid  + '/' + gadget.v;
                                }
                                else if (gadget.groupId) {
                                    url += '/Groups/Overview/' + gadget.groupId;
                                } else {
                                    return false;
                                }
                                break;
            case 'popup'    :
                                if (gadgets.sandbox) {
                                    url += gadgets.sandbox.url.popup + gadget.aid  + '/' + gadget.v;
                                } else {
                                    url += '/Gadgets/Popup/' + gadget.aid;
                                }

                                if (gadget.profileId) {
                                    url += '/profileId/' + gadget.profileId;
                                }

                                type = 'popup';
                                break;
            case 'integration'    :
                                if (gadgets.sandbox) {
                                    url += gadgets.sandbox.url.integration + gadget.aid  + '/' + gadget.v;
                                } else {
                                    url += '/Gadgets/Integration/' + gadget.aid;
                                }
                                break;
            case 'preview'  :
                                if (gadgets.sandbox) {
                                    url += gadgets.sandbox.url.preview + gadget.aid  + '/' + gadget.v;
                                } else {
                                    url += '/Gadgets/Install/' + gadget.aid;
                                }
                                break;
            case 'canvas'   :   if (gadgets.sandbox) {
                                    url += gadgets.sandbox.url.canvas + gadget.aid + '/' + gadget.v;
                                }
                                else {
                                    url += '/Gadgets/Canvas/' + gadget.mid;
                                    if (gadget.groupId) {
                                        url += '/groupId/' + gadget.groupId;
                                    } else if (gadget.profileId) {
                                        url += '/profileId/' + gadget.profileId;
                                    }
                                }
                                break;
            default         :   if (gadgets.sandbox) {
                                    url += gadgets.sandbox.url.canvas + gadget.aid + '/' + gadget.v;
                                }
                                else {
                                    url += '/Gadgets/Canvas/' + gadget.mid;
                                    if (gadget.groupId) {
                                        url += '/groupId/' + gadget.groupId;
                                    } else if (gadgets.profileId) {
                                        url += '/profileId/' + gadget.profileId;
                                    }
                                }
                                break;
        }

        if (params) {
            var paramStr = JSON.stringify(params);
            if (paramStr.length > 0) {
               url += '/params/' + encodeURIComponent(paramStr);
            }
        }

        return {'type': type, 'url': url};
    };

    _services.basic.prototype.setHeight = function (args, gadget, callback) {
            if(args[0] < this.maxHeight) {
                $('#remote-iframe-' + gadget.mid).height(args[0]);
            } else {
                $('#remote-iframe-' + gadget.mid).height(this.maxHeight);
            }
    };


    /**
     *
     *
     */
    _services.basic.prototype.setPref = function (args, gadget, callback) {
        if (gadget.owner != gadget.viewer) {
            return;
        }
        
        var formObj = gadgets.models.main.form2object('#gadgets-gadget-prefs-' + gadget.mid + ' form');
        formObj[args[1]] = args[2];

        gadgets.models.main.savePreferences(gadget.mid, JSON.stringify(formObj), function (responseData) {
            $('#gadgets-gadget-prefs-' + gadget.mid + ' form').replace(responseData.module.data.html);
        });
    };

    /**
     * Setting the title of the gadgets chrome
     *
     */
    _services.basic.prototype.setTitle = function (args, gadget, callback) {
        $('#gadgets-gadget-title-' + gadget.mid).text(args[0]);
    };

    _services.basic.prototype.invite = function (args, gadget, callback) {
        if (! gadgets.sandbox) {
            var params = '&consumerId=' + gadget.c + '&consumerName=' + gadget.title;
            if (args[0].token) {
                params += '&token=' + args[0].token;
            }
            if (args[0].message) {
                params += '&message=' + args[0].message;
            }
            if (args[0].image) {
                params += '&image=' + args[0].image;
            }
            Phx.Application.RequestRegistry.append({
                1:  'Gadgets_getFriendsInviteList',
                2:  function(response) {                        
                        Phx.Application.Modules.vcard.showInviteFriendsDialog(response, gadget.title, 'Gadgets');
                    },
                3:  '',
                4:  params
            });
        } else {
            alert('Invite Dialog is shown');
        }
    };

    _services.basic.prototype.uniqueToken = function (args, gadget, callback) {
        Phx.AJAX.callproxy('Gadgets_CreateUniqueToken', function (responseData) {
            if (typeof callback === 'function') {
                callback(responseData.module.data.token);
            }
        },"",'','POST');
    };

    _services.basic.prototype.install = function (args, gadget, callback) {
        var newArgs = {0:'preview', 1:null};
        this.requestNavigateTo(newArgs, gadget, callback);
    };

    /**
     * Service for Navigating to another view
     *
     * @param (String) requested View
     *
     * @return (void)
     */
    _services.basic.prototype.requestNavigateTo = function (args, gadget, callback) {
        var url;
        if((url = this._buildUrlForView(args[0], args[1], gadget))){
            if (url.type === 'popup') {
                Phx.Application.Modules.popuplinks.openWindow(url.url);
            } else {
                if (gadget.view === 'popup') {
                    var handle = window.opener;
                    document.domain.domain = handle.domain;
                    handle.window.location.href = url.url;
                    handle.focus();
                } else {
                    window.location.href = url.url;
                }
            }
        } else {
            throw Error('UNSUPPORTED VIEW');
        }
    };

    /**
     * Implement view specific services here
     * ervery service inherits from the basic service
     */

    _services.canvas    = function (){
        this.maxHeight = 60000;
        _services.basic.call(this);

        this.setHeight = function (args, gadget, callback) {
            if(gadget.changeSize) {
                this.maxHeight = 60000;
            }
            if(args[0] < this.maxHeight) {
                $('#remote-iframe-' + gadget.mid).height(args[0]);
            } else {
                $('#remote-iframe-' + gadget.mid).height(this.maxHeight);
            }
        };
    };
    _services.canvas.inherits(_services.basic);

    _services.group     = function (){
        this.maxHeight = 400;
        _services.basic.call(this);
    };
    _services.group.inherits(_services.basic);


    _services.popup = function (){
        this.maxHeight = 400;
        _services.basic.call(this);
    };

    _services.popup.inherits(_services.basic);

     _services.integration = function (){
        this.maxHeight = 60000;
        _services.basic.call(this);

        this.setHeight = function (args, gadget, callback) {
            if(gadget.changeSize) {
                this.maxHeight = 60000;
            }
            if(args[0] < this.maxHeight) {
                $('#remote-iframe-' + gadget.mid).height(args[0]);
            } else {
                $('#remote-iframe-' + gadget.mid).height(this.maxHeight);
            }
        };
    };

    _services.integration.inherits(_services.basic);

    _services.preview = function (){
        this.maxHeight = 400;
        _services.basic.call(this);
    };

    _services.preview.inherits(_services.basic);

    _services.profile   = function (){
        this.maxHeight = 400;
        _services.basic.call(this);
    };
    _services.profile.inherits(_services.basic);

//
//    _services.start     = function (){
//        _services.basic.call(this);
//    };
//    _services.start.inherits(_services.basic);




    return {

        /**
         * get a service by view
         * !Service instances are Singletons!
         *
         * @param {String} view
         * @return (Object) instanceOf Basic Service
         */
        get : function (view) {
            if (_serviceRegistry[view]){
                return _serviceRegistry[view];
            } else {
                return (_serviceRegistry[view] = new _services[view]());
            }

        }

    };

};


/**
 * gadget Manager
 * returns the gadget data objects by iframeId
 *
 * @param {Object} gadgets
 *
 */
gadgets.gadgetManager = (function (gadgets) {

    /**
     * Gadget data objects
     * @var (Object)
     */
    var _gadgets = gadgets;

    /**
     * saves a prmitive map of iframe to gadget ids
     * prevents extracting the same id more than once
     */
    var _ifrToGidMap = {};

    /**
     * helper to extract the gadgetid from the given iframe id
     *
     * @param {String} frameId
     */
    var _getGid = function (frameId) {
        if(!_ifrToGidMap[frameId]) {
            _ifrToGidMap[frameId] = frameId.substring(frameId.lastIndexOf('-') + 1) || false;
        }
        return _ifrToGidMap[frameId];
    };


    return {
        /**
         * returns a gadget data object by id
         *
         *
         * @param {String} ifrId
         * @return (Object)
         */
        getGadgetById : function (ifrId) {
            if (isNaN(ifrId)) {
                if (ifrId.indexOf('remote') > -1) {
                    ifrId = 'inst' + _getGid(ifrId);
                }
                return _gadgets[ifrId]
            } else {
                return _gadgets['inst' + ifrId]
            }

        },

        setGadgetById : function (id, data) {
            _gadgets['inst' + id] = data;
        },

        /**
         *
         */
        getAllGadgets : function () {
           return _gadgets;
        }
    };
// If gadget data store is changed it only has to be changed here
}(gadgets.data));

/**
 * @package
 */
gadgets.models = {};

/**
 * Main Models
 *
 * @static
 * @class Provides persistence methods
 * @name gadgets.models.main
 *
 */
gadgets.models.main = {

    /**
     * Save preferences for an installation
     * callback can be provided
     *
     * @param {Int} mid
     * @param {Object} prefs
     * @param {Funcition} optCb
     */
    savePreferences : function (mid, prefs, optCb) {
        var gadget = gadgets.gadgetManager.getGadgetById(mid);
        if (gadget.groupId) {
            var identifierParam = '&groupId=' + gadget.groupId;
        } else if (gadget.profileId) {
            var identifierParam = '&profileId=' + gadget.profileId;
        } else {
            var identifierParam = '';
        }
        var canvas = (gadget.view == 'canvas') ? 1 : 0;
        Phx.AJAX.callproxy('Gadgets_Gadget_Prefs', function (responseData) {
            var gadgets_ = gadgets.gadgetManager.setGadgetById(responseData.module.data.gadget.mid, responseData.module.data.gadget);
            if(optCb) {
               optCb(responseData);
            }
            gadgets.controller.bindPrefsMenue(gadget.mid);
        },"",'&pref=' + prefs + '&installationId=' + mid + identifierParam + '&canvas=' + canvas,'POST');

    },

    /**
     * Uninstall a gadget by id
     *
     * @param {Int} id
     */
    uninstallGadget : function (id) {
        Phx.AJAX.callproxy('Gadgets_Gadget_Uninstall', Phx.Util.createDelegate(function(installId) {
            $('#remote-iframe-' + id + '-title').parent('.gadgets-gadget-chrome').remove();
        }, this, id),"",'&installationId='  + id ,'POST');
    },

    /**
     * serializes a form to an object
     * uses jquery serialize and splits result
     *
     * @param {String} selector
     */
    form2object : function (selector) {
        var serFor = $(selector).serialize();
        var serForArr = serFor.split('&');
        var helpObj = {};

        $.each(serForArr, function (i, data) {
            var parts = data.split('=');
            helpObj[parts[0]] = parts[1];
        });

        return helpObj;
    },

    /**
     * saves user preference for gadget visibility
     *
     * @param {Int} installationId
     */
    saveGadgetVisibilityUserPref : function (installationId, collapse, fn) {
        var gadget   = gadgets.gadgetManager.getGadgetById(installationId);
        var viewType = '';

        if (gadget.groupId) {
            viewType = 'group';
        } else if (gadget.profileId) {
            viewType = 'profile';
        }

        collapse = collapse ? 'true' : 'false';

        Phx.AJAX.callproxy('Gadgets_Gadget_VisibilityUserPref', function(responseData) {fn(gadget); },"",'&viewType=' + viewType + '&collapse=' + collapse,'POST');
    }

}

gadgets.view = function () {

    /**
     * toggles preferences form visibility
     *
     * @param {Int} id
     */
    this.togglePrefVisibility = function (id) {
        if($('#gadgets-gadget-prefs-' + id).is(':visible'))
            $('#gadgets-gadget-prefs-' + id).hide();
        else
            $('#gadgets-gadget-prefs-' + id).show();

        this.toggleTitlebarVisibility(id);
    };

    /**
     * toggles the titlebar
     *
     * @param {Int} id
     */
    this.toggleTitlebarVisibility = function (id) {
        if($('#gadgets-gadget-title-bar-' + id).is(':visible'))
            $('#gadgets-gadget-title-bar-' + id).hide();
        else
            $('#gadgets-gadget-title-bar-' + id).show();
    };

    /**
     * Toggles the visibility of the whole gadget
     *
     * @param {Int} id
     */
    this.toggleGadgetVisibility = function (id) {
        if($('#gadgets-gadget-content-' + id).is(':visible')) {
            $('#gadgets-gadget-content-' + id).addClass('hidden');
            this.toggleMinMaxIcon(id, true);
        } else {
            $('#gadgets-gadget-content-' + id).removeClass('hidden');
            this.toggleMinMaxIcon(id, false);
        }
    };

    this.toggleMinMaxIcon = function (id, collapse) {
        if(collapse) {
            $('#gadget-collapse-' + id).attr('class','window-controls-expand');
        } else {
            $('#gadget-collapse-' + id).attr('class','window-controls-collapse');
        }
    }
}


/**
 * Gadget Controller
 *
 * self executing on app startup, registration of rpc services is done here
 * handles the the provided services for the different views
 *
 */
gadgets.controller = (function (){

        /**
         * gadgets view instance
         *
         * @var object
         */
        var _view = new gadgets.view();

        /**
         * Factory for the services
         * should be used to get the rpc functionality for a view
         *
         * @var object
         */
        var ifrRemoteServiceFactory = new gadgets.remoteServiceFactory();

        /**
         * safe proxy
         * verifying whether a gadget may use the requested service or not
         *
         * @param {String} serviceName
         * @param {Array}  args
         * @param {Object} con
         *
         * @return (void)
         */
        var _proxy = function (serviceName, args, con) {            
            var gadget = gadgets.gadgetManager.getGadgetById(con.f);
            var receiver = gadget.iframeUrl;
            gadgets.rpc.setRelayUrl(con.f, receiver, false);
            var remoteService = ifrRemoteServiceFactory.get(gadget.view);
            if ('function' === typeof remoteService[serviceName]) {
                var r = remoteService[serviceName](args, gadget, con.callback);
            }
        };

        /**
         * startup routine - generating the gadget iframes
         *
         * @return (void)
         */
        var _generateGadgets = function () {
            var gadgets_ = gadgets.gadgetManager.getAllGadgets();
            for (var i in gadgets_) {
                $('<iframe ' + gadgets_[i].frameParams + ' />').appendTo('#gadgets-gadget-content-' + gadgets_[i].mid).attr({src: gadgets_[i].iframeUrl});
            }
        };

        /**
         * binds all gui events
         *
         * @return (void)
         */
        var _bindGui = function () {

            var gadgets_ = gadgets.gadgetManager.getAllGadgets();
            for (var i in gadgets_) {
                var installationId = gadgets_[i].mid;

                this.bindPrefsMenue(installationId);
                
                this.bindCollapse(gadgets_[i]);
                
                //do not bind install/uninstall buttons when in sandbox
                if (gadgets.sandbox) {
                    $('#gadgets-gadget-install-' + gadgets_[i].mid).unbind('click').bind('click', function(event){Phx.Event.stop(event);});
                    $('#gadgets-gadget-uninstall-' + gadgets_[i].mid).unbind('click').bind('click',function(event){Phx.Event.stop(event);});
                    continue;
                }


                $('#gadgets-gadget-uninstall-' + gadgets_[i].mid).unbind('click').bind('click',  Phx.Util.createDelegate(
                    function (installationId, event) {
                        Phx.Event.stop(event);
                        var uninstallDialog = Phx.UI.Dialog.Confirm(
                            i18n.getText('gadgets_uninstall_title'),
                            {
                                message: i18n.getPText('gadgets_uninstall_confirm', gadgets.gadgetManager.getGadgetById(installationId).title),
                                events: {
                                    onButtonClicked: function(decision, target){
                                        if (decision === 'true') {
                                            gadgets.models.main.uninstallGadget(installationId);
                                        }
                                    }
                                }
                            },
                            i18n.getText('gadgets_deleteList'), i18n.getPText('gadgets_cancel'));

                        uninstallDialog.show();
                        //_view.togglePrefVisibility(i);
                    }, this, installationId)
                );


            }
        };

        this.bindCollapse = function (gadget) {
                $('#gadget-collapse-' + gadget.mid).unbind('click').bind('click', Phx.Util.createDelegate(function(gadget){
                        $('#gadget-collapse-' + gadget.mid).unbind('click');
                        _view.toggleGadgetVisibility(gadget.mid);

                        // get current gadget visibility
                        var collapse = true;
                        if($('#gadgets-gadget-content-' + gadget.mid).is(':visible'))
                            collapse = false;
                        var _this = this;
                        // save user preference for gadget visibility
                        if (gadgets.isLoggedIn === true) {
                            gadgets.models.main.saveGadgetVisibilityUserPref(gadget.mid, collapse, _this.bindCollapse);
                        } else {
                            _this.bindCollapse(gadget);
                        }
                    }, this, gadget)
                );
            }

        /**
         *
         */
        this.bindPrefsMenue = function (i) {
               $('#gadgets-gadget-prefs-' + i + ' input[name=submit]').unbind('click').bind('click' , Phx.Util.createDelegate(
                    function (installId, event ) {
                        event.preventDefault();
                        Phx.Event.stop(event);

                        var helpObj = gadgets.models.main.form2object('#gadgets-gadget-prefs-' + i + ' form');
                        gadgets.models.main.savePreferences(installId, JSON.stringify(helpObj), function(responseData) {
                            $('#remote-iframe-' + responseData.module.data.gadget.mid).attr({'src': responseData.module.data.gadget.iframeUrl});
                        });
                    }, this, i)
                );

                $('#gadgets-gadget-prefs-' + i + ' .form-buttons a').unbind('click').bind('click' , Phx.Util.createDelegate(
                    function (installId) {
                        _view.togglePrefVisibility(installId);
                    }, this, i)
                );

                $('#settings-gadget-' + i).unbind('click').bind('click', Phx.Util.createDelegate(
                    function (installId) {
                        _view.togglePrefVisibility(installId);
                    }, this, i)
                );
        };

        /**
         * Constructor stuff
         *
         * register all available rpc calls here and implement them in the views
         */
        gadgets.rpc.register('resize_iframe',       function () {
            _proxy('setHeight', arguments, this);
        });
        gadgets.rpc.register('set_pref',            function () {
            _proxy('setPref', arguments, this);
        });
        gadgets.rpc.register('set_title',            function () {
            _proxy('setTitle', arguments, this);
        });
        gadgets.rpc.register('requestNavigateTo',    function () {
            _proxy('requestNavigateTo', arguments, this);
        });
        gadgets.rpc.register('invite',    function () {
            _proxy('invite', arguments, this);
        });
        gadgets.rpc.register('uniqueToken',    function () {
            _proxy('uniqueToken', arguments, this);
        });
        gadgets.rpc.register('install',    function () {
            _proxy('install', arguments, this);
        });

        _generateGadgets();

        _bindGui();
        this.bindPrefsMenue();

        return this;
}());