// Main
(() => {
  function copyToClipboard(text) {
    const clip = document.createElement('input');
    clip.id = 'clipper';
    clip.value = text;
    document.body.appendChild(clip);

    clip.select();
    document.execCommand('copy');

    clip.value = '';
    clip.parentNode.removeChild(clip);
  }

  function setInnerText(id, text) {
    document.getElementById(id).innerText = text;
  }

  function getInnerText(id) {
    return document.getElementById(id).innerText;
  }

  function setValue(id, value) {
    document.getElementById(id).value = value;
  }

  function setChecked(id, value) {
    document.getElementById(id)["checked"] = value;
  }

  function getChecked(id) {
    return document.getElementById(id)["checked"];
  }

  function getValue(id) {
    return document.getElementById(id).value;
  }

  function setSelect(id, itemList) {
    const select = document.getElementById(id);
    const allowChange = select['allow_change'] !== false;

    if (allowChange) {
      while (select.options.length > itemList.length) {
        select.removeChild(select.options[select.options.length - 1]);
      }

      for (let i = 0; i < itemList.length; i++) {
        if (select.options[i]) {
          if (select.options[i].text !== itemList[i]) {
            select.options[i].text = itemList[i];
          }
        } else {
          const opt = document.createElement('option');
          opt.text = itemList[i];
          select.appendChild(opt);
        }
      }
    }
  }

  window.uiUpdate = (() => {

    const _renter = (() => {

      return {
        setAllocatedFunds: (currency) => {
          setInnerText('ID_Renter_AllocatedFunds', currency);
        },
        setUsedFunds: (currency) => {
          setInnerText('ID_Renter_UsedFunds', currency);
        },
        setAvailableFunds: (currency) => {
          setInnerText('ID_Renter_AvailableFunds', currency);
        },
        setHostCount: (count) => {
          setInnerText('ID_Renter_HostCount', count);
        },
        setEstimatedSpace: (space) => {
          setInnerText('ID_Renter_EstimatedSpace', space);
        },
        setUsedSpace: (space) => {
          setInnerText('ID_Renter_UsedSpace', space);
        },
        setEstimatedCost: (currency) => {
          setInnerText('ID_Renter_EstimatedCost', currency);
        },
        setAvailableSpace: (space) => {
          setInnerText('ID_Renter_AvailablSpace', space);
        },
        setDownloadCost: (currency) => {
          setInnerText('ID_Renter_EstimatedDownloadCost', currency);
        },
        setUploadCost: (currency) => {
          setInnerText('ID_Renter_EstimatedUploadCost', currency);
        },
        setEstimatedCost: (currency) => {
          setInnerText('ID_Renter_EstimatedCost', currency);
        },
        setEstimatedDownloadCost: (currency) => {
          setInnerText('ID_Renter_EstimatedDownloadCost', currency);
        },
        setEstimatedUploadCost: (currency) => {
          setInnerText('ID_Renter_EstimatedUploadCost', currency);
        },
        setAllowance: (allowance) => {
          if (document.getElementById('renter_settings_window').classList.contains('hidden-element')) {
            setValue('ID_RenterSetFunds', allowance.Funds);
            setValue('ID_RenterSetHosts', allowance.Hosts);
            setValue('ID_RenterSetPeriod', allowance.Period);
            setValue('ID_RenterSetRenewWindow', allowance.RenewWindowInBlocks);
            AppActions.calculateEstimatedStorage(allowance.Funds, (res) => {
              setInnerText('ID_RenterCalcStorage', '~' + res);
            });
          }
        },
        setUploadProgress: (items) => {
          _uploadItems = JSON.parse(items || "[]");
          buildUploadTable();
        }
      };
    })();

    const _wallet = (() => {
      return {
        setConfirmedBalance: (balance) => {
          setInnerText('ID_WalletConfirmedBalance', balance);
          setInnerText('ID_Send_Balance', balance);
        },
        setUnconfirmedBalance: (balance) => {
          setInnerText('ID_WalletBalanceUnconfirmed', balance);
        },
        setTotalBalance: (balance) => {
          setInnerText('ID_WalletTotalBalance', balance);
        },
        setReceiveAddress: (address) => {
          setInnerText('ID_WalletReceiveAddress', address);
        },
        setLockWalletOnExit: (lock) => {
          if (document.getElementById('sia_settings_window').classList.contains('hidden-element')) {
            setChecked('ID_SettingsLockWalletOnExit', lock);
          }
        }
      };
    })();

    return {
      Renter: _renter,
      Wallet: _wallet,
      setBlockHeight: (height) => {
        setInnerText('ID_BlockHeight', height);
      },
      setServerVersion: (version) => {
        setInnerText('ID_ServerVersion', version);
      },
      setAvailableDriveLetters: (drives) => {
        setSelect('ID_MountDrives', drives);
      },
      notifyDriveUnmounted: _notifyDriveUnmounted,
      reloadApplication: reloadApplication,
      setSiaSettings: (settings) => {
        if (document.getElementById('sia_settings_window').classList.contains('hidden-element')) {
          const j = JSON.parse(settings);
          for (const s in j) {
            if (j.hasOwnProperty(s)) {
              const id = 'ID_Settings_' + s;
              const input = document.getElementById(id);
              if (input.type === 'checkbox') {
                setChecked(id, j[s]);
              } else {
                setValue(id, j[s]);
              }
            }
          }
        }
      },
      displayShutdownWindow: () => {
        const div = document.getElementById('shutdown_window');
        document.body.innerHTML = '';
        document.body.appendChild(div);
        div.classList.remove('hidden-element');
      },
      notifyDriveMounting: _notifyDriveMounting,
      displayPrompt: (title) => {
        return confirm(title);
      }
    };
  })();

  const UiState = (() => {
    function _clientVersion() {
      return 'v' + window.uiState.clientVersion;
    }

    function _isOnline() {
      return window.uiState.isOnline;
    }

    function _isWalletConfigured() {
      return window.uiState.isWalletConfigured;
    }

    function _isWalletLocked() {
      return window.uiState.isWalletLocked;
    }

    function _allocatedRenterFunds() {
      return window.uiState.allocatedRenterFunds;
    }

    function _defaultRenterSettings() {
      return window.uiState.defaultRenterSettings;
    }

    function _getStoreUnlockPassword() {
      return window.uiState.storeUnlockPassword;
    }

    return {
      clientVersion: _clientVersion,
      isOnline: _isOnline,
      isWalletConfigured: _isWalletConfigured,
      isWalletLocked: _isWalletLocked,
      allocatedRenterFunds: _allocatedRenterFunds,
      defaultRenterSettings: _defaultRenterSettings,
      getStoreUnlockPassword: _getStoreUnlockPassword
    };
  })();

  const AppActions = (() => {
    function _createWallet(password, cb) {
      console.log('Create wallet');
      return window.appActions.createWallet(password, cb);
    }

    function _mountDrive(mountLocation, cb) {
      console.log('Mount drive: ' + mountLocation);
      return window.appActions.mountDrive(mountLocation, cb);
    }

    function _autoUnlockWallet(cb) {
      return window.appActions.autoUnlockWallet(cb);
    }

    function _unlockWallet(pwd, cb) {
      return window.appActions.unlockWallet(pwd, cb);
    }

    function _unmountDrive(cb) {
      console.log('Unmount drive');
      return window.appActions.unmountDrive(cb);
    }

    function _shutdown() {
      window.appActions.shutdown();
    }

    function _setRenterSettings(allowance, cb) {
      window.appActions.setRenterSettings(allowance, cb);
    }

    function _calculateEstimatedStorage(funds, cb) {
      window.appActions.calculateEstimatedStorage(funds, cb)
    }

    function _setSiaSettings(settings, cb) {
      window.appActions.setSiaSettings(settings, cb);
    }

    function _autoMountDrive() {
      window.appActions.autoMountDrive();
    }

    function _walletSend(address, amount, cb) {
      window.appActions.walletSend(address, amount, cb);
    }

    return {
      createWallet: _createWallet,
      mountDrive: _mountDrive,
      unlockWallet: _unlockWallet,
      autoUnlockWallet: _autoUnlockWallet,
      unmountDrive: _unmountDrive,
      shutdown: _shutdown,
      setRenterSettings: _setRenterSettings,
      calculateEstimatedStorage: _calculateEstimatedStorage,
      setSiaSettings: _setSiaSettings,
      autoMountDrive: _autoMountDrive,
      walletSend: _walletSend
    };
  })();

  let _mountHandler;
  let _allowRenterSave = true;
  let _uploadItems;
  let _uploadTableInitialized = false;

  function buildUploadTable() {
    const table = $('#ID_UploadProgressTable');
    if (!table.hasClass('hidden-element')) {
      if (!_uploadTableInitialized) {
        _uploadTableInitialized = true;
        table.DataTable({
          data: [],
          columns: [
            {title: "SiaPath"},
            {title: "Progress"}
          ],
          deferRender: true,
          scrollY: 343,
          scrollCollapse: false,
          paging: false,
          dom: '<"pull-left"f>rt<"bottom"lip><"clear">',
        });
      }
      const dataTable = table.DataTable();
      dataTable.clear();
      dataTable.rows.add(_uploadItems);
      dataTable.draw(false);
    }
  }

  function setMainWindow(name) {
    console.log('Setting main window: ' + name);
    const elem = document.getElementById(name);
    const mainWindow = document.getElementById('main_window');
    if (mainWindow.childElementCount === 1) {
      const curElem = mainWindow.firstChild;
      mainWindow.removeChild(curElem);
      curElem.classList.add('hidden-element');
      document.body.appendChild(curElem);
    }

    elem.parentElement.removeChild(elem);
    elem.classList.remove('hidden-element');
    mainWindow.appendChild(elem);
    const focusElem = elem.getElementsByClassName('vfocus');
    if (focusElem.length) {
      focusElem[0].focus();
    }
  }

  function displayErrorPopup(title, msg, cb) {
    alert(msg);
    if (cb) {
      cb();
    }
  }

  function _notifyDriveMounting(mountLocation) {
    const mountButton = document.getElementById('ID_MountButton');
    const mountSelect = document.getElementById('ID_MountDrives');
    mountButton.innerText = "Unmount";
    mountButton.onclick = _mountHandler;
    mountSelect['allow_change'] = false;
    mountSelect.disabled = true;
    mountSelect.value = mountLocation;
  }

  function _notifyDriveUnmounted() {
    const mountButton = document.getElementById('ID_MountButton');
    const mountSelect = document.getElementById('ID_MountDrives');
    if (mountButton.innerText === 'Unmount') {
      mountButton.innerText = "Mount";
      mountButton.onclick = _mountHandler;
      mountButton.disabled = false;
      mountSelect.disabled = false;
      mountSelect['allow_change'] = true;
    }
  }

  function displayFormingContracts(show) {
    const img = document.getElementById('ID_Renter_Allowance_Active');
    if (show) {
      img.style.display = 'inline-block';
    } else {
      img.style.display = 'none';
    }
  }

  function handleRenterUploads() {
    const table = $('#ID_UploadProgressTable');

    const okButton = document.getElementById('ID_RenterUploadsOk');
    okButton.onclick = () => {
      okButton.onclick = null;
      table.addClass('hidden-element');
      beginMainApplication(false);
    };

    setMainWindow('upload_progress_window');
    table.removeClass('hidden-element');
    buildUploadTable();
  }

  function handleSiaEditSettings() {
    const cancelButton = document.getElementById('ID_SiaSettingsCancel');
    cancelButton.onclick = () => {
      cancelButton.onclick = null;
      saveButton.onclick = null;
      beginMainApplication(false);
    };

    const saveButton = document.getElementById('ID_SiaSettingsOK');
    saveButton.onclick = () => {
      saveButton.onclick = null;
      cancelButton.onclick = null;
      AppActions.setSiaSettings({
        'AutoMountOnUnlock': getChecked('ID_Settings_AutoMountOnUnlock'),
        'AutoStartOnLogon': getChecked('ID_Settings_AutoStartOnLogon'),
        'CloseToTray': getChecked('ID_Settings_CloseToTray'),
        'ConfirmApplicationExit': getChecked('ID_Settings_ConfirmApplicationExit'),
        'LaunchFileMgrOnMount': getChecked('ID_Settings_LaunchFileMgrOnMount'),
        'LockWalletOnExit': getChecked('ID_Settings_LockWalletOnExit'),
        'StoreUnlockPassword': getChecked('ID_Settings_StoreUnlockPassword'),
        'LaunchBundledSiad': getChecked('ID_Settings_LaunchBundledSiad'),
        'ApiPort': getValue('ID_Settings_ApiPort'),
        'HostPort': getValue('ID_Settings_HostPort'),
        'RpcPort': getValue('ID_Settings_RpcPort')
      }, (success, reason) => {
        if (success) {
          reloadApplication(false);
        } else {
          displayErrorPopup('Settings Failed', reason);
          handleSiaEditSettings();
        }
      });
    };
    setMainWindow('sia_settings_window');
  }

  function handleWalletSend() {
    const saveButton = document.getElementById('ID_SendOK');
    const cancelButton = document.getElementById('ID_SendCancel');
    cancelButton.onclick = () => {
      cancelButton.onclick = null;
      saveButton.onclick = null;
      beginMainApplication(false);
    };

    saveButton.onclick = () => {
      cancelButton.onclick = null;
      saveButton.onclick = null;
      const address = getValue('ID_Send_Address');
      const amount = getValue('ID_Send_Amount');
      AppActions.walletSend(address, amount, (success, reason) => {
        if (success) {
          setValue('ID_Send_Address', '');
          setValue('ID_Send_Amount', '');
        } else {
          displayErrorPopup('Send Failed', reason);
        }
        beginMainApplication(false);
      });
    };
    setMainWindow('send_window');
  }

  function beginMainApplication(checkAutoMount) {
    const settingsEditLink = document.getElementById('ID_Sia_Settings_Edit');
    settingsEditLink.onclick = () => {
      settingsEditLink.onclick = null;
      handleSiaEditSettings();
    };

    const copyAddressLink = document.getElementById('ID_WalletReceiveAddressCopy');
    copyAddressLink.onclick = () => {
      const address = getInnerText('ID_WalletReceiveAddress');
      copyToClipboard(address);
    };

    const sendLink = document.getElementById('ID_Wallet_Send');
    sendLink.onclick = () => {
      sendLink.onclick = null;
      handleWalletSend();
    };

    const renterEditLink = document.getElementById('ID_Renter_Edit');
    renterEditLink.onclick = () => {
      renterEditLink.onclick = null;
      handleRenterEditSettings();
    };
    const renterUploadsLink = document.getElementById('ID_Renter_Uploads');
    renterUploadsLink.onclick = () => {
      renterUploadsLink.onclick = null;
      handleRenterUploads();
    };
    const mountButton = document.getElementById('ID_MountButton');
    const mountSelect = document.getElementById('ID_MountDrives');

    _mountHandler = () => {
      mountSelect['allow_change'] = false;
      if (UiState.allocatedRenterFunds() === '0') {
        displayErrorPopup('Error', 'Renter funding must be configured before trying to mount.')
      } else {
        mountButton.onclick = null;
        mountButton.disabled = true;
        mountSelect.disabled = true;
        if (mountButton.innerText === "Mount") {
          AppActions.mountDrive(mountSelect.value, (success, reason) => {
            if (success) {
              mountButton.innerText = "Unmount";
            } else {
              displayErrorPopup('Mount Failed', reason);
            }
            mountButton.onclick = _mountHandler;
            mountButton.disabled = false;
          });
        } else {
          AppActions.unmountDrive((success, reason) => {
            if (success) {
              _notifyDriveUnmounted()
            } else {
              displayErrorPopup('Unmount Failed', reason);
              mountButton.onclick = _mountHandler;
              mountButton.disabled = false;
              mountSelect['allow_change'] = true;
            }
          });
        }
      }
    };
    mountButton.onclick = _mountHandler;
    if (checkAutoMount) {
      AppActions.autoMountDrive( );
    }
    setMainWindow('app_window');
  }

  function handleRenterEditSettings() {
    const funds = document.getElementById('ID_RenterSetFunds');
    funds.oninput = () => {
      AppActions.calculateEstimatedStorage(funds.value, (res) => {
        setInnerText('ID_RenterCalcStorage', '~' + res);
      });
    };

    const defaultsButton = document.getElementById('ID_RenterSettingsDefaults');
    const cancelButton = document.getElementById('ID_RenterSettingsCancel');
    const saveButton = document.getElementById('ID_RenterSettingsOK');

    cancelButton.onclick = () => {
      funds.oninput = null;
      saveButton.onclick = null;
      cancelButton.onclick = null;
      defaultsButton.onclick = null;
      beginMainApplication(false);
    };

    if (_allowRenterSave) {
      defaultsButton.classList.remove('hidden-element');
      saveButton.classList.remove('hidden-element');
      defaultsButton.onclick = () => {
        funds.oninput = null;
        const settings = UiState.defaultRenterSettings();
        if (getValue('ID_RenterSetFunds') === '0') {
          setValue('ID_RenterSetFunds', settings.Funds);
        }
        setValue('ID_RenterSetHosts', settings.Hosts);
        setValue('ID_RenterSetPeriod', settings.Period);
        setValue('ID_RenterSetRenewWindow', settings.RenewWindowInBlocks);
      };

      saveButton.onclick = () => {
        _allowRenterSave = false;
        funds.oninput = null;
        saveButton.onclick = null;
        cancelButton.onclick = null;
        defaultsButton.onclick = null;
        AppActions.setRenterSettings({
          'Funds': getValue('ID_RenterSetFunds'),
          'Hosts': getValue('ID_RenterSetHosts'),
          'Period': getValue('ID_RenterSetPeriod'),
          'RenewWindowInBlocks': getValue('ID_RenterSetRenewWindow')
        }, (success, reason) => {
          if (!success) {
            displayErrorPopup('Allocation Failed', reason);
          }
          displayFormingContracts(false);
          _allowRenterSave = true;
        });
        displayFormingContracts(true);
        beginMainApplication(false);
      };
    } else {
      defaultsButton.classList.add('hidden-element');
      saveButton.classList.add('hidden-element');
    }

    setMainWindow('renter_settings_window');
  }

  function manualUnlockWallet() {
    const unlockButton = document.getElementById('ID_UnlockWalletButton');
    unlockButton.onclick = () => {
      unlockButton.onclick = null;
      const password = document.getElementById('ID_WalletUnlockPwd');
      if (AppActions.unlockWallet(password.value, (success, reason) => {
          if (success) {
            beginMainApplication(true);
          } else {
            displayErrorPopup('Error', reason, () => {
              handleUnlockWallet();
            });
          }
        })) {
        password.value = '';
        setMainWindow('unlocking_window');
      } else {
        password.value = '';
      }
    };
    setMainWindow('unlock_window');
  }

  function handleUnlockWallet() {
    if (UiState.getStoreUnlockPassword()) {
      if (AppActions.autoUnlockWallet((success) => {
        if (success) {
          beginMainApplication(true);
        } else {
          manualUnlockWallet();
        }
      })) {
        setMainWindow('unlocking_window');
      } else {
        manualUnlockWallet();
      }
    } else {
      manualUnlockWallet();
    }
  }

  function handleWalletCreated(seed) {
    document.getElementById('ID_WalletSeed').innerText = seed;
    const button = document.getElementById('ID_WalletCreatedButton');
    button.onclick = () => {
      button.onclick = null;
      handleUnlockWallet();
    };
    setMainWindow('wallet_created_window');
  }

  function handleCreateWallet() {
    const createButton = document.getElementById('ID_CreateWalletButton');
    const createClickHandler = () => {
      createButton.onclick = null;
      let create = true;
      let password = null;
      if (getChecked('ID_UsePwdForUnlock')) {
        document.getElementById('ID_SetWalletPassword').focus();
        const pwd1 = getValue('ID_SetWalletPassword');
        const pwd2 = getValue('ID_ConfirmWalletPassword');
        if (pwd1) {
          create = (pwd1 === pwd2);
          if (create) {
            password = pwd1;
          } else {
            displayErrorPopup('Password Error', 'Password\'s do not match');
          }
        } else {
          displayErrorPopup('Password Error', 'Password cannot be empty');
          create = false;
        }
      }

      if (create) {
        AppActions.createWallet(password, (success, reasonOrSeed) => {
          password = null;
          if (success) {
            useSeedButton.onclick = null;
            usePwdButton.onclick = null;
            handleWalletCreated(reasonOrSeed);
          } else {
            displayErrorPopup('Error', reasonOrSeed, () => {
              createButton.onclick = createClickHandler;
            });
          }
        });
      } else {
        createButton.onclick = createClickHandler;
      }
    };
    createButton.onclick = createClickHandler;

    const div = document.getElementById('create_wallet_password');
    const useSeedButton = document.getElementById('ID_UseSeedForUnlock');
    useSeedButton.onclick = () => {
      if (!div.classList.contains('hidden-element')) {
        div.classList.add('hidden-element');
      }
    };

    const usePwdButton = document.getElementById('ID_UsePwdForUnlock');
    usePwdButton.onclick = () => {
      if (div.classList.contains('hidden-element')) {
        div.classList.remove('hidden-element');
      }
    };

    setMainWindow('create_window');
  }

  function reloadApplication(checkAutoMount) {
    document.getElementById('ID_SiaDrive').innerText = 'SiaDrive ' + UiState.clientVersion();
    if (UiState.isOnline()) {
      if (UiState.isWalletConfigured()) {
        if (UiState.isWalletLocked()) {
          handleUnlockWallet();
        } else {
          beginMainApplication(checkAutoMount);
        }
      } else {
        handleCreateWallet();
      }
    } else {
      setMainWindow('offline_window');
    }
  }

  window.addEventListener('load', ()=> {
    console.log('Main window load');
    document.getElementById('ID_ServerVersion').innerText = '...';

    reloadApplication(true);
  });
})();