/**
 * @fileoverview Add-on for binding to remote data
 * @author NHN Ent. FE Development Lab
 */

'use strict';

var $ = require('jquery');
var Backbone = require('backbone');
var _ = require('underscore');

var View = require('../base/view');
var Router = require('./net-router');
var util = require('../common/util');
var formUtil = require('../common/formUtil');
var i18n = require('../common/i18n');
var GridEvent = require('../event/gridEvent');

var renderStateMap = require('../common/constMap').renderState;
var DELAY_FOR_LOADING_STATE = 200;

var requestMessageMap = {
    createData: 'net.confirmCreate',
    updateData: 'net.confirmUpdate',
    deleteData: 'net.confirmDelete',
    modifyData: 'net.confirmModify'
};
var errorMessageMap = {
    createData: 'net.noDataToCreate',
    updateData: 'net.noDataToUpdate',
    deleteData: 'net.noDataToDelete',
    modifyData: 'net.noDataToModify'
};

/**
 * Add-on for binding to remote data
 * @module addon/net
 * @param {object} options
 *      @param {jquery} [options.el] - Form element (to be used for ajax request)
 *      @param {boolean} [options.initialRequest=true] - Whether to request 'readData' after initialized
 *      @param {string} [options.readDataMethod='POST'] - Http method to be used for 'readData' API ('POST' or 'GET')
 *      @param {object} [options.api] - URL map
 *          @param {string} [options.api.readData] - URL for read-data
 *          @param {string} [options.api.createData] - URL for create
 *          @param {string} [options.api.updateData] - URL for update
 *          @param {string} [options.api.modifyData] - URL for modify (create/update/delete at once)
 *          @param {string} [options.api.deleteData] - URL for delete
 *          @param {string} [options.api.downloadExcel] - URL for download data of this page as an excel-file
 *          @param {string} [options.api.downloadExcelAll] - URL for download all data as an excel-file
 *      @param {number} [options.perPage=500] - The number of items to be shown in a page
 *      @param {boolean} [options.enableAjaxHistory=true] - Whether to use the browser history for the ajax requests
 * @example
 *   <form id="data_form">
 *   <input type="text" name="query"/>
 *   </form>
 *   <script>
 *      var net;
 *      var grid = new tui.Grid({
 *          //...options...
 *      });
 *
 *      // Activate 'Net' addon
 *      grid.use('Net', {
 *         el: $('#data_form'),
 *         initialRequest: true,
 *         readDataMethod: 'GET',
 *         perPage: 500,
 *         enableAjaxHistory: true,
 *         api: {
 *             'readData': './api/read',
 *             'createData': './api/create',
 *             'updateData': './api/update',
 *             'deleteData': './api/delete',
 *             'modifyData': './api/modify',
 *             'downloadExcel': './api/download/excel',
 *             'downloadExcelAll': './api/download/excelAll'
 *         }
 *      });
 *
 *      // Bind event handlers
 *      grid.on('beforeRequest', function(data) {
 *          // For all requests
 *      }).on('response', function(data) {
 *          // For all response (regardless of success or failure)
 *      }).on('successResponse', function(data) {
 *          // Only if response.result is true
 *      }).on('failResponse', function(data) {
 *          // Only if response.result is false
 *      }).on('errorResponse', function(data) {
 *          // For error response
 *      });
 *
 *      net = grid.getAddOn('Net');
 *
 *      // Request create
 *      net.request('createData');
 *
 *      // Request update
 *      net.request('updateData');
 *
 *      // Request delete
 *      net.request('deleteData');
 *
 *      // Request create/update/delete at once
 *      net.request('modifyData');
 *   </script>
 */
var Net = View.extend(/** @lends module:addon/net.prototype */{
    initialize: function(options) {
        var defaultOptions = {
            initialRequest: true,
            perPage: 500,
            enableAjaxHistory: true
        };
        var defaultApi = {
            readData: '',
            createData: '',
            updateData: '',
            deleteData: '',
            modifyData: '',
            downloadExcel: '',
            downloadExcelAll: ''
        };

        options = _.assign(defaultOptions, options);
        options.api = _.assign(defaultApi, options.api);

        _.assign(this, {
            // models
            dataModel: options.dataModel,
            renderModel: options.renderModel,

            // extra objects
            router: null,
            domEventBus: options.domEventBus,
            pagination: options.pagination,

            // configs
            api: options.api,
            enableAjaxHistory: options.enableAjaxHistory,
            readDataMethod: options.readDataMethod || 'POST',
            perPage: options.perPage,

            // state data
            curPage: 1,
            timeoutIdForDelay: null,
            requestedFormData: null,
            isLocked: false,
            lastRequestedReadData: null
        });

        this._initializeDataModelNetwork();
        this._initializeRouter();
        this._initializePagination();

        this.listenTo(this.dataModel, 'sortChanged', this._onSortChanged);
        this.listenTo(this.domEventBus, 'click:excel', this._onClickExcel);

        if (options.initialRequest) {
            if (!this.lastRequestedReadData) {
                this._readDataAt(1, false);
            }
        }
    },

    tagName: 'form',

    events: {
        submit: '_onSubmit'
    },

    /**
     * pagination instance 를 초기화 한다.
     * @private
     */
    _initializePagination: function() {
        var pagination = this.pagination;

        if (pagination) {
            pagination.setItemsPerPage(this.perPage);
            pagination.setTotalItems(1);
            pagination.on('beforeMove', $.proxy(this._onPageBeforeMove, this));
        }
    },

    /**
     * Event listener for 'route:read' event on Router
     * @param  {String} queryStr - Query string
     * @private
     */
    _onRouterRead: function(queryStr) {
        var data = util.toQueryObject(queryStr);
        this._requestReadData(data);
    },

    /**
     * Event listener for 'click:excel' event on domEventBus
     * @param {module:event/gridEvent} gridEvent - GridEvent
     * @private
     */
    _onClickExcel: function(gridEvent) {
        var downloadType = (gridEvent.type === 'all') ? 'excelAll' : 'excel';
        this.download(downloadType);
    },

    /**
     * dataModel 이 network 통신을 할 수 있도록 설정한다.
     * @private
     */
    _initializeDataModelNetwork: function() {
        this.dataModel.url = this.api.readData;
        this.dataModel.sync = $.proxy(this._sync, this);
    },

    /**
     * ajax history 를 사용하기 위한 router 를 초기화한다.
     * @private
     */
    _initializeRouter: function() {
        if (this.enableAjaxHistory) {
            this.router = new Router({
                net: this
            });
            this.listenTo(this.router, 'route:read', this._onRouterRead);

            if (!Backbone.History.started) {
                Backbone.history.start();
            }
        }
    },

    /**
     * pagination 에서 before page move가 발생했을 때 이벤트 핸들러
     * @param {{page:number}} customEvent pagination 으로부터 전달받는 이벤트 객체
     * @private
     */
    _onPageBeforeMove: function(customEvent) {
        var page = customEvent.page;
        if (this.curPage !== page) {
            this._readDataAt(page, true);
        }
    },

    /**
     * form 의 submit 이벤트 발생시 이벤트 핸들러
     * @param {event} submitEvent   submit 이벤트 객체
     * @private
     */
    _onSubmit: function(submitEvent) {
        submitEvent.preventDefault();
        this._readDataAt(1, false);
    },

    /**
     * 폼 데이터를 설정한다.
     * @param {Object} data - 폼 데이터 정보
     * @private
     */
    _setFormData: function(data) {
        var formData = _.clone(data);

        _.each(this.lastRequestedReadData, function(value, key) {
            if ((_.isUndefined(formData[key]) || _.isNull(formData[key])) && value) {
                formData[key] = '';
            }
        });
        formUtil.setFormData(this.$el, formData);
    },

    /**
     * fetch 수행 이후 custom ajax 동작 처리를 위해 Backbone 의 기본 sync 를 오버라이드 하기위한 메서드.
     * @param {String} method   router 로부터 전달받은 method 명
     * @param {Object} model    fetch 를 수행한 dataModel
     * @param {Object} options  request 정보
     * @private
     */
    _sync: function(method, model, options) {
        var params;
        if (method === 'read') {
            options = options || {};
            params = $.extend({}, options);
            if (!options.url) {
                params.url = _.result(model, 'url');
            }
            this._ajax(params);
        } else {
            Backbone.sync(Backbone, method, model, options);
        }
    },

    /**
     * network 통신에 대한 _lock 을 건다.
     * @private
     */
    _lock: function() {
        var renderModel = this.renderModel;

        this.timeoutIdForDelay = setTimeout(function() {
            renderModel.set('state', renderStateMap.LOADING);
        }, DELAY_FOR_LOADING_STATE);

        this.isLocked = true;
    },

    /**
     * network 통신에 대해 unlock 한다.
     * loading layer hide 는 rendering 하는 로직에서 수행한다.
     * @private
     */
    _unlock: function() {
        if (this.timeoutIdForDelay !== null) {
            clearTimeout(this.timeoutIdForDelay);
            this.timeoutIdForDelay = null;
        }

        this.isLocked = false;
    },

    /**
     * form 으로 지정된 엘리먼트의 Data 를 반환한다.
     * @returns {object} formData 데이터 오브젝트
     * @private
     */
    _getFormData: function() {
        return formUtil.getFormData(this.$el);
    },

    /**
     * DataModel 에서 Backbone.fetch 수행 이후 success 콜백
     * @param {object} dataModel grid 의 dataModel
     * @param {object} responseData 응답 데이터
     * @private
     */
    _onReadSuccess: function(dataModel, responseData) {
        var pagination = this.pagination;
        var page, totalCount;

        dataModel.setOriginalRowList();

        if (pagination && responseData.pagination) {
            page = responseData.pagination.page;
            totalCount = responseData.pagination.totalCount;

            pagination.setItemsPerPage(this.perPage);
            pagination.setTotalItems(totalCount);
            pagination.movePageTo(page);
            this.curPage = page;
        }
    },

    /**
     * DataModel 에서 Backbone.fetch 수행 이후 error 콜백
     * @param {object} dataModel grid 의 dataModel
     * @param {object} responseData 응답 데이터
     * @param {object} options  ajax 요청 정보
     * @private
     */
    _onReadError: function(dataModel, responseData, options) {}, // eslint-disable-line

    /**
     * Requests 'readData' with last requested data.
     */
    reloadData: function() {
        this._requestReadData(this.lastRequestedReadData);
    },

    /**
     * Requests 'readData' to the server. The last requested data will be extended with new data.
     * @param {Number} page - Page number
     * @param {Object} data - Data(parameters) to send to the server
     * @param {Boolean} resetData - If set to true, last requested data will be ignored.
     */
    readData: function(page, data, resetData) {
        if (resetData) {
            if (!data) {
                data = {};
            }
            data.perPage = this.perPage;
            this._changeSortOptions(data, this.dataModel.sortOptions);
        } else {
            data = _.assign({}, this.lastRequestedReadData, data);
        }
        data.page = page;
        this._requestReadData(data);
    },

    /**
     * 데이터 조회 요청.
     * @param {object} data 요청시 사용할 request 파라미터
     * @private
     */
    _requestReadData: function(data) {
        var startNumber = 1;

        this._setFormData(data);

        if (!this.isLocked) {
            this.renderModel.initializeVariables();
            this._lock();

            this.requestedFormData = _.clone(data);
            this.curPage = data.page || this.curPage;
            startNumber = ((this.curPage - 1) * this.perPage) + 1;
            this.renderModel.set({
                startNumber: startNumber
            });

            // 마지막 요청한 reloadData에서 사용하기 위해 data 를 저장함.
            this.lastRequestedReadData = _.clone(data);
            this.dataModel.fetch({
                requestType: 'readData',
                data: data,
                type: this.readDataMethod,
                success: $.proxy(this._onReadSuccess, this),
                error: $.proxy(this._onReadError, this),
                reset: true
            });
            this.dataModel.setSortOptionValues(data.sortColumn, data.sortAscending);
        }

        if (this.router) {
            this.router.navigate('read/' + util.toQueryString(data), {
                trigger: false
            });
        }
    },

    /**
     * sortChanged 이벤트 발생시 실행되는 함수
     * @private
     * @param {object} sortOptions 정렬 옵션
     * @param {string} sortOptions.sortColumn 정렬할 컬럼명
     * @param {boolean} sortOptions.ascending 오름차순 여부
     */
    _onSortChanged: function(sortOptions) {
        if (sortOptions.requireFetch) {
            this._readDataAt(1, true, sortOptions);
        }
    },

    /**
     * 데이터 객체의 정렬 옵션 관련 값을 변경한다.
     * @private
     * @param {object} data 데이터 객체
     * @param {object} sortOptions 정렬 옵션
     * @param {string} sortOptions.sortColumn 정렬할 컬럼명
     * @param {boolean} sortOptions.ascending 오름차순 여부
     */
    _changeSortOptions: function(data, sortOptions) {
        if (!sortOptions) {
            return;
        }
        if (sortOptions.columnName === 'rowKey') {
            delete data.sortColumn;
            delete data.sortAscending;
        } else {
            data.sortColumn = sortOptions.columnName;
            data.sortAscending = sortOptions.ascending;
        }
    },

    /**
     * 현재 form data 기준으로, page 에 해당하는 데이터를 조회 한다.
     * @param {Number} page 조회할 페이지 정보
     * @param {Boolean} [isUsingRequestedData=true] page 단위 검색이므로, form 수정여부와 관계없이 처음 보낸 form 데이터로 조회할지 여부를 결정한다.
     * @param {object} sortOptions 정렬 옵션
     * @param {string} sortOptions.sortColumn 정렬할 컬럼명
     * @param {boolean} sortOptions.ascending 오름차순 여부
     * @private
     */
    _readDataAt: function(page, isUsingRequestedData, sortOptions) {
        var data;

        isUsingRequestedData = _.isUndefined(isUsingRequestedData) ? true : isUsingRequestedData;
        data = isUsingRequestedData ? this.requestedFormData : this._getFormData();
        data.page = page;
        data.perPage = this.perPage;
        this._changeSortOptions(data, sortOptions);
        this._requestReadData(data);
    },

    /**
     * Send request to server to sync data
     * @param {String} requestType - 'createData|updateData|deleteData|modifyData'
     * @param {object} options - Options
     *      @param {String} [options.url] - URL to send the request
     *      @param {String} [options.hasDataParam=true] - Whether the row-data to be included in the request param
     *      @param {String} [options.checkedOnly=true] - Whether the request param only contains checked rows
     *      @param {String} [options.modifiedOnly=true] - Whether the request param only contains modified rows
     *      @param {String} [options.showConfirm=true] - Whether to show confirm dialog before sending request
     *      @param {String} [options.updateOriginal=false] - Whether to update original data with current data
     * @returns {boolean} Whether requests or not
     */
    request: function(requestType, options) {
        var newOptions = _.extend({
            url: this.api[requestType],
            type: null,
            hasDataParam: true,
            checkedOnly: true,
            modifiedOnly: true,
            showConfirm: true,
            updateOriginal: false
        }, options);
        var param = this._getRequestParam(requestType, newOptions);

        if (param) {
            if (newOptions.updateOriginal) {
                this.dataModel.setOriginalRowList();
            }
            this._ajax(param);
        }

        return !!param;
    },

    /**
     * Change window.location to registered url for downloading data
     * @param {string} type - Download type. 'excel' or 'excelAll'.
     *        Will be matched with API 'downloadExcel', 'downloadExcelAll'.
     */
    download: function(type) {
        var apiName = 'download' + util.toUpperCaseFirstLetter(type),
            data = this.requestedFormData,
            url = this.api[apiName],
            paramStr;

        if (type === 'excel') {
            data.page = this.curPage;
            data.perPage = this.perPage;
        } else {
            data = _.omit(data, 'page', 'perPage');
        }

        paramStr = $.param(data);
        window.location = url + '?' + paramStr;
    },

    /**
     * Set number of rows per page and reload current page
     * @param {number} perPage - Number of rows per page
     */
    setPerPage: function(perPage) {
        this.perPage = perPage;
        this._readDataAt(1);
    },

    /**
     * 서버로 요청시 사용될 파라미터 중 Grid 의 데이터에 해당하는 데이터를 Option 에 맞추어 반환한다.
     * @param {String} requestType  요청 타입. 'createData|updateData|deleteData|modifyData' 중 하나를 인자로 넘긴다.
     * @param {Object} [options] Options
     *      @param {boolean} [options.hasDataParam=true] request 데이터에 rows 관련 데이터가 포함될 지 여부.
     *      @param {boolean} [options.modifiedOnly=true] rows 관련 데이터 중 수정된 데이터만 포함할 지 여부
     *      @param {boolean} [options.checkedOnly=true] rows 관련 데이터 중 checked 된 데이터만 포함할 지 여부
     * @returns {{count: number, data: {requestType: string, url: string, rows: object,
     *      type: string, dataType: string}}} 옵션 조건에 해당하는 그리드 데이터 정보
     * @private
     */
    _getDataParam: function(requestType, options) {
        var dataModel = this.dataModel,
            checkMap = {
                createData: ['createdRows'],
                updateData: ['updatedRows'],
                deleteData: ['deletedRows'],
                modifyData: ['createdRows', 'updatedRows', 'deletedRows']
            },
            checkList = checkMap[requestType],
            data = {},
            count = 0,
            dataMap;

        options = _.defaults(options || {}, {
            hasDataParam: true,
            modifiedOnly: true,
            checkedOnly: true
        });

        if (options.hasDataParam) {
            if (options.modifiedOnly) {
                // {createdRows: [], updatedRows:[], deletedRows: []} 에 담는다.
                dataMap = dataModel.getModifiedRows({
                    checkedOnly: options.checkedOnly
                });
                _.each(dataMap, function(list, name) {
                    if (_.contains(checkList, name) && list.length) {
                        count += list.length;
                        data[name] = JSON.stringify(list);
                    }
                }, this);
            } else {
                // {rows: []} 에 담는다.
                data.rows = dataModel.getRows(options.checkedOnly);
                count = data.rows.length;
            }
        }

        return {
            data: data,
            count: count
        };
    },

    /**
     * requestType 에 따라 서버에 요청할 파라미터를 반환한다.
     * @param {String} requestType 요청 타입. 'createData|updateData|deleteData|modifyData' 중 하나를 인자로 넘긴다.
     * @param {Object} [options] Options
     *      @param {String} [options.url=this.api[requestType]] 요청할 url.
     *      지정하지 않을 시 option 으로 넘긴 API 중 request Type 에 해당하는 url 로 지정됨
     *      @param {String} [options.type='POST'] request method 타입
     *      @param {boolean} [options.hasDataParam=true] request 데이터에 rowList 관련 데이터가 포함될 지 여부.
     *      @param {boolean} [options.modifiedOnly=true] rowList 관련 데이터 중 수정된 데이터만 포함할 지 여부
     *      @param {boolean} [options.checkedOnly=true] rowList 관련 데이터 중 checked 된 데이터만 포함할 지 여부
     * @returns {{requestType: string, url: string, data: object, type: string, dataType: string}}
     *      ajax 호출시 사용될 option 파라미터
     * @private
     */
    _getRequestParam: function(requestType, options) {
        var defaultOptions = {
            url: this.api[requestType],
            type: null,
            hasDataParam: true,
            modifiedOnly: true,
            checkedOnly: true
        };
        var newOptions = $.extend(defaultOptions, options);
        var dataParam = this._getDataParam(requestType, newOptions);
        var param = null;

        if (!newOptions.showConfirm || this._isConfirmed(requestType, dataParam.count)) {
            param = {
                requestType: requestType,
                url: newOptions.url,
                data: dataParam.data,
                type: newOptions.type
            };
        }

        return param;
    },

    /**
     * requestType 에 따른 컨펌 메세지를 노출한다.
     * @param {String} requestType 요청 타입. 'createData|updateData|deleteData|modifyData' 중 하나를 인자로 넘긴다.
     * @param {Number} count   전송될 데이터 개수
     * @returns {boolean}    계속 진행할지 여부를 반환한다.
     * @private
     */
    _isConfirmed: function(requestType, count) {
        var result = false;

        if (count > 0) {
            result = confirm(this._getConfirmMessage(requestType, count));
        } else {
            alert(this._getConfirmMessage(requestType, count));
        }

        return result;
    },

    /**
     * confirm message 를 반환한다.
     * @param {String} requestType 요청 타입. 'createData|updateData|deleteData|modifyData' 중 하나를 인자로 넘긴다.
     * @param {Number} count 전송될 데이터 개수
     * @returns {string} 생성된 confirm 메세지
     * @private
     */
    _getConfirmMessage: function(requestType, count) {
        var messageKey = (count > 0) ? requestMessageMap[requestType] : errorMessageMap[requestType];
        var replacedValues = {
            count: count
        };

        return i18n.get(messageKey, replacedValues);
    },

    /**
     * ajax 통신을 한다.
     * @param {{requestType: string, url: string, data: object, type: string, dataType: string}} options ajax 요청 파라미터
     * @private
     */
    _ajax: function(options) {
        var gridEvent = new GridEvent(null, options.data);
        var params;

        /**
         * Occurs before the http request is sent
         * @event Grid#beforeRequest
         * @type {module:event/gridEvent}
         * @property {Grid} instance - Current grid instance
         */
        this.trigger('beforeRequest', gridEvent);
        if (gridEvent.isStopped()) {
            return;
        }

        options = $.extend({requestType: ''}, options);
        params = {
            url: options.url,
            data: options.data || {},
            type: options.type || 'POST',
            dataType: options.dataType || 'json',
            complete: $.proxy(this._onComplete, this, options.complete, options),
            success: $.proxy(this._onSuccess, this, options.success, options),
            error: $.proxy(this._onError, this, options.error, options)
        };
        if (options.url) {
            $.ajax(params);
        }
    },

    /**
     * ajax complete 이벤트 핸들러
     * @param {Function} callback   통신 완료 이후 수행할 콜백함수
     * @param {object} jqXHR    jqueryXHR  객체
     * @param {number} status   http status 정보
     * @private
     */
    _onComplete: function(callback, jqXHR, status) { // eslint-disable-line no-unused-vars
        this._unlock();
    },

    /* eslint-disable complexity */
    /**
     * ajax success 이벤트 핸들러
     * @param {Function} callback Callback function
     * @param {{requestType: string, url: string, data: object, type: string, dataType: string}} options ajax 요청 파라미터
     * @param {Object} responseData 응답 데이터
     * @param {number} status   http status 정보
     * @param {object} jqXHR    jqueryXHR  객체
     * @private
     */
    _onSuccess: function(callback, options, responseData, status, jqXHR) {
        var responseMessage = responseData && responseData.message;
        var gridEvent = new GridEvent(null, {
            httpStatus: status,
            requestType: options.requestType,
            requestParameter: options.data,
            responseData: responseData
        });

        /**
         * Occurs when the response is received from the server
         * @event Grid#reponse
         * @type {module:event/gridEvent}
         * @property {number} httpStatus - HTTP status
         * @property {string} requestType - Request type
         * @property {string} requestParameter - Request parameters
         * @property {Object} responseData - response data
         * @property {Grid} instance - Current grid instance
         */
        this.trigger('response', gridEvent);
        if (gridEvent.isStopped()) {
            return;
        }
        if (responseData && responseData.result) {
            /**
             * Occurs after the response event, if the result is true
             * @event Grid#successReponse
             * @type {module:event/gridEvent}
             * @property {number} httpStatus - HTTP status
             * @property {string} requestType - Request type
             * @property {string} requestParameter - Request parameter
             * @property {Object} responseData - response data
             * @property {Grid} instance - Current grid instance
             */
            this.trigger('successResponse', gridEvent);
            if (gridEvent.isStopped()) {
                return;
            }
            if (_.isFunction(callback)) {
                callback(responseData.data || {}, status, jqXHR);
            }
        } else {
            /**
             * Occurs after the response event, if the result is false
             * @event Grid#failResponse
             * @type {module:event/gridEvent}
             * @property {number} httpStatus - HTTP status
             * @property {string} requestType - Request type
             * @property {string} requestParameter - Request parameter
             * @property {Object} responseData - response data
             * @property {Grid} instance - Current grid instance
             */
            this.trigger('failResponse', gridEvent);
            if (gridEvent.isStopped()) {
                return;
            }
            if (responseMessage) {
                alert(responseMessage);
            }
        }
    },
    /* eslint-enable complexity */

    /**
     * ajax error 이벤트 핸들러
     * @param {Function} callback Callback function
     * @param {{requestType: string, url: string, data: object, type: string, dataType: string}} options ajax 요청 파라미터
     * @param {object} jqXHR    jqueryXHR  객체
     * @param {number} status   http status 정보
     * @param {String} errorMessage 에러 메세지
     * @private
     */
    _onError: function(callback, options, jqXHR, status) {
        var eventData = new GridEvent(null, {
            httpStatus: status,
            requestType: options.requestType,
            requestParameter: options.data,
            responseData: null
        });
        this.renderModel.set('state', renderStateMap.DONE);

        this.trigger('response', eventData);
        if (eventData.isStopped()) {
            return;
        }

        /**
         * Occurs after the response event, if the response is Error
         * @event Grid#errorResponse
         * @type {module:event/gridEvent}
         * @property {number} httpStatus - HTTP status
         * @property {string} requestType - Request type
         * @property {string} requestParameter - Request parameters
         * @property {Grid} instance - Current grid instance
         */
        this.trigger('errorResponse', eventData);
        if (eventData.isStopped()) {
            return;
        }

        if (jqXHR.readyState > 1) {
            alert(i18n.get('net.failResponse'));
        }
    }
});

module.exports = Net;