/// <reference path="../references.js" />

rwthapp.util.initNamespace("error.Error");

rwthapp.error.Error = function (message, code, userfriendlyMessage, displayDetailedErrorInformation) {
    this.message = message;
    this.code = code;
    this.userfriendlyMessage = userfriendlyMessage; // TODO use langString key instead to localize messages just before display?
    this.displayDetailedErrorInformation = displayDetailedErrorInformation;
    this.timestamp = Date.now();
    this.stack = (new Error()).stack;
};
rwthapp.error.Error.constructor = rwthapp.error.Error;

rwthapp.error.AjaxError = function (message, code, userfriendlyMessage, displayDetailedErrorInformation, url) {
    rwthapp.error.Error.call(this, message, code, userfriendlyMessage, displayDetailedErrorInformation);
    this.url = url;
};
rwthapp.error.AjaxError.prototype = new rwthapp.error.Error();
rwthapp.error.AjaxError.constructor = rwthapp.error.AjaxError;

rwthapp.error.ProxyApiError = function (message, code, userfriendlyMessage, displayDetailedErrorInformation, apiStatusCode, apiStatusInfo) {
    rwthapp.error.Error.call(this, message, code, userfriendlyMessage, displayDetailedErrorInformation, apiStatusInfo);
    this.apiStatusCode = apiStatusCode;
    this.apiStatusInfo = apiStatusInfo;
};
rwthapp.error.ProxyApiError.prototype = new rwthapp.error.Error();
rwthapp.error.ProxyApiError.constructor = rwthapp.error.ProxyApiError;

rwthapp.error.createErrorFromXHR = function (xhr, textStatus) {
    var errorObject = null;

    if (textStatus && textStatus === "timeout") {
        errorObject = new rwthapp.error.Error("Request timeout.", 12, rwthapp.localization.getLocalizedString("errors.request.timeout"), false);
    } else {
        switch (xhr.status) {
            case 404: errorObject = new rwthapp.error.Error("Ajax request returned code " + xhr.status, 14, rwthapp.localization.getLocalizedString("errors.request.clientError"), true);
                break;
            case 500: errorObject = new rwthapp.error.Error("Ajax request returned code " + xhr.status, 15, rwthapp.localization.getLocalizedString("errors.request.serverError"), false);
                break;
            case 400: errorObject = new rwthapp.error.Error("Ajax request returned code " + xhr.status, 13, rwthapp.localization.getLocalizedString("errors.request.clientError"), true);
                break;
            default: errorObject = new rwthapp.error.Error("Ajax request returned code " + xhr.status, 11, rwthapp.localization.getLocalizedString("errors.request.general"), false);
        }
    }

    return errorObject;
};

rwthapp.error.createErrorFromProxyApiResponse = function (response) {
    if (response.IsError === undefined || response.StatusCode === undefined || response.StatusInfo === undefined) {
        return new rwthapp.error.ProxyApiError("Invalid API response.", 30, rwthapp.localization.getLocalizedString("errors.api.general"), true, null, null);
    } else if (response.IsError) {
        var errorObject = null;

        switch (response.ErrorCode) {
            case 1: errorObject = new rwthapp.error.ProxyApiError("Token invalid.", 31, rwthapp.localization.getLocalizedString("errors.api.tokenInvalid"), true, response.StatusCode, response.StatusInfo);
                break;
            default: errorObject = new rwthapp.error.ProxyApiError("API returned code " + response.StatusCode + ": " + response.StatusInfo, 30, rwthapp.localization.getLocalizedString("errors.api.general"), true, response.StatusCode, response.StatusInfo);
        }

        return errorObject;
    } else {
        // No error occurred
        return null;
    }
};

rwthapp.error.createErrorFromOAuthError = function (error) {
    if (error instanceof rwthapp.error.Error) {
        return error;
    } else {
        var errorObject = null;

        switch (error) {
            default: errorObject = new rwthapp.error.Error(error, 20, rwthapp.localization.getLocalizedString("errors.oauth.general"), false);
        }

        return errorObject;
    }
};

rwthapp.error.getErrorObject = function (error, targetPage) {

    var errorUserMessage = "";
    var errorObjectSerialized = "";
    var logMessage = "";

    if (error instanceof rwthapp.error.Error) {
        errorUserMessage = error.userfriendlyMessage;
        logMessage = error.message;

        if (error.displayDetailedErrorInformation) {
            errorObjectSerialized = JSON.stringify(error);
        }
    } else if (error instanceof Error) {
        errorUserMessage = error.message; // TODO replcae with own error message for unexpected error?
        errorObjectSerialized = JSON.stringify(error, ["message", "arguments", "type", "name", "stack"]);
        logMessage = error;
    } else {
        errorUserMessage = error; // TODO replcae with own error message for unexpected error?
        errorObjectSerialized = error;
        logMessage = error;
    }
    rwthapp.logging.logger.log(rwthapp.logging.LogLevel.Error, logMessage, error);

    return {

        template: 'errorpage',
        message: errorUserMessage,
        targetPage: targetPage,
        error: errorObjectSerialized
    };
}

rwthapp.error.showErrorPage = function (error, targetPage) {
    
    var error = rwthapp.error.getErrorObject(error, targetPage);

    // Load error page
    rwthapp.navigator.gotoPage(error.template, {
        message: error.message,
        targetPage: error.targetPage,
        error: error.error,
        _: Date.now()
    }, false);
};

rwthapp.error.extractTargetPage = function (error, sourcePage) {

    var targetPage = sourcePage;
    if (sourcePage === undefined) {
        // Default value if not supplied
        targetPage = location.hash;
    }

    // Add # if necessary
    if (targetPage.indexOf("#") !== 0) {
        targetPage = "#" + targetPage;
    }

    if (error instanceof rwthapp.error.Error
        && (error.code === 21 // Not logged in
            || error.code === 22)) {// Login invalid
        targetPage = "#home";
    }

    return targetPage;
}

rwthapp.error.handleError = function (error, sourcePage) {
    /// <summary>Performs basic error handling. An error page will be displayed to the user. Error is logged.</summary>
    /// <param name="error" type="object">Error object thrown by the exception.</param>
    /// <param name="sourcePage" type="object">The location hash of the current page, will be used to give the user a possibility to retry the action. 
    ///     This parameter may be ignored for example if the user is not logged in to redirect to login page.</param>

    // Always hide loading bar
    rwthapp.util.hideLoadingScreen();

    var targetPage = rwthapp.error.extractTargetPage(error, sourcePage);

    // Load error page
    rwthapp.error.showErrorPage(error, targetPage);
};

rwthapp.error.handleAndDeliverError = function (error, sourcePage) {

    var targetPage = rwthapp.error.extractTargetPage(error, sourcePage);

    return rwthapp.error.getErrorObject(error, targetPage);
}

rwthapp.error.displayErrorMessage = function (error) {
    /// <summary>Displays an error message to the user. User stays on the current page. Error is logged.</summary>
    /// <param name="error" type="object">Error object thrown by the exception, alternatively the error message as a string.</param>

    var logMessage = "";
    var errorUserMessage = "";

    if (typeof error === "string") {
        errorUserMessage = error;
        logMessage = error;
    } else {
        if (error instanceof rwthapp.error.Error) {
            errorUserMessage = error.userfriendlyMessage;
            logMessage = error.message;
        } else {
            errorUserMessage = error; // TODO replcae with own error message for unexpected error?
            logMessage = error;
        }
    }
    
    rwthapp.logging.logger.log(rwthapp.logging.LogLevel.Error, logMessage, error);

    // Display error message
    rwthapp.notifications.showDialog(errorUserMessage);
};

rwthapp.error.generateDebugInformation = function (error) {
    var debugInformation = {};

    // Error information
    if (error) {
        debugInformation.isError = true;
        if (typeof error === "string") {
            debugInformation.message = error;
        } else {
            debugInformation.message = error.message;
            debugInformation.timestamp = error.timestamp;
            debugInformation.code = error.code;
            debugInformation.stack = error.stack;
            debugInformation.url = error.url;
            debugInformation.apiStatusCode = error.apiStatusCode;
            debugInformation.apiStatusInfo = error.apiStatusInfo;
        } 
    } else {
        debugInformation.isError = false;
    }

    // App information
    debugInformation.appVersion = rwthapp.options.getVersionNumber() + "." + rwthapp.options.getVersionCode();
    debugInformation.testSystem = rwthapp.options.getActiveProxyConfigName() !== "live";
    debugInformation.userLoggedIn = rwthapp.tokenManager.isUserLoggedIn();
    debugInformation.userLoginPersonalized = rwthapp.tokenManager.isLoginPersonalized();

    // User options
    debugInformation.language = rwthapp.localization.getCurrentLanguage();
    debugInformation.menuPinned = rwthapp.templates.menu.isMenuPinned();
    debugInformation.vibrationEnabled = rwthapp.options.vibration.isEnabled();
    debugInformation.wavesEffectEnabled = rwthapp.options.wavesEffect.isEnabled();
    // Get active feeds
    try {
        var cachedFeeds = rwthapp.options.feeds.getCachedFeeds();
        // Get comma separated list of active feed ids
        debugInformation.activeFeeds = cachedFeeds.filter(function (element) { return element.isActive; }).map(function (element) { return element.id; }).join(",");
    } catch (e) {
        debugInformation.activeFeeds = "";
    }

    // Device information
    debugInformation.deviceModel = device.model;
    debugInformation.devicePlatform = device.platform;
    debugInformation.devicePlatformVersion = device.version;
    debugInformation.connectionType = navigator.connection.type;
    debugInformation.userAgent = navigator.userAgent;
    debugInformation.screenOrientationIsLandscape = rwthapp.util.isLandscape();
    debugInformation.windowWidth = window.innerWidth;
    debugInformation.windowHeight = window.innerHeight;

    // Log information
    debugInformation.history = $.extend(true, [], rwthapp.logging.logger.history); // Create copy of array

    return debugInformation;
};