﻿$engine JScript
$uname codegen_manager
$dname Менеджер генераторов кода
$addin stdlib

// (c) Александр Орефков orefkov at gmail.com
// Скрипт - для запуска различных генераторов кода
// Данный скрипт должен быть загружен в addins.ini РАНЕЕ других скриптов - генераторов кода
var attrTypeCategory        = "{30E571BC-A897-4A78-B2E5-1EA6D48B5742}"

// Сразу загрузим форму, т.к. ее дерево будет использоваться для хранения функций-кодогенераторов
var codeGens = [], form
form = loadScriptForm(SelfScript.fullPath.replace(/js$/, 'ssf'), SelfScript.self)
form.ИспользоватьМетаданные = 1
form.Дерево.Колонки.Добавить("caller")

// Регистрация функции кодогенератора.
function registerCodeGen(description, caller)
{
    var descr = description.split("/")
    var root = form.Дерево.Строки
    for(var i = 0; i < descr.length - 1; i++)
    {
        var row = root.Найти(descr[i], "Генератор")
        if(!row)
        {
            row = root.Добавить()
            row.Генератор = descr[i]
            row.Картинка = 0
        }
        root = row.Строки
    }
    // Сначала попробуем найти, может такая запись уже есть.
    // Это позволит перезагружать скрипты-кодогенераторы
    row = root.Найти(descr[i])
    if(!row)
    {
        row = root.Добавить()
        row.Генератор = descr[i]
    }
    row.Картинка = 1
    row.caller = caller
}

// Собственно, выбор и запуск генерации
SelfScript.Self["macrosХочу Кода!!!"] = function()
{
    var pathToForm = SelfScript.fullPath.replace(/js$/, 'ssf')
    // Обработку событий формы привяжем к самому скрипту
    if(form.ОткрытьМодально())
    {
        var mdCont = form.ИспользоватьМетаданные == 1 ? metadata.ib : metadata.current
        var caller = form.ЭлементыФормы.Дерево.ТекущиеДанные.caller
        var param = {mdCont:mdCont, text:"", caretToBegin:true}
        if(!caller(param))
            return
        var text = param.text
        var txtWnd = snegopat.activeTextWindow()
        if(!txtWnd || txtWnd.readOnly)
            Message(text)
        else
        {
            // Надо получить отступ
            var sel = txtWnd.getSelection()
            var textLine = txtWnd.line(sel.beginRow)
            // Курсор может быть за концом строки
            while(textLine.length < sel.beginCol - 1)	
                textLine += ' '
            // Оставим только часть строки перед курсором
            textLine = textLine.substr(0, sel.beginCol - 1)
            var m = textLine.match(/^\s+/)
            if(m)	// Есть пробельные символы в начале строки
                text = text.replace(/\n/g, '\n' + m[0])	// Заменим переводы строк на перевод строк + отступ
            text = text.replace(/\s+$/m, '')			// СокрП
            // Вставим текст
            txtWnd.selectedText = text
            if(param.caretToBegin)
                txtWnd.setCaretPos(sel.beginRow, sel.beginCol)
        }
    }
}

// Обработчики событий формы
function ПриОткрытии()
{
    // Если текущая конфа не открыта или не отличается от конфы ИБ,
    // то нет смысла выбирать метаданные
    if(!stdlib.isConfigOpen() || !stdlib.isConfigsDifferent())
    {
        form.ИспользоватьМетаданные = 1
        form.ЭлементыФормы.ОткрытаяКонфигурация.Доступность = false
    }
    else
        form.ЭлементыФормы.ОткрытаяКонфигурация.Доступность = true
}
function КоманднаяПанель1ОК(Кнопка)
{
    form.Закрыть(true)
}

function ДеревоПриАктивизацииСтроки(Элемент)
{
    form.ЭлементыФормы.КоманднаяПанель1.Кнопки.Ок.Доступность = !!Элемент.val.ТекущиеДанные.caller
}
function ДеревоВыбор(Элемент, ВыбраннаяСтрока, Колонка, СтандартнаяОбработка)
{
    if(Элемент.val.ТекущиеДанные.caller)
        form.Закрыть(true)
}
/////////////////////////////////////////////////////////
// Разные полезняшки для кодогенераторов

// Класс для получения названий типов объекта матаданных, т.к. штатный объект ОписаниеТипов в
// режиме Конфигуратора не выдает типы, основанные на метаданных.
function TypeFinder()
{
    var types = new VBArray(metadata.current.typeList(attrTypeCategory, 1)).toArray()
    for(var i in types)
        this[types[i].clsid] = types[i].name
}

TypeFinder.prototype.getTypeString = function(mdObj)
{
    var text = []
    var types = new VBArray(mdObj.types()).toArray()
    for(var i in types)
        text.push(this[types[i]]);
    return text.join(", ")
}

// Функция, обрабатывает переданный массив строк, выравнивая в них знаки "="
function formatAssign(lines)
{
    var tabSize = profileRoot.getValue("ModuleTextEditor/TabSize")
    var ll = []
    maxEqualPos = -1
    for(var l in lines)
    {
        var line = {text: lines[l]}
        line.eqRealPos = line.text.indexOf("=")
        if(line.eqRealPos >= 0)
        {
            line.eqPosInSpaces = 0
            for(var k = 0; k < line.eqRealPos; k++)
            {
                if(line.text.charAt(k) == "\t")
                    line.eqPosInSpaces += tabSize - (line.eqPosInSpaces % tabSize)
                else
                    line.eqPosInSpaces++
            }
            if(line.eqPosInSpaces > maxEqualPos)
                maxEqualPos = line.eqPosInSpaces
        }
        ll.push(line)
    }
    var text = ""
    for(var l in ll)
    {
        var line = ll[l]
        if(line.eqRealPos < 0)
            text += line.text + "\n"
        else
            text += line.text.substr(0, line.eqRealPos) + fillLine(" ", maxEqualPos - line.eqPosInSpaces) + line.text.substr(line.eqRealPos) + "\n"
    }
    return text
}

// Получить строку одинаковых символов указанной длины
function fillLine(symbol, count)
{
    var text = ""
    if(count < 17)
    {
        while(count--)
            text += symbol
    }
    else
    {
        var part = fillLine(symbol, Math.floor(count / 2))
        text = part + part
        if(count % 2)
            text += symbol
    }
    return text
}
