/// class PD.Shared.Dialogs.TaskStatusDialog
/// using PD.Web.UI.Dialog

/**
@class TaskStatusDialog
@namespace Web.UI.Shared.Dialogs
@extends Web.UI.Dialog
@constructor
**/
PD.Shared.Dialogs.TaskStatus =
PD.Web.UI.Dialog.extend({

    //================================
    // FIELDS
    //================================

    _alertDialog: null,
    _alertDialogTypes: null,

    //================================
    // PROPERTIES
    //================================

    get_btnClose: function () {
        return this.get_node().find(".-pd-task-status-btn-close");
    },

    get_btnCancel: function () {
        return this.get_node().find(".-pd-task-status-btn-cancel");
    },

    get_btnDetail: function () {
        return this.get_node().find(".-pd-task-status-btn-detail");
    },

    get_label: function () {
        return this.get_node().find(".-pd-task-status-label");
    },
    
    get_progress: function () {
        return this.get_node().find(".-pd-task-status-progress");
    },
    
    get_progressBar: function () {
        return this.get_node().find(".-pd-task-status-progress-bar");
    },

    get_detail: function () {
        return this.get_node().find(".-pd-task-status-detail");
    },

    get_btnDetailLabel: function () {
        return this.get_node().find(".-pd-task-status-deck > DIV > SPAN");
    },

    //================================
    // EVENT HANDLERS
    //================================

    _closeButton_onClick: function (e) {
        this.close(this._getTaskEventArgs());
    },

    _cancelButton_onClick: function (e) {
        this.close(this._getTaskEventArgs());
    },

    _detail_onClick: function (e) {

        var isDetailDisplayed = this.get_detail().css("display") !== "none";

        if (isDetailDisplayed) {
            this._hideDetail();
        }
        else {
            this._showDetail();
        }
        
    },
    
    _pollStatus_onSuccess: function (e) {

        this._status = e;

        this._updateStatus(e);
    
    },
    
    _pollStatus_onError: function (e) {

        var message = "";

        try {
            message = e.responseJSON.message;
        }
        catch (ex) { 
            message = "Fatal Error.";
        }

        this._fatalError(message);
        
    },

    //================================
    // PUBLIC METHODS
    //================================

    onInit: function (e) {

        this._options = $.extend(true, {
            pollUrl: "~/Shared/Task/Status",
            pollFrequency: 500,
            taskStart: null,
            taskCancel: null,
            showDetail: false,
            allowClose: true,
            enableClose: true,
            config: {
                resizable: false,
                height: "110px",
                width: "400px"
            }
        }, this._options);

    },

    onActivate: function () {

        this.get_btnClose().on("click", $.proxy(this._closeButton_onClick, this));
        this.get_btnCancel().on("click", $.proxy(this._cancelButton_onClick, this));
        this.get_btnDetail().parent().on("click", $.proxy(this._detail_onClick, this));

        this._enableClose(this._options.enableClose);

        this._window._kendo.setOptions({
            actions: []
        });

    },

    onComplete: function () {

        var that = this,
            showDetail = this.get_options()["showDetail"],
            allowClose = this.get_options()["allowClose"];

        this._addLabelMessage("Starting task ...");
        this._addDetailMessage(0, "Starting task ...");

        if (allowClose) {
            this.get_btnClose().show();
        }

        if (showDetail) {
            this._showDetail();
        }

        setTimeout(function () {
            that._start();
        }, 2000);

    },

    template: function (options) {

        return [
            "<div class='-pd-task-status'>",
                "<label class='-pd-task-status-label'></label>",
                "<div class='-pd-task-status-progress'>",
                    "<div class='-pd-task-status-progress-bar'>",
                    "</div>",
                "</div>",
                "<div class='-pd-task-status-detail' style='display:none;'></div>",
                "<div class='-pd-task-status-deck'>",
                    "<div>",
                        "<button class='-pd-task-status-btn-detail' style=''>",
                            "<img src='" + PD.Path.to16x16("navigate_down.png") + "'/>",
                        "</button>",
                        "<span>More Detail</span>",
                    "</div>",
                    "<button class='-pd-button -pd-task-status-btn-close' style='display:none;'>Close</button>",
                    "<button class='-pd-button -pd-task-status-btn-cancel' style='display:none;'>Cancel</button>",
                "</div>",
            "</div>"
        ];

    },

    close: function (options) {
        this._super(options);

        var closeFn = this.get_options()["close"];

        if (_.isFunction(closeFn)) {
            closeFn(options);
        }

    },

    ajax: function (options) {

        var that = this;

        options = _.extend({
            success: function (e) {
                that.startPolling(e);
            },
            error: function (e) {
                args.abort(e.responseJSON);
                e.errorHandled = true;
            }
        }, options);

        PD.ajax(options);

    },

    //================================
    // PRIVATE METHODS
    //================================

    _start: function () {

        var that = this,
            args = this._getTaskEventArgs(),
            taskCancelFn = this.get_options()["taskCancel"],
            taskStartFn = this.get_options()["taskStart"];

        if (!PD.Type.isFunction(taskStartFn)) {
            this._fatalError("No task start was provided.");
            return;
        }

        if (PD.Type.isFunction(taskCancelFn)) {
            this.get_btnCancel().show();
        }

        taskStartFn(args);

    },

    _pollStatus: function (taskId) {

        var that = this,
            pollUrl = this.get_options()["pollUrl"];

        if (!pollUrl) {
            this._fatalError("Unable to poll task.");
            return;
        }

        pollUrl += (taskId != null ? "/" + taskId : "");

        PD.ajax({
            type: "GET",
            url: PD.Path.resolve(pollUrl),
            success: function (e) {
                if (taskId != null) {
                    e.taskId = taskId;
                }
                that._pollStatus_onSuccess(e);
            },
            error: $.proxy(this._pollStatus_onError, this)
        });

    },

    _updateStatus: function (status) {

        var that = this;

        this._addLabelMessage(status.lastAction);

        this._addDetailMessages(status.messages);

        this._setProgressBar(status.percentComplete);
        
        this._handleAlert(status);

        if (status.complete) {
            this._complete(status);
        }
        else {

            setTimeout(function () {
                that._pollStatus(status.taskId);
            }, this.get_options()["pollFrequency"])

        }

    },

    _alert: function (e) {

        var taskAlertEventArgs = this._getTaskEventArgs(),
            taskAlertFn = this.get_options()["taskAlert"];

        taskAlertEventArgs.timeout = function () {};

        if (_.isFunction(taskAlertFn)) {
            taskAlertFn(taskAlertEventArgs);
        }

    },

    _alertTimeout: function () {
    
        var taskAlertTimeoutEventArgs = this._getTaskEventArgs(),
            taskAlertTimeoutFn = this.get_options()["taskAlertTimeout"];

        if (_.isFunction(taskAlertTimeoutFn)) {

        }

    },

    _scrollDetailToBottom: function () {
        //TODO: Use jQuery here instaed of DOM API directly.
        this.get_detail()[0].scrollTop = this.get_detail()[0].scrollHeight;
    },

    _showDetail: function () {
        this.get_detail().show();
        this.get_btnDetail().find("IMG").prop("src", PD.Path.resolve("~/Areas/Shared/Assets/Internal/Icons/16x16/navigate_up.png"));
        this.get_btnDetail().css({ paddingTop:1 });
        this.setDimensions(300, 400);
        this.get_btnDetailLabel().text("Less Detail");
        this._scrollDetailToBottom();
    },

    _hideDetail: function () {
        this.get_detail().hide();
        this.get_btnDetail().find("IMG").prop("src", PD.Path.resolve("~/Areas/Shared/Assets/Internal/Icons/16x16/navigate_down.png"));
        this.setDimensions(110, 400);
        this.get_btnDetailLabel().text("More Detail");
    },

    _addLabelMessage: function (message) {
        if (message != null) {
            this.get_label().empty();
            this.get_label().prop("title", message);
            this.get_label().append("<span>" + message + "</span>");
        }
    },

    _addDetailMessages: function (messages, indent) {

        var that = this;

        indent = indent == null ? 0 : indent;

        if (_.isArray(messages)) {

            if (messages.length > 0) {

                _.each(messages, function (item) {

                    that._addDetailMessage(item.level, item.message, indent);

                    if (_.isArray(item.subMessages)) {
                        that._addDetailMessages(item.subMessages, indent + 15);
                    }

                });

            }

        }

    },

    _addDetailMessage: function (type, message, indent) {
        
        var cssClass = "";

        indent = indent == null ? 0 : indent;

        switch (type) {
            case 1:
                cssClass = "warning";
                break;
            case 2:
                cssClass = "error";
                break;
        }

        this.get_detail().append("<div class='" + cssClass + "' style='margin:0px 0px 0px " + indent + "px;'>" + (message != null ? message : "") + "</div>");

        this._scrollDetailToBottom();

    },

    _complete: function (e) {

        var taskSuccessEventArgs = this._getTaskEventArgs(),
            taskSuccessFn = this.get_options()["taskSuccess"];

        this.get_label().addClass("success");
        this._setProgressBar(100, false)

        this.get_btnClose().focus();

        if (PD.Type.isFunction(taskSuccessFn)) {
            $.proxy(taskSuccessFn, this)(_.extend({
                taskId: e.taskId,
                tags: e.tags,
            }, taskSuccessEventArgs));
        }

    },

    _fatalError: function (message) {
        message = message || "Task was unexpectedly aborted.";
        this._addLabelMessage(message);
        this._addDetailMessage(2, message);
        this._addDetailMessage(0, "Task Aborted.");
        this.get_label().addClass("error");
        this._enableClose(true);
    },

    _setProgressBar: function (percentComplete, isError) {

        if (isError != null) {
            if (isError) {
                this.get_progressBar().addClass("error");
            }
            else {
                this.get_progressBar().removeClass("error");
            }
        }
        
        this.get_progressBar().css({
            width: (percentComplete != null ? percentComplete : 0) + "%"
        });

    },

    _enableClose: function (value) {
        this.get_btnClose().prop("disabled", !value);
        this.get_btnClose().focus();
    },

    _getTaskEventArgs: function () {

        var that = this;

        return {
            ajax: this.ajax,
            startPolling: function (e) {
                that._registerAlertDialogTypes(e.alerts);
                that._pollStatus(e.taskId);
            },
            abort: function (message) {
                if (_.isArray(message)) {
                    _.each(message, function (msg) {
                        that._fatalError(msg.message);
                    });
                }
                else if (_.isString(message)) {
                    that._fatalError(message);
                }
                else if (_.isObject(message)) {
                    that._fatalError(message.message);
                }
                else {
                    that._fatalError();
                }
            },
            complete: function (message) {
                if (message != null) {
                    that._addDetailMessage(0, message);
                }
                that._complete();
            },
            enableClose: function (value) {
                that._enableClose(value);
            },
            close: _.bind(this.close, this),
            taskStatus: this._status,
            addDetailMessage: _.bind(this._addDetailMessage, this)
        }

    },

    _registerAlertDialogTypes: function (types) {
        
        var that = this;

        this._alertDialogTypes = {};

        _.each(types, function (value, key) {
            
            var type = PD.Type.getType(value);

            if (type != null) {
                that._alertDialogTypes[key] = type;
            }

        });

    },

    _showAlertDialog: function (taskId, alert) {

        var that = this,
            alertDialogType = this._alertDialogTypes[alert.code];

        if (alertDialogType != null) {
            this._alertDialog = new alertDialogType({
                alert: alert,
                callbacks: {
                    ok: function (sender, e) {
                        that._sendAlertResponse(taskId, e);
                        that._alertDialog = null;
                    }
                }
            });
        }

    },

    _sendAlertResponse: function (taskId, tags) {

        var that = this;

        PD.ajax({
            type: "POST",
            url: PD.Path.resolve("~/Shared/Task/Notify"),
            data: {
                reply: JSON.stringify({
                    taskId: taskId,
                    tags: tags
                })
            },
            error: function (e) {
                alert("OH NO");
            }
        });

    },

    _handleAlert: function (status) {

        var isTaskAlerting = status.alert != null,
            isDialogAlerting = this._alertDialog != null;

        if (!isTaskAlerting && isDialogAlerting) {
            this._alertDialog.close();
            this._alertDialog = null;
        }
        else if (isTaskAlerting && !isDialogAlerting) {
            this._showAlertDialog(status.taskId, status.alert);
        }

    }

});

//================================
// STATIC METHODS
//================================

PD.Shared.Dialogs.TaskStatus.open = function (options) {
    return new PD.Shared.Dialogs.TaskStatus(options);
};
