/*
 *
 * Внешний вид
 *
 */

function задатьВнешнийВид()
{
    var вид = document.createElement("style");
    document.head.appendChild(вид);
    вид.innerHTML =
`
.муром-кнопка
{
    padding: 0.5em 2em 0.5em 2em;
    margin-right: 0.5em;
    float: right;
    color: #222;
    font-family: sans-serif;
    border: 1px solid #ddd;
    background-color: transparent;
    cursor: pointer;
    text-transform: uppercase;
    -webkit-transition-duration: 0.2s; /* Safari */
    transition-duration: 0.2s;
}
.муром-кнопка:hover
{
    border: 1px solid #222;
}
.муром-отступ-по-сторонам
{
    margin-left: 0.5em;
    margin-right: 0.5em;
}
`;
}

/*
 *
 * Список модулей
 *
 */

function СписокМодулей()
{
    var я = this;

    this.создатьИнтерфейс();
    this.задатьВид();
    this.выбрали = new Уведомитель();
    this.выбрали.подписать(function(){
        я.отобразитьВыбор();
    });
}
СписокМодулей.prototype.создатьИнтерфейс = function()
{
    // Помещаем таблицу в div для реализации промотки.
    this.иф = document.createElement("div");
    this.таблица = document.createElement("table");
    this.иф.appendChild(this.таблица);
};
СписокМодулей.prototype.задатьВид = function()
{
    this.иф.style.cssText =
`
overflow: auto;
height: 18.5em;
border: 1px solid #ddd;
/*
padding: 0.5em;
margin: 0.5em;
*/
`;
    this.таблица.style.cssText =
`
color: #666666;
font-family: sans-serif;
cursor: default;
border-collapse: collapse;
`;
};
СписокМодулей.prototype.очистить = function()
{
    while (this.таблица.rows.length)
    {
        this.таблица.deleteRow(0);
    };
};
СписокМодулей.prototype.добавитьЭлемент = function(статус, имя)
{
    var статусHTML = "";
    if (статус)
    {
        статусHTML = "checked";
    }

    var ряд = this.таблица.insertRow();
    var ячейка = 0;

    var номер = ряд.insertCell(ячейка++);
    номер.innerHTML = this.таблица.rows.length - 1;
    номер.style.cssText = "padding: 0.5em;";

    var вкл = ряд.insertCell(ячейка++);
    вкл.innerHTML = `<input type="checkbox" disabled ` + статусHTML + `></input>`;
    
    var название = ряд.insertCell(ячейка++);
    название.innerHTML = имя;
    название.style.cssText = "padding: 0.5em; width: 100%;";
};
СписокМодулей.prototype.отобразитьСписок = function(список)
{
    this.очистить();
    for (var номер in список)
    {
        var элемент = список[номер];
        var статус = элемент[0];
        var имя = элемент[1];
        this.добавитьЭлемент(статус, имя);
    }
};
СписокМодулей.prototype.улавливатьВыборЭлемента = function(номер)
{
    var я = this;
    
    var ряд = this.таблица.rows[номер]
    ряд.onclick = function()
    {
        я.выборРанее = я.выбор;
        я.выбор = номер;
        я.выбрали.уведомить();
    };
};
СписокМодулей.prototype.улавливатьВыбор = function()
{
    this.выборРанее = null;
    this.выбор = null;
    for (var номер = 0; номер < this.таблица.rows.length; ++номер)
    {
        this.улавливатьВыборЭлемента(номер);
    }
};
СписокМодулей.prototype.отобразитьВыбор = function()
{
    if (this.выборРанее != null)
    {
        var ряд = this.таблица.rows[this.выборРанее];
        ряд.style.backgroundColor = null;
    }
    var ряд = this.таблица.rows[this.выбор];
    ряд.style.backgroundColor = "#eee";
};
СписокМодулей.prototype.задатьСписок = function(список)
{
    this.отобразитьСписок(список);
    this.улавливатьВыбор();
};
СписокМодулей.prototype.выбрать = function(номер)
{
    var ряд = this.таблица.rows[номер];
    ряд.scrollIntoView();
    ряд.onclick();
};
СписокМодулей.prototype.обновитьЭлемент = function(номер, статус, имя)
{
    var ряд = this.таблица.rows[номер];
    ряд.cells[1].childNodes[0].checked = статус;
    ряд.cells[2].innerHTML = имя;
};
СписокМодулей.prototype.удалитьЭлемент = function(номер)
{
    var ряд = this.таблица.rows[номер];
    ряд.parentNode.removeChild(ряд);
}

/*
 *
 * Тест списка модулей
 *
 */

function ТестСпискаМодулей()
{
    this.создатьИнтерфейс();
}
ТестСпискаМодулей.prototype.создатьИнтерфейс = function()
{
    var я = this;
    
    this.иф = document.createElement("div");
    this.список = new СписокМодулей();
    this.иф.appendChild(this.список.иф);
    
    var модули = [
        [true,  "муром.загрузка_1.0.0"],
        [true,  "муром.uuid_1.0.0"],
        [true,  "Уведомитель_1.0.0"],
        [false, "uikit_3.2.0.css"],
        [false, "uikit_3.2.0.js"],
        [false, "ПанельУправления.UIKit"],
        [false, "ПанельУправления_1.0.0"],
    ];
    
    this.список.задатьСписок(модули);
    this.список.выбрать(0);
    
    this.создатьКнопку("Выбрать последний", function(){
        console.log("выбрать");
        я.список.выбрать(модули.length - 1);
    });
    this.создатьКнопку("Обновить последний", function(){
        я.список.обновитьЭлемент(модули.length - 1, true, "Новое имя");
    });
    this.создатьКнопку("Удалить последний", function(){
        я.список.удалитьЭлемент(модули.length - 1);
    });
    this.создатьКнопку("Добавить", function(){
        я.список.добавитьЭлемент(true, "Новый-599");
        var номер = я.список.таблица.rows.length - 1;
        я.список.улавливатьВыборЭлемента(номер);
        я.список.выбрать(номер);
    });
};
ТестСпискаМодулей.prototype.создатьКнопку = function(имя, реакция)
{
    var кнопка = document.createElement("button");
    кнопка.innerHTML = имя;
    this.иф.appendChild(кнопка);
    кнопка.onclick = реакция;
};

/*
 *
 * Свойства модуля
 *
 */

function СвойстваМодуля()
{
    this.создатьИнтерфейс();
    this.изменилиНомер = new Уведомитель();
    this.настроитьНомер();
    this.изменилиИмя = new Уведомитель();
    this.настроитьИмя();
    this.изменилиСтатус = new Уведомитель();
    this.настроитьСтатус();
    this.удалить = new Уведомитель();
    this.настроитьУдаление();
}
СвойстваМодуля.prototype.создатьИнтерфейс = function()
{
    this.иф = document.createElement("div");
    this.иф.style.cssText =
`
border: 1px solid #ddd;
/*
padding: 0.5em;
margin: 0.5em;
*/
color: #666666;
font-family: sans-serif;
`;
    this.таблица = document.createElement("table");
    this.иф.appendChild(this.таблица);
};
Object.defineProperty(СвойстваМодуля.prototype, "номер", {
    get: function()
    {
        return Number(this.полеНомер.value);
    },
    set: function(значение)
    {
        this.полеНомер.value = значение;
    }
});
СвойстваМодуля.prototype.настроитьНомер = function()
{
    var я = this;
    
    var ряд = this.таблица.insertRow();
    var ячейка = 0;

    var ключ = ряд.insertCell(ячейка++);
    ключ.innerHTML = "Номер:";
    ключ.style.cssText = "padding: 0.5em;";

    var значение = ряд.insertCell(ячейка++);
    this.полеНомер = document.createElement("input");
    this.полеНомер.type = "number";
    this.полеНомер.min = 0;
    значение.style.cssText = "width: 100%; padding: 0.5em;";
    this.полеНомер.style.cssText = "width: 100%;";
    значение.appendChild(this.полеНомер);
    
    this.полеНомер.oninput = function()
    {
        я.изменилиНомер.уведомить();
    };
};
Object.defineProperty(СвойстваМодуля.prototype, "имя", {
    get: function()
    {
        return this.полеИмя.value;
    },
    set: function(значение)
    {
        this.полеИмя.value = значение;
    }
});
СвойстваМодуля.prototype.настроитьИмя = function()
{
    var я = this;

    var ряд = this.таблица.insertRow();
    var ячейка = 0;

    var ключ = ряд.insertCell(ячейка++);
    ключ.innerHTML = "Имя:";
    ключ.style.cssText = "padding: 0.5em;";

    var значение = ряд.insertCell(ячейка++);
    this.полеИмя = document.createElement("input");
    значение.style.cssText = "width: 100%; padding: 0.5em;";
    this.полеИмя.style.cssText = "width: 100%;";
    значение.appendChild(this.полеИмя);

    this.полеИмя.oninput = function()
    {
        я.изменилиИмя.уведомить();
    };
};
Object.defineProperty(СвойстваМодуля.prototype, "статус", {
    get: function()
    {
        return this.переключатель.checked;
    },
    set: function(значение)
    {
        this.переключатель.checked = значение;
    }
});
СвойстваМодуля.prototype.настроитьСтатус = function()
{
    var я = this;
    
    var ряд = this.таблица.insertRow();
    var ячейка = 0;
    
    var ключ = ряд.insertCell(ячейка++);
    ключ.innerHTML = "Исполнять:";
    ключ.style.cssText = "padding: 0.5em;";

    var значение = ряд.insertCell(ячейка++);
    this.переключатель = document.createElement("input");
    this.переключатель.type = "checkbox";
    this.переключатель.style.cssText = "padding: 0.5em;";
    значение.appendChild(this.переключатель);

    this.переключатель.onchange = function()
    {
        я.изменилиСтатус.уведомить();
    };
    ключ.onclick = function()
    {
        я.переключатель.checked = !я.переключатель.checked;
        я.изменилиСтатус.уведомить();
    };
};
СвойстваМодуля.prototype.настроитьУдаление = function()
{
    var я = this;
    
    var ряд = this.таблица.insertRow();
    var ячейка = 0;

    ряд.insertCell(ячейка++);
    var значение = ряд.insertCell(ячейка++);

    this.кнопкаУдалить = document.createElement("button");
    this.кнопкаУдалить.innerHTML = "Удалить";
    this.кнопкаУдалить.classList.add("муром-кнопка");
    значение.appendChild(this.кнопкаУдалить);
    
    this.кнопкаУдалить.onclick = function()
    {
        я.удалить.уведомить();  
    };
};

/*
 *
 * Тест свойства модуля
 *
 */
 
function ТестСвойстваМодуля()
{
    this.создатьИнтерфейс();
}
ТестСвойстваМодуля.prototype.создатьИнтерфейс = function()
{
    var я = this;
    
    this.иф = document.createElement("div");
    this.свойства = new СвойстваМодуля();
    this.иф.appendChild(this.свойства.иф);

    this.свойства.изменилиНомер.подписать(function(){
        console.log("номер: '" + я.свойства.номер + "'");
    });
    this.свойства.изменилиИмя.подписать(function(){
        console.log("имя: '" + я.свойства.имя + "'");
    });
    this.свойства.изменилиСтатус.подписать(function(){
        console.log("статус: '" + я.свойства.статус + "'");
    });
    this.свойства.удалить.подписать(function(){
        console.log("удалить модуль '" + я.свойства.имя + "'");
    });
};

/*
 *
 * Модули
 *
 */

function Модули()
{
    
}
Модули.prototype.свойства = function(номер)
{
    return murom.moduleProperties(номер);
};
Модули.prototype.задатьСвойства = function(номер, свойства)
{
    var м = муром.модули[номер];
    м[2] = свойства;
};
Модули.prototype.статус = function(номер)
{
    return murom.moduleStatus(номер);
};
Модули.prototype.задатьСтатус = function(номер, статус)
{
    var св = this.свойства(номер);
    св["status"] = статус;
    this.задатьСвойства(номер, св);
};
Модули.prototype.задатьИмя = function(номер, имя)
{
    var м = муром.модули[номер];
    м[0] = имя;
};
Модули.prototype.задатьНомер = function(старый, новый)
{
    //console.log("задать номер. '" + старый + "' -> '" + новый + "'");
    var модуль = муром.модули[старый];
    // Удаляем старую запись.
    муром.модули.splice(старый, 1);
    // Добавляем модуль в новую позицию.
    муром.модули.splice(новый, 0, модуль);
};

/*
 *
 * Панель управления
 *
 */

function ПанельУправления()
{
    this.модули = new Модули();
    this.создатьОснову();
    this.создатьСохранениеСкачиваниеДобавление();
    this.создатьСписокМодулей();
    this.создатьСвойстваМодуля();
}
ПанельУправления.prototype.создатьОбёрткуЯчейку = function()
{
    var обёртка = document.createElement("table");
    обёртка.style.cssText = "width: 100%;";
    var ряд = обёртка.insertRow();
    var ячейка = ряд.insertCell();
    return [обёртка, ячейка];
};
ПанельУправления.prototype.создатьОснову = function()
{
    this.иф = document.createElement("table");
    this.иф.style.cssText = "width: 100%;";
    var ряд = this.иф.insertRow();
    this.лево = ряд.insertCell();
    this.лево.style.cssText = "width: 100%;";
    var право = ряд.insertCell();
    право.style.cssText = "height: 100%;";
    this.кнопки = document.createElement("table");
    this.кнопки.style.cssText = "height: 100%;";
    право.appendChild(this.кнопки);
    ряд = this.иф.insertRow();
    this.низ = ряд.insertCell();
    this.низ.colSpan = 2;
};
ПанельУправления.prototype.создатьСписокМодулей = function()
{
    this.список = new СписокМодулей();
    this.список.задатьСписок(this.списокМодулей());
    var оя = this.создатьОбёрткуЯчейку();
    this.лево.appendChild(оя[0]);
    оя[1].appendChild(this.список.иф);
};
ПанельУправления.prototype.создатьСвойстваМодуля = function()
{
    this.свойства = new СвойстваМодуля();
    оя = this.создатьОбёрткуЯчейку();
    this.низ.appendChild(оя[0]);
    оя[1].appendChild(this.свойства.иф);
};
ПанельУправления.prototype.списокМодулей = function()
{
    var список = [];
    for (var номер in муром.модули)
    {
        var м = муром.модули[номер];
        var статус = this.модули.статус(номер);
        var имя = м[0];
        var элемент = [статус, имя];
        список.push(элемент);
    }
    
    return список;
};
ПанельУправления.prototype.создатьКнопку = function(имя, уведомитель)
{
    var кнопка = document.createElement("button");
    кнопка.innerHTML = имя;
    кнопка.style.cssText = "width: 100%;";
    кнопка.classList.add("муром-кнопка");
    кнопка.onclick = function()
    {
        уведомитель.уведомить();  
    };
    
    return кнопка;
};
ПанельУправления.prototype.создатьСохранениеСкачиваниеДобавление = function()
{
    var я = this;
    
    var ряд = this.кнопки.insertRow();
    var ячейка = ряд.insertCell();
    this.сохранить = new Уведомитель();
    this.кнопкаСохранить = this.создатьКнопку("Сохранить", this.сохранить);
    ячейка.appendChild(this.кнопкаСохранить);
    
    ряд = this.кнопки.insertRow();
    ячейка = ряд.insertCell();
    this.скачать = new Уведомитель();
    this.кнопкаСкачать = this.создатьКнопку("Скачать", this.скачать);
    ячейка.appendChild(this.кнопкаСкачать);
    
    // Пробел.
    ряд = this.кнопки.insertRow();
    ячейка = ряд.insertCell();
    ячейка.style.cssText = "height: 100%;";

    ряд = this.кнопки.insertRow();
    ячейка = ряд.insertCell();
    this.добавить = new Уведомитель();
    this.кнопкаДобавить = this.создатьКнопку("Добавить", this.добавить);
    ячейка.appendChild(this.кнопкаДобавить);
};
ПанельУправления.prototype.имяФайла = function()
{
    var путь = window.location.pathname;
    var имя = путь.split("/").pop();
    return decodeURI(имя);
};

function запуститьПУ()
{
    var пу = new ПанельУправления();
    муром.пу = пу;
    var области = муром.создатьЛевуюПравуюОбласти();
    var по = области[1];
    по.appendChild(пу.иф);
    муром.создатьРедакторВЛевойОбласти();
    var список = пу.список;
    var свойства = пу.свойства;
    var модули = пу.модули;
    
    function отобразитьКодВыбранногоМодуля()
    {
        var модуль = муром.модули[список.выбор];
        var код = муром.atob(модуль[1]);
        муром.редактор.session.setValue(код);
    }
    function отобразитьСвойстваВыбранногоМодуля()
    {
        var модуль = муром.модули[список.выбор];
        
        свойства.номер = список.выбор;
        свойства.имя = модуль[0];
        свойства.статус = пу.модули.статус(список.выбор);
    }
    список.выбрали.подписатьМного([
        отобразитьКодВыбранногоМодуля,
        отобразитьСвойстваВыбранногоМодуля,
    ]);
    
    function обновитьСтатусМодуля()
    {
        var номер = список.выбор;
        var имя = свойства.имя;
        var статус = свойства.статус;
        модули.задатьСтатус(номер, статус);
        список.обновитьЭлемент(номер, статус, имя);
    }
    свойства.изменилиСтатус.подписать(обновитьСтатусМодуля);
    
    function обновитьИмяМодуля()
    {
        var номер = список.выбор;
        var имя = свойства.имя;
        var статус = свойства.статус;
        модули.задатьИмя(номер, имя);
        список.обновитьЭлемент(номер, статус, имя);
    }
    свойства.изменилиИмя.подписать(обновитьИмяМодуля);
    
    function обновитьНомерМодуля()
    {
        var старый = список.выбор;
        var новый = свойства.номер;
        if (старый == новый)
        {
            return;
        }
        if (новый > муром.модули.length - 1)
        {
            новый = муром.модули.length - 1;
        }
        модули.задатьНомер(старый, новый);
        список.задатьСписок(пу.списокМодулей());
        список.выбрать(новый);
    }
    свойства.изменилиНомер.подписать(обновитьНомерМодуля);
    
    function добавитьМодуль()
    {
        var число = Math.floor(Math.random() * Math.floor(1000));
        var имя = "новый-" + число; 
        var код = `console.log("НАДО Добавить код в модуль '` + имя + `'");`;
        var модуль = [имя, муром.btoa(код)];
        муром.модули.push(модуль);
        var модули = пу.списокМодулей();
        список.задатьСписок(модули);
        список.выбрать(модули.length - 1);
    }
    пу.добавить.подписать(добавитьМодуль);
    
    function удалитьМодуль()
    {
        var номер = список.выбор;
        
        var статус = пу.модули.статус(номер);
        if (статус)
        {
            alert("ОШИБКА Удалить можно лишь неисполняемый модуль");
            return;
        }
        
        // Удалить выбранный модуль.
        муром.модули.splice(номер, 1);
        --номер;
        if (номер < 0)
        {
            номер = 0;
        }
        var модули = пу.списокМодулей();
        список.задатьСписок(модули);
        список.выбрать(номер);
    }
    свойства.удалить.подписать(удалитьМодуль);
    
    function сохранитьВыбранныйМодуль()
    {
        var модуль = муром.модули[список.выбор];
        var код = муром.редактор.session.getValue();
        модуль[1] = муром.btoa(код);
    }
    function сохранить()
    {
        пу.кнопкаСохранить.disabled = true;
        localforage.setItem("modules", муром.модули, function(ошибка, значение){
            пу.кнопкаСохранить.disabled = false;
            if (ошибка)
            {
                console.error("Не удалось сохранить модули: '" + ошибка + "'");
            }
        });
    }
    пу.сохранить.подписатьМного([
        сохранитьВыбранныйМодуль,
        сохранить,
    ]);

    // How to create a file in memory for user to download, but not through server?
    // https://stackoverflow.com/a/18197341
    function скачать()
    {
        var содержимое = муром.файл.начало;
        for (var номер in муром.модули)
        {
            var модуль = муром.модули[номер];
            var имя = модуль[0];
            var код64 = модуль[1];
            var свойства = модули.свойства(номер);
            содержимое +=
`

[
"` + имя + `",
"` + код64 + `",
`
+
JSON.stringify(свойства)
+
`
],
`
;
        }
        содержимое += муром.файл.конец;
        содержимое = муром.btoa(содержимое);
    
        var ссыль = document.createElement("a");
        ссыль.setAttribute("href", "data:text/html;charset=utf-8;base64," + содержимое);
        var имя = пу.имяФайла();
        ссыль.setAttribute("download", имя);
        ссыль.style.display = "none";
        document.body.appendChild(ссыль);
        ссыль.click();
        document.body.removeChild(ссыль);
    }
    пу.скачать.подписать(скачать);

    // При запуске.
    список.выбрать(0);
}

/*
 *
 * Пуск
 *
 */

if (window.location.search == "?0")
{
    console.debug("Запуск панели управления");
    задатьВнешнийВид();
    запуститьПУ();
    console.debug("Панель управления запущена")
}
