
// passwordWrapp()
function passwordWrapp() {

   // в классе ниже коллбэки расположены в ивентлистенерах, что неправильно, 
   // их нужно размещать в сеттерах, а в ивентлистеннерах вызывать сеттеры

   // function Password(parent=document.body, open=false) {
   //    const passField = document.createElement('input')
   //    const checkBox = document.createElement('input')
   //    checkBox.type = 'checkbox'
   //    parent.append(passField)
   //    parent.append(checkBox)
   //    this.setValue = (newValue) => {
   //       passField.value = newValue
   //    }
   //    this.getValue = () => passField.value
   //    this.setOpen = (newOpen) => {
   //       open = newOpen
   //       if (open === true) {
   //          checkBox.checked = true
   //          passField.type = 'text'
   //       } else if (open === false) {
   //          checkBox.checked = false
   //          passField.type = 'password'
   //       }
   //    }
   //    this.setOpen(open)
   //    this.getOpen = () => checkBox.checked
   //    passField.oninput = () => {
   //       if (typeof this.onChange === 'function') {
   //          this.onChange(this.getValue())
   //       }      
   //    }
   //    checkBox.oninput = () => {
   //       if (this.getOpen() === true) {
   //          this.setOpen(true)
   //       } else {
   //          this.setOpen(false)
   //       }
   //       if (typeof this.onOpenChange === 'function') {
   //          this.onOpenChange(this.getOpen())
   //       } 
   //    }
   // }

   // здесь коллбэки расположены правильно
   function Password(parent=document.body, open=false) {

      const passField = document.createElement('input')

      const checkBox = document.createElement('input')
      checkBox.type = 'checkbox'

      parent.append(passField)
      parent.append(checkBox)

      this.setValue = (newValue) => {
         passField.value = newValue
         if (typeof this.onChange === 'function') {
            this.onChange(newValue)
         }  
      }
      this.getValue = () => passField.value

      this.setOpen = (newOpen) => {
         open = newOpen
         
         if (open === true) {
            checkBox.checked = true
            passField.type = 'text'
         } else if (open === false) {
            checkBox.checked = false
            passField.type = 'password'
         }
         if (typeof this.onOpenChange === 'function') {
            this.onOpenChange(open)
         } 
      }
      this.setOpen(open)

      this.getOpen = () => checkBox.checked


      passField.oninput = () => {
         this.setValue(this.getValue())
      }

      checkBox.oninput = () => {
         if (this.getOpen() === true) {
            this.setOpen(true)
         } else {
            this.setOpen(false)
         }
      }
   }

   let p = new Password(document.body, 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())
}


// loginFormWrapp()
function loginFormWrapp() {

   function Password(parent=document.body, open=false) {

      const passField = document.createElement('input')

      const checkBox = document.createElement('input')
      checkBox.type = 'checkbox'

      parent.append(passField)
      parent.append(checkBox)

      this.setValue = (newValue) => {
         passField.value = newValue
         if (typeof this.onChange === 'function') {
            this.onChange(newValue)
         }  
      }
      this.getValue = () => passField.value

      this.setOpen = (newOpen) => {
         open = newOpen
         
         if (open === true) {
            checkBox.checked = true
            passField.type = 'text'
         } else if (open === false) {
            checkBox.checked = false
            passField.type = 'password'
         }
         if (typeof this.onOpenChange === 'function') {
            this.onOpenChange(open)
         } 
      }
      this.setOpen(open)

      this.getOpen = () => checkBox.checked


      passField.oninput = () => {
         this.setValue(this.getValue())
      }

      checkBox.oninput = () => {
         if (this.getOpen() === true) {
            this.setOpen(true)
         } else {
            this.setOpen(false)
         }
      }
   }

   let loginInput = document.createElement('input')
   formContainer.append(loginInput)

   let passwordInput = new Password(formContainer, false)

   let loginButton = document.createElement('button')
   loginButton.innerText = 'Подтвердить'
   loginButton.disabled = true

   formContainer.append(loginButton)   

   function changeBtnStatus() {
      if (loginInput.value && passwordInput.getValue()) {
         loginButton.disabled = false
      } else {
         loginButton.disabled = true
      }
   }
   passwordInput.onChange = changeBtnStatus
   loginInput.oninput = changeBtnStatus
}


// loginFormConstructorWrapp()
function loginFormConstructorWrapp() {

   function Password(parent=document.body, open=false) {

      const passField = document.createElement('input')

      const checkBox = document.createElement('input')
      checkBox.type = 'checkbox'

      parent.append(passField)
      parent.append(checkBox)

      this.setValue = (newValue) => {
         passField.value = newValue
         if (typeof this.onChange === 'function') {
            this.onChange(newValue)
         }  
      }
      this.getValue = () => passField.value

      this.setOpen = (newOpen) => {
         open = newOpen
         
         if (open === true) {
            checkBox.checked = true
            passField.type = 'text'
         } else if (open === false) {
            checkBox.checked = false
            passField.type = 'password'
         }
         if (typeof this.onOpenChange === 'function') {
            this.onOpenChange(open)
         } 
      }
      this.setOpen(open)

      this.getOpen = () => checkBox.checked


      passField.oninput = () => {
         this.setValue(this.getValue())
      }

      checkBox.oninput = () => {
         if (this.getOpen() === true) {
            this.setOpen(true)
         } else {
            this.setOpen(false)
         }
      }
   }

   function LoginForm(parent=document.body, open=false) {
      // let currThis = this

      const loginField = document.createElement('input')
      loginField.type = 'text'


      const button = document.createElement('button')
      button.innerText = 'Подтвердить'

      parent.append(loginField)
      let passField = new Password(parent, open)
      parent.append(button)


      this.setLoginValue = (newValue) => {
         loginField.value = newValue
         this.makeCallback(this.onLoginChange, newValue)     
      }
      this.getLoginValue = () => loginField.value


      let btnState = true
      this.setBtn = (newValue=btnState) => {
         btnState = newValue
         if (this.getLoginValue() && passField.getValue()) {
            btnState = false
         } else {
            btnState = true
         }
         button.disabled = btnState
      }
      this.setBtn()
      this.getBtn = () => button.disabled


      this.makeCallback = (name, content) => {
         if (typeof name === 'function') {
            name(content)
         } 
      }


      loginField.oninput = () => {
         this.setBtn()
         this.setLoginValue(this.getLoginValue())
      }

      passField.onChange = () => {
         this.setBtn()
      }

      button.onclick = () => {
         this.makeCallback(this.onBtnClick, 'click')
      }

   }

   let loginForm = new LoginForm(document.body)

   loginForm.onLoginChange = (data) => console.log(data)
   loginForm.onBtnClick = (data) => console.log(data)
}


passwordVerifyWrapp()
function passwordVerifyWrapp() {

   function Password(parent=document.body, open=false) {

      const passField = document.createElement('input')

      const checkBox = document.createElement('input')
      checkBox.type = 'checkbox'

      parent.append(passField)
      parent.append(checkBox)

      this.setValue = (newValue) => {
         passField.value = newValue
         if (typeof this.onChange === 'function') {
            this.onChange(newValue)
         }  
      }
      this.getValue = () => passField.value

      this.setOpen = (newOpen) => {
         open = newOpen
         
         if (open === true) {
            checkBox.checked = true
            passField.type = 'text'
         } else if (open === false) {
            checkBox.checked = false
            passField.type = 'password'
         }
         if (typeof this.onOpenChange === 'function') {
            this.onOpenChange(open)
         } 
      }
      this.setOpen(open)

      this.getOpen = () => checkBox.checked


      passField.oninput = () => {
         this.setValue(this.getValue())
      }

      checkBox.oninput = () => {
         if (this.getOpen() === true) {
            this.setOpen(true)
         } else {
            this.setOpen(false)
         }
      }
   }


   function RegForm(parent=document.body, open=false) {

      const loginField = document.createElement('input')
      loginField.type = 'text'

      const passField2 = document.createElement('input')
      passField2.type = 'password'

      const button = document.createElement('button')
      button.innerText = 'Подтвердить'

      parent.append(loginField)
      parent.append(passField2)
      let passField = new Password(parent, open)
      parent.append(button)


      this.setLoginValue = (newValue) => {
         loginField.value = newValue
         this.makeCallback(this.onLoginChange, newValue)
      }
      this.getLoginValue = () => loginField.value


      this.setPassValue2 = (newValue) => {
         passField2.value = newValue
         this.makeCallback(this.onPass2Change, newValue)  

         if (passField.getOpen()) {
            passField2.style.display = 'none'
         } else {
            passField2.style.display = 'inline'
         }

      }
      this.getPassValue2 = () => passField2.value


      this.setPassState2 = (state=open) => {
         if (state) {
            passField2.style.display = 'none'
         } else {
            passField2.style.display = 'inline'
         }
      }
      this.getPassState2 = () => {
         if (passField2.style.display = 'none') {
            return true
         } else {
            return false
         }
      }


      let btnState = true
      this.setBtn = (newValue=btnState) => {
         btnState = newValue
         if (passField.getOpen() ? this.getLoginValue() && passField.getValue() : 
               this.getLoginValue() && passField.getValue() && passField.getValue() === this.getPassValue2()) {
            btnState = false
         } else {
            btnState = true
         }
         button.disabled = btnState
      }
      this.setBtn()
      this.getBtn = () => button.disabled



      this.makeCallback = (name, content) => {
         if (typeof name === 'function') {
            name(content)
         } 
      }


      loginField.oninput = () => {
         this.setBtn()
         this.setLoginValue(this.getLoginValue())
      }

      passField.onChange = () => {
         this.setBtn()
      }

      passField.onOpenChange = () => {
         this.setPassValue2(this.getPassValue2()) 
         this.setBtn()
      }

      passField2.oninput = () => {
         this.setBtn()
         this.setPassState2(passField.getOpen())    
      }


      button.onclick = () => {
         this.makeCallback(this.onBtnClick, 'click')
      }
   }

   let regForm = new RegForm()
}


// В коде ниже не используется класс Password, все написано общими классами

// loginFormWrapp2()
// function loginFormWrapp2() {

//    function LoginForm(parent=document.body, open=false) {

//       const loginField = document.createElement('input')
//       loginField.type = 'text'

//       const passField = document.createElement('input')

//       const checkBox = document.createElement('input')
//       checkBox.type = 'checkbox'

//       const button = document.createElement('button')
//       button.innerText = 'Подтвердить'
//       button.disabled = true

//       parent.append(loginField)
//       parent.append(passField)
//       parent.append(checkBox)
//       parent.append(button)

//       this.setLoginValue = (newValue) => {
//          loginField.value = newValue
//       }
//       this.getLoginValue = () => loginField.value


//       this.setPassValue = (newValue) => {
//          passField.value = newValue
//       }
//       this.getPassValue = () => passField.value


//       this.setOpen = (newOpen) => {
//          open = newOpen         
//          if (open === true) {
//             checkBox.checked = true
//             passField.type = 'text'
//          } else if (open === false) {
//             checkBox.checked = false
//             passField.type = 'password'
//          }
//       }
//       this.setOpen(open)
//       this.getOpen = () => checkBox.checked

//       loginField.oninput = () => {
//          if (this.getLoginValue() && this.getPassValue()) {
//             button.disabled = false
//          } else {
//             button.disabled = true
//          }
//          if (typeof this.onLoginChange === 'function') {
//             this.onLoginChange(this.getLoginValue())
//          }      
//       }

//       passField.oninput = () => {
//          if (this.getLoginValue() && this.getPassValue()) {
//             button.disabled = false
//          } else {
//             button.disabled = true
//          }
//          if (typeof this.onPassChange === 'function') {
//             this.onPassChange(this.getPassValue())
//          }      
//       }

//       checkBox.oninput = () => {
//          if (this.getOpen() === true) {
//             this.setOpen(true)
//          } else {
//             this.setOpen(false)
//          }
//          if (typeof this.onOpenChange === 'function') {
//             this.onOpenChange(this.getOpen())
//          } 
//       }
//    }

//    let loginForm = new LoginForm(document.body)
// }


// loginFormConstructorWrapp2()
// function loginFormConstructorWrapp2() {

//    function LoginForm(parent=document.body, open=false) {

//       const loginField = document.createElement('input')
//       loginField.type = 'text'

//       const passField = document.createElement('input')

//       const checkBox = document.createElement('input')
//       checkBox.type = 'checkbox'

//       const button = document.createElement('button')
//       button.innerText = 'Подтвердить'

//       parent.append(loginField)
//       parent.append(passField)
//       parent.append(checkBox)
//       parent.append(button)


//       this.setLoginValue = (newValue) => {
//          loginField.value = newValue
//       }
//       this.getLoginValue = () => loginField.value


//       this.setPassValue = (newValue) => {
//          passField.value = newValue
//       }
//       this.getPassValue = () => passField.value


//       this.setOpen = (newOpen) => {
//          open = newOpen         
//          if (open === true) {
//             checkBox.checked = true
//             passField.type = 'text'
//          } else if (open === false) {
//             checkBox.checked = false
//             passField.type = 'password'
//          }
//       }
//       this.setOpen(open)
//       this.getOpen = () => checkBox.checked


//       let btnState = true
//       this.setBtn = (newValue=btnState) => {
//          btnState = newValue
//          if (this.getLoginValue() && this.getPassValue()) {
//             btnState = false
//          } else {
//             btnState = true
//          }
//          button.disabled = btnState
//       }
//       this.setBtn()
//       this.getBtn = () => button.disabled


//       this.makeCallback = (name, content) => {
//          if (typeof name === 'function') {
//             name(content)
//          } 
//       }


//       loginField.oninput = () => {
//          this.setBtn()
//          this.makeCallback(this.onLoginChange, this.getLoginValue())     
//       }

//       passField.oninput = () => {
//          this.setBtn()
//          this.makeCallback(this.onPassChange, this.getPassValue())     
//       }

//       checkBox.oninput = () => {
//          if (this.getOpen() === true) {
//             this.setOpen(true)
//          } else {
//             this.setOpen(false)
//          }
//          this.setBtn()
//          this.makeCallback(this.onOpenChange, this.getOpen())
//       }

//       button.onclick = () => {
//          this.makeCallback(this.onBtnClick, 'click')
//       }
//    }

//    let loginForm = new LoginForm(document.body)

//    loginForm.onLoginChange = data => console.log(data)
//    loginForm.onPassChange = data => console.log(data)
//    loginForm.onBtnClick = click => console.log(click)
// }


// passwordVerifyWrapp2()
// function passwordVerifyWrapp2() {

//    function LoginForm(parent=document.body, open=false) {

//       const loginField = document.createElement('input')
//       loginField.type = 'text'

//       const passField = document.createElement('input')
//       const passField2 = document.createElement('input')

//       const checkBox = document.createElement('input')
//       checkBox.type = 'checkbox'

//       const button = document.createElement('button')
//       button.innerText = 'Подтвердить'

//       parent.append(loginField)
//       parent.append(passField)
//       parent.append(passField2)
//       parent.append(checkBox)
//       parent.append(button)


//       this.setLoginValue = (newValue) => {
//          loginField.value = newValue
//       }
//       this.getLoginValue = () => loginField.value


//       this.setPassValue = (newValue) => {
//          passField.value = newValue
//       }
//       this.getPassValue = () => passField.value

//       this.setPassValue2 = (newValue) => {
//          passField2.value = newValue
//       }
//       this.getPassValue2 = () => passField2.value

//       this.setOpen = (newOpen) => {
//          open = newOpen 
//          checkBox.checked = open
//          if (open === true) {
//             passField.type = 'text'
//             passField2.style.display = 'none'
//          } else if (open === false) {
//             passField.type = 'password'
//             passField2.style.display = 'inline'
//             passField2.type = 'password'
//          }
//       }
//       this.setOpen(open)
//       this.getOpen = () => checkBox.checked

//       let btnState = true
//       this.setBtn = (newValue=btnState) => {
//          btnState = newValue
//          if (this.getOpen() ? this.getLoginValue() && this.getPassValue() : 
//                this.getLoginValue() && this.getPassValue() && this.getPassValue() === this.getPassValue2()) {
//             btnState = false
//          } else {
//             btnState = true
//          }
//          button.disabled = btnState
//       }
//       this.setBtn()
//       this.getBtn = () => button.disabled



//       this.makeCallback = (name, content) => {
//          if (typeof name === 'function') {
//             name(content)
//          } 
//       }


//       loginField.oninput = () => {
//          this.setBtn()
//          this.makeCallback(this.onLoginChange, this.getLoginValue())     
//       }

//       passField.oninput = () => {
//          this.setBtn()
//          this.makeCallback(this.onPassChange, this.getPassValue())     
//       }

//       passField2.oninput = () => {
//          this.setBtn()
//          this.makeCallback(this.onPass2Change, this.getPassValue2())     
//       }

//       checkBox.oninput = () => {
//          if (this.getOpen() === true) {
//             this.setOpen(true)
//          } else {
//             this.setOpen(false)
//          }
//          this.setBtn()
//          this.makeCallback(this.onOpenChange, this.getOpen())
//       }

//       button.onclick = () => {
//          this.makeCallback(this.onBtnClick, 'click')
//       }
//    }

//    let loginForm = new LoginForm()
// }


// formWrapp()
function formWrapp() {

   function Form(el, data, okCallback, cancelCallback){
      let formBody = document.createElement('div')
      let okButton = document.createElement('button')
      okButton.innerHTML = 'OK'
   
      let cancelButton = document.createElement('button')
      cancelButton.innerHTML = 'Cancel'
   
      formBody.innerHTML = '<h1>Форма</h1>'
      const table = document.createElement('table')
      formBody.append(table)

      let callBackValidator = {}
      let checkObj = (obj) => {
         for (let key in obj) {
            if (obj[key] === false) {
               return true
            } 
         }
         return false 
      }
      if (typeof okCallback === 'function'){
         formBody.appendChild(okButton)

         okButton.onclick = () => {
            // ??
            // console.log(this)  
            this.okCallback(data)
         }
      }
   
      if (typeof cancelCallback === 'function'){
         formBody.appendChild(cancelButton)
         cancelButton.onclick = () => {
            table.innerHTML = ''
            createTable(this.dataBackup)
            this.cancelCallback()
         }
      }

            
      let inputCreators = {
         String(key, value, oninput){
            let input = document.createElement('input')
            // console.log(value.match(/\**/)[0])
            if (value.match(/\**/)[0] === value && value !== '') {
               input.type = 'password'
               input.value       = ''
               input.oninput     = () => oninput(input.value)
               setTimeout(() => {
                  oninput(input.value)
               }, 0)
            } else {
               input.type = 'text'
               input.placeholder = key
               input.value       = value
               input.oninput     = () => oninput(input.value)
               setTimeout(() => {
                  oninput(input.value)
               }, 0)
            }
            return input
         },
         Boolean(key, value, oninput){
            let input = document.createElement('input')
            input.type = 'checkbox'
            input.checked     = value
            input.oninput     = () => oninput(input.checked)
            setTimeout(() => {
               oninput(input.checked)
            }, 0)
            return input
         },
         Date(key, value, oninput){
            let input = document.createElement('input')
            input.type = 'datetime-local'
            // при преобразовании объекта к строке смещается часовой пояс на нулевой, выражение ниже восстанавливает текущий
            input.value       = new Date(value - (new Date()).getTimezoneOffset() * 60 * 1000).toISOString().slice(0,-1)
            input.oninput     = () => oninput(new Date(input.value))
            setTimeout(() => {
               oninput(new Date(input.value))
            }, 0)
            return input
         },
         Number(key, value, oninput){
            let input = document.createElement('input')
            input.type = 'text'
            input.placeholder = key
            input.value       = value
            input.oninput     = () => oninput(input.value)
            setTimeout(() => {
               oninput(input.value)
            }, 0)
            return input
         },
      }

      this.okCallback     = okCallback
      this.cancelCallback = cancelCallback
   
      this.data           = data
      this.dataBackup      = Object.assign({}, data)

      this.validators     = {}
         // код ниже дает возможность выполнять что-либо при модификации объекта
            // this.validators  = new Proxy(this.validators , {
            //    set(target, prop, val) { 
            //       if (typeof val == 'function') {
            //       target[prop] = val
               // тут можно написать функцию, 
               // которая будет выполняться при добавлении в 
               // объект функции в качестве свойства
            //       return true
            //       } else {
            //       return false
            //       }
            //    }
            // })            
      let formThis = this


      el.appendChild(formBody)

      function createTable(inputData) {

         for (const [key, value] of Object.entries(inputData)) {

            let dataUpdateValidation = (valueOfInput) => {
               // console.log(valueOfInput)

               if (rowMandatory && !valueOfInput) {
                  input.style.border = '4px solid red'
                  callBackValidator[key] = false
      
                  if (formThis.validators && key in formThis.validators) {
                     let valid = formThis.validators[key](valueOfInput,key,data,input)
                     if (valid === true) {   
                        data[key] = valueOfInput
                        tdErr.innerText = ''
                        input.style.backgroundColor = 'white'
                     } else if (typeof valid === 'string') {   
                        tdErr.innerText = valid
                        input.style.backgroundColor = '#800000'
                     }
                  } else {
                     data[key] = valueOfInput
                  }
      
               } else {
                  input.style.border = '1px solid rgb(118, 118, 118)'
      
                  if (formThis.validators && key in formThis.validators) {
                     let valid = formThis.validators[key](valueOfInput,key,data,input)
                     if (valid === true) {
                        callBackValidator[key] = true  
                        data[key] = valueOfInput
                        tdErr.innerText = ''
                        input.style.backgroundColor = 'white'
                     } else if (typeof valid === 'string') {
                        callBackValidator[key] = false
                        tdErr.innerText = valid
                        input.style.backgroundColor = '#800000'
                     }
                  } else {
                     callBackValidator[key] = true
                     data[key] = valueOfInput
                  }
               }

               okButton.disabled = checkObj(callBackValidator)
            }

            const tr = document.createElement('tr')
            table.append(tr)

            let rowMandatory = false
            const th = document.createElement('th')
            if (key[0] === '*') {
               const thPre = document.createElement('span')
               thPre.innerText = '* '
               thPre.style.color = 'red'
               th.append(thPre)
               const thCont = document.createElement('span')
               thCont.innerText = key.slice(1)
               th.append(thCont)
               rowMandatory = true
            } else {
               th.innerText = key
            }
            tr.append(th)

            const td = document.createElement('td')
            tr.append(td)  
            


            const input = inputCreators[value.constructor.name](key, value, dataUpdateValidation)
            td.append(input)


            const tdErr = document.createElement('td')
            tr.append(tdErr)
         }
      }
      createTable(this.data)     

   }
   
   
   let form = new Form(formContainer, {
      '*name': '',
      '*surname': 'AAA',
      fathername: 'batkovch',
      married: true,
      password: '***',
      birthday: new Date((new Date).getTime() - 86400000 * 30*365)
   }, () => console.log('ok'),() => console.log('cancel') )

   form.okCallback = (data) => console.log(data)
   form.cancelCallback = () => console.log('aaaa')


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


   // fetch('https://open.er-api.com/v6/latest/USD')
   // .then(res => res.json())
   // .then(data => {
   //    currencyRates = data.rates
   //    let rates = new Form(formContainer, currencyRates, () => console.log('ok'),() => console.log('cancel') )
   // })
}



