/*

Jappix - An open social platform
This is the server features JS script for Jappix

-------------------------------------------------

License: AGPL
Author: Valérian Saliou, Maranda

*/

// Bundle
var Features = (function () {

    /**
     * Alias of this
     * @private
     */
    var self = {};


    /* Constants */
    self.SERVER_NAMES = [
        'metronome',
        'prosody',
        'ejabberd',
        'jabberd',
        'openfire',
        'tigase',
        'isode'
    ];


    /* Variables */
    self.server_name = null;


    /**
     * Gets the features of a server
     * @public
     * @return {undefined}
     */
    self.get = function() {

        /* REF: http://xmpp.org/extensions/xep-0030.html */

        try {
            // Get the main values
            var to = Utils.getServer();
            var caps = con.server_caps;
            var xml = null;
            
            // Try to get the stored data
            if(caps) {
                xml = Common.XMLFromString(
                    DataStore.getPersistent('global', 'caps', caps)
                );
            }
            
            // Any stored data?
            if(xml) {
                self.handle(xml);
                
                Console.log('Read server CAPS from cache.');
            } else {
                // Not stored (or no CAPS)!
                var iq = new JSJaCIQ();
                
                iq.setTo(to);
                iq.setType('get');
                iq.setQuery(NS_DISCO_INFO);
                
                con.send(iq, Caps.handleDiscoInfos);
                
                Console.log('Read server CAPS from network.');
            }
        } catch(e) {
            Console.error('Features.get', e);
        }

    };


    /**
     * Handles the features of a server
     * @public
     * @param {string} xml
     * @return {boolean}
     */
    self.handle = function(xml) {

        try {
            // Selector
            var selector = $(xml);
            
            // Functions
            var check_feature_fn = function(namespace) {
                // This weird selector fixes an IE8 bug...
                return (selector.find('feature').filter(function() {
                    return ($(this).attr('var') == namespace);
                }).size() > 0 ? true : false);
            };

            // Markers
            var namespaces = [NS_PUBSUB, NS_PUBSUB_CN, NS_URN_MAM, NS_COMMANDS, NS_URN_CARBONS];

            var identity = selector.find('identity');

            var cur_feature;
            var features = {
                // This weird selector fixes the same IE8 bug as above...
                'pep': (identity.filter(function() {
                    var this_sel = $(this);
                    return (this_sel.attr('category') == 'pubsub' && this_sel.attr('type') == 'pep');
                }).size() && true)
            };

            $.each(namespaces, function(n, namespace) {
                features[namespace] = check_feature_fn(namespace);

                if(features[namespace] === true) {
                    self.enable(namespace);
                }
            });

            // Retrieve server identity
            self.server_name = self._normalizeServerName(
                identity.filter('[category="server"]').attr('name')
            );

            // Enable the pep elements if available
            if(features.pep === true) {
                // Update our database
                self.enable('pep');

                // Get the PEP nodes to initiate
                Microblog.getInit();
                PEP.getInitGeoloc();
                
                // Get the notifications
                Notification.get();
                
                // Geolocate the user
                PEP.geolocate();
                
                // Enable microblogging send tools
                Microblog.wait('sync');
                $('.postit.attach').css('display', 'block');
                
                Console.info('XMPP server supports PEP.');
            } else {
                Microblog.wait('unsync');
                
                Console.warn('XMPP server does not support PEP.');
            }

            // Hide the private life fieldset if nothing to show
            if(features.pep === false && features[NS_URN_MAM] === false) {
                $('#options fieldset.privacy').hide();
            }
            
            // Apply the features
            self.apply('talk');
            
            // Process the roster height
            if(features.pep === true) {
                Roster.adapt();
            }

            // Enable Message Carbons?
            if(features[NS_URN_CARBONS] === true) {
                Carbons.enable();
            }
        } catch(e) {
            Console.error('Features.handle', e);
        } finally {
            return false;
        }

    };


    /**
     * The function to apply the features to an element
     * @public
     * @param {string} id
     * @return {undefined}
     */
    self.apply = function(id) {

        try {
            // Path to the elements
            var path = '#' + id + ' .';
            
            // PEP features
            if(self.enabledPEP()) {
                $(path + 'pep-hidable').show();
            }
            
            // PubSub features
            if(self.enabledPubSub()) {
                $(path + 'pubsub-hidable').show();
            }

            // PubSub Config-Node features
            if(self.enabledPubSubCN()) {
                $(path + 'pubsub-hidable-cn').show();
            }
            
            // MAM features
            if(self.enabledMAM()) {
                $(path + 'mam-hidable').show();
                $(path + 'mam-showable').hide();
            }

            // MAM Purge
            if(self.enabledMAMPurge()) {
                $(path + 'mam-purge-hidable').show();
            }
            
            // Commands features
            if(self.enabledCommands()) {
                $(path + 'commands-hidable').show();
            }
            
            // XMPP links (browser feature)
            if(navigator.registerProtocolHandler) {
                $(path + 'xmpplinks-hidable').show();
            }
        } catch(e) {
            Console.error('Features.apply', e);
        }

    };


    /**
     * Enables a feature
     * @public
     * @param {string} feature
     * @return {undefined}
     */
    self.enable = function(feature) {

        try {
            DataStore.setDB(Connection.desktop_hash, 'feature', feature, 'true');
        } catch(e) {
            Console.error('Features.enable', e);
        }

    };


    /**
     * Checks if a feature is enabled
     * @public
     * @param {string} feature
     * @return {boolean}
     */
    self.isEnabled = function(feature) {

        try {
            return DataStore.getDB(Connection.desktop_hash, 'feature', feature) === 'true';
        } catch(e) {
            Console.error('Features.isEnabled', e);
        }

    };


    /**
     * Returns the XMPP server PEP support
     * @public
     * @return {boolean}
     */
    self.enabledPEP = function() {

        try {
            return self.isEnabled('pep');
        } catch(e) {
            Console.error('Features.enabledPEP', e);
        }

    };


    /**
     * Returns the XMPP server PubSub support
     * @public
     * @return {boolean}
     */
    self.enabledPubSub = function() {

        try {
            return self.isEnabled(NS_PUBSUB);
        } catch(e) {
            Console.error('Features.enabledPubSub', e);
        }

    };


    /**
     * Returns the XMPP server PubSub Config-Node support
     * @public
     * @return {boolean}
     */
    self.enabledPubSubCN = function() {

        try {
            return self.isEnabled(NS_PUBSUB_CN);
        } catch(e) {
            Console.error('Features.enabledPubSubCN', e);
        }

    };


    /**
     * Returns the XMPP server MAM support
     * @public
     * @return {boolean}
     */
    self.enabledMAM = function() {

        try {
            return self.isEnabled(NS_URN_MAM);
        } catch(e) {
            Console.error('Features.enabledMAM', e);
        }

    };


    /**
     * Returns Metronome MAM Purge support
     * @public
     * @return {boolean}
     */
    self.enabledMAMPurge = function() {

        try {
            if(self.isEnabled(NS_URN_MAM)) {
                return self.isEnabled(NS_METRONOME_MAM_PURGE);
            } else {
               return false;
            }
        } catch(e) {
            Console.error('Features.enabledMAMPurge', e);
        }

    };


    /**
     * Returns the XMPP server Carbons support
     * @public
     * @return {boolean}
     */
    self.enabledCarbons = function() {

        try {
            return self.isEnabled(NS_URN_CARBONS);
        } catch(e) {
            Console.error('Features.enabledCarbons', e);
        }

    };


    /**
     * Returns the XMPP server commands support
     * @public
     * @return {boolean}
     */
    self.enabledCommands = function() {

        try {
            return self.isEnabled(NS_COMMANDS);
        } catch(e) {
            Console.error('Features.enabledCommands', e);
        }

    };


    /**
     * Normalizes the XMPP server name
     * @private
     * @return {string}
     */
    self._normalizeServerName = function(name) {

        try {
            var cur_r;

            for(var i in self.SERVER_NAMES) {
                cur_r = new RegExp(self.SERVER_NAMES[i], 'gi');

                if(cur_r.exec(name) !== null) {
                    name = self.SERVER_NAMES[i];
                    break;
                }
            }
        } catch(e) {
            Console.error('Features._normalizeServerName', e);
        } finally {
            return name;
        }

    };


    /**
     * Returns the XMPP server name
     * @public
     * @return {string}
     */
    self.getServerName = function() {

        try {
            return self.server_name;
        } catch(e) {
            Console.error('Features.getServerName', e);
        }

    };


    /**
     * Return class scope
     */
    return self;

})();