define(['domReady', 'slickgrid'], function(domReady, Slick) {

    // A custom editor for the localization type
    Slick.Editors.LocalizeType = function(args) {
        var $select;
        var defaultValue;
        var scope = this;

        this.init = function () {
            $select = $("<SELECT tabIndex='0' class='editor-yesno'><OPTION value='lm'>lm</OPTION><OPTION value='lt'>lt</OPTION></SELECT>");
            $select.appendTo(args.container);
            $select.focus();
        };
        this.destroy = function () {
            $select.remove();
        };
        this.focus = function () {
            $select.focus();
        };
        this.loadValue = function (item) {
            $select.val((defaultValue = item[args.column.field]) ? "lm" : "lt");
            $select.select();
        };
        this.serializeValue = function () {
            return $select.val();
        };
        this.applyValue = function (item, state) {
            item[args.column.field] = state;
        };
        this.isValueChanged = function () {
            return ($select.val() != defaultValue);
        };
        this.validate = function () {
            return {
            valid: true,
            msg: null
            };
        };

        this.init();
    };

    var new_id = 0;
    // Add a new row
    function addRow(location) {
        if(location === null)
            location = 0;
        // Check that we have columns
        if(!cols.length) { return; }

        // Create a new row object
        var newRow = {type:'', key:'', aux:''};
        _.each(languages, function(lang) {
            newRow[lang.field] = '';
        });

        // Grab the DataView
        var dv = grid.getData();
        // Grab all items
        var items = dv.getItems();
        // Assign a new ID
        newRow.id = "new_" + (++new_id);
        // Add the row to the right location
        items.splice(location, 0, newRow);
        // Reset the items
        dv.setItems(items);
        // Reset the grid data
        grid.setData(dv);
        // Scroll to the newly inserted row
        grid.scrollRowIntoView(location, false);
        return newRow;
    }

    // Update a row from data recieved from the popup window
    function updateData(data) {
        if (!data.id || !dataView.getItemById(data.id))
        {
            if(grid.getActiveCell() !=  null)
                var location = grid.getActiveCell().row;
            else
                var location = 0;
            var new_item = addRow(location);
            data.id = new_item.id;
            data.status = 'added';
        }
        if (data.status === undefined || data.status === '')
            data.status = 'changed';
        dataView.updateItem(data.id, data);

        grid.invalidate();
    }

    // The Grid object
    var grid;

    // The static columns
    var cols = [
        {id: "status", name: "Status", field: "status", width: 70, sortable: true },
        {id: "type", name: "Type", field: "type", width: 40, editor: Slick.Editors.LocalizeType, sortable: true },
        {id: "key", name: "Key", field: "key", width: 400, editor: Slick.Editors.Text, sortable: true},
        {id: "aux", name: "Aux", field: "aux", width: 200, editor: Slick.Editors.Text, sortable: true}
    ];

    // SlickView DataView - Holds all of our data
    var dataView = new Slick.Data.DataView();

    var popupTemplate = null;

    // SlickGrid options
    var options = {
        enableCellNavigation: true,
        enableColumnReorder: false,
        editable: editable === 1,
        autoEdit: false
    };

    // Loop through all languages and define a Long Text Editor
    for(var i = 0; i < languages.length ; i++) {
        languages[i].editor = Slick.Editors.LongText;
        languages[i].sortable = true;
        cols.push(languages[i]);
    }

    // The filter function defined against the SlickGrid DataView
    function myFilter(item, args) {
        // If we're called without params, we'll simply return true
        if(!_.isObject(args)) {
            return true;
        }

        if (args.changed !== undefined && args.changed)
        {
            return (item.status !== undefined && item.status !== '');
        }

        var str = args.searchString;
        if (str[0] === '"' && str[str.length - 1] === '"')
        {
            str = str.substr(1, str.length - 2);
            return matchPhrase(item, str);
        }

        if (str[0] === '"' && str[str.length - 1] === '"')
        {
            str = str.substr(1, str.length - 2);
            return matchPhrase(item, str);
        }


        var words = str.split(/\s/);

        var match = true;
        _.each(words, function (word) {
            if (!matchPhrase(item, word))
                match = false;
        });
        return match;
    }

    function matchPhrase(item, phrase) {
        // Check against each of the languages
        phrase = phrase.toLowerCase();
        var match = false;
        _.each(languages, function(lang) {
            if (item[lang.field] !== undefined && item[lang.field] !== null)
            {
                if (item[lang.field].toLowerCase().indexOf(phrase) !== -1)
                    match = true;
            }
        });
        if (match)
            return true;

        // Check against the key
        if(item.key.indexOf(phrase) !== -1) { return true; }

        if(item.aux.indexOf(phrase) !== -1) { return true; }

        // Looks like this item doesn't match then!
        return false;
    }


    function applyFilter()
    {
        var value = $('#filter').val().toLowerCase();
        dataView.setFilterArgs({
            searchString: value
        });
        dataView.refresh();
        grid.invalidate();
    }

    function showPhrasePopup(item)
    {
        if (!popupTemplate)
        {
            popupTemplate = _.template(jQuery('#popup-template').html());
        }

        var dialog = window.open("about:blank", "_blank", "dependent=on,width=900,location=0,resizable=yes,addres,height=" + (languages.length * 26 + 165 + 30)); // phrase.php?edit_mode=" + edit_mode + "&app=" + app
        if (dialog) {
            dialog.document.write('<html><head><title>Edit phrase</title></head><body>' + popupTemplate({data: item}) + '</body></html>');
            dialog.document.close();
            $("#saveBtn", dialog.document).click(function() {
                var d = dialog.document;
                var results = {};
                results.type = $("input[name=type]:checked", d).val();
                results.key = $("#key", d).val();
                results.aux = $("#aux", d).val();
                $.each(languages, function(key, lang_info) {
                    results[lang_info.id] = $("#input-" + lang_info.id, d).val();
                });
                var changed = 0;
                $.each(results, function (key) {
                    if (item[key] !== results[key])
                    {
                        changed = 1;
                        item[key] = results[key];
                    }
                });
                if (changed)
                    updateData(item);
                dialog.close();
            });
        } else {
            alert("Please disable any popup blockers");
        }
    }


    function makeBackup(item)
    {
        if (item.backup === undefined)
            item.backup = $.extend({}, item);
    }


    // Ready?
    domReady(function() {
        _.templateSettings = {
            interpolate : /\{\{=(.+?)\}\}/g,
            evaluate : /\{\{(.+?)\}\}/g,
            escape : /\{\{-(.+?)\}\}/g
        };

        // Add the items to the DataView
        dataView.setItems(data);

        // Assign the custom filter method to the DataView
        dataView.setFilter(myFilter);

        // Instantiate SlickGrid
        grid = new Slick.Grid("#container", dataView, cols, options);

        // Set the selection model
        //grid.setSelectionModel(new Slick.CellSelectionModel());
        grid.setSelectionModel(new Slick.RowSelectionModel({selectActiveRow: true}));

        // Override the getItemMetadata function to highlight changed/deleted rows
        dataView.getItemMetadata = function(row) {
            // var item = dataView.getItemById(row + 1);
            var item = grid.getDataItem(row);
            if(item) {
                if(item.status === 'deleted') {
                    return { cssClasses: "rowDeleted" };
                }
                if(item.status === 'changed' || item.status === 'added') {
                    return { cssClasses: "rowChanged" };
                }
            }
        };

        // Make backups for data
        grid.onBeforeEditCell.subscribe(function(e,args) {
            makeBackup(args.item);
            grid.invalidate();
        });

        // Listen for changing cells
        grid.onCellChange.subscribe(function(e,args) {
            if (args.item.status === undefined || args.item.status === '')
                args.item.status = 'changed';
            _.each(languages, function (lang_obj) {
                args.item[lang_obj.id] = args.item[lang_obj.id].replace(/\s*[\r\n]+\s*/g, " ");
            });
            grid.invalidate();
        });

        // Context menu
        grid.onContextMenu.subscribe(function (e) {
            // Check to see whether we're allowing edits
            if(editable === 0) {
                return true;
            }
            // Prevent the usual right click
            e.preventDefault();
            // Grab our location
            var cell = grid.getCellFromEvent(e);

            // check if the current cell is within selection
            var selected_rows = grid.getSelectedRows();
            if (_.indexOf(selected_rows, cell.row) === -1)
            {
                // If not - reset the selection and set it to the right-clicked row
                grid.setActiveCell(cell.row, 1);
            }

            // Reveal the menu
            $("#contextMenu")
                .data("row", cell.row)
                .css("top", e.pageY)
                .css("left", e.pageX)
                .show();

            // Hide the menu when clicking elsewhere
            $("body").one("click", function () {
                $("#contextMenu").hide();
            });
        });

        $('#container').contextmenu(function(event){
            event.preventDefault();
            // Reveal the menu
            $("#contextMenu")
                .data("row", -1)
                .css("top", event.pageY)
                .css("left", event.pageX)
                .show();

            // Hide the menu when clicking elsewhere
            $("body").one("click", function () {
                $("#contextMenu").hide();
            });
        });

        // Resort our DataView and rerender the grid
        grid.onSort.subscribe(function (e, args) {
            dataView.fastSort(args.sortCol.field, args.sortAsc);
            grid.invalidate();
        });

        // Context menu listeners
        $("#contextMenu").click(function (e) {
            var target = $(e.target);

            if (!target.is("li")) { return; }
            if (!grid.getEditorLock().commitCurrentEdit()) { return; }

            var row = $(this).data("row");

            var selected_rows = grid.getSelectedRows();
            var items = _.map(selected_rows, function (row_num) {
                return grid.getDataItem(row_num);
            });

            switch(target.attr("id")) {
                case "context-delete":
                    if(grid.getActiveCell() == null)
                        break;
                    _.each(items, function (item) {
                        if (item.status === 'added')
                            dataView.deleteItem(item.id);
                        else
                        {
                            makeBackup(item);
                            item.status = 'deleted';
                            dataView.updateItem(item.id, item);
                        }
                    });
                    grid.invalidate();
                    grid.render();
                break;
                case "restore-phrase":
                    if(grid.getActiveCell() == null)
                        break;
                    _.each(items, function (item) {
                        if (item.backup !== undefined)
                            item = item.backup;

                        dataView.updateItem(item.id, item);
                    });
                    grid.invalidate();
                    grid.render();
                    break;
                case "context-add":
                    //addRow(row);
                    if(grid.getActiveCell() != null) {
                        var cur_item = grid.getDataItem(grid.getActiveCell().row);
                        var type = cur_item.type;
                    }else{
                        var type = "lm";
                    }
                    showPhrasePopup({type: type});
                break;
                case "new-window":
                    if(grid.getActiveCell() == null)
                        break;
                    var cur_item = grid.getDataItem(grid.getActiveCell().row);
                    makeBackup(cur_item);
                    showPhrasePopup(cur_item);
                break;
                case "mark-modified":
                    if(grid.getActiveCell() == null)
                        break;
                    _.each(items, function (item) {
                        if (item.status === undefined || item.status === '')
                        {
                            makeBackup(item);
                            item.status = 'changed';
                        }
                    });
                    grid.invalidate();
                    grid.render();
                break;
            }
        });

        // Override form submission and update our hidden fields for posting
        $("#saveButton").click(function() {
            var changedItems = {};
            var deletedItems = [];
            var key;
            var changed = _.where(data, {status:'changed'});
            var saveNeeded = 0;
            _.each(changed, function (item) {
                key = item.backup.type + ' ' + item.backup.key;
                changedItems[key] = $.extend({}, item);
                changedItems[key].backup = undefined;
                saveNeeded = 1;
            });

            var added = _.where(data, {status:'added'});
            _.each(added, function (item) {
                key = item.type + ' ' + item.key;
                changedItems[key] = $.extend({}, item);
                changedItems[key].backup = undefined;
                saveNeeded = 1;
            });

            var deleted = _.where(data, {status:'deleted'});
            _.each(deleted, function (item) {
                key = item.backup.type + ' ' + item.backup.key;
                deletedItems.push(key);
                saveNeeded = 1;
            });


            if (saveNeeded)
            {
                var post_data = {
                    'edit_mode': edit_mode,
                    'app': app,
                    'changedData': JSON.stringify(changedItems),
                    'deletedData': JSON.stringify(deletedItems)
                };
                $.post('msg_edit.php', post_data, function (text) {
                    if (text[0] === '1')
                    {
                        alert(text.substr(1));
                        var arr = dataView.getItems();
                        for (var i = arr.length-1; i >= 0; --i)
                        {
                            var item = arr[i];
                            if (item.status === 'deleted')
                            {
                                dataView.deleteItem(item.id);
                            }
                            else if (item.status !== undefined || item.status !== '')
                            {
                                item.status = undefined;
                                item.backup = undefined;
                            }
                        }

                        grid.invalidate();
                        grid.render();
                    } else
                    {
                        var new_win = window.open("about:blank", "_blank");
                        if (new_win)
                        {
                            new_win.document.write(text);
                            new_win.document.close();
                        }
                    }

                    $("#saveButton").prop('disabled', 0);
                });

                $("#saveButton").prop('disabled', 1);
            } else
            {
                alert("Nothing to save - no changes found");
            }
        });


        var filter_timer;
        // Filtering
        $("#filter").keyup(function(e) {
            if(e.keyCode === 27) {
                $(this).val("");
            }
            clearTimeout(filter_timer);
            filter_timer = setTimeout(applyFilter, 300);
        });

        $('#reset-filter').on('click', function () { $("#filter").val(''); applyFilter(); });

        $(window).bind('beforeunload', function(event) {
                if (_.every(dataView.getItems(), function (item) { return item.status === undefined || item.status === ''; }))
                    return;

                var bg_backup = $(document.body).css('background-color');
                $(document.body).css('background-color', 'red');
                dataView.setFilterArgs({
                    changed: true
                });
                dataView.refresh();
                grid.invalidate();
                setTimeout(function() {
                    setTimeout(function() {
                        $(document.body).css('background-color', bg_backup);
                    }, 1);
                },1);
                //jQuery('body').append('<div style="background-color: #000000; bottom: 0; left: 0; position: fixed; right: 0; top: 0; z-index: 10000; opacity: 0.7" onmouseover="$(this).detach();"></div>');
                return 'You have some unsaved changes';
            }
        );
    });
});
