﻿//Intercept Xval rules Information
var jValidatePlugin = xVal.Plugins;
xVal.Plugins = {};
xVal.Plugins["MDD_Custom"] = {
    AttachValidator: function (elementPrefix, rulesConfig, options) {
        if (window.eval(elementPrefix + "Grid") !== undefined) {
            window.eval(elementPrefix + "Grid").SetGridValidationRules(rulesConfig);
        }
        jValidatePlugin["jquery.validate"].AttachValidator(elementPrefix, rulesConfig, options);
    }
};

(function ($) {

    // Mdd.SlickGrid
    $.extend(true, window, {
        Mdd: {
            SlickGrid: {
                Grid: MddSlickGrid
            }
        }
    });
    
    //////////////////////////////////////////////////////////////////
    // Mdd SlickGrid class implementation (available as Mdd.SlickGrid)

    /**
    * @constructor
    * @param {Object}            gridInfo  Grid definition and configuration information.
    * @param {Array,Object}      gridData  An array of objects for databinding.
    **/
    function MddSlickGrid(gridInfo, gridData) {

        //private variables
        //
        var grid;
        var gridDataView = new Slick.Data.DataView();
        var selectedRowIds = [];
        var searchString = "";
        var filterColumns = [];
        var columnsMetaData = [];
        
        //variables shared across all Mdd SlickGrids
            var checkboxSelector = new Slick.CheckboxSelectColumn({
                cssClass: "slick-cell-checkboxsel"
            });
        
        function init() {
            try {
                RuntimeSettings(gridInfo);
            } catch (e) {
                //let the seeting be off which are not implemented
            }
            _UpdateColumnFormatter(gridInfo);
            //_UpdateColumnValidator(gridInfo);

            //gridInfo.Options.editable = true;
            //prepare edit column
            if (gridInfo.EnableRowSelectionColumn) {
                gridInfo.Columns = _AddEditColumn(gridInfo.Columns);
            }            
            //Create Grid
            grid = new Slick.Grid($("#" + gridInfo.GridElement), gridDataView, gridInfo.Columns, gridInfo.Options);
            grid.setSelectionModel(new Slick.RowSelectionModel({ selectActiveRow: false }));
            
            if (gridInfo.EnableRowSelectionColumn) {
                grid.registerPlugin(checkboxSelector);
            }
            

            //prepare filter panel
            _PrepareFilterPanel(gridInfo);

            var pager = new Slick.Controls.Pager(gridDataView, grid, $("#" + gridInfo.PagerElement));
            var columnpicker = new Slick.Controls.ColumnPicker(gridInfo.Columns, grid, gridInfo.Options);

            this.grid = grid;
            this.gridInfo = gridInfo;
            this.gridDataView = gridDataView;
            this.saveCallBack = {};
            this.deleteCallBack = {};
            this.cellChangeCallback = {};
            this.beforeCellChangeCallBack = {};

            //Filter based upon the Column MetaData
            var getRowFilterDelegate = function (filterColumns) {
                return function _RowFilter(item) {

//                    for (f in this.filterColumns) {

//                    }
//                    if (this.searchString != "" && undefined != event.srcElement && item[this.event.srcElement.name].toLowerCase().indexOf(this.searchString) == -1) {
//                        return false;
//                    }
                    return true;
                };
            };

            //set row Filter
            gridDataView.setFilter(getRowFilterDelegate(filterColumns));

            var getOnCellChangeDelegate = function (grid, gridInfo) {
                return function (e, args) {
                    try {
                        var field = gridInfo.Columns[args.cell].id;
                        RuntimeCellChange(gridInfo, field, args);
                    } catch (ex) {
                        //Pass the change to be overridden
                    }
                    grid.updateRow(args.row);
                    e.stopPropagation();
                };
            };

            grid.onCellChange.subscribe(getOnCellChangeDelegate(grid, gridInfo));

            //grid.onAddNewRow = AddItem;
            // wire up model events to drive the grid
            //    gridDataView.onRowCountChanged.subscribe(function (e, args) {
            //        grid.updateRowCount();
            //        grid.render();
            //    });

            //adding the new rows in the grid
            grid.onAddNewRow.subscribe(function (e, args) {
                grid.invalidateRow(gridDataView.rows.length);
                gridInfo.rowLength = gridInfo.rowLength + 1;
                args.item.id = gridInfo.rowLength;
                for (var i = 0; i < gridInfo.Columns.length; i++) {
                    var column = gridInfo.Columns[i];
                    if (column.columndatatype === "AutoIncrement") {
                        args.item[column.id] = gridInfo.rowLength;
                    }
                }   
                // try calling Runtime call Change
               try {
                    var currentCell = grid.getActiveCell();
                    var cellArgs = [];
                    cellArgs.item = args.item;
                    cellArgs.cell = currentCell.cell;
                    cellArgs.row = currentCell.row;
                    RuntimeCellChange(gridInfo, args.column.id, cellArgs);
                } catch (ex) {
                    //Pass the change to be overridden
                }
                gridDataView.addItem(args.item);
                grid.updateRowCount();
                grid.render();
            });

            gridDataView.onRowsChanged.subscribe(function (e, args) {
                grid.invalidate(args.rows);
                grid.render();

                if (selectedRowIds.length > 0) {
                    // since how the original data maps onto rows has changed,
                    // the selected rows in the grid need to be updated
                    var selRows = [];
                    for (var i = 0; i < selectedRowIds.length; i++) {
                        var idx = gridDataView.getRowById(selectedRowIds[i]);
                        if (idx != undefined)
                            selRows.push(idx);
                    }
                    grid.setSelectedRows(selRows);
                }
            });

//           gridDataView.onPagingInfoChanged.subscribe(function (e, pagingInfo) {
//                var isLastPage = pagingInfo.pageSize * (pagingInfo.pageNum + 1) - 1 >= pagingInfo.totalRows;
//                var enableAddRow = isLastPage || pagingInfo.pageSize == 0;
//                var options = grid.getOptions();
//                if (options.enableAddRow != enableAddRow)
//                    grid.setOptions({ enableAddRow: enableAddRow });
//                grid.render();
//            });

            grid.onClick.subscribe(function (e, args) {
                if (gridInfo.Columns[args.cell].id == "delete") {
                    $.ajax({
                        url: gridInfo.DeleteURL,
                        data: gridDataView.rows[row],
                        success: function (deleted) {
                            if (deleted.toLowerCase() == 'true') {
                                gridDataView.rows.splice(row, 1);
                                grid.invalidate();
                                grid.setSelectedRows([]);
                                grid.updateRowCount();
                                return true;
                            } else {
                                mddMsg.error($("#" + gridInfo.ErrorMessageElement), "The row could not be deleted");
                            }
                        },
                        error: function (message) { return false; }
                    });
                }
                else {
                    try {
                        var field = gridInfo.Columns[args.cell].id;
                        RuntimeCellClick(gridInfo, field, gridInfo.Columns[args.cell], grid.getDataItem(args.row));
                    } catch (ex) {
                        //Pass the change to be overridden
                    }
                    grid.updateRow(grid.getDataItem(args.row));
                    e.stopPropagation();
                }
            });
            //Sorting functionality
            grid.onSort.subscribe(function (e, args) {
                currentSortCol = args.sortCol;
                //                isAsc = sortAsc;
                gridDataView.sort(function (a, b) {
                    var compA = a[currentSortCol.id];
                    var compB = b[currentSortCol.id];
                    if (args.sortAsc) {
                        return (compA < compB) ? -1 : (compA > compB) ? 1 : 0;
                    } else {
                        return (compA > compB) ? -1 : (compA < compB) ? 1 : 0;
                    }
                })
            });
            gridDataView.beginUpdate();
            gridDataView.setItems(_PrepareDataSourceForGrid(gridInfo, gridData));
            gridDataView.endUpdate();
        }
        // Adds additional id property column
        function _PrepareDataSourceForGrid(gridInfo, rows) {
            $.each(rows, function (i, element) { element["id"] = i; });
            gridInfo.rowLength = rows.length;
            return rows;
        }
        // Adds delete link to the grid
        function _AddEditColumn(columns) {
            var changedColumns = [];
            changedColumns.push(checkboxSelector.getColumnDefinition());
            $.each(columns, function (i, element) { changedColumns[i + 1] = columns[i]; });
            return changedColumns;
        }
        //Select All functionality
        function _SelectAllRows() {
            var selAllState = $("#selAllChkBx").attr('checked');
            var data = gridDataView.rows;
            $.each(data, function (i, element) { element._gridAction = selAllState; })
            grid.removeAllRows();
            grid.render();
        }
        //Updates the column formatters
        function _UpdateColumnFormatter(gridInfo) {
            //To-do: should write an advanced logic to prepare proper
            $.each(gridInfo.Columns, function (i, element) {
            if (element.name) {
                var headerLength = element.name.length;
                if (headerLength >= 18) {
                     element.width = 130;
                  } else if (headerLength >= 15) {
                     element.width = 110;
                  } else if (headerLength >= 10) {
                    element.width = 95;
                  } else if (headerLength = 9) {
                    element.width = 70;
                  }
                  else if (headerLength >= 5) {
                    element.width = 60;
                  }else {
                    element.width = 50;
                }
            }
                switch (element.columndatatype) {
                    case "bool":
                        element.editor = YesNoCheckboxCellEditor;
                        element.formatter = YesNoCellFormatter;
                        break;
                    case "selectlist":
                        element.editor = SelectCellEditor;
                        break;
                    case "readonly":
                        element.editor = undefined;
                        break;
                    case "timestamp":
                        element.formatter = DateTimeFormatter;
                        element.editor = DateTimeCellEditor;
                        element.width = 150;
                        break;
                    case "datetime":
                        element.formatter = DateTimeFormatter;
                        element.editor = DateCellEditor;
                        element.width = 120;
                        break;
                    case "SingleDecimal":
                        element.formatter = SingleDecimalFormatter;                        
                        break;
                    case "Custom":
                        break;
                    default:
                        element.editor = TextCellEditor
                        break;
                }
            });
        }

        //Updates the column validators
        function _UpdateColumnValidator(gridInfo, gridDataValidationRules) {
            //To-do: should write an advanced logic to prepare proper
            $.each(gridInfo.Columns, function (i, element) { element.validator = fieldValidatorDelegate(element.id, gridDataValidationRules) });
        }
        //togg;es the search filter row
        function toggleFilterRow() {
            if ($(grid.getSecondaryHeaderRow()).is(":visible"))
                grid.hideSecondaryHeaderRow();
            else
                grid.showSecondaryHeaderRow();
        }
        //fieldValidator delegate
        var fieldValidatorDelegate = function (field, rules) {
                return function (value) {
                    return _FieldValidator(field, rules, value);
                };
            };

        //Function to validate a field
        function _FieldValidator(field, validationRules, value) {
            var errorList = [];
            if (null != validationRules) {
                if (null != validationRules["Fields"]) {
                    for (var i = 0; i < validationRules.Fields.length; i++) {
                        if (validationRules["Fields"][i].FieldName == field) {
                            if (null != validationRules["Fields"][i].FieldRules) {
                                for (var j = 0; j < validationRules["Fields"][i].FieldRules.length; j++) {
                                    var errmsg = _ValidateRule(value, validationRules["Fields"][i].FieldRules[j]);
                                    if (null != errmsg && undefined != errmsg && errmsg != "") {
                                        errorList.push(errmsg);
                                    }
                                }
                            }
                        }
                    }
                }
            }
            else {
                mddMsg.error($("#" + gridInfo.ErrorMessageElement), "There are no validation rules defined for the grid.");
                return { valid: false, msg: null };
            }

            if (null != errorList && errorList != undefined && errorList.length > 0) {
                mddMsg.error($("#" + gridInfo.ErrorMessageElement), errorList.toString());
                return { valid: false, msg: null };
            }
            else {
                return { valid: true, msg: null };
            }
        }

        //validate a rule on the field
        function _ValidateRule(value, fieldRule) {
            var errormsg = "";
            switch (fieldRule.RuleName.toLowerCase()) {
                case "required":
                    if (null == value || value == undefined || !value.length) {
                        errormsg = fieldRule.Message || "Field is required.";
                    }
                    break;
                case "stringlength":
                    for (param in fieldRule.RuleParameters) {
                        errormsg = fieldRule.Message || "Field is required.";
                    }
                    break;
                case "datatype":
                    for (param in fieldRule.RuleParameters) {
                        switch (fieldRule.RuleParameters[param].toLowerCase()) {
                            case "integer":
                            case "decimal":
                                if (isNaN(value)) {
                                    errormsg = fieldRule.Message || "Field should be of type: " + fieldRule.RuleParameters[param];
                                }
                                break;
                            default:
                                errormsg = fieldRule.Message || "The data type is mismatched.";
                                break;
                        }
                    }
                    break;
                default:
                    errormsg = "There was an validation error";
                    break;
            }
            return errormsg;
        }

        //Prepares grid filter panel
        function _PrepareFilterPanel(gridInfo) {
            $("#" + gridInfo.FilterElement).empty();
            var isFirstFilter = true;
            for (i in gridInfo.ColumnsMetadata) {
                if (gridInfo.ColumnsMetadata[i].IsIdProperty) {
                    //should set it as IdProperty 
                }
                if (null != gridInfo.ColumnsMetadata[i].IsFilterable && undefined != gridInfo.ColumnsMetadata[i].IsFilterable && gridInfo.ColumnsMetadata[i].IsFilterable) {
                    // prepare Filterable column
                    if (isFirstFilter) {
                        $("#" + gridInfo.FilterElement).append("<b>Filter Criteria:</b> <br/> Show data with ");
                        isFirstFilter = false;
                    } else {
                        $("#" + gridInfo.FilterElement).append(" & ");
                    }
                    $("#" + gridInfo.FilterElement).append(gridInfo.ColumnsMetadata[i].ColumnName + " in: &nbsp; <input type='text' id= '" + gridInfo.ColumnsMetadata[i].ColumnName + "Filter' name= '" + gridInfo.ColumnsMetadata[i].ColumnName + "' style='width:80px' />");

                    // wire up the search textbox to apply the filter to the model
                    $("#" + gridInfo.ColumnsMetadata[i].ColumnName + "Filter").keyup(function (e) {
                        Slick.GlobalEditorLock.cancelCurrentEdit();

                        // clear on Esc
                        if (e.which == 27) {
                            this.value = "";
                        } else {
                            if (undefined != e.srcElement && undefined != e.srcElement.name && null != e.srcElement.name && this.value != "") {
                                mddMsg.notice($("#" + gridInfo.ErrorMessageElement), "Searching grid data with " + e.srcElement.name + " having '" + this.value + "'");
                            }
                        }
                        searchString = this.value;
                        gridDataView.refresh();
                    });
                }
            }

            // move the filter panel defined in a hidden div into an inline secondary grid header row
            //$("#" + gridInfo.FilterElement).appendTo(grid.getSecondaryHeaderRow()).show();
        }

        function SetSaveCallBack(callback) {
            this.saveCallBack = callback;
        }

        function SetDeleteCallBack(callback) {
            this.deleteCallBack = callback;
        }

        function SetBeforeCellChangeCallBack(callback) {
           if (typeof callback == 'function') {
                grid.onBeforeEditCell.subscribe(callback);
            }       
        }

        function SetOnAddNewRowCallBack(callback){
            if (typeof callback == 'function') {
                grid.onAddNewRow.subscribe(callback);
            }
        }

        function SaveSelectedRows() {
            try {
                if (typeof this.saveCallBack == 'function') {
                    this.saveCallBack.call(this);
                }
            } catch (e) {
                mddMsg.error($("#" + gridInfo.ErrorMessageElement), "Could not save data, please contact Administrator.");
            }
        }

        function DeleteSelectedRows() {
            try {
                if (typeof this.deleteCallBack == 'function') {
                    this.deleteCallBack.call(this);
                }
            } catch (e) {
                mddMsg.error($("#" + gridInfo.ErrorMessageElement), "Could not delete data, please contact Administrator.");
            }
        }
        

        function SetGridValidationRules(rules) {
            _UpdateColumnValidator(this.gridInfo, rules);
        }

        function SetData(data) {
            grid.invalidateAllRows();            
            gridDataView.beginUpdate();
            gridDataView.setItems(_PrepareDataSourceForGrid(gridInfo, data));
            gridDataView.endUpdate();
        }
        //////////////////////////////////////////////////////////////////////////////////////////////
        // Public API
        $.extend(this, {
            // Methods
            "SetSaveCallBack": SetSaveCallBack,
            "SetDeleteCallBack": SetDeleteCallBack,
            "SaveSelectedRows": SaveSelectedRows,
            "DeleteSelectedRows": DeleteSelectedRows,
            "SetGridValidationRules": SetGridValidationRules,
            "SetBeforeCellChangeCallBack": SetBeforeCellChangeCallBack,
            "SetOnAddNewRowCallBack": SetOnAddNewRowCallBack,
            "SetData": SetData
        });
        init.apply(this);
    }
})(jQuery);
