/**
 * Checks if the Web Central server is available
 */
Ext.define('Common.util.Network', {
    alternateClassName: ['Network'],
    singleton: true,

    requires: [
        'Common.util.Mask',
        'Common.env.Feature',
        'Common.controller.EventBus'
    ],

    /**
     * Framework level timeout value for asynchronous service calls.
     * The units for SERVICE_TIMEOUT are seconds
     * @property {Number} SERVICE_TIMEOUT
     */
    SERVICE_TIMEOUT: 500,

    NETWORK_CONNECTION_UNAVAILABLE: LocaleManager.getLocalizedString('Network connection is not available', 'Common.util.Network'),
    NETWORK_UNREACHABLE: LocaleManager.getLocalizedString('Network Unreachable', 'Common.util.Network'),

    /**
     * Checks if the connection to the URL is successful.
     * @param url
     * @returns {Object} Object containing the isConnected and isRedirected properties. The connection to the URL
     * is successful when isConnected is true. The isRedirected property will be true if the URL was redirected.
     * The request may be redirected in different authentication schemes.
     */
    isServerReachable: function (url) {
        var me = this;
        if (Ext.isEmpty(url)) {
            url = me.getCurrentUrl();
        }
        return new Promise(function (resolve) {
            if (Common.env.Feature.isNative) {
                Connection.isConnected(url, resolve, function () {
                    // TODO: Log error
                    resolve({isConnected: false, isRedirected: false});
                });
            } else {
                me.isServerReachableAsync(url, function (result) {
                    resolve({isConnected: result, isRedirected: false});
                }, me);
            }
        });
    },

    isServerReachableAsync: function (url, onCompleted, scope) {
        var xhr = new XMLHttpRequest(),
            xhrComplete = function (result) {
                Ext.callback(onCompleted, scope, [result]);
            },
            requestTimer;

        if (Ext.isEmpty(url)) {
            url = this.getCurrentUrl();
        }
        url = url + ((url.indexOf('?') === -1) ? '?' : '&') + Date.now();

        try {
            xhr.open('GET', url, true);
            requestTimer = setTimeout(function () {
                xhr.abort();
            }, 10000);
            xhr.onreadystatechange = function () {
                var status,
                    content;
                if (xhr.readyState === 4) {
                    clearTimeout(requestTimer);
                    status = xhr.status;
                    content = xhr.responseText;

                    if ((status >= 200 && status < 400) || (status === 0 && content.length > 0)) {
                        xhrComplete(true);
                    }
                    else {
                        xhrComplete(false);
                    }
                }
            };
            xhr.send(null);
        } catch (e) {
            xhrComplete(false);
        }
    },

    /**
     * Queries the device for the status of the network connection
     *
     * @return {Boolean} True if the device detects a network connection.
     */
    isDeviceConnected: function () {
        var networkState;

        // Always return true if we running on the Desktop
        // TODO: Windows Phone emulator always returns Connnection.UNKNOWN...
        // Create plugin to check if we are running in an emulator
        if (Ext.os.is.Desktop || Ext.os.is.WindowsPhone) {
            return true;
        }

        networkState = Connection.NONE;

        if (navigator.network.connection) {
            networkState = navigator.network.connection.type;
        }
        return networkState !== Connection.UNKNOWN && networkState !== Connection.NONE;
    },

    isDeviceAndServerConnected: function (url) {
        if (!Common.util.Network.isDeviceConnected()) {
            return Promise.resolve(false);
        } else {
            return Common.util.Network.isServerReachable(url)
                .then(function (result) {
                    var isConnected = result.isConnected;
                    if (isConnected && result.isRedirected) {
                        isConnected = false;
                        Common.controller.EventBus.performRedirect();
                    }
                    return Promise.resolve(isConnected);
                });
        }
    },

    /**
     * Checks if the device has an active network connection and if the Web Central server is online.
     * @param {Function} onCompleted Called when the check is complete
     * @param {Object} scope The scope to execute the onCompleted function
     */
    checkNetworkConnectionAndDisplayMessageAsync: function (onCompleted, scope) {
        var me = this;
        Mask.displayLoadingMask();
        Network.isDeviceAndServerConnected(null)
            .then(function (result) {
                Mask.hideLoadingMask();
                if (result) {
                    Ext.callback(onCompleted, scope || me, [result]);
                } else {
                    Common.util.Network.displayConnectionMessage();
                    Ext.callback(onCompleted, scope || me, [result]);
                }
            });
    },

    /**
     * Returns the URL of the current page. Removes the hash value if it exists
     */
    getCurrentUrl: function () {
        var hash = window.location.hash,
            url = window.location.href;

        if (url.indexOf(hash) !== -1) {
            url = url.replace(hash, '');
        }

        return url;
    },

    checkNetworkConnectionAndDisplayMessage: function () {
        return Network.isDeviceAndServerConnected(null)
            .then(function (isConnected) {
                if (!isConnected) {
                    Common.util.Network.displayConnectionMessage();
                }
                return Promise.resolve(isConnected);
            });
    },

    checkNetworkConnectionAndLoadDwrScripts: function (displayErrorMessage) {
        var isConnected = false;
        return Network.isDeviceAndServerConnected(null)
            .then(function (result) {
                isConnected = result;
                if (isConnected) {
                    return Common.scripts.ScriptManager.loadDwrScripts();
                } else {
                    if(displayErrorMessage) {
                        Common.util.Network.displayConnectionMessage();
                    }
                    return Promise.resolve();
                }
            })
            .then(function () {
                return Promise.resolve(isConnected);
            });
    },

    /**
     * Displays the 'Network Connection Unavailable' message
     */
    displayConnectionMessage: function () {
        Ext.Msg.alert(Common.util.Network.NETWORK_UNREACHABLE, Common.util.Network.NETWORK_CONNECTION_UNAVAILABLE);
    }
});