//ДЗ: Functional OOP
//Password
//LoginForm
//LoginForm Constructor
//Password Verify
let wrapper = document.querySelector(".wrapper");     // Сюда буду создавать поле ввода для пароля

function Password(parent, open){                      // Функция конструктор
    let container = document.createElement("div");    // Создаю контейнер для инпутов
    let button    = document.createElement("button"); // Создание кнопки
        button.disabled = true;                       // Отключаю кнопку т.к. при создании формы инпут логина по умолчанию пустой
    let openCheck = open;                             // Переменная с которой я буду сравнивать открытость текста в поле ввода

    let buildInputs = function(type, innerText) {     // Функция для создания одних и тех же инпутов с разными типами
        let input = document.createElement("input");
        let label = document.createElement("label");

        input.type = type;
        label.innerText = innerText;
        label.appendChild(input);

        return label;
    }

    let toggleHiddenPassword = function(type, open) { // Функция для переключения состояния инпута с паролем с видимого на невидимый и переключение чекбокса
        inputPassword.type = type;
        inputCheckbox.checked = open;
    };

    let toggleHiddenCheckPassword = function(check) { // Функция для скрытия повтора пароля если Password в открытом режиме
        if(check) {
            container.removeChild(checkPasswordLabel);
        } else {
            container.insertBefore(checkPasswordLabel, container.children[2]);
        }
    };

    let verifyPassword = function(additional = true) { // Проверка на наличие символов в логине и пароле, если в одном из полей пусто то кнопка disabled
        if(inputLogin.value.length > 0 && inputPassword.value.length > 0 && additional) {
            button.disabled = false;
        } else {
            button.disabled = true;
        }
    }

    container.appendChild(buildInputs("login", "Login")); // Собираю форму ввода
    container.appendChild(buildInputs("password", "Password"));
    container.appendChild(buildInputs("password", "Повторите пароль")).classList.add("check-password"); // Тут добавил класс что бы различать два инпута, type = password, друг от друга
    container.appendChild(buildInputs("checkbox", "Показать пароль"));
    container.appendChild(button).innerText = "Отправить";
    parent.appendChild(container);

    let inputLogin         = container.querySelector("input[type='login']"); // Нахожу все инпуты и присваиваю их в переменные для дальнейшей работы с ними
    let inputPassword      = container.querySelector("input[type='password']");
    let inputCheckPassword = container.querySelector(".check-password input");
    let checkPasswordLabel = inputCheckPassword.parentElement;
    let inputCheckbox      = container.querySelector("input[type='checkbox']");

    open == true ? toggleHiddenPassword("text", true) : toggleHiddenPassword("password", false); // Один раз запускаю функцию toggleHiddenPassword для корректной отрисовки инпутов в зависимости от переданных параметров в конструкторе
    if(open == true) {   // Скрываю inputCheckPassword если конструктор вызвали с параметром open = true, то есть когда Password в открытом режиме 
        container.removeChild(container.querySelector(".check-password"));
    }

    this.setValue = function(value) {
        inputPassword.value = value;
    };

    this.getValue = function() {
        return inputPassword.value;
    };

    this.setOpen = function(hidden) {
        hidden == true ? toggleHiddenPassword("text", true) : toggleHiddenPassword("password", false);
        openCheck = hidden;
        toggleHiddenCheckPassword(hidden);
    };

    this.getOpen = function() {
        return openCheck;
    };

    container.oninput = (evt) => {                                         // Навешиваю слушатель события на весь контейнер, а не на каждый инпут в отдельности
        if(evt.target.type == "text" || evt.target.type == "password") {   // Тут идет проверка что изменения происходят на инпутах типа text или password для передачи value в onChange
            this.onChange(evt.target.value);
        } else {                                                           // Если эти изменения в инпуте с другим типом (Остается только чекбокс) то я запускаю setOpen с противоположным значением openCheck, как бы переключаю значение на противоположное
            this.setOpen(!openCheck);
            this.onOpenChange(openCheck);
        }

        if(openCheck == true) {   // Тут идет проверка, если Password в открытом режиме то мне не нужно проверять на совпадение value у inputPassword и inputCheckPassword
            verifyPassword();
        } else {
            verifyPassword(inputPassword.value == inputCheckPassword.value);
        }
    };
};

let p = new Password(wrapper, true);

p.onChange = data => console.log(data);
p.onOpenChange = open => console.log(open);

p.setValue('qwerty');
console.log(p.getValue());

p.setOpen(false);
console.log(p.getOpen());


//Form
//Отображение
//Sync
//Validators
//Many Inputs
//Validators messages
//OkButton
//CancelButton
let formContainer = document.querySelector(".form-container"); // Контейнер для формы

function Form(el, data, okCallback, cancelCallback){
    let formBody = document.createElement('div')
    let okButton = document.createElement('button')
    let table    = document.createElement("table"); // Создаю таблицу, в ней буду отрисовывать key и value из data
    let copyData = data;                            // Копия объекта data для возможности перейти к дефолтным значениям
    okButton.innerHTML = 'OK'

    let cancelButton = document.createElement('button')
    cancelButton.innerHTML = 'Cancel'

    formBody.innerHTML = '<h1>тут будет форма после перервы</h1>'
    if (typeof okCallback === 'function'){
        formBody.appendChild(okButton);
        okButton.onclick = (e) => {
            console.log(this)
            this.okCallback(this.data) // Отдаю текущий поредактированный объект data первым параметром в okCallback
        }
    }

    if (typeof cancelCallback === 'function'){
        formBody.appendChild(cancelButton);
        cancelButton.onclick = cancelCallback
    }

    let trCreator = function(key, value, trElement, labelElement, inputElement, inputType) { // Функция для корректной сборки таблицы и расположению в ней key и value
        for(let i = 0; i < 2; i++) {                
            let td = document.createElement("td");

            if(i == 0) {                            // В tr нужно поместить два элемента tb, в первом должен быть label с key внутри, а во втором input, собсна тут я этим и занимаюсь
                labelElement.innerText = key;
                labelElement.htmlFor   = key;
                td.appendChild(labelElement);
            } else {
                inputElement.value = value;
                inputElement.id    = key;
                inputElement.type  = inputType;
                td.appendChild(inputElement);
            }

            trElement.appendChild(td);
        }

        return trElement;
    };

    let inputCreators = {
        String(key, value, oninput){
            let tr    = document.createElement("tr");   
            let label = document.createElement("label");
            let input = document.createElement("input");

            input.oninput = () => oninput(input.value);

            return trCreator(key, value, tr, label, input, "text");
        },
        Boolean(key, value, oninput){
            let tr    = document.createElement("tr");   
            let label = document.createElement("label");
            let input = document.createElement("input");

            if(value == true) {
                input.checked = true;
            }

            input.oninput = () => oninput(input.checked);

            return trCreator(key, value, tr, label, input, "checkbox");
        },
        Date(key, value, oninput){
            let tr    = document.createElement("tr");   
            let label = document.createElement("label");
            let input = document.createElement("input");

            let timespan = value.getTime();
            let dateValue = ((new Date(timespan - value.getTimezoneOffset() * 60 * 1000)).toISOString()).slice(0, -14);

            input.oninput = () => oninput(new Date(input.value));

            return trCreator(key, dateValue, tr, label, input, "date");
        }
    }

    for(let [key, value] of Object.entries(data)) {                        // Итерирую объект data и создаю для каждой пары ключ-значение input
        let inputCreatorFunction = inputCreators[value.constructor.name];

        let tr = inputCreatorFunction(key, value, (newValue) => {
            if(this.validators[key] != undefined) {                 // Если this.validator[key] не равен undefined для этого input предусмотрена валидация и поэтому ее нужно запустить
                if(typeof(this.validators[key](newValue, key, data, tr.querySelector(`#${key}`))) == "string") { // Если все это чудо вернуло тип данных который равен "String" то значит поле не прошло валидацию
                    let span = document.createElement("span");                                                   // Тут будет лежать текст ошибки
                        span.innerText = this.validators[key](newValue, key, data, tr.querySelector(`#${key}`)); // Собсна пишу сам текст ошибки в span
                        span.style.position = "absolute";                                                        // Задаю спану absolute что бы табличка не скакала когда я его добавлю в tr

                    tr.style.backgroundColor = "red";
                    tr.appendChild(span);

                    okButton.disabled = true; // Отключаю кнопку okButton если форма не прошла валидацию
                } else {
                    tr.style.backgroundColor = "inherit";
                    data[key] = newValue;
                    if(tr.querySelector("span") != null) {                                                        // Тут идет проверка на наличие span с ошибкой, если его нет то удалять не нужно
                        tr.removeChild(tr.querySelector("span"));

                        okButton.disabled = false; // Включаю кнопку okButton если форма прошла валидацию
                    }
                };
            } else {
                data[key] = newValue;
            }
        });
        
        table.appendChild(tr);
    }

    formBody.insertBefore(table, formBody.children[1]);
    el.appendChild(formBody);

    this.okCallback     = okCallback
    this.cancelCallback = cancelCallback

    this.data           = data
    this.validators     = {}
}

let form = new Form(formContainer, {
    name: 'Anakin',
    surname: 'Skywalker',
    married: true,
    birthday: new Date((new Date).getTime() - 86400000 * 30*365)
}, () => console.log('ok'),() => console.log('cancel') )
form.okCallback = (e) => console.log(e);

form.validators.surname = (value, key, data, input) => value.length > 2 && 
                                                     value[0].toUpperCase() == value[0] &&
                                                    !value.includes(' ') ? true : 'Wrong name'
console.log(form)