var ресурсы = [
    [БАЗА + "модели/фишка/2019-09-08.osgt", "mod"],
    [БАЗА + "текстуры/заглушка.png", "tex.stub"],
    [БАЗА + "шейдеры/освещение-изображение.vert", "ver"],
    [БАЗА + "шейдеры/освещение-изображение.frag", "fra"],
    [БАЗА + "раскладки/X_shaped.layout", "lay"],

    [БАЗА + "классы/Раскладка/2019-08-16.js", "Layout"],
    [БАЗА + "классы/Фишка/2019-09-07.js", "Tile"],
    [БАЗА + "темыФишек/заглушка/2019-09-08.js", "theme.stub"],
];

мж.начали = new Уведомитель();
мж.начать = function()
{
    муром.камера.позиция = [0, -70, 0];
    муром.камера.вращение = [90, 0, 0];
    мж.сцена = муром.узлы.создатьСферу("sce", 0);
    мж.сцена.вращение = [60, 0, 0];
    var мир = муром.узлы.узел("mir");
    мир.добавитьДитя(мж.сцена);
    
    мж.начали.уведомить();
};

мж.задатьНейтральныйМатериал = function()
{
    var мат = муром.материалы.создатьМатериал("N");
    var изо = муром.ресурсы.ресурс("tex.stub");
    мат.задатьТекстуру("image", изо);
    var вер = муром.ресурсы.ресурс("ver").содержимое;
    var фра = муром.ресурсы.ресурс("fra").содержимое;
    мат.задатьШейдеры(вер, фра);
    мж.сцена.задатьМатериал(мат);
};

мж.разобратьРаскладку = function()
{
    eval(муром.ресурсы.ресурс("Layout").содержимое);
    
    var содержимое = муром.ресурсы.ресурс("lay").содержимое;
    мж.раскладка = new Раскладка();
    мж.раскладка.разобрать(содержимое);
};

мж.фишки = [];
мж.создатьФишки = function()
{
    eval(муром.ресурсы.ресурс("Tile").содержимое);
    
    for (var номер in мж.раскладка.позиции)
    {
        var ф = new Фишка();
        ф.позиция = мж.раскладка.позиции[номер];
        мж.фишки.push(ф);
    }
};

мж.размерФишки = {
    "ширина": 2.0,
    "высота": 3.0,
    "глубина": 1.0,
};
мж.создатьУзлыФишек = function()
{
    const шагФишки = 2.0;
    const коэффициенты = {
        "x": мж.размерФишки.ширина / шагФишки,
        "y": -мж.размерФишки.высота / шагФишки,
        "z": мж.размерФишки.глубина,
    };
    var мод = муром.ресурсы.ресурс("mod");
    
    for (var номер in мж.фишки)
    {
        var имя = номер.toString();
        var узел = муром.узлы.создатьУзел(имя, мод);
        мж.сцена.добавитьДитя(узел);
        
        var ф = мж.фишки[номер];
        var п = ф.позиция;
        узел.позиция = [
            п[2] * коэффициенты.x,
            п[1] * коэффициенты.y,
            п[0] * коэффициенты.z,
        ];
        ф.узел = узел;
    }
};

мж.центрироватьСцену = function()
{
    var границы = {
        "лево": 1000,
        "право": -1000,
        "верх": -1000,
        "низ": 1000,
    };
    for (var номер in мж.фишки)
    {
        const ф = мж.фишки[номер];
        const x = ф.узел.позиция[0];
        const y = ф.узел.позиция[1];
        if (x < границы.лево)
        {
            границы.лево = x;
        }
        if (x > границы.право)
        {
            границы.право = x;
        }
        if (y < границы.низ)
        {
            границы.низ = y;
        }
        if (y > границы.верх)
        {
            границы.верх = y;
        }
    }

    const ширина = границы.право - границы.лево + мж.размерФишки.ширина;
    const высота = границы.верх - границы.низ + мж.размерФишки.высота;
    мж.сцена.позиция = [-ширина / 2.0, 0, высота / 2.0];
};

// http://www.rubl.com/rules/mahjong-solitaire-rules.html
мж.задатьФишкамГруппыПоследовательно = function()
{
    var группы = [];
    // Генерируем группы.
    const группВсего = 42;
    const группПо4Дубля = 34;
    for (var г = 0; г < группВсего; ++г)
    {
        const четыреДубля = (г < группПо4Дубля);
        const колвоДублей = четыреДубля ? 4 : 1;
        for (var д = 0; д < колвоДублей; ++д)
        {
            группы.push(г);
        }
    }
    // Задаём.
    for (var номер in мж.фишки)
    {
        var ф = мж.фишки[номер];
        ф.группа = Number(группы[номер]);
    }
};

мж.применитьТемуФишек = function()
{
    eval(муром.ресурсы.ресурс("theme.stub").contents);
    const R = RR();
    
    // Создать текстуры.
    var обозначения = [];
    var текстуры = [];
    for (var номер in R)
    {
        var обозначение = R[номер][0];
        обозначения.push(обозначение);
        var имя = "tile.tex/" + обозначение;
        var содержимое = R[номер][1];
        var текстура = муром.ресурсы.создатьРесурс(имя, содержимое);
        текстуры.push(текстура);
    }
    
    // Создать материалы.
    var нейтраль = [];
    var выбор = [];
    var вер = муром.ресурсы.ресурс("ver").содержимое;
    var фра = муром.ресурсы.ресурс("fra").содержимое;
    // Нейтраль.
    for (var номер = 0; номер < 42; ++номер)
    {
        var имя = "tile.mat/" + обозначения[номер];
        var изо = текстуры[номер];
        var мат = муром.материалы.создатьМатериал(имя);
        мат.задатьТекстуру("image", изо);
        мат.задатьШейдеры(вер, фра);
        нейтраль.push(мат);
    }
    // Выбор.
    for (var номер = 42; номер < 83; ++номер)
    {
        var имя = "tile.mat/" + обозначения[номер];
        var изо = текстуры[номер];
        var мат = муром.материалы.создатьМатериал(имя);
        мат.задатьТекстуру("image", изо);
        мат.задатьШейдеры(вер, фра);
        выбор.push(мат);
    }

    // Применить тему.
    for (var номер in мж.фишки)
    {
        var ф = мж.фишки[номер];
        ф.нейтраль = нейтраль[ф.группа];
        ф.выбор = выбор[ф.группа];
        
        ф.показатьНейтраль();
    }
};

мж.маскаВыбора = 0x2;
мж.сделатьФишкиВыбираемыми = function()
{
    for (var номер in мж.фишки)
    {
        var ф = мж.фишки[номер];
        ф.узел.задатьМаску(мж.маскаВыбора);
    }
}

мж.индексПозиции = function(п)
{
    return п[0] * 1000000 + п[1] * 1000 + п[2];
};

мж.индексПозиций = {};
мж.проиндексироватьПозиции = function()
{
    for (var номер in мж.фишки)
    {
        var ф = мж.фишки[номер];
        var и = мж.индексПозиции(ф.позиция);
        мж.индексПозиций[и] = true;
    }
};

мж.естьСоседи = function(позиция, смещениеПоля, смещениеСтолбца)
{
    for (var смещениеРяда = -1; смещениеРяда <= 1; ++смещениеРяда)
    {
        var сосед = [
            Number(позиция[0]) + смещениеПоля,
            Number(позиция[1]) + смещениеРяда,
            Number(позиция[2]) + смещениеСтолбца,
        ];
        var и = мж.индексПозиции(сосед);
        if (и in мж.индексПозиций)
        {
            return true;
        }
    }
    
    // Соседей нет.
    return false;
};

мж.можноВыбратьФишку = function(ф)
{
    // Проверяем наличие фишек с левой и правой сторон одновременно.
    var слева = this.естьСоседи(ф.позиция, 0, -2);
    var справа = this.естьСоседи(ф.позиция, 0, 2);
    if (слева && справа)
    {
        return false;
    }
    
    // Проверяем наличие фишек непосредственно сверху.
    for (var смещение = -1; смещение <= 1; ++смещение)
    {
        if (this.естьСоседи(ф.позиция, 1, смещение))
        {
            return false;
        }
    }
    
    // Фишка не заблокирована.
    return true;
};

мж.номерВыбраннойФишки = null;
мж.выбраннаяФишка = null;
мж.выбранаФишка = new Уведомитель();
мж.выбратьФишку = function()
{
    // Определить щелчок.
    if (муром.мышь.нажатыеКнопки.length == 1)
    {
        var узел =
            муром.камера.узелВПозиции(
                муром.мышь.позиция,
                мж.маскаВыбора
            );
        if (узел)
        {
            var номер = Number(узел.имя);
            var ф = мж.фишки[номер];
            if (мж.можноВыбратьФишку(ф))
            {
                мж.номерВыбраннойФишки = номер;
                мж.выбраннаяФишка = ф;
                мж.выбранаФишка.уведомить();
            }
        }
    }
};

мж.отладитьВыборФишки = function()
{
    мж.выбранаФишка.подписать(function(){
        console.log(
            "Выбор. Номер: '" +
            мж.номерВыбраннойФишки +
            "' Группа: '" +
            мж.выбраннаяФишка.группа +
            "'"
        );
    });
};

мж.показатьВыбраннуюФишку = function()
{
    мж.выбраннаяФишка.показатьВыбор();
};

мж.выбранныеФишки = [];
мж.фишкиРазличаются = new Уведомитель();
мж.фишкиСовпадают = new Уведомитель();
мж.фишкиСравнили = new Уведомитель();
мж.сравнитьВыбранныеФишки = function()
{
    // Собираем.
    мж.выбранныеФишки.push(мж.выбраннаяФишка);
    // Удостоверяемся в наличии пары фишек.
    if (мж.выбранныеФишки.length != 2)
    {
        return;
    }
    var ф1 = мж.выбранныеФишки[0];
    var ф2 = мж.выбранныеФишки[1];
    // Убираем дубликат при двойном выборе одной фишки.
    if (ф1.имя == ф2.имя)
    {
        мж.выбранныеФишки.shift();
        return;
    }
    // Сравниваем.
    if (ф1.группа == ф2.группа)
    {
        мж.фишкиСовпадают.уведомить();
    }
    else
    {
        мж.фишкиРазличаются.уведомить();
    }
    мж.фишкиСравнили.уведомить();
};

мж.отладитьСравнениеФишек = function()
{
    мж.фишкиСовпадают.подписать(function(){
        console.log("Фишки совпадают");
    });
    мж.фишкиРазличаются.подписать(function(){
        console.log("Фишки различаются");
    });
};

мж.скрытьСовпадающиеФишки = function()
{
    мж.выбранныеФишки[0].скрыть();
    мж.выбранныеФишки[1].скрыть();
};

мж.убратьСовпадающиеФишки = function()
{
    var ф1 = мж.выбранныеФишки[0];
    var ф2 = мж.выбранныеФишки[1];
    var и1 = мж.индексПозиции(ф1.позиция);
    var и2 = мж.индексПозиции(ф2.позиция);
    delete мж.индексПозиций[и1];
    delete мж.индексПозиций[и2];
};

мж.очиститьОтображениеВыбора = function()
{
    мж.выбранныеФишки[0].показатьНейтраль();
    мж.выбранныеФишки[1].показатьНейтраль();
};

мж.очиститьВыбор = function()
{
    мж.номерВыбраннойФишки = 0;
    мж.выбраннаяФишка = null;
    мж.выбранныеФишки = [];
};

мж.оставшиесяФишки = [];
мж.задатьОставшиесяФишки = function()
{
    мж.оставшиесяФишки = мж.фишки.slice();
};

мж.обновилиОставшиесяФишки = new Уведомитель();
мж.обновитьОставшиесяФишки = function()
{
    var и1 = мж.оставшиесяФишки.indexOf(мж.выбранныеФишки[0]);
    мж.оставшиесяФишки.splice(и1, 1);
    var и2 = мж.оставшиесяФишки.indexOf(мж.выбранныеФишки[1]);
    мж.оставшиесяФишки.splice(и2, 1);

    мж.обновилиОставшиесяФишки.уведомить();
};

мж.доступныеДляВыбораФишки = function()
{
    var фишки = [];
    for (var номер in мж.оставшиесяФишки)
    {
        var ф = мж.оставшиесяФишки[номер];
        if (мж.можноВыбратьФишку(ф))
        {
            фишки.push(ф);
        }
    }
    
    return фишки;
};

мж.естьХод = function()
{
    var фишки = мж.доступныеДляВыбораФишки();
    for (var н1 in фишки)
    {
        for (var н2 in фишки)
        {
            var ф1 = фишки[н1];
            var ф2 = фишки[н2];
            if (
                (ф1.имя != ф2.имя) &&
                (ф1.группа == ф2.группа)
            ) {
                return true;
            }
        }
    }
    
    return false;
}

мж.победа = new Уведомитель();
мж.поражение = new Уведомитель();
мж.проверитьЗавершение = function()
{
    var кончилисьФишки = (мж.оставшиесяФишки.length == 0);
    if (кончилисьФишки)
    {
        мж.победа.уведомить();
        return;
    }
    
    if (!мж.естьХод())
    {
        мж.поражение.уведомить();
    }
};

мж.отладитьЗавершение = function()
{
    мж.победа.подписать(function(){
        console.log("Игра завершена. ПОБЕДА!");
    });
    мж.поражение.подписать(function(){
        console.log("Игра завершена. ПОРАЖЕНИЕ :(");
    });
};

мж.задатьОтображениеЗавершения = function()
{
    мж.победа.подписать(function(){
        муром.камера.цветОчистки = [0.2, 0.5, 0.2];
    });
    мж.поражение.подписать(function(){
        муром.камера.цветОчистки = [0.5, 0.2, 0.2];
    });
};
