﻿$engine JScript
$uname SelectValueDialog
$dname Класс SelectValueDialog
$addin global
$addin stdcommands
$addin stdlib

////////////////////////////////////////////////////////////////////////////////////////
////{ Cкрипт-библиотека SelectValueDialog (SelectValueDialog.js) для проекта "Снегопат"
////
//// Описание: Диалог выбора значения из списка с фильтрацией элементов. 
//// Пример использования см. в скрипте Tests\Examples\SelectValueDialog_example.js
//// Может наследоваться.
////
//// Автор: Александр Кунташов <kuntashov@gmail.com>, http://compaud.ru/blog
////}
////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////

global.connectGlobals(SelfScript)
stdlib.require("ScriptForm.js", SelfScript);
stdlib.require("TextChangesWatcher.js", SelfScript);
stdlib.require("TextWindow.js", SelfScript);

SelectValueDialog = ScriptForm.extend({

    caption: "Выберите значение",

    settingsRootPath : 'SelectValueDialog',
    
    settings : {
        pflSnegopat : {
            'DoNotFilter': false, 
            'SortByName' : false, 
            'GreedySearch': false //Жадный поиск, ищем в независимости от порядка занесения строк.
        }
    },

    construct : function (caption, values) {    
        this._super(stdlib.getSnegopatMainFolder() + "scripts\\Libs\\SelectValueDialog.ssf");
        if (!values) {
        	values = [];
        }
        this.loadValues(values);
        this.caption = caption ? caption : "Выберите значение";
        //Сохраним ключ положения окна.
        this.form.WindowOptionsKey =this.caption;
        this.form.ValuesList.Columns.Add('Value');
        this.setValuesList(this.originalList);
        
        var sv = this;
        this.tcWatcher = new TextChangesWatcher(this.form.Controls.SearchText, 3, function(t){sv.updateList(t)});
    },

    selectValue: function (values) {
        if (values) {
            this.loadValues(values);
            this.setValuesList(this.originalList);
        }
        this.selectedValue = this.form.DoModal();
        return this.selectedValue ? true : false;
    },

    addRowToVT: function(vt, value, name) {
        var newRow = vt.Add();
        newRow.Order = vt.Count();
        newRow.Value = value;
        newRow.Name = '' + (name ? name : value);		
    },

    loadValues: function (values) {
        var vt = v8New('ValueTable');
        vt.Columns.Add('Name');
        vt.Columns.Add('Order');
        vt.Columns.Add('Value');
        
        //TODO: добавить поддержку соответствия и структуры.
        var typeName = Object.prototype.toString.call(values);
        if (typeName === '[object Array]') {
            for (var i=0; i<values.length; i++) {
                this.addRowToVT(vt, values[i]);
            }
        } else if (typeName === '[object Object]') {			
            // Или объект 1С, или объект JavaScript.
            typeName = toV8Value(values).typeName(0);
            if (typeName === 'COMObject') { 
                // Значит, это объект JavaScript или COM-объект. 
                // Ключ - представление, значение - значение.
                for (var prop in values) {
                    if (values.hasOwnProperty(prop)) {
                        this.addRowToVT(vt, values[prop], prop);
                    }
                }
            } else if (typeName === 'ValueList') {
                // TODO: картинку тоже можно показывать!
                for (var i=0; i<values.Count(); i++) {
                    var el = values.Get(i);
                    this.addRowToVT(vt, el.Value, el.Presentation);
                }
            } else if (typeName === 'Array') {
                for (var i=0; i<values.Count(); i++) {
                    this.addRowToVT(vt, values.Get(i));
                }
            } else {
                // Переданный параметр - не поддерживаемая коллекция.
                // Тогда в списке только одно переданное значение.
                this.addRowToVT(vt, values);
            }		
        } else {
            this.addRowToVT(vt, values);
        }
                
        this.sortValuesList(this.form.SortByName, vt);
        this.originalList	= vt;
        return vt;
    },

    sortValuesList: function (sortByName, vt) {
        if (!vt) {
            vt = this.form.ValuesList;
        }
        vt.Sort(sortByName ? 'Name' : 'Order');
    },

    setValuesList: function(vt) {
        this.form.ValuesList = vt.Copy();
    },

    updateList: function (newText) {
    
        if (!newText || newText.match(/^\s*$/))
        {
            if (this.loadedOnOpen)
                this.loadedOnOpen = false;
            else
            	this.setValuesList(this.originalList);
        }
        else 
        {
            var a = newText.split(/\s+/);
            for (var i=0; i<a.length; i++)
                a[i] = StringUtils.addSlashes(a[i]);
                
            var re = new RegExp(a.join(".*?"), 'i');    
            
            if (this.form.DoNotFilter)
            {
                var currentRow = undefined;
                
                var vtList = this.originalList.Copy();
                for (var rowNo = 0; rowNo < vtList.Count(); rowNo++)
                {
                    var row = vtList.Get(rowNo);
                    if (re.test(row.Name))
                    {
                        currentRow = row;
                        break;
                    }
                }
                
                this.form.Controls.ValuesList.Value = vtList;
                if (currentRow)
                    this.form.Controls.ValuesList.CurrentRow = currentRow;
            }
              
            else
            {
                if (this.form.GreedySearch){
                    var a = newText.split(/\s+/);
                    var vtList = this.form.Controls.ValuesList.Value;
                    vtList.Clear();    
                    for (var rowNo = 0; rowNo < this.originalList.Count(); rowNo++)
                    {
                        var row = this.originalList.Get(rowNo);
                        needAdd = true;
                        var title = row.Name.toLowerCase();
                        for (var i=0; i<a.length; i++){

                            if(title.indexOf(a[i]) < 0)
                            {
                                needAdd = false;
                                break;
                            }
                        }

                        if (needAdd) {                        
                            var newRow = vtList.Add();                      
                            newRow.Value = row.Value;
                            newRow.Name = row.Name;
                            newRow.Order = row.Order
                        }
                    }
                    if (this.form.Controls.ValuesList.Value.Count()) {
                        this.form.Controls.ValuesList.CurrentRow = this.form.Controls.ValuesList.Value.Get(0);
                    }

                }  else {

                    var vtList = this.form.Controls.ValuesList.Value;
                    vtList.Clear();    
                    for (var rowNo = 0; rowNo < this.originalList.Count(); rowNo++)
                    {
                        var row = this.originalList.Get(rowNo);
                        if (re.test(row.Name)) {                        
                            //FillPropertyValues(vtList.Add(), row);                                            
                            var newRow = vtList.Add();                      
                            newRow.Value = row.Value;
                            newRow.Name = row.Name;
                            newRow.Order = row.Order
                        }
                    }
                    if (this.form.Controls.ValuesList.Value.Count()) {
                        this.form.Controls.ValuesList.CurrentRow = this.form.Controls.ValuesList.Value.Get(0);
                    }

                }

            }
        }
    
        this.sortValuesList(this.form.SortByName);
        
    },

    Form_OnOpen: function () {

        this.form.Caption = this.caption ? this.caption : "Выберите значение";

        this.form.Controls.CmdBar.Buttons.SortByName.Check = this.form.SortByName;
        this.form.Controls.CmdBar.Buttons.DoNotFilter.Check = this.form.DoNotFilter;	    
        	   
        this.loadedOnOpen = true;	     
        
        this.tcWatcher.start();
    },

    Form_BeforeClose : function (Cancel, StandardHandler) {
        this.tcWatcher.stop();
    },

    ValuesList_Selection: function (Control, SelectedRow, Column, DefaultHandler) {
        this.form.Close(SelectedRow.val.Value);
    },

    CmdBar_SortByName: function (button) {
        button.val.Check = !button.val.Check;
        this.form.SortByName = button.val.Check;
        this.sortValuesList(button.val.Check);
    },

    CmdBar_DoNotFilter: function (button) {
        button.val.Check = !button.val.Check;
        this.form.DoNotFilter = button.val.Check;
        this.updateList(this.form.Controls.SearchText.Value);
    },

    CmdBarMain_ОК: function (Кнопка) {
        var SelectedRow = this.form.Controls.ValuesList.CurrentRow;
        if (SelectedRow)
            this.form.Close(SelectedRow.Value);
        else
            this.form.CurrentControl = this.form.Controls.SearchText;
    },

    SearchText_Tuning: function(Ctrl, Direction, DefaultHandler) {
        var curIndex = -1,
            grid = this.form.Controls.ValuesList;
        if (grid.CurrentRow) {
            curIndex = grid.Value.IndexOf(grid.CurrentRow);
            curIndex -= Direction.val;
            if (curIndex < 0) {
                curIndex = grid.Value.Count() - 1;
            } else if (curIndex >= grid.Value.Count()) {
                curIndex = 0;
            }
            grid.CurrentRow = grid.Value.Get(curIndex);
        }
        DefaultHandler.val = false;
    },
    // Вставляет кнопку в командную панель, в правую часть.
    AddCmdButton: function(commands) {
        function tuneButton(button, params)
        {
            for(var k in params)
                button[k] = params[k]
        }
        var pThis = this;
        (function InsertCmdButtons(cmds, to, startIdx) {
            for(var k in cmds)
            {
                var cmd = cmds[k]
                if(cmd.id == '|')
                    to.Вставить(startIdx, '', ТипКнопкиКоманднойПанели.Разделитель)
                else if(cmd.id == '>')
                {
                    var subMenu = to.Вставить(startIdx, '', ТипКнопкиКоманднойПанели.Подменю)
                    tuneButton(subMenu, cmd.params)
                    InsertCmdButtons(cmd.buttons, subMenu.Кнопки, 0)
                }
                else
                {
                    var button = to.Вставить(startIdx, cmd.id, ТипКнопкиКоманднойПанели.Действие, undefined, v8New("Действие", "_onAdditionalButton"))
                    tuneButton(button, cmd.params)
                    if(!pThis.handlers)
                        pThis.handlers = {}
                    pThis.handlers[cmd.id] = cmd.handler
                }
                startIdx++
                
            }
        })(commands, this.form.Controls.CmdBarMain.Кнопки, 0)
    },
    // Обработчик нажатий дополнительных кнопок
    _onAdditionalButton: function(button){
        button = button.val
        var SelectedVal = this.form.Controls.ValuesList.CurrentRow;
        if(SelectedVal)
            SelectedVal = SelectedVal.Value;
        this.handlers[button.Имя](this, SelectedVal, button)
    }
});
