/** @class */
jscape.LogSearch = Class.extend(
    /** @lends {jscape.LogSearch.prototype} */
{
    /** @constructor */
    initialize: function (a, b, c, d, e, f, g, h) {
        this.name = a || "";
        this.maxRecords = parseInt(b) || 0;
        this.date = parseInt(c) || $.now();
        this.startDate = parseInt(d) || null;
        this.endDate = parseInt(e) || null;
        this.criteria = f || "";
        this.progress = parseInt(g) || 0;
        this.error = h || null;
    },

    completed: function() {
        return this.progress == 100 || this.error;
    }
});
jscape.LogSearch.fromJSON = function(data) {
    return data ? new jscape.LogSearch(data.name, data.maxRecords, data.date, data.startDate, data.endDate, data.criteria, data.progress, data.error) : null;
};

/** @class */
jscape.SearchCriteria = Class.extend(
    /** @lends {jscape.SearchCriteria.prototype} */
{
    /** @constructor */
    initialize: function(variable, operator, value) {
        this.variable = variable || "";
        this.operator = operator || null;
        this.value = value || null;
    },

    toString: function () {
        return ($.type(this.value) === "string" ? '{0} {1} "{2}"' : "{0} {1} {2}")
                .supplant({0: this.variable, 1: this.operator, 2: this.value});
    }
});
/** @class */
jscape.SearchDateCriteria = Class.extend(
    /** @lends {jscape.SearchDateCriteria.prototype} */
{
    /** @constructor */
    initialize: function(variable, startDate, endDate) {
        this.variable = variable || "";
        this.startDate = startDate || null;
        this.endDate = endDate || null;
    },

    toString: function() {
        return "({0} >= {1} AND {0} <= {2})".supplant({
            0: this.variable,
            1: $.type(this.startDate) === "date" ? this.startDate.getTime() : this.startDate,
            2: $.type(this.endDate) === "date" ? this.endDate.getTime() : this.endDate
        });
    }
});

/** @class */
jscape.domain.LogSearchController = Class.extend(
    /** @lends {jscape.domain.LogSearchController.prototype} */
{
    criteriaView: null,
    resultsView: null,

    /** @constructor */
    initialize: function () {
        this._initValidators();
    },

    onCreate: function (managementService, domainName) {
        this.managementService = managementService;
        this.domainName = domainName;

        this.exportController = new jscape.domain.ExportLogSearchController();
        this.resultController = new jscape.domain.LogSearchResultController();
        this.deleteController = new jscape.domain.DeleteLogSearchController();
    },

    onStart: function () {
        if (this.criteriaView == null) {
            this.criteriaView = new jscape.domain.LogSearchCriteriaView();
        }
        if (this.resultsView == null) {
            this.resultsView = new jscape.domain.LogSearchResultsView();
        }
        this.criteriaView.show(this);
        this.resultsView.show(this);
    },

    hasChanged: function() {
        return false;
    },

    onResume: function() {
        this.resultsView.refresh();
    },

    onRefresh: function() {
        return this.managementService.getLogSearches(this.domainName);
    },

    onSearch: function () {
        var search = this._createNewSearch();
        return this.managementService.searchLog(this.domainName, search)
                .done($.proxy(this._searchComplete, this, search));
    },

    onExport: function (search) {
        return this.exportController.start(this.managementService, this.domainName, search.name);
    },

    onView: function (search) {
        return this.resultController.start(this.managementService, this.domainName, search);
    },

    onRerun: function (search) {
        return this.managementService.startLogSearch(this.domainName, search.name)
                .done($.proxy(function() { this.resultsView.refresh(); }, this));
    },

    onDelete: function (searches) {
        return this.deleteController.start(this.managementService, this.domainName, searches)
                .done($.proxy(this._searchResultDeleted, this, searches));
    },

    _searchResultDeleted: function(searches) {
        for (var i = 0; i < searches.length; i++) {
            this.resultsView.deleteRecord(searches[i]);
        }
        this.resultsView.refresh();
    },

    _searchComplete: function(search) {
        this._navigateFrom(this.resultsView.fieldset);

        this.resultsView.refresh($.proxy(function() {
            this.resultsView.selectSearch(search);
        }, this));
    },

    _createNewSearch: function () {
        var dateCriteria = this.criteriaView.getDateCriteria();
        return new jscape.LogSearch(this.criteriaView.getName(),
                                    this.criteriaView.getMaxRecords(),
                                    $.now(),
                                    dateCriteria != null ? dateCriteria.startDate : null,
                                    dateCriteria != null ? dateCriteria.endDate : null,
                                    this._createSearchCriteria());
    },

    _createSearchCriteria: function() {
        return $.map($.grep([
                this.criteriaView.getDateCriteria(),
                this.criteriaView.getSessionIdCriteria(),
                this.criteriaView.getClientIpCriteria(),
                this.criteriaView.getClientPortCriteria(),
                this.criteriaView.getServerIpCriteria(),
                this.criteriaView.getServerPortCriteria(),
                this.criteriaView.getUsernameCriteria(),
                this.criteriaView.getClientRequestCriteria(),
                this.criteriaView.getClientMessageCriteria(),
                this.criteriaView.getServerStatusCriteria(),
                this.criteriaView.getServerMessageCriteria(),
                this.criteriaView.getInboundCriteria(),
                this.criteriaView.getOutboundCriteria()
            ], function (criteria) { return criteria != null; }),
                     function (criteria) { return criteria.toString(); }).join(" AND ");
    },

    _navigateFrom: function (source) {
        source.parents(".tabs-container").each($.proxy(function (_, elem) {
            var tabs = $(elem);
            var tabIndex = -1;
            $.each(tabs.tabs("tabs"), function (i, target) {
                if (target.has(source).length != 0) {
                    tabIndex = i;
                    return false;
                }
                return true;
            });
            if (tabIndex != -1) {
                tabs.tabs("select", tabIndex);
            }
            if (this.tabs != tabs) {
                this._navigateFrom(tabs);
            }
        }, this));
    },

    _initValidators: function() {
        var v = new jscape.Validator();
        v.rule("logging_name", $.proxy(this._nameValid, this), window.R.string.LOGGING_ERROR_BAD_NAME);
        v.rule("logging_unique", $.proxy(this._searchNotExists, this), window.R.string.LOGGING_ERROR_BAD_NAME);
    },

    _nameValid: function(value) {
        return value && value.trim().length != 0 && !/[<>\\/]/g.test(value);
    },

    _searchNotExists: function(value) {
        return $.grep(this.resultsView.getSearches(), function(search) { return search.name == value; }).length == 0;
    }
});

/** @class */
jscape.domain.LogSearchCriteriaView = Class.extend(
    /** @lends {jscape.domain.LogSearchCriteriaView.prototype} */
{
    /** @constructor */
    initialize: function() {
        this.fieldset = $("fieldset[name=searchcriteriafields]");

        this.name = $("input[name=name]", this.fieldset).textbox({required: true, validType: ["non_empty", "logging_name", "logging_unique"], missingMessage: window.R.string.LOGGING_ERROR_BAD_NAME, invalidMessage: window.R.string.LOGGING_ERROR_BAD_NAME, width: "60%"});
        this.maxRecords = $("input[name=maxrecords]", this.fieldset).numberspinner({required: true, min: 1, max: 100000, value: 1000, increment: 10, width: 125});


        this.dateCriteria = new jscape.domain.SearchCriteriaDateView($("input[name=daterange]:checkbox", this.fieldset),
                                                                     $("input[name=datebegin]", this.fieldset),
                                                                     $("input[name=dateend]", this.fieldset));

        this.sessionIdCriteria = new jscape.domain.SearchCriteriaTextView($("input[name=bysessionid]:checkbox", this.fieldset),
                                                                          $("select[name=sessionidoperator]", this.fieldset),
                                                                          $("input[name=sessionid]", this.fieldset));

        this.clientIpCriteria = new jscape.domain.SearchCriteriaTextView($("input[name=byclientip]:checkbox", this.fieldset),
                                                                         $("select[name=clientipoperator]", this.fieldset),
                                                                         $("input[name=clientip]", this.fieldset));

        this.clientPortCriteria = new jscape.domain.SearchCriteriaPortView($("input[name=byclientport]:checkbox", this.fieldset),
                                                                           $("select[name=clientportoperator]", this.fieldset),
                                                                           $("input[name=clientport]", this.fieldset));

        this.serverIpCriteria = new jscape.domain.SearchCriteriaTextView($("input[name=byserverip]:checkbox", this.fieldset),
                                                                         $("select[name=serveripoperator]", this.fieldset),
                                                                         $("input[name=serverip]", this.fieldset));

        this.serverPortCriteria = new jscape.domain.SearchCriteriaPortView($("input[name=byserverport]:checkbox", this.fieldset),
                                                                           $("select[name=serverportoperator]", this.fieldset),
                                                                           $("input[name=serverport]", this.fieldset));

        this.usernameCriteria = new jscape.domain.SearchCriteriaTextView($("input[name=byuser]:checkbox", this.fieldset),
                                                                         $("select[name=usernameoperator]", this.fieldset),
                                                                         $("input[name=username]", this.fieldset));

        this.clientRequestCriteria = new jscape.domain.SearchCriteriaTextView($("input[name=byclientrequest]:checkbox", this.fieldset),
                                                                              $("select[name=clientrequestoperator]", this.fieldset),
                                                                              $("input[name=clientrequest]", this.fieldset));

        this.clientMessageCriteria = new jscape.domain.SearchCriteriaTextView($("input[name=byclientmessage]:checkbox", this.fieldset),
                                                                          $("select[name=clientmessageoperator]", this.fieldset),
                                                                          $("input[name=clientmessage]", this.fieldset));

        this.serverStatusCriteria = new jscape.domain.SearchCriteriaTextView($("input[name=byserverstatus]:checkbox", this.fieldset),
                                                                             $("select[name=serverstatusoperator]", this.fieldset),
                                                                             $("input[name=serverstatus]", this.fieldset));

        this.serverMessageCriteria = new jscape.domain.SearchCriteriaTextView($("input[name=byservermessage]:checkbox", this.fieldset),
                                                                              $("select[name=servermessageoperator]", this.fieldset),
                                                                              $("input[name=servermessage]", this.fieldset));

        this.inboundCriteria = new jscape.domain.SearchCriteriaSizeView($("input[name=byinbound]:checkbox", this.fieldset),
                                                                        $("select[name=inboundoperator]", this.fieldset),
                                                                        $("input[name=inbound]", this.fieldset),
                                                                        $("select[name=inboundfactor]", this.fieldset));

        this.outboundCriteria = new jscape.domain.SearchCriteriaSizeView($("input[name=byoutbound]:checkbox", this.fieldset),
                                                                         $("select[name=outboundoperator]", this.fieldset),
                                                                         $("input[name=outbound]", this.fieldset),
                                                                         $("select[name=outboundfactor]", this.fieldset));

        this.searchButton = $("a[role=button][name=search]", this.fieldset).linkbutton({onClick: $.proxy(this._onClick$SearchButton, this)});
    },

    getName: function() {
        return this.name.textbox("getValue");
    },

    getMaxRecords: function() {
        return parseInt(this.maxRecords.numberspinner("getValue"));
    },

    getDateCriteria: function() {
        return this.dateCriteria.val();
    },

    getSessionIdCriteria: function() {
        return this.sessionIdCriteria.val();
    },

    getClientIpCriteria: function() {
        return this.clientIpCriteria.val();
    },

    getClientPortCriteria: function() {
        return this.clientPortCriteria.val();
    },

    getServerIpCriteria: function() {
        return this.serverIpCriteria.val();
    },

    getServerPortCriteria: function() {
        return this.serverPortCriteria.val();
    },

    getUsernameCriteria: function() {
        return this.usernameCriteria.val();
    },

    getClientRequestCriteria: function() {
        return this.clientRequestCriteria.val();
    },

    getClientMessageCriteria: function() {
        return this.clientMessageCriteria.val();
    },

    getServerStatusCriteria: function() {
        return this.serverStatusCriteria.val();
    },

    getServerMessageCriteria: function() {
        return this.serverMessageCriteria.val();
    },

    getInboundCriteria: function() {
        return this.inboundCriteria.val();
    },

    getOutboundCriteria: function() {
        return this.outboundCriteria.val();
    },

    show: function(listener) {
        this.listener = listener || jscape.domain.LogSearchCriteriaView.LISTENER;
    },

    _onClick$SearchButton: function() {
        if (this.fieldset.form("validate")) {
            this.searchButton.linkbutton("disable");
            this.listener.onSearch()
                    .done($.proxy(function() { this.name.textbox("clear"); }, this))
                    .always($.proxy(function() { this.searchButton.linkbutton("enable"); }, this));
        }
    }
});
jscape.domain.LogSearchCriteriaView.LISTENER = {
    onSearch: $.noop
};

/** @class */
jscape.domain.SearchCriteriaTextView = Class.extend(
    /** @lends {jscape.domain.SearchCriteriaTextView.prototype} */
{
    /** @constructor */
    initialize: function(enableBox, operatorBox, valueField) {
        this.enabled = enableBox.change($.proxy(function() {
            var enabled = this.enabled.is(":checked");
            this.operator.combobox(enabled ? "enable" : "disable");
            this.value.textbox(enabled ? "enable" : "disable").textbox(enabled ? "enableValidation" : "disableValidation");
        }, this));
        this.operator = operatorBox.combobox({editable: false, width: 120, panelHeight: "auto"});
        this.value = valueField.textbox({required: true, width: "45%"});
        this.enabled.change();
    },

    val: function(criteria) {
        if (!arguments.length) {
            return this.enabled.is(":checked")
                    ? new jscape.SearchCriteria(this.enabled.val(), this.operator.combobox("getValue"), this.value.textbox("getValue"))
                    : null;
        }
        if (criteria != null && criteria.variable == this.enabled.val(criteria)) {
            this.enabled.prop("checked", true).change();
            this.operator("setValue", criteria.operator);
            this.value.textbox("setValue", criteria.value);
        }
        return this;
    }
});

/** @class */
jscape.domain.SearchCriteriaDateView = Class.extend(
    /** @lends {jscape.domain.SearchCriteriaDateView.prototype} */
{
    /** @constructor */
    initialize: function(enableBox, startDate, endDate) {
        this.enabled = enableBox.change($.proxy(function() {
            var enabled = this.enabled.is(":checked");
            this.startDate.datebox(enabled ? "enable" : "disable").datebox(enabled ? "enableValidation" : "disableValidation");
            this.endDate.datebox(enabled ? "enable" : "disable").datebox(enabled ? "enableValidation" : "disableValidation");
        }, this));
        this.startDate = startDate.datebox({required: true, width: 120});
        this.endDate = endDate.datebox({required: true, width: 100});

        var now = new Date();
        var dateString = (now.getMonth() + 1) + "/" + now.getDate() + "/" + now.getFullYear();
        this.startDate.datebox("setValue", dateString);
        this.endDate.datebox("setValue", dateString);

        this.enabled.change();
    },

    val: function(criteria) {
        if (!arguments.length) {
            return this.enabled.is(":checked")
                    ? new jscape.SearchDateCriteria(this.enabled.val(),
                                                    this.startDate.datebox("options").parser(this.startDate.datebox("getValue")).getTime(),
                                                    this.endDate.datebox("options").parser(this.endDate.datebox("getValue")).getTime())
                    : null;
        }
        if (criteria != null && criteria.variable === this.enabled.val()) {
            this.enabled.prop("checked", true).change();
            this.startDate.datebox("setValue", criteria.startDate);
            this.endDate.datebox("setValue", criteria.endDate);
        }
        return this;
    }
});

/** @class */
jscape.domain.SearchCriteriaPortView = Class.extend(
    /** @lends {jscape.domain.SearchCriteriaPortView.prototype} */
{
    /** @constructor */
    initialize: function(enableBox, operatorBox, portField) {
        this.enabled = enableBox.change($.proxy(function() {
            var enabled = this.enabled.is(":checked");
            this.operator.combobox(enabled ? "enable" : "disable");
            this.port.numberspinner(enabled ? "enable" : "disable").numberspinner(enabled ? "enableValidation" : "disableValidation");
        }, this));
        this.operator = operatorBox.combobox({required: true, editable: false, width: 120, panelHeight: "auto"});
        this.port = portField.numberspinner({required: true, disabled: true, min: 1, max: 65535, value: 1, width: 100});
        this.enabled.change();
    },

    val: function(criteria) {
        if (!arguments.length) {
            return this.enabled.is(":checked")
                    ? new jscape.SearchCriteria(this.enabled.val(), this.operator.combobox("getValue"), parseInt(this.port.numberspinner("getValue")))
                    : null;
        }
        if (criteria != null && criteria.variable === this.enabled.val()) {
            this.enabled.prop("checked", true).change();
            this.operator.combobox("setValue", criteria.variable);
            this.port.numberspinner("setValue", parseInt(criteria.value));
        }
        return this;
    }
});

/** @class */
jscape.domain.SearchCriteriaSizeView = Class.extend(
    /** @lends {jscape.domain.SearchCriteriaSizeView.prototype} */
{
    /** @constructor */
    initialize: function(enableBox, operatorBox, sizeField, factorField) {
        this.enabled = enableBox.change($.proxy(function() {
            var enabled = this.enabled.is(":checked");
            this.operator.combobox(enabled ? "enable" : "disable");
            this.size.numberspinner(enabled ? "enable" : "disable").numberspinner(enabled ? "enableValidation" : "disableValidation");
            this.factor.combobox(enabled ? "enable" : "disable");
        }, this));
        this.operator = operatorBox.combobox({required: true, editable: false, width: 120, panelHeight: "auto"});
        this.size = sizeField.numberspinner({required: true, disabled: true, min: 1, max: 1000000, value: 1, increment:10, width: 150});
        this.factor = factorField.combobox({editable: false, width: 120, panelHeight: "auto"});
        this.enabled.change();
    },

    val: function (criteria) {
        if (!arguments.length) {
            return this.enabled.is(":checked")
                    ? new jscape.SearchCriteria(this.enabled.val(),
                                                this.operator.combobox("getValue"),
                                                parseInt(this.size.numberspinner("getValue")) * parseInt(this.factor.combobox("getValue")))
                    : null;
        }
        if (criteria != null && criteria.variable === this.enabled.val()) {
            this.enabled.prop("checked", true).change();
            this.operator.combobox("setValue", criteria.operator);
            var factors = this.factor.combobox("getData");
            var minValue = parseInt(this.size.numberspinner("options").min);
            var maxValue = parseInt(this.size.numberspinner("options").max);
            while (factors) {
                var factor = parseInt(factors.shift());
                var value = parseInt(criteria.value) / factor;
                if (minValue >= value && value <= maxValue) {
                    this.size.numberspinner("setValue", value);
                    this.factor.combobox("select", factor);
                    break;
                }
            }
        }
        return this;
    }
});

/** @class */
jscape.domain.LogSearchResultsView = jscape.ui.DatagridView.extend(
    /** @lends {jscape.domain.LogSearchResultsView.prototype} */
{
    selection: null,

    /** @constructor */
    initialize: function() {
        var initializing = true;

        this.fieldset = $("fieldset[name=searchresultsfields]");

        this.data = $("table[role=grid][aria-label=searchresults]", this.fieldset);
        this.data.datagrid({
            fit: true,
            fitColumns: true,
            ctrlSelect: true,
            remoteSort: false,
            idField: "name",
            sortName: "name",
            columns: [[
                {field: "name", title: $("thead th:nth-child(1)", this.data).text(), sortable: true, width: 150},
                {field: "date", title: $("thead th:nth-child(2)", this.data).text(), sortable: true, width: 150, align: "right", formatter: function(value) { return new Date(value).toLocaleString(); }},
                {field: "criteria", title: $("thead th:nth-child(3)", this.data).text(), sortable: false, width: 350},
                {field: "status", title: $("thead th:nth-child(4)", this.data).text(), sortable: false, width: 100, formatter: function(_, row) { return String(row.error ? row.error : row.progress + "%").escapeXml(); }, styler: function(_, row) { return row.error ? "color:red" : "color:green"; }}
            ]],
            onSelect: $.proxy(this._adjustState, this),
            onUnselect: $.proxy(this._adjustState, this),
            onDblClickRow: $.proxy(this._onClick$ViewButton, this),
            loader: $.proxy(this._onLoad$Data, this),
            onBeforeLoad: function() { return !initializing; },
            onLoadSuccess: $.proxy(this._adjustState, this)
        });

        this.refreshButton = $("a[role=button][name=reload]", this.fieldset).linkbutton({onClick: $.proxy(this._onClick$RefreshButton, this)});
        this.exportButton = $("a[role=button][name=export]", this.fieldset).linkbutton({disabled: true, onClick: $.proxy(this._onClick$ExportButton, this)});
        this.viewButton = $("a[role=button][name=view]", this.fieldset).linkbutton({disabled: true, onClick: $.proxy(this._onClick$ViewButton, this)});
        this.startButton = $("a[role=button][name=start]", this.fieldset).linkbutton({disabled: true, onClick: $.proxy(this._onClick$StartButton, this)});
        this.deleteButton = $("a[role=button][name=delete]", this.fieldset).linkbutton({disabled: true, onClick: $.proxy(this._onClick$DeleteButton, this)});

        initializing = false;
    },

    show: function(listener) {
        this.listener = listener || jscape.domain.LogSearchResultsView.LISTENER;
        this._adjustState();
    },

    getSearches: function() {
        return this.getRecords();
    },

    selectSearch: function(value) {
        this.selectRecord(value);
    },

    _onLoad$Data: function (params, success, error) {
        this.listener.onRefresh(params).done(success).fail(error);
    },

    _onClick$RefreshButton: function() {
        this.refresh();
    },

    _onClick$ExportButton: function() {
        this.exportButton.linkbutton("disable");
        this.listener.onExport(this.selection[0])
                .always($.proxy(function() { this.exportButton.linkbutton("enable"); }, this));
    },

    _onClick$ViewButton: function() {
        this.viewButton.linkbutton("disable");
        this.listener.onView(this.selection[0])
                .always($.proxy(function() { this.viewButton.linkbutton("enable"); }, this));
    },

    _onClick$StartButton: function() {
        this.listener.onRerun(this.selection[0]);
    },

    _onClick$DeleteButton: function() {
        this.listener.onDelete(this.selection);
    },

    _adjustState: function() {
        this.selection = this.data.datagrid("getSelections");
        var allSearchComplete = this._allSearchComplete(this.selection);
        this.exportButton.linkbutton(this.selection.length == 1 && allSearchComplete ? "enable" : "disable");
        this.viewButton.linkbutton(this.selection.length == 1 && allSearchComplete ? "enable" : "disable");
        this.startButton.linkbutton(this.selection.length == 1 ? "enable" : "disable");
        this.deleteButton.linkbutton(this.selection.length != 0 ? "enable" : "disable");
    },

    _allSearchComplete: function(searches) {
        return $.grep(searches, function(search) { return search.completed(); }).length == searches.length;
    }
});
jscape.domain.LogSearchResultsView.LISTENER = {
    onRefresh: $.noop,
    onExport: $.noop,
    onView: $.noop,
    onRerun: $.noop,
    onDelete: $.noop
};

/** @class */
jscape.domain.LogSearchResultController = Class.extend(
    /** @lends {jscape.domain.LogSearchResultController.prototype} */
{
    MAX_RECORDS: 50,

    deferred: null,

    /** @constructor */
    initialize: function() {
        this.exportController = new jscape.domain.ExportLogSearchController();
    },

    start: function(managementService, domainName, search) {
        this.managementService = managementService;
        this.domainName = domainName;
        this.searchName = search.name;
        this.deferred = $.Deferred();

        var maxRecords = search.maxRecords;
        var truncated = false;
        if (search.maxRecords > this.MAX_RECORDS) {
            maxRecords = this.MAX_RECORDS;
            truncated = true;
        }
        this.managementService.getLogSearchResult(this.domainName, search.name, maxRecords)
                .done($.proxy(function(data) { this._setupDialog(data, truncated, maxRecords).show(this); }, this))
                .fail($.proxy(function() { this.deferred.reject(); this.deferred = null; }, this));

        return this.deferred.promise();
    },

    onExport: function() {
        this.exportController.start(this.managementService, this.domainName, this.searchName);
    },

    onClose: function(dialog) {
        dialog.destroy();
        this.deferred.resolve();
        this.deferred = null;
    },

    _setupDialog: function(data, truncated, recordsCount) {
        var dialog = new jscape.domain.LogSearchResultDialog();
        dialog.setData(data, truncated);
        dialog.setRecordsCount(recordsCount);
        return dialog;
    }
});

/** @class */
jscape.domain.LogSearchResultDialog = Class.extend(
    /** @lends {jscape.domain.LogSearchResultDialog.prototype} */
{
    /** @constructor */
    initialize: function() {
        this.dialog = $("#d-logging-view").clone().attr("id", "");
        this.dialog.dialog({
            width: 800, height: "auto",
            modal: true, resizable: true, closable: true, closed: true,
            buttons: [
                {text: window.R.string.DIALOG_BUTTON_CLOSE || "Cancel", handler: $.proxy(this._onCancel, this)}
            ],
            onClose: $.proxy(function () {if (!this.closing) { this._onCancel(); }}, this)
        }).show();

        this.fieldset = $("fieldset[name=logviewfields]", this.dialog);

        this.text = $("textarea[name=result]", this.fieldset).prop("readonly", true).css({width: "52em", height: "28em"});
        this.truncatedInfo = $("div[aria-label=search-results-truncated]", this.fieldset);

        this.exportButton = $("a[role=button][name=export]", this.fieldset).linkbutton({disabled: true, onClick: $.proxy(this._onClick$ExportButton, this)});
    },

    setData: function(value, truncated) {
        this.text.val(value);
        this.exportButton.linkbutton(value && value.trim().length != 0 ? "enable" : "disable");

        if (truncated) {
            this.truncatedInfo.show();
        } else {
            this.truncatedInfo.hide();
        }
    },

    setRecordsCount: function(value) {
        this.truncatedInfo.text(this.truncatedInfo.text().supplant({0: value || ""}));
    },

    show: function (listener) {
        this.listener = listener || jscape.domain.LogSearchResultDialog.LISTENER;
        this.dialog.dialog("center").dialog("open");
    },

    hide: function () {
        if (!this._closed()) {
            this.closing = true;
            this.dialog.dialog("close");
            this.closing = false;
        }
    },

    destroy: function() {
        this.dialog.dialog("destroy");
    },

    _onClick$ExportButton: function() {
        this.listener.onExport(this);
    },

    _onCancel: function () {
        this.hide();
        this.listener.onClose(this);
    },

    _closed: function () {
        return !!this.dialog.dialog("options").closed;
    }
});
jscape.domain.LogSearchResultDialog.LISTENER = {
    onExport: $.noop,
    onClose: $.noop
};

/** @class */
jscape.domain.ExportLogSearchController = Class.extend(
    /** @lends {jscape.domain.ExportLogSearchController.prototype} */
{
    deferred: null,

    start: function(managementService, domainName, searchName) {
        this.managementService = managementService;
        this.domainName = domainName;
        this.searchName = searchName;
        this.deferred = $.Deferred();
        this._setupDialog().show(this);
        return this.deferred.promise();
    },

    onSubmit: function(dialog) {
        var filename = dialog.getFilename();
        dialog.destroy();
        this.managementService.exportLogSearchResult(this.domainName, this.searchName, filename)
                .done($.proxy(function() { this.deferred.resolve(filename); this.deferred = null; }, this))
                .fail($.proxy(function() { this.deferred.reject(); this.deferred = null; }, this));
    },

    onCancel: function(dialog) {
        dialog.destroy();
        this.deferred.reject();
        this.deferred = null;
    },

    _setupDialog: function() {
        return new jscape.domain.ExportLogSearchView();
    }
});

/** @class */
jscape.domain.ExportLogSearchView = Class.extend(
    /** @lends {jscape.domain.ExportLogSearchView.prototype} */
{
    /** @constructor */
    initialize: function() {
        this.dialog = $("#d-logging-export").clone().attr("id", "");
        this.dialog.dialog({
            width: 530, height: "auto",
            modal: true, resizable: false, closable: true, closed: true,
            buttons: [
                {text: window.R.string.DIALOG_BUTTON_OK || "Ok", handler: $.proxy(this._onSubmit, this)},
                {text: window.R.string.DIALOG_BUTTON_CANCEL || "Cancel", handler: $.proxy(this._onCancel, this)}
            ],
            onClose: $.proxy(function () {if (!this.closing) { this._onCancel(); }}, this)
        }).show();

        this.fieldset = $("fieldset[name=logexportfields]", this.dialog);
        this.filename = $("input[name=filename]", this.fieldset);
        this.filename.validatebox({required: true});
    },

    getFilename: function() {
        return this.filename.val();
    },

    show: function (listener) {
        this.listener = listener;
        this.dialog.dialog("center").dialog("open");
        this.fieldset.form("validate");
        this.filename.focus();
    },

    hide: function () {
        if (!this._closed()) {
            this.closing = true;
            this.dialog.dialog("close");
            this.fieldset.form("disableValidation");
            this.closing = false;
        }
    },

    destroy: function() {
        this.dialog.dialog("destroy");
    },

    _onSubmit: function () {
        if (this.fieldset.form("validate")) {
            this.hide();
            this.listener.onSubmit(this);
        }
    },

    _onCancel: function () {
        this.hide();
        this.listener.onCancel(this);
    },

    _closed: function () {
        return !!this.dialog.dialog("options").closed;
    }
});

/** @class */
jscape.domain.DeleteLogSearchController = Class.extend(
    /** @lends {jscape.domain.DeleteLogSearchController.prototype} */
{
    deferred: null,

    start: function(managementService, domainName, searches) {
        this.managementService = managementService;
        this.domainName = domainName;
        this.deferred = $.Deferred();
        this._confirmDelete(searches)
                .done($.proxy(this._deleteConfirmed, this, searches))
                .fail($.proxy(function() { this.deferred.reject(); this.deferred = null; }, this));
        return this.deferred.promise();
    },

    _deleteConfirmed: function (searches) {
        $.when.apply(jQuery, $.map(searches, $.proxy(function(search) { return this.managementService.deleteLogSearch(this.domainName, search.name); }, this)))
                .done($.proxy(function () { this.deferred.resolve(searches); this.deferred = null; }, this))
                .fail($.proxy(function() { this.deferred.reject(); this.deferred = null; }, this));
    },

    _confirmDelete: function(searches) {
        var text = $.map(searches, function(search) { return search.name; }).join(", ");
        return jscape.ConfirmDialog.confirm(window.R.string.LOGGING_CONFIRM_DELETE_TITLE,
                                            window.R.string.LOGGING_CONFIRM_DELETE_MESSAGE.supplant({0: text}));
    }
});