'use strict';

window.mainSite = undefined;
window.onbeforeunload = function() {
  IscWebService('resetUploadSlot', '', function() {});
};

function init() {
  i18n.init({
    supportLocale: false
  });
  mainSite = new MainSite();
  try {
    if (typeof window.localStorage !== undefined) {
      mainSite.localStorage = window.localStorage;
    }
    if (typeof window.sessionStorage !== undefined) {
      mainSite.sessionStorage = window.sessionStorage
    }
  } catch (error) {
    mainSite.localStorage = new Storage();
    mainSite.sessionStorage = new Storage();
  }
  IscWebService('setKeepAlive', '', function() {});
  mainSite.prepare();
  if (navigator.cookieEnabled == true) {
  } else if (navigator.cookieEnabled == false) {
    mainSite.requestsEnabled = false;
    new ModalConfirmDialogOk(i18n.translate("something_wrong"), i18n.translate("Your browser does not accept Cookies! Please make sure to use a Webbrowser that accept Cookies!")).prepare();
    document.body.appendChild(document.createTextNode("Your browser does not accept Cookies! Please make sure to use a Webbrowser that accept Cookies!"));
  } else {
    mainSite.requestsEnabled = false;
    new ModalConfirmDialogOk(i18n.translate("something_wrong"), i18n.translate("Your browser does not accept Cookies! Please make sure to use a Webbrowser that accept Cookies!")).prepare();
    document.body.appendChild(document.createTextNode("Your browser does not accept Cookies! Please make sure to use a Webbrowser that accept Cookies!"));
  }
}

/*
 * ##################################################### Start Common #####################################################
 */

function Storage() {
  var store = {}
  this.setItem = function(key, value) {
    store[key] = value;
  }
  this.getItem = function(key) {
    if (!store[key]) {
      return null;
    }
    return store[key];
  }
  this.removeItem = function(key) {
    if (store['key']) {
      delete store['key'];
    }
  }
}

function getCookieValue(name) {
  var cookieValue = document.cookie.replace('/(?:(?:^|.*;\s*)' + name + '\s*\=\s*([^;]*).*$)|^.*$/', '$3');
  return cookieValue;
}

function removeCookie(name) {
  document.cookie = name + '=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/;';
}

function checkBrowserName(name) {
  return navigator.userAgent.toLowerCase().indexOf(name.toLowerCase()) > -1;
}
/*
 * ##################################################### End Common #####################################################
 */

/*
 * ##################################################### Start Menu|MenuItem #####################################################
 */
function Menu(first) {
  this[first.name] = first;
  this.first = first;
  this.last = first;
  this.add = function(menuItem) {
    this[menuItem.name] = menuItem;
    this.last.next = menuItem;
    this.last = menuItem;
  };
  this.insertAfter = function(menuItem, insertAfter) {
    this[menuItem.name] = menuItem;
    menuItem.next = insertAfter.next;
    insertAfter.next = menuItem;
    if (this.last === insertAfter) {
      this.last = menuItem;
    }
  };
  this.insertAsFirst = function(menuItem) {
    this[menuItem.name] = menuItem;
    menuItem.next = this.first;
    this.first = menuItem;
  };
  this.next = undefined;
}

function MenuItem(name, target) {
  this.name = name;
  this.target = target;
  this.next = undefined;
}
/*
 * ##################################################### End Menu|MenuItem #####################################################
 */

/*
 * ##################################################### Start PageTemplate #####################################################
 */
var deviceInfoMinimumKeys = 22;

function PageTemplate() {
  var thisClass = this;
  this.visible = false;
  this.contentSection = undefined;
  this.dataBindings = [];

  this.hide = function() {
    if (thisClass.contentSection && mainSite.main.contains(thisClass.contentSection)) {
      mainSite.main.removeChild(thisClass.contentSection);
    }
    this.visible = false;
  };

  this.show = function() {
    if (!this.visible) {
      for (var pageToHide in thisClass.pages) {
        thisClass.pages[pageToHide].hide();
      }
      this.visible = true;
      this.prepare();
    }
  };
}
/*
 * ##################################################### End PageTemplate #####################################################
 */
/*
 * ##################################################### Start TimedRequest #####################################################
 */
var INTERVAL = {
  NONE: null,
  MINUTE: 60000,
  HALFMINUTE: 30000,
  TENSECONDS: 10000,
  SECOND: 1000,
  TWOSECONDS: 2000,
  FIVEHUNDREDMILLIS: 500,
  FIFTYMILLIS: 50
};

function TimedRequest(timeout, cmd, value, setDataFunction, origin) {
  var thisClass = this;
  this.cmd = cmd;
  this.value = value;
  this.timeout = timeout;
  this.origin = origin;
  var keepAlive = false
  this.setKeepAlive = function(newKeepAlive) {
    keepAlive = newKeepAlive;
  }
  this.requestFunction = function() {
    if (thisClass.origin && !thisClass.origin.visible) {
      thisClass.resetTimeout();
      return;
    }
    if (typeof thisClass.cmd === "function") {
      thisClass.cmd(thisClass.value, thisClass.callCallbackFunctions);
    } else {
      IscWebService(thisClass.cmd, thisClass.value, thisClass.callCallbackFunctions, keepAlive);
    }
  };
  this.setDataFunction = setDataFunction;
  this.callbackFunctions = [];
  var timer = undefined;
  this.oneShot = function() {
    thisClass.requestFunction();
  };
  this.resetTimeout = function() {
    if (thisClass.timeout == INTERVAL.NONE) {
      return;
    }
    if (timer !== undefined)
      clearTimeout(timer);
    timer = setTimeout(thisClass.requestFunction, thisClass.timeout);
  };
  this.abortTimeout = function() {
    clearTimeout(timer);
    timer = undefined;
  };
  this.addCallbackFunction = function(callbackFunction) {
    if (thisClass.callbackFunctions.indexOf(callbackFunction) === -1) {
      thisClass.callbackFunctions.push(callbackFunction);
    }
  };
  this.callCallbackFunctions = function(response) {
    thisClass.setDataFunction(response);
    for (var i = 0; i < thisClass.callbackFunctions.length; i++) {
      thisClass.callbackFunctions[i]();
    }
    thisClass.resetTimeout();
  };
}
/*
 * ##################################################### End TimedRequest #####################################################
 */

/*
 * ##################################################### Start MainSite #####################################################
 */
function MainSite() {
  if (mainSite) {
    return mainSite;
  }
  if (!(this instanceof MainSite)) {
    return new MainSite();
  }
  var thisClass = this;
  this.requestsEnabled = true;
  this.headerAndFooterMenu = false;
  this.knxEnabled = true;
  this.kimFriendlyName = function() {
    if (typeof thisClass.getKimFriendlyName === 'function')
      return thisClass.getKimFriendlyName();
    return 'ise smart connect';
  }
  this.rebootBecauseOfAnUpdate = false;
  this.connectionError = false;
  this.homepage = undefined;
  this.pages = {};
  this.deviceInfo = undefined;
  this.shortDeviceInfo = undefined;
  this.currentCOValues = undefined;
  this.appState = undefined;
  this.dataBindings = [];

  this.menu = new Menu(new MenuItem('device_status', 'StatusPage'));
  this.menu.add(new MenuItem('system', new Menu(new MenuItem('download_logs', 'DownloadLogs'))));
  this.menu.system.target.add(new MenuItem('reboot', 'RebootDevice'));
  this.menu.system.target.add(new MenuItem('factory_reset', 'FactoryReset'));
  this.menu.system.target.add(new MenuItem('firmware_update', 'FirmwareUpdatePage'));
  this.pages['FirmwareUpdatePage'] = new FirmwareUpdatePage();
  this.menu.system.target.add(new MenuItem('disclaimer', 'Disclaimer'));
  this.menu.system.target.add(new MenuItem('licenses', 'LicensesPage'));
  this.pages['LicensesPage'] = new LicensesPage();
  this.topnav = undefined;

  this.headerMenu = undefined;
  this.headerNav = undefined;

  this.footerMenu = undefined;
  this.footerNav = undefined;


  var main = undefined;
  this.modal = undefined;
  this.modalWaitForContent = undefined;
  this.currentModalDialog = undefined;

  this.createNavMenu = function() {
    if (typeof thisClass.addProductTopNavMenuItems === 'function')
      thisClass.addProductTopNavMenuItems();
    var menuItem = this.menu.first;
    while (menuItem) {
      thisClass.addMenuItem(menuItem, thisClass.topnav);
      menuItem = menuItem.next;
    }
    if (thisClass.headerMenu && thisClass.headerNav) {
      var headerMenuItem = thisClass.headerMenu.first;
      while (headerMenuItem) {
        thisClass.addMenuItem(headerMenuItem, thisClass.headerNav);
        headerMenuItem = headerMenuItem.next;
      }
    }
    thisClass.footerMenu = new Menu(new MenuItem('disclaimer', 'Disclaimer'));
    thisClass.footerMenu.add(new MenuItem('licenses', 'LicensesPage'));
    if (thisClass.footerMenu && thisClass.footerNav) {
      var footerMenuItem = thisClass.footerMenu.first;
      while (footerMenuItem) {
        thisClass.addMenuItem(footerMenuItem, thisClass.footerNav);
        footerMenuItem = footerMenuItem.next;
      }
    }
  };

  this.addMenuItem = function(item, parentmenuitem) {
    var listElem = document.createElement('li');
    if (item.target instanceof Menu) {
      var divSubmenu = document.createElement('div');
      divSubmenu.setAttribute('tabindex', '0');
      divSubmenu.setAttribute('class', 'dropdown');
      var ankerElem = document.createElement('a');
      ankerElem.appendChild(document.createTextNode(i18n.translate(item.name)));
      divSubmenu.appendChild(ankerElem);
      var ulSubmenu = document.createElement('ul');
      ulSubmenu.setAttribute('class', 'dropdown-content navdropdown');
      divSubmenu.appendChild(ulSubmenu);
      if (navigator.userAgent.match(/iPad|Phone|Pod/i) != null) {
        ulSubmenu.style.opacity = '1';
        ulSubmenu.style.visibility = 'hidden';
        ulSubmenu.setAttribute('class', 'dropdown-content navdropdown ipaddropdown');
        divSubmenu.ontouchstart = function(evt) {
          var elements = document.getElementsByClassName('ipaddropdown');
          if (ulSubmenu.style.visibility == 'hidden') {
            ulSubmenu.style.visibility = 'visible';
            var hideElement = function(evt) {
              ulSubmenu.style.visibility = 'hidden';
              this.removeEventListener('touchstart', hideElement, false);
            };
            setTimeout(function() {
              document.addEventListener("touchstart", hideElement, false)
            }, 100);;
          }
        };
      }
      var menuItem = item.target.first;
      while (menuItem) {
        this.addMenuItem(menuItem, ulSubmenu);
        menuItem = menuItem.next;
      }
      listElem.appendChild(divSubmenu);
    } else {
      var ankerElem = document.createElement('a');
      ankerElem.setAttribute('href', '#' + item.target);
      ankerElem.onclick = function() {
        return thisClass.show(item.target);
      };
      ankerElem.appendChild(document.createTextNode(i18n.translate(item.name)));
      listElem.appendChild(ankerElem);
    }
    parentmenuitem.appendChild(listElem);
  };

  this.oneShotAllTimer = function() {
    for (var timerName in thisClass.timer) {
      thisClass.timer[timerName].oneShot();
    }
  }
  this.abortAllTimer = function() {
    for (var timerName in thisClass.timer) {
      thisClass.timer[timerName].abortTimeout();
    }
  }

  this.show = function(nextPage) {
    switch (nextPage) {
      case undefined:
      case '#close':
      case '#':
      case '':
        for (var pageToHide in thisClass.pages) {
          if (pageToHide != nextPage) {
            thisClass.pages[pageToHide].hide();
          }
        }
        location.hash = '';
        thisClass.homepage.show();
        document.body.appendChild(mainSite.modalWaitForContent);
        return true;
      case thisClass.menu.system.target.reboot.target:
        if (thisClass.pages.LoginPage && thisClass.pages.LoginPage.visible) {
          return false;
        }
        thisClass.modal.setAttribute('id', thisClass.menu.system.target.reboot.target);
        new RebootDevice().prepare();
        return true;
      case thisClass.menu.system.target.factory_reset.target:
        if (thisClass.pages.LoginPage && thisClass.pages.LoginPage.visible) {
          return false;
        }
        thisClass.modal.setAttribute('id', thisClass.menu.system.target.factory_reset.target);
        new FactoryReset().prepare();
        return true;
      case 'Disclaimer':
        if (thisClass.pages.LoginPage && thisClass.pages.LoginPage.visible) {
          return false;
        }
        new Disclaimer().prepare();
        return true;
      case thisClass.menu.system.target.download_logs.target:
        if (thisClass.pages.LoginPage && thisClass.pages.LoginPage.visible) {
          return false;
        }
        thisClass.modal.setAttribute('id', thisClass.menu.system.target.download_logs.target);
        new DownloadLogs().prepare();
        return true;
      default:
        for (var pageToHide in thisClass.pages) {
          if (pageToHide != nextPage) {
            thisClass.pages[pageToHide].hide();
          }
        }
        if (thisClass.pages[nextPage] !== undefined) {
          thisClass.pages[nextPage].show();
        } else {
          thisClass.homepage.show();
        }
        return true;
    }
    location.hash = '';
    document.body.appendChild(mainSite.modalWaitForContent);
    return false;
  }

  var createLanguageRow = function() {
    // default language English
    var language = "en";
    // try get get a value from the browser (not always senseful)
    var browserLang = navigator.language || navigator.userLanguage;
    language = typeof browserLang !== 'undefined' ? browserLang : "en";
    // Check language cookie and set the language, default is "en"
    var cookieLang = (typeof window.mainSite.localStorage !== 'undefined') ? mainSite.localStorage.getItem("isc_language") : undefined;
    language = cookieLang ? cookieLang : language;

    i18n.userSelected(language);

    // build language selection
    var langSelection = document.createElement('span');
    langSelection.setAttribute('class', 'glyphicons white globe_af');
    langSelection.setAttribute('column', '1');
    var langSelect = document.createElement('select');
    langSelection.appendChild(langSelect);
    langSelect.setAttribute('class', 'langSelection input--small')
    langSelect.setAttribute('column', '1')
    langSelect.onchange = function() {
      // Store as cookie
      document.cookie = "isc_language=" + this.value;
      if (typeof window.mainSite.localStorage !== 'undefined')
        mainSite.localStorage.setItem('isc_language', this.value);
      // and reload page
      location.reload(true);
    };

    // The supported language names and codes are stored in i18n
    for (var i = 0; i < i18n.lang_names.length; i++) {
      var langOption = document.createElement('option');
      langOption.value = i18n.lang_codes[i];
      // cut locale, use only main code, e.g. "de"
      if (language.substring(0, 2) === i18n.lang_codes[i]) {
        langOption.setAttribute('selected', '');
      }
      langOption.appendChild(document.createTextNode(i18n.lang_names[i]));
      langSelect.appendChild(langOption);
    }

    var languageRow = document.createElement('div');
    languageRow.setAttribute('row', '');
    languageRow.setAttribute('class', 'langBlock');
    var p2 = document.createElement('p');
    p2.setAttribute('column', '9');
    p2.appendChild(langSelection);
    languageRow.appendChild(p2);
    return languageRow;
  }

  var createHeaderRow = function() {
    var div = document.createElement('div');
    div.setAttribute('row', '');
    var h1 = document.createElement('h3');
    h1.setAttribute('column', '9');
    h1.setAttribute('class', 'h3 logo');
    var title = document.createTextNode('');
    h1.appendChild(title);
    thisClass.dataBindings.push(
      function() {
        document.title = (thisClass.shortDeviceInfo) ? thisClass.shortDeviceInfo['KIM-FriendlyName'] : thisClass.kimFriendlyName();
        title.nodeValue = document.title;
      });
    var divLogo = document.createElement('div');
    divLogo.setAttribute('class', 'logoImg');
    divLogo.setAttribute('column', '1');
    var aLogo = document.createElement('a');
    aLogo.setAttribute('href', 'http://www.ise.de');
    var imgLogo = document.createElement('img');
    imgLogo.setAttribute('src', './logo_small.svg');
    imgLogo.setAttribute('width', '102px');
    imgLogo.setAttribute('height', '58px');
    imgLogo.setAttribute('alt', 'ise GmbH Logo');
    aLogo.appendChild(imgLogo);

    divLogo.appendChild(aLogo);
    //divLogo.appendChild(langswitch);
    var nav = document.createElement('nav');
    nav.setAttribute('column', '9');
    nav.setAttribute('class', 'nav');
    var ul = document.createElement('ul');
    thisClass.topnav = ul;
    nav.appendChild(ul);
    div.appendChild(divLogo);
    div.appendChild(h1);
    div.appendChild(nav);
    return div;
  }

  var createFooterRow = function() {
    var div = document.createElement('div');
    div.setAttribute('row', '');
    var p = document.createElement('p');
    var a = document.createElement('a');
    a.setAttribute('href', 'http://www.ise.de');
    a.appendChild(document.createTextNode('ise Individuelle Software und Elektronik GmbH'));
    var version = document.createTextNode('');
    thisClass.dataBindings.push(
      function() {
        if (thisClass.shortDeviceInfo) {
          version.nodeValue = " V" + thisClass.shortDeviceInfo.CurrentFirmwareVersion;
        }
      });
    p.appendChild(document.createTextNode('\u00A9 Copyright 2011-2018 '));
    p.appendChild(a);
    p.appendChild(version);

    div.appendChild(p);
    return div;
  }

  this.prepare = function() {
    if (thisClass.main) {
      return;
    }
    var body = document.body;
    // we use Concise containers and within the containers rows and columns
    // but first create the language row elements; this will also initialize the translations!
    var languageRow = createLanguageRow();

    if (thisClass.headerAndFooterMenu) {
      var headerMenuElem = document.createElement('header');
      headerMenuElem.setAttribute('container', '');
      headerMenuElem.setAttribute('class', 'siteHeaderMenu');
      body.appendChild(headerMenuElem);
      var headerMenuNav = document.createElement('nav');
      headerMenuNav.setAttribute('class', 'headerNav nav');
      thisClass.headerNav = document.createElement('ul');
      headerMenuNav.appendChild(thisClass.headerNav);
      headerMenuElem.appendChild(headerMenuNav);
    }
    // Page header
    var header = document.createElement('header');
    header.setAttribute('container', '');
    header.setAttribute('class', 'siteHeader');
    header.appendChild(createHeaderRow());
    body.appendChild(header);

    // Page content
    thisClass.main = document.createElement('main');
    thisClass.main.setAttribute('container', '');
    thisClass.main.setAttribute('class', 'siteContent');
    body.appendChild(thisClass.main);

    // Page footer
    var footer = document.createElement('footer');
    footer.setAttribute('container', '');
    footer.setAttribute('class', 'siteFooter');
    var sectionLeft = document.createElement('section');
    sectionLeft.setAttribute('class', 'left');
    var sectionRight = document.createElement('section');
    sectionRight.setAttribute('class', 'right');
    sectionLeft.appendChild(createFooterRow());
    sectionRight.appendChild(languageRow);
    footer.appendChild(sectionLeft);
    footer.appendChild(sectionRight);
    body.appendChild(footer);

    if (thisClass.headerAndFooterMenu) {
      var footerMenuElem = document.createElement('footer');
      footerMenuElem.setAttribute('container', '');
      footerMenuElem.setAttribute('class', 'siteFooterMenu');
      body.appendChild(footerMenuElem);
      var footerMenuNav = document.createElement('nav');
      footerMenuNav.setAttribute('class', 'footerNav nav');
      thisClass.footerNav = document.createElement('ul');
      footerMenuNav.appendChild(thisClass.footerNav);
      footerMenuElem.appendChild(footerMenuNav);
    }

    thisClass.createNavMenu();

    // Page modals for messages
    thisClass.modal = document.createElement('div');
    thisClass.modal.setAttribute('id', 'modal');
    thisClass.modal.setAttribute('class', 'modal');
    body.appendChild(thisClass.modal);
    thisClass.modalWaitForContent = document.createElement('div');
    thisClass.modalWaitForContent.setAttribute('class', 'waitForContent modal');
    var spinner = document.createElement('div');
    spinner.setAttribute('class', 'spinner');
    thisClass.modalWaitForContent.appendChild(spinner);
    body.appendChild(thisClass.modalWaitForContent);
    //end createInitialStructure
    try {
      thisClass.setDeviceInfo(JSON.parse(mainSite.sessionStorage.getItem('deviceInfoCache')));
      thisClass.update();
    } catch (err) {}
    thisClass.pages['StatusPage'] = new StatusPage();
    if (!thisClass.homepage) {
      thisClass.homepage = thisClass.pages['StatusPage'];
    }
    var target = location.hash;
    // bugfix if a user presses reload and the target is #modal
    if (target == "#modal") {
      target = "";
      // firefox needs a clean reload:
      location.hash = "";
      location.reload(true);
    }
    if (target.length > 1) {
      target = target.slice(1);
    }
    thisClass.requestData();
    thisClass.show(target);
  };

  this.setDeviceInfo = function(response) {
    if (response && response.data) {
      if (Object.keys(response.data).length > 2) {
        thisClass.deviceInfo = response.data;
        try {
          mainSite.sessionStorage.setItem('deviceInfoCache', JSON.stringify(response));
        } catch (err) {}
      }
      thisClass.shortDeviceInfo = response.data;
    }
  }
  this.setCOs = function(response) {
    if (response && response.data) {
      thisClass.currentCOValues = response.data;
    }
  }

  this.setAppState = function(response) {
    if (response) {
      if (response.data) {
        thisClass.appState = response.data;
      } else if (response.error && response.id == '222') {
        thisClass.appState = null;
      } else {
        thisClass.appState = undefined;
      }
    } else {
      thisClass.appState = undefined;
    }
  }

  this.requestData = function() {
    if (!thisClass.timer.getDeviceInfo) {
      thisClass.timer.getDeviceInfo = new TimedRequest(INTERVAL.MINUTE, 'getDeviceInfo', '', thisClass.setDeviceInfo);
    } else {
      thisClass.timer.getDeviceInfo.timeout = INTERVAL.HALFMINUTE;
    }
    thisClass.timer.getDeviceInfo.addCallbackFunction(thisClass.update);
    thisClass.timer.getDeviceInfo.resetTimeout();
  }
  this.update = function() {
    //update data in site
    for (var i = 0; i < thisClass.dataBindings.length; i++) {
      thisClass.dataBindings[i]();
    }
  }
  this.timer = {};
}
/*
 * ##################################################### End MainSite #####################################################
 */

/*
 * ##################################################### Start StatusPage #####################################################
 */
function StatusPage() {
  if (!(this instanceof StatusPage)) {
    return new StatusPage();
  }
  PageTemplate.call(this);
  var thisClass = this;
  this.hasSDCard = true;
  this.visible = false;
  this.contentSection = undefined;
  this.dataBindings = [];
  this.prepare = function() {
    IscWebService('setKeepAlive', '', function(response) {});
    if (!thisClass.contentSection) {
      thisClass.contentSection = document.createElement('div');
      thisClass.contentSection.setAttribute('row', '');

      var divSystemInfomation = document.createElement('div');
      divSystemInfomation.setAttribute('column', '6');

      var headerSystemInfomation = document.createElement('h3');
      headerSystemInfomation.setAttribute('class', 'h3');
      headerSystemInfomation.appendChild(document.createTextNode(i18n.translate('system_information')));
      divSystemInfomation.appendChild(headerSystemInfomation);

      divSystemInfomation.appendChild(document.createTextNode(i18n.translate('date') + ': '));
      var date = document.createTextNode('');
      divSystemInfomation.appendChild(date);

      divSystemInfomation.appendChild(document.createElement('br'));

      divSystemInfomation.appendChild(document.createTextNode(i18n.translate('startup_time') + ': '));
      var startupTime = document.createTextNode('');
      divSystemInfomation.appendChild(startupTime);

      divSystemInfomation.appendChild(document.createElement('br'));

      divSystemInfomation.appendChild(document.createTextNode(i18n.translate('sd_card_status') + ': '));
      var sdState = document.createTextNode('');
      divSystemInfomation.appendChild(sdState);
      var sdLink = document.createElement('a');
      var sdLinkText = document.createTextNode('');
      sdLink.appendChild(sdLinkText);
      divSystemInfomation.appendChild(sdLink);

      divSystemInfomation.appendChild(document.createElement('br'));
      divSystemInfomation.appendChild(document.createElement('br'));

      divSystemInfomation.appendChild(document.createTextNode(i18n.translate('hostname') + ': '));
      var hostname = document.createTextNode('');
      divSystemInfomation.appendChild(hostname);

      divSystemInfomation.appendChild(document.createElement('br'));

      divSystemInfomation.appendChild(document.createTextNode(i18n.translate('firmware_version') + ': '));
      var firmware_version = document.createTextNode('');
      divSystemInfomation.appendChild(firmware_version);

      divSystemInfomation.appendChild(document.createElement('br'));

      divSystemInfomation.appendChild(document.createTextNode(i18n.translate('macaddress') + ': '));
      var macaddress = document.createTextNode('');
      divSystemInfomation.appendChild(macaddress);

      divSystemInfomation.appendChild(document.createElement('br'));

      divSystemInfomation.appendChild(document.createTextNode(i18n.translate('dhcp') + ': '));
      var dhcp = document.createTextNode('');
      divSystemInfomation.appendChild(dhcp);

      divSystemInfomation.appendChild(document.createElement('br'));

      divSystemInfomation.appendChild(document.createTextNode(i18n.translate('ipaddress') + ': '));
      var ipaddress = document.createTextNode('');
      divSystemInfomation.appendChild(ipaddress);

      divSystemInfomation.appendChild(document.createElement('br'));

      divSystemInfomation.appendChild(document.createTextNode(i18n.translate('subnetmask') + ': '));
      var subnetmask = document.createTextNode('');
      divSystemInfomation.appendChild(subnetmask);

      divSystemInfomation.appendChild(document.createElement('br'));

      divSystemInfomation.appendChild(document.createTextNode(i18n.translate('gateway') + ': '));
      var gateway = document.createTextNode('');
      divSystemInfomation.appendChild(gateway);

      divSystemInfomation.appendChild(document.createElement('br'));

      divSystemInfomation.appendChild(document.createTextNode(i18n.translate('nameserver') + ': '));
      var nameserver = document.createTextNode('');
      divSystemInfomation.appendChild(nameserver);

      divSystemInfomation.appendChild(document.createElement('br'));

      divSystemInfomation.appendChild(document.createTextNode(i18n.translate('ntp') + ': '));
      var ntp = document.createTextNode('');
      divSystemInfomation.appendChild(ntp);

      divSystemInfomation.appendChild(document.createElement('br'));

      divSystemInfomation.appendChild(document.createTextNode(i18n.translate('ntpserver') + ': '));
      var ntpserver = document.createTextNode('');
      divSystemInfomation.appendChild(ntpserver);

      divSystemInfomation.appendChild(document.createElement('br'));

      divSystemInfomation.appendChild(document.createTextNode(i18n.translate('ntpinterval') + ': '));
      var ntpinterval = document.createTextNode('');
      divSystemInfomation.appendChild(ntpinterval);

      divSystemInfomation.appendChild(document.createElement('br'));
      divSystemInfomation.appendChild(document.createElement('br'));

      divSystemInfomation.appendChild(document.createTextNode(i18n.translate('serialnumber') + ': '));
      var serialnumber = document.createTextNode('');
      divSystemInfomation.appendChild(serialnumber);

      divSystemInfomation.appendChild(document.createElement('br'));

      if (mainSite.knxEnabled) {
        divSystemInfomation.appendChild(document.createTextNode(i18n.translate('individual_address') + ': '));
        var individual_address = document.createTextNode('');
        divSystemInfomation.appendChild(individual_address);

        divSystemInfomation.appendChild(document.createElement('br'));

        var additional_individual_addresses_span = document.createElement('span');
        additional_individual_addresses_span.appendChild(document.createTextNode(i18n.translate('additional_individual_addresses') + ': '));
        var additional_individual_addresses = document.createTextNode('');
        additional_individual_addresses_span.appendChild(additional_individual_addresses);
        divSystemInfomation.appendChild(additional_individual_addresses_span);

        divSystemInfomation.appendChild(document.createElement('br'));

        var etsDownloadLabel = document.createTextNode('');
        divSystemInfomation.appendChild(etsDownloadLabel);
        var etsDownload = document.createElement('b');
        var etsDownloadText = document.createTextNode('');
        etsDownload.appendChild(etsDownloadText);
        divSystemInfomation.appendChild(etsDownload);

        divSystemInfomation.appendChild(document.createElement('br'));
      }

      thisClass.dataBindings.push(
        function() {
          if (mainSite.deviceInfo) {
            if (mainSite.deviceInfo.Time) {
              date.nodeValue = new Date(mainSite.deviceInfo.Time.replace(/\+/g, ':') + 'Z').toUTCString();
            }
            if (mainSite.deviceInfo.StartupTime) {
              startupTime.nodeValue = new Date(mainSite.deviceInfo.StartupTime.replace(/\+/g, ':') + 'Z').toUTCString();
            }
            if (mainSite.deviceInfo.SdCardPresent) {
              sdState.nodeValue = i18n.translate('sd_card_status_active').replace(/SDCARDUSAGE|SDCARDSIZE/gi,
                  function(subst) {
                    switch (subst) {
                      case 'SDCARDUSAGE':
                        return mainSite.deviceInfo.SdCardUsage;
                      case 'SDCARDSIZE':
                        return mainSite.deviceInfo.SdCardSize;
                    }
                  }) + ' ';
              if (thisClass.hasSDCard) {
                var href = (checkBrowserName('Firefox') ? 'file://///' : 'file://') + location.host + '/data/';
                sdLink.setAttribute('href', href);
                sdLinkText.nodValue = i18n.translate("sd_card_directory");
              }
            } else {
              sdState.nodeValue = i18n.translate("sd_card_status_not_present");
              sdLink.removeAttribute('href');
              sdLinkText.nodValue = '';
            }
            hostname.nodeValue = mainSite.deviceInfo.Hostname;
            firmware_version.nodeValue = mainSite.deviceInfo.CurrentFirmwareVersion;
            macaddress.nodeValue = mainSite.deviceInfo.MacAddress;
            if (mainSite.deviceInfo.Dhcp.toString().toLowerCase() == "true") {
              dhcp.nodeValue = i18n.translate('on');
            } else {
              dhcp.nodeValue = i18n.translate('off');
            }
            ipaddress.nodeValue = mainSite.deviceInfo.IpAddress;
            subnetmask.nodeValue = mainSite.deviceInfo.SubnetMask;
            gateway.nodeValue = mainSite.deviceInfo.DefaultGateway;
            nameserver.nodeValue = mainSite.deviceInfo.NameServer;
            if (mainSite.deviceInfo.Ntp.toString().toLowerCase() == "true") {
              ntp.nodeValue = i18n.translate('on');
            } else {
              ntp.nodeValue = i18n.translate('off');
            }
            ntpserver.nodeValue = mainSite.deviceInfo.NtpServerAddress;
            ntpinterval.nodeValue = mainSite.deviceInfo.NtpInterval + ' ' + i18n.translate('uom_min');
            serialnumber.nodeValue = mainSite.deviceInfo.KnxSerialNumber;

            if (mainSite.knxEnabled) {
              if (!mainSite.deviceInfo['KIM-IA']) {
                individual_address.nodeValue = i18n.translate("not_set");
                additional_individual_addresses_span.setAttribute('hidden', '');
                additional_individual_addresses.nodeValue = '';
              } else {
                individual_address.nodeValue = mainSite.deviceInfo['KIM-IA'];
                if (!mainSite.deviceInfo['KIM-AIAs']) {
                  additional_individual_addresses_span.setAttribute('hidden', '');
                  additional_individual_addresses.nodeValue = '';
                } else {
                  additional_individual_addresses_span.removeAttribute('hidden');
                  additional_individual_addresses.nodeValue = mainSite.deviceInfo['KIM-AIAs'];
                }
              }
              etsDownloadLabel.nodeValue = i18n.translate("device_APPNAME_is").replace(/APPNAME/gi,
                function(subst) {
                  switch (subst) {
                    case "APPNAME":
                      return mainSite.deviceInfo.AppName;
                  }
                });
              if (mainSite.deviceInfo.EtsDownload) {
                etsDownload.setAttribute('class', 'text--success');
                etsDownloadText.nodeValue = i18n.translate("device_projected");
              } else {
                etsDownload.setAttribute('class', 'text--muted');
                etsDownloadText.nodeValue = i18n.translate("device_not_projected");
              }
            }
          }
        });

      if (mainSite.knxEnabled) {
        divSystemInfomation.appendChild(document.createElement('br'));

        divSystemInfomation.appendChild(document.createTextNode(i18n.translate('knx_programming_mode_is') + ': '));
        var programmingMode = document.createElement('b');
        var programmingModeText = document.createTextNode('');
        programmingMode.appendChild(programmingModeText);
        divSystemInfomation.appendChild(programmingMode);
        var changeProgrammingMode = document.createElement('button');
        changeProgrammingMode.setAttribute('class', 'button--xxsm');
        changeProgrammingMode.onclick = function() {
          changeProgrammingMode.setAttribute('disabled', true);
          IscWebService('setProgrammingMode', {
            'value': !mainSite.deviceInfo.ProgrammingMode
          }, function(response) {
            changeProgrammingMode.removeAttribute('disabled');
            if (response == undefined || response.error) {
              DisplayError(response);
            } else {
              if (mainSite.deviceInfo) {
                mainSite.deviceInfo.ProgrammingMode = response.data.status;
              }
              thisClass.update();
            }
          });
        };
        var changeProgrammingModeText = document.createTextNode('');
        changeProgrammingMode.appendChild(changeProgrammingModeText);
        divSystemInfomation.appendChild(changeProgrammingMode);
        divSystemInfomation.appendChild(document.createElement('br'));

        var spanBusVoltage = document.createElement('span');
        divSystemInfomation.appendChild(document.createTextNode(i18n.translate('knx_bus_voltage_is') + ': '));
        var busVoltage = document.createElement('b');
        var busVoltageText = document.createTextNode('');
        busVoltage.appendChild(busVoltageText);
        divSystemInfomation.appendChild(busVoltage);

        thisClass.dataBindings.push(
          function() {
            // Programming mode button
            if (mainSite.deviceInfo) {
              if (mainSite.deviceInfo.ProgrammingMode == true) {
                programmingModeText.nodeValue = i18n.translate('on') + ' ';
                changeProgrammingModeText.nodeValue = i18n.translate('change_Programming_mode').replace(/CHANGE/gi,
                  function(subst) {
                    switch (subst) {
                      case "CHANGE":
                        return i18n.translate('disable');
                    }
                  });
              } else if (mainSite.deviceInfo.ProgrammingMode == false) {
                programmingModeText.nodeValue = i18n.translate('off') + ' ';
                changeProgrammingModeText.nodeValue = i18n.translate("change_Programming_mode").replace(/CHANGE/gi,
                  function(subst) {
                    switch (subst) {
                      case "CHANGE":
                        return i18n.translate('enable');
                    }
                  });
              }
            }
            // KNX bus voltage active
            if (mainSite.deviceInfo) {
              if (mainSite.deviceInfo.KnxBusVoltage == true) {
                busVoltageText.nodeValue = i18n.translate('on');
              } else if (mainSite.deviceInfo.KnxBusVoltage == false) {
                busVoltageText.nodeValue = i18n.translate('off');
              }
            }
          });
      }

      divSystemInfomation.appendChild(document.createElement('br'));
      divSystemInfomation.appendChild(document.createElement('br'));

      var headerSystemConfiguration = document.createElement('h3');
      headerSystemConfiguration.setAttribute('class', 'h3');
      headerSystemConfiguration.appendChild(document.createTextNode(i18n.translate('system_configuration')));
      divSystemInfomation.appendChild(headerSystemConfiguration);

      var italicRebootOnChangeWarning = document.createElement('i');
      italicRebootOnChangeWarning.appendChild(document.createTextNode(i18n.translate('system_configuration_reboot_on_change_warning')));
      divSystemInfomation.appendChild(italicRebootOnChangeWarning);

      divSystemInfomation.appendChild(document.createElement('br'));
      divSystemInfomation.appendChild(document.createElement('br'));

      var divDebugMode = document.createElement('div');
      divDebugMode.appendChild(document.createTextNode(i18n.translate('logging_mode') + ': '));
      var loggingMode = document.createTextNode('');
      divDebugMode.appendChild(loggingMode);
      var changeLoggingMode = document.createElement('button');
      changeLoggingMode.setAttribute('class', 'button--xxsm');
      changeLoggingMode.onclick = function() {
        var modal = new DebugLogging();
        modal.prepare();
      };
      var changeLoggingModeText = document.createTextNode('');
      changeLoggingMode.appendChild(changeLoggingModeText);
      divDebugMode.appendChild(changeLoggingMode);
      var loggingModeAutoDisable = document.createTextNode('');
      divDebugMode.appendChild(loggingModeAutoDisable);
      thisClass.dataBindings.push(
        function() {
          if (mainSite.deviceInfo && mainSite.deviceInfo.DebugMode) {
            if (mainSite.deviceInfo.DebugMode === "INACTIVE") {
              loggingMode.nodeValue = i18n.translate("logging_mode_normal") + " ";
              changeLoggingModeText.nodeValue = i18n.translate("logging_mode_change").replace(/CHANGE/gi,
                function(subst) {
                  switch (subst) {
                    case "CHANGE":
                      return i18n.translate("logging_mode_activate");
                  }
                });
              loggingModeAutoDisable.nodeValue = '';
            } else {
              loggingMode.nodeValue = i18n.translate("logging_mode_extended") + " ";
              changeLoggingModeText.nodeValue = i18n.translate("logging_mode_change").replace(/CHANGE/gi,
                function(subst) {
                  switch (subst) {
                    case "CHANGE":
                      return i18n.translate("logging_mode_deactivate");
                  }
                });
              loggingModeAutoDisable.nodeValue = ' (' + i18n.translate('logging_automatically_disabled') + ' ' + mainSite.deviceInfo.DebugMode + ")";
            }
          }
        });
      divSystemInfomation.appendChild(divDebugMode);

      divSystemInfomation.appendChild(document.createElement('br'));
      divSystemInfomation.appendChild(document.createElement('br'));

      thisClass.contentSection.appendChild(divSystemInfomation);

      var divAppInfomation = document.createElement('div');
      divAppInfomation.setAttribute('column', '6');
      thisClass.prepareAppInfo(divAppInfomation);
      divAppInfomation.appendChild(document.createElement('br'));
      divAppInfomation.appendChild(document.createElement('br'));
      thisClass.contentSection.appendChild(divAppInfomation);
    }
    mainSite.main.appendChild(thisClass.contentSection);
    thisClass.requestData();
    thisClass.update();
  };

  this.appendDOMFragmentKimCoInfoTo = function(parentElement, kimCoID) {
    var textNode = document.createTextNode(i18n.translate('pending'));
    parentElement.appendChild(document.createTextNode(i18n.translate('co_state_' + kimCoID) + ': '));
    var span = document.createElement('span');
    span.setAttribute('class', 'text--muted');
    span.appendChild(textNode);
    parentElement.appendChild(span);
    this.dataBindings.push(function() {
      if (mainSite.currentCOValues && mainSite.currentCOValues.COs) {
        for (var i in mainSite.currentCOValues.COs) {
          var currentCO = mainSite.currentCOValues.COs[i];
          if (kimCoID == currentCO.id) {
            span.setAttribute('class', 'text--muted');
            textNode.nodeValue = i18n.translate('unknown');
            thisClass.updateCO(span, textNode, currentCO)
          }
        }
      }
    });
  };

  this.appendDOMFragmentAppStateTo = function(parentElement) {
    var appStateText = document.createTextNode('');
    parentElement.appendChild(appStateText);
    var b = document.createElement('b');
    var stateTxt = document.createTextNode('')
    b.appendChild(stateTxt);
    parentElement.appendChild(b);
    var ending = document.createTextNode('');
    parentElement.appendChild(ending);
    parentElement.appendChild(document.createElement('br'));
    parentElement.appendChild(document.createElement('br'));
    thisClass.dataBindings.push(function() {
      if (mainSite.appState && mainSite.deviceInfo) {
        if (mainSite.appState != null) {
          appStateText.nodeValue = i18n.translate('state_of_app').replace('APPNAME', mainSite.deviceInfo.AppName) + ' ';
          switch (mainSite.appState.state) {
            case 'Stopped':
              stateTxt.nodeValue = i18n.translate('state_of_app_stopped');
              b.setAttribute('class', 'text--error');
              break;
            case 'Starting':
              stateTxt.nodeValue = i18n.translate('state_of_app_starting');
              b.setAttribute('class', 'text--warning');
              break;
            case 'Running':
              stateTxt.nodeValue = i18n.translate('state_of_app_running');
              b.setAttribute('class', 'text--success');
              break;
            case 'Stopping':
              stateTxt.nodeValue = i18n.translate('state_of_app_stopping');
              b.setAttribute('class', 'text--warning');
              break;
            default:
              stateTxt.nodeValue = i18n.translate('state_of_app_unknown');
              b.setAttribute('class', 'text--muted');
          }
          ending.nodeValue = '!';
        } else {
          b.setAttribute('class', 'text--error');
          appStateText.nodeValue = i18n.translate('logical_knx_id') + ' ' + mainSite.deviceInfo.AppName;
          stateTxt.nodeValue = ' ' + i18n.translate('not_found');
          ending.nodeValue = '!';

        }
      }
    });
  }

  this.requestData = function() {
    mainSite.timer.getDeviceInfo.addCallbackFunction(thisClass.update);
    mainSite.timer.getDeviceInfo.oneShot();

    if (!mainSite.timer.getAllCOs) {
      mainSite.timer.getAllCOs = new TimedRequest(INTERVAL.HALFMINUTE, 'getAllCOs', '', mainSite.setCOs, thisClass);
      mainSite.timer.getAllCOs.addCallbackFunction(thisClass.update);
    } else {
      mainSite.timer.getAllCOs.timeout = INTERVAL.HALFMINUTE;
      mainSite.timer.getAllCOs.addCallbackFunction(thisClass.update);
    }
    mainSite.timer.getAllCOs.resetTimeout();
    mainSite.timer.getAllCOs.oneShot();

    if (!mainSite.timer.getAppState) {
      mainSite.timer.getAppState = new TimedRequest(INTERVAL.HALFMINUTE, 'getAppState', '', mainSite.setAppState, thisClass);
      mainSite.timer.getAppState.addCallbackFunction(thisClass.update);
      mainSite.timer.getAppState.oneShot();
    } else {
      mainSite.timer.getAppState.timeout = INTERVAL.HALFMINUTE;
      mainSite.timer.getAppState.addCallbackFunction(thisClass.update);
    }
    mainSite.timer.getAppState.resetTimeout();
    mainSite.timer.getAppState.oneShot();
  };
  this.update = function() {
    //update data in site
    for (var i = 0; i < thisClass.dataBindings.length; i++) {
      thisClass.dataBindings[i]();
    }
  };
}
StatusPage.prototype = new PageTemplate();
StatusPage.prototype.constructor = StatusPage;
/*
 * ##################################################### End StatusPage #####################################################
 */

/*
 * ##################################################### Start DebugLogging #####################################################
 */
function DebugLogging() {
  if (!(this instanceof DebugLogging)) {
    return new DebugLogging();
  }
  IscWebService('setKeepAlive', '', function(response) {});
  var modalHeaderText = i18n.translate("logging_mode_change").replace(/CHANGE/gi,
    function(subst) {
      switch (subst) {
        case "CHANGE":
          return i18n.translate((mainSite.deviceInfo.DebugMode == "INACTIVE") ? "logging_mode_activate" : "logging_mode_deactivate");
      }
    });
  var modalBodyText = i18n.translate("confirm_change_debug_mode");
  ModalConfirmDialogYesNo.call(this, modalHeaderText, modalBodyText);
  var thisClass = this;
  this.id = 'DebugLogging';
  this.DebugModeOn = 'on';
  this.DebugModeOff = 'off';

  this.setCallbackFunction(function(returnVal) {
    if (returnVal) {
      var val = (mainSite.deviceInfo.DebugMode == "INACTIVE") ? thisClass.DebugModeOn : thisClass.DebugModeOff;
      IscWebService("writeDebug", {
        'value': val
      }, function(response) {
        if (response == undefined || response.error) {
          DisplayError(response);
        } else {
          setTimeout(function() {
            location.reload(true);
          }, 1000 * 60 * 2);
          new WaitForReboot().prepare();
        }
      });
    }
  });
}
DebugLogging.prototype = new ModalConfirmDialogYesNo();
DebugLogging.prototype.constructor = DebugLogging;

/*
 * ##################################################### End DebugLogging #####################################################
 */

/*
 * ##################################################### Start RebootDevice #####################################################
 */

function RebootDevice() {
  if (!(this instanceof RebootDevice)) {
    return new RebootDevice();
  }
  IscWebService('setKeepAlive', '', function(response) {});
  ModalConfirmDialogYesNo.call(this, i18n.translate('reboot'), i18n.translate('confirm_reboot'))
  var thisClass = this;
  this.id = 'RebootDevice';
  this.setCallbackFunction(function(returnVal) {
    if (returnVal) {
      IscWebService("doReboot", "", function(response) {
        if (response == undefined || response.error) {
          DisplayError(response);
        } else {
          new WaitForReboot().prepare();
        }
      });
    }
  });
}
RebootDevice.prototype = new ModalConfirmDialogYesNo();
RebootDevice.prototype.constructor = RebootDevice;
/*
 * ##################################################### End RebootDevice #####################################################
 */

/*
 * ##################################################### Start DisplayError #####################################################
 */
function DisplayError(response) {
  if (response == undefined) {
    var dialog = new ModalConfirmDialogOk(i18n.translate("something_wrong"), i18n.translate('device_unavailable'));
    dialog.setCallbackFunction(function() {
      document.body.appendChild(mainSite.modalWaitForContent);
    });
    dialog.prepare();
  } else if (response.id) {
    if (response.id == ERROR_ID.NOT_AUTHORIZED) {
      new ModalConfirmDialogOk(i18n.translate("something_wrong"), i18n.translate('error_' + response.id)).prepare();
    } else if (response.id == ERROR_ID.NO_UPLOADSLOT) {
      new ModalConfirmDialogOk(i18n.translate("something_wrong"), i18n.translate('no_upload_slot'), i18n.translate('no_upload_slot') + ' ' + i18n.translate('hint_reboot_after_error')).prepare();
    } else {
      new ModalConfirmDialogOk(i18n.translate("something_wrong"), i18n.translate(response.error) + ' (' + response.id + ')').prepare();
    }
  } else {
    new ModalConfirmDialogOk(i18n.translate("something_wrong"), i18n.translate(response.error)).prepare();
  }
}
function CreateErrorDialog(text) {
  new ModalConfirmDialogOk(i18n.translate('something_wrong'), text).prepare();
}
/*
 * ##################################################### End DisplayError #####################################################
 */

/*
* ##################################################### Start Disclaimer #####################################################
*/

function Disclaimer() {
  if (!(this instanceof Disclaimer)) {
    return new Disclaimer();
  }
  IscWebService('setKeepAlive', '', function(response) {});
  ModalConfirmDialogOk.call(this, i18n.translate('disclaimer'), i18n.translate('disclaimer_text'));
  var thisClass = this;
  this.id = 'Disclaimer';
}
Disclaimer.prototype = new ModalConfirmDialogOk();
Disclaimer.prototype.constructor = Disclaimer;
/*
 * ##################################################### End Disclaimer #####################################################
 */

/*
* ##################################################### Start FactoryReset #####################################################
*/

function FactoryReset() {
  if (!(this instanceof FactoryReset)) {
    return new FactoryReset();
  }
  IscWebService('setKeepAlive', '', function(response) {});
  ModalConfirmDialogYesNo.call(this, i18n.translate('factory_reset'), i18n.translate('confirm_factory_reset'));
  this.waitForRebootDialog = undefined;
  var thisClass = this;
  this.id = 'FactoryReset';
  this.setCallbackFunction(function(returnVal) {
    if (returnVal) {
      IscWebService("doFactoryReset", {}, function(response) {
        if (response == undefined || response.error) {
          DisplayError(response);
        } else {
          new WaitForReboot().prepare();
        }
      });
    }
  });

}
FactoryReset.prototype = new ModalConfirmDialogYesNo();
FactoryReset.prototype.constructor = FactoryReset;
/*
 * ##################################################### End FactoryReset #####################################################
 */

/*
 * ##################################################### Start WaitForReboot #####################################################
 */

function WaitForReboot() {
  if (!(this instanceof WaitForReboot)) {
    return new WaitForReboot();
  }
  ModalSpinnerDialog.call(this, i18n.translate('wait_for_reboot_header'), i18n.translate('wait_for_reboot_text'));
  var thisClass = this;
  this.id = 'WaitForReboot';
  this.setCallbackFunction(function() {});
  this.prepareBase = thisClass.prepare;
  this.prepare = function() {
    thisClass.prepareBase();
    setTimeout(thisClass.request, INTERVAL.HALFMINUTE);
  }
  this.request = function() {
    IscWebService('setKeepAlive', '', thisClass.waitForReboot);
  }
  this.waitForReboot = function(response) {
    if (response != undefined) {
      thisClass.close();
      mainSite.rebootBecauseOfAnUpdate = false;
      mainSite.show();
    } else {
      setTimeout(thisClass.request, INTERVAL.HALFMINUTE);
    }
  };
}
WaitForReboot.prototype = new ModalSpinnerDialog();
WaitForReboot.prototype.constructor = WaitForReboot;
/*
 * ##################################################### End WaitForReboot #####################################################
 */

/*
 * ##################################################### Start DownloadLogs #####################################################
 */
var MAXRETRIES = 3;

function DownloadLogs() {
  if (!(this instanceof DownloadLogs)) {
    return new DownloadLogs();
  }
  IscWebService('setKeepAlive', '', function(response) {});
  ModalSpinnerDialog.call(this, i18n.translate("download_logs"), i18n.translate("download_logs_started"));
  var thisClass = this;
  this.id = 'DownloadLogs';
  this.setCallbackFunction(function() {});
  this.prepareBase = thisClass.prepare;
  this.prepare = function() {
    thisClass.prepareBase();
    thisClass.downloadLogs();
  }
  this.downloadLogs = function(retries) {
    var retries = retries || MAXRETRIES;
    IscWebService('getLogfile', '', function(response) {
      if (response == undefined) {
        DisplayError(response);
        return;
      }
      if (response.error) {
        if (response.id == ERROR_ID.ENCRYPTION_EXPCTED && retries > 0) {
          setTimeout(function() {
            thisClass.downloadLogs(retries--);
          }, 1000);
        } else {
          DisplayError(response);
        }
        return;
      }

      var name = '';
      if (mainSite.deviceInfo) {
        name = mainSite.deviceInfo.DeviceId + '_';
      }
      name += new Date().toJSON() + '-logfile.zip';
      var byteCharacters = atob(response.data.content);
      var byteNumbers = new Array(byteCharacters.length);
      for (var i = 0; i < byteCharacters.length; i++) {
        byteNumbers[i] = byteCharacters.charCodeAt(i);
      }
      var byteArray = new Uint8Array(byteNumbers);

      if (navigator.userAgent.match(/Macintosh|iPad|Phone|Pod/i) == null) {
        var blob = new Blob([byteArray], {
          type: "application/zip"
        });
      }
      thisClass.showDone(i18n.translate('download_logs_finished'));
      var link = document.createElement('a');
      if (navigator.userAgent.match(/Macintosh|iPad|Phone|Pod/i) != null) {
        link.setAttribute("href", "data:application/zip;base64," + response.data.content);
        link.appendChild(document.createTextNode(i18n.translate('click_here')));
        link.setAttribute("download", name);
      } else {
        link.setAttribute("href", URL.createObjectURL(blob));
        link.appendChild(document.createTextNode(i18n.translate('click_here')));
        link.setAttribute("download", name);
      }
      thisClass.modalBody.appendChild(link);
      if (navigator.msSaveBlob) {
        window.navigator.msSaveOrOpenBlob(blob, name);
      } else {

        console.log(navigator.appVersion);
        link.click();
      //        window.URL.revokeObjectURL(link.href);
      }
    });
  }

}
DownloadLogs.prototype = new ModalSpinnerDialog();
DownloadLogs.prototype.constructor = DownloadLogs;
/*
 * ##################################################### End DownloadLogs #####################################################
 */

/*
 * ##################################################### Start ModalDialog #####################################################
 * ModalDialogs need Header and Text There are several Dialogtypes (YesNo, OkCancel, Ok, Progress, Spinner)
 */
function ModalConfirmDialogYesNo(modalHeaderText, modalBodyText) {
  ModalDialog.call(this, modalHeaderText, modalBodyText);
  var thisClass = this;
  this.callbackFunction = function() {};
  this.setCallbackFunction = function(newCallbackFunction) {
    thisClass.callbackFunction = newCallbackFunction;
  }
  this.onYes = function() {
    thisClass.callbackFunction(true);
    thisClass.close();
  };
  this.onNo = function() {
    thisClass.callbackFunction(false);
    thisClass.close();
  };
  this.prepare = function() {
    if (!thisClass.modalContainer) {
      thisClass.prepareDialog();
      thisClass.prepareYesNo();
    }
    thisClass.show();
    return thisClass.modalContainer;
  };
  this.prepareYesNo = function() {
    var yesNoUl = document.createElement('ul');
    var yesLi = document.createElement('li');
    var yesButton = document.createElement('button');
    yesButton.setAttribute('class', 'button--xsm');
    yesButton.setAttribute('column', '2');
    yesButton.onclick = thisClass.onYes;
    yesButton.appendChild(document.createTextNode(i18n.translate('btn_yes')));
    yesLi.appendChild(yesButton);
    yesNoUl.appendChild(yesLi);
    var noLi = document.createElement('li');
    var noButton = document.createElement('button');
    noButton.setAttribute('class', 'button--xsm');
    noButton.setAttribute('column', '2');
    noButton.onclick = thisClass.onNo;
    noButton.appendChild(document.createTextNode(i18n.translate('btn_no')));
    noLi.appendChild(noButton);
    yesNoUl.appendChild(noLi);
    thisClass.modalFooter.appendChild(yesNoUl);
  }

}
ModalConfirmDialogYesNo.prototype = new ModalDialog();
ModalConfirmDialogYesNo.prototype.constructor = ModalConfirmDialogYesNo;

function ModalConfirmDialogOkCancel(modalHeaderText, modalBodyText, btnOKText, btnCancelText) {
  ModalDialog.call(this, modalHeaderText, modalBodyText);
  var thisClass = this;
  var btnOKText = btnOKText || i18n.translate('btn_ok');
  var btnCancelText = btnCancelText || i18n.translate('btn_cancel');
  this.callbackFunction = function() {};
  this.setCallbackFunction = function(newCallbackFunction) {
    thisClass.callbackFunction = newCallbackFunction;
  }
  this.onOk = function() {
    thisClass.callbackFunction(true);
    thisClass.close();
  };
  this.onCancel = function() {
    thisClass.callbackFunction(false);
    thisClass.close();
  };
  this.prepare = function() {
    if (!thisClass.modalContainer) {
      thisClass.prepareDialog();
      thisClass.prepareOKCancel();
    }
    thisClass.show();
    return thisClass.modalContainer;
  };
  this.prepareOKCancel = function() {
    var okCancelUl = document.createElement('ul');
    var okLi = document.createElement('li');
    var okButton = document.createElement('button');
    okButton.setAttribute('class', 'button--xsm');
    okButton.setAttribute('column', '2');
    okButton.onclick = thisClass.onOk;
    okButton.appendChild(document.createTextNode(btnOKText));
    okLi.appendChild(okButton);
    okCancelUl.appendChild(okLi);
    var cancelLi = document.createElement('li');
    var cancelButton = document.createElement('button');
    cancelButton.setAttribute('class', 'button--xsm');
    cancelButton.setAttribute('column', '2');
    cancelButton.onclick = thisClass.onCancel;
    cancelButton.appendChild(document.createTextNode(btnCancelText));
    cancelLi.appendChild(cancelButton);
    okCancelUl.appendChild(cancelLi);
    thisClass.modalFooter.appendChild(okCancelUl);
  }

}
ModalConfirmDialogOkCancel.prototype = new ModalDialog();
ModalConfirmDialogOkCancel.prototype.constructor = ModalConfirmDialogOkCancel;

function ModalConfirmDialogOk(modalHeaderText, modalBodyText) {
  ModalDialog.call(this, modalHeaderText, modalBodyText);
  var thisClass = this;
  this.callbackFunction = function() {};
  this.setCallbackFunction = function(newCallbackFunction) {
    thisClass.callbackFunction = newCallbackFunction;
  }
  this.onOk = function() {
    thisClass.callbackFunction(true);
    thisClass.close();
  };
  this.prepare = function() {
    if (!thisClass.modalContainer) {
      thisClass.prepareDialog();
      thisClass.prepareOK();
    }
    thisClass.show();
    return thisClass.modalContainer;
  };
  this.prepareOK = function() {
    var okUl = document.createElement('ul');
    var okLi = document.createElement('li');
    var okButton = document.createElement('button');
    okButton.setAttribute('class', 'button--xsm');
    okButton.setAttribute('column', '2');
    okButton.onclick = thisClass.onOk;
    okButton.appendChild(document.createTextNode(i18n.translate('btn_ok')));
    okLi.appendChild(okButton);
    okUl.appendChild(okLi);
    thisClass.modalFooter.appendChild(okUl);
  };
}
ModalConfirmDialogOk.prototype = new ModalDialog();
ModalConfirmDialogOk.prototype.constructor = ModalConfirmDialogOk;

function ModalProgressDialog(modalHeaderText, modalBodyText) {
  ModalDialog.call(this, modalHeaderText, modalBodyText);
  var thisClass = this;
  this.callbackFunction = function() {};
  this.setCallbackFunction = function(newCallbackFunction) {
    thisClass.callbackFunction = newCallbackFunction;
  }
  this.updateProgress = function() {};
  thisClass.okFooter = undefined;
  this.showDone = thisClass.addFooterOK;
  this.onOk = function() {
    thisClass.callbackFunction(true);
    thisClass.close();
  };
  this.prepare = function() {
    if (!thisClass.modalContainer) {
      thisClass.prepareDialog();
      thisClass.prepareProgress();
    }
    thisClass.show();
    return thisClass.modalContainer;
  };
  this.prepareProgress = function() {
    var divProgress = document.createElement('div');
    divProgress.setAttribute('class', 'progress');
    var spanProgress = document.createElement('span');
    spanProgress.setAttribute('style', 'width: 50%');
    var txtProgress = document.createTextNode('');
    spanProgress.appendChild(txtProgress);
    divProgress.appendChild(spanProgress);
    thisClass.modalFooter.appendChild(divProgress);
    thisClass.updateProgress = function(progress, newText) {
      if (0 <= progress && progress <= 100) {
        spanProgress.setAttribute('style', 'width: ' + progress + '%');
        txtProgress.nodeValue = Math.floor(progress) + '%';
        if (thisClass.okFooter && thisClass.modalFooter.contains(thisClass.okFooter)) {
          thisClass.modalFooter.removeChild(thisClass.okFooter);
        }
      } else if (progress == 101) {
        spanProgress.setAttribute('style', 'width: 100%');
        txtProgress.nodeValue = '100%';
        if (!thisClass.modalFooter.contains(thisClass.okFooter)) {
          thisClass.addFooterOK();
        }
        // signal reboot because of an update
        mainSite.rebootBecauseOfAnUpdate = true;
      }
      if (newText && thisClass.modalBody.hasChildNodes()) {
        thisClass.modalBody.childNodes[0].nodeValue = i18n.translate(newText);
      }
    };
  };
  thisClass.addFooterOK = function() {
    if (thisClass.okFooter == undefined) {
      thisClass.okFooter = document.createElement('ul');
      var okLi = document.createElement('li');
      var okButton = document.createElement('button');
      okButton.setAttribute('class', 'button--xsm');
      okButton.setAttribute('column', '2');
      okButton.onclick = thisClass.onOk;
      okButton.appendChild(document.createTextNode(i18n.translate('btn_ok')));
      okLi.appendChild(okButton);
      thisClass.okFooter.appendChild(okLi);
    }
    thisClass.modalFooter.appendChild(thisClass.okFooter);
  };
}
ModalProgressDialog.prototype = new ModalDialog();
ModalProgressDialog.prototype.constructor = ModalProgressDialog;

function ModalSpinnerDialog(modalHeaderText, modalBodyText) {
  ModalDialog.call(this, modalHeaderText, modalBodyText);
  var thisClass = this;
  this.callbackFunction = function() {};
  this.setCallbackFunction = function(newCallbackFunction) {
    thisClass.callbackFunction = newCallbackFunction;
  }
  this.showDone = function() {};
  this.prepare = function() {
    if (!thisClass.modalContainer) {
      thisClass.prepareDialog();
      thisClass.prepareSpinner();
    }
    thisClass.show();
    return thisClass.modalContainer;
  };
  this.prepareSpinner = function() {
    var divSpinner = document.createElement('div');
    divSpinner.setAttribute('class', 'spinner');
    thisClass.modalBody.appendChild(divSpinner);
    thisClass.showDone = function(doneText) {
      if (doneText) {
        thisClass.setText(i18n.translate(doneText));
        divSpinner.setAttribute('hidden', '');
        thisClass.addFooterOK();
      } else {
        thisClass.onOk();
      }
    };
  }
  this.onOk = function() {
    thisClass.callbackFunction(true);
    thisClass.close();
  };
  this.addFooterOK = function() {
    var okUl = document.createElement('ul');
    var okLi = document.createElement('li');
    var okButton = document.createElement('button');
    okButton.setAttribute('class', 'button--xsm');
    okButton.setAttribute('column', '2');
    okButton.onclick = thisClass.onOk;
    okButton.appendChild(document.createTextNode(i18n.translate('btn_ok')));
    okLi.appendChild(okButton);
    okUl.appendChild(okLi);
    thisClass.modalFooter.appendChild(okUl);
  };
}
ModalSpinnerDialog.prototype = new ModalDialog();
ModalSpinnerDialog.prototype.constructor = ModalSpinnerDialog;

function ModalDialog(modalHeaderText, modalBodyText) {
  var thisClass = this;
  this.id = 'modal';
  this.modalHeaderText = modalHeaderText;
  this.modalBodyText = modalBodyText;
  this.lastPage = undefined;
  this.modalContainer = undefined;
  thisClass.modalHeader = undefined;
  thisClass.modalBody = undefined;
  thisClass.modalFooter = undefined;

  this.getLastPage = function() {
    return thisClass.lastPage
  };
  this.setHeader = function(newModalHeaderText) {
    modalHeaderText = newModalHeaderText;
    thisClass.modalBody.firstChild.nodeValue = modalHeaderText;
  }
  this.setText = function(newModalBodyText) {
    modalBodyText = newModalBodyText;
    thisClass.modalBody.firstChild.nodeValue = modalBodyText;
  }

  this.prepareDialog = function() {
    thisClass.modalContainer = document.createElement('div');
    thisClass.modalContainer.setAttribute('class', 'modal-container');
    thisClass.modalHeader = document.createElement('div');
    thisClass.modalHeader.setAttribute('class', 'modal-header');
    thisClass.modalHeader.appendChild(document.createTextNode(modalHeaderText));
    var modalClose = document.createElement('a');
    modalClose.setAttribute('class', 'modal-close');
    modalClose.setAttribute('href', '#close');
    modalClose.appendChild(document.createTextNode('\u00D7'));
    thisClass.modalHeader.appendChild(modalClose);
    thisClass.modalBody = document.createElement('div');
    thisClass.modalBody.setAttribute('class', 'modal-body');
    thisClass.modalBody.appendChild(document.createTextNode(modalBodyText));
    thisClass.modalFooter = document.createElement('div');
    thisClass.modalFooter.setAttribute('class', 'modal-footer ');
    thisClass.modalContainer.appendChild(thisClass.modalHeader);
    thisClass.modalContainer.appendChild(thisClass.modalBody);
    thisClass.modalContainer.appendChild(thisClass.modalFooter);
  };
  this.show = function() {
    thisClass.lastPage = (mainSite.currentModalDialog !== undefined) ? mainSite.currentModalDialog.getLastPage() : (location.hash.length > 1 ? location.hash.slice(1) : '');
    if (mainSite.modal && mainSite.modal.hasChildNodes()) {
      mainSite.modal.removeChild(mainSite.modal.childNodes[0]);
    }
    mainSite.modal.appendChild(thisClass.modalContainer);
    mainSite.currentModalDialog = thisClass;
    mainSite.modal.setAttribute('id', thisClass.id);
    location.hash = '#' + thisClass.id;
  };
  this.close = function() {
    location.hash = '#close';
    location.hash = thisClass.lastPage;
    mainSite.modal.setAttribute('id', 'modal');
    mainSite.currentModalDialog = undefined;
    mainSite.show(thisClass.lastPage);
  };
}
/*
 * ##################################################### End ModalDialog #####################################################
 */

/*
 * ##################################################### Start Encryption #####################################################
 */

var encryption = new NullEncryption();
var RSA_DECRYPTION_METHOD = 'RSAES-PKCS1-V1_5';
var RSA_KEYLENGTH = 1024;
var AES_CIPHER = 'AES-OFB';
var IV_LENGTH = 16;

function Encryption() {
  var thisClass = this;
  this.disabled = false;
  this.isActivated = function() {
    return false;
  }
  this.decrypt = function(encrypted) {
    return encrypted;
  }
  this.encrypt = function(encrypted) {
    return encrypted;
  }
  this.rsaEncryption = undefined;
}

function NullEncryption() {
  if (!(this instanceof NullEncryption)) {
    return new NullEncryption();
  }
  Encryption.call(this);
}
NullEncryption.prototype = new Encryption();
NullEncryption.prototype.constructor = NullEncryption;

function RSAEncryption() {
  if (encryption.rsaEncryption) {
    encryption.rsaEncryption.initSecureSession();
    return encryption.rsaEncryption;
  } else {
    encryption.rsaEncryption = this;
  }
  Encryption.call(this);
  var thisClass = this;
  this.rsaEncryption = thisClass;
  var cipher = undefined;
  var decipher = undefined;
  this.initializing = true;
  var privateKey = undefined;
  this.isActivated = function() {
    return thisClass.rsaEncryption && !thisClass.initializing;
  };
  this.decrypt = function(encrypted) {
    if (decipher == undefined) {
      return encrypted;
    } else if (encrypted.charAt(0) == '{') {
      mainSite.sessionStorage.removeItem('symmetricKey');
      decipher = undefined;
      cipher = undefined;
      return encrypted;
    }
    var iv = forge.util.hexToBytes(encrypted.substr(0, IV_LENGTH * 2));
    var data = encrypted.substr(IV_LENGTH * 2);
    decipher.start({
      iv: iv
    });
    decipher.update(forge.util.createBuffer(forge.util.hexToBytes(data)));
    decipher.finish();
    return decipher.output;
  };
  this.encrypt = function(data) {
    if (cipher == undefined || thisClass.initializing) {
      return data;
    }
    var iv = forge.random.getBytesSync(IV_LENGTH);
    cipher.start({
      iv: iv
    });
    cipher.update(forge.util.createBuffer(data));
    cipher.finish();
    return forge.util.bytesToHex(iv) + cipher.output.toHex();
  };
  this.setPrivateKey = function(newPrivateKey) {
    privateKey = newPrivateKey
  };
  var timeout;
  this.onHeloEncryption = function(event) {
    if (event.key === 'heloEncryption') {
      mainSite.localStorage.setItem('transferSymmetricKey', mainSite.sessionStorage.getItem('symmetricKey'));
      mainSite.localStorage.removeItem('transferSymmetricKey');
    }
  }
  this.onTransferSymmetricKey = function() {
    if (event.key === 'transferSymmetricKey') {
      var hexKey = event.newValue;
      if (hexKey != null) {
        thisClass.updateKey(hexKey);
        privateKey = 'readSymmetricKeyFrommainSite.sessionStorage';
        mainSite.oneShotAllTimer();
      }
    }
  }
  this.initSecureSession = function() {
    if (thisClass.initializing) {
      return;
    }
    thisClass.initializing = true;
    var keypair = forge.pki.rsa.generateKeyPair({
      bits: RSA_KEYLENGTH,
      workers: 2
    });
    thisClass.setPrivateKey(keypair.privateKey);
    IscWebService('initSecureSession', {
      'time': new Date().toISOString(),
      'public_key': forge.pki.publicKeyToPem(keypair.publicKey)
    }, function(response) {
      thisClass.init(response);
      mainSite.oneShotAllTimer();
    });
  }
  this.init = function(response) {
    try {
      var decoded = atob(response);
      var decrypted = privateKey.decrypt(decoded, RSA_DECRYPTION_METHOD);
      var json = JSON.parse(decrypted);
      thisClass.updateKey(json.data.secret_key);
      return true;
    } catch (exception) {
      cipher = undefined;
      decipher = undefined;
    }
    return false;
  }
  this.updateKey = function(hexKey) {
    var oldKey = mainSite.sessionStorage.getItem('symmetricKey');
    if (encryption == thisClass && hexKey == oldKey)
      return;
    var key = forge.util.hexToBytes(hexKey);
    mainSite.sessionStorage.setItem('symmetricKey', hexKey);
    window.removeEventListener('storage', thisClass.onTransferSymmetricKey, false);
    mainSite.localStorage.setItem('transferSymmetricKey', mainSite.sessionStorage.getItem('symmetricKey'));
    mainSite.localStorage.removeItem('transferSymmetricKey');
    window.addEventListener('storage', thisClass.onTransferSymmetricKey, false);
    if (thisClass.cipher == undefined) {
      window.addEventListener('storage', thisClass.onHeloEncryption, false);
    }
    cipher = forge.cipher.createCipher(AES_CIPHER, key);
    decipher = forge.cipher.createDecipher(AES_CIPHER, key);
    encryption = thisClass;
    thisClass.initializing = false;
  }
  var hexKey = mainSite.sessionStorage.getItem('symmetricKey')
  if (hexKey) {
    thisClass.updateKey(hexKey);
    privateKey = 'readSymmetricKeyFrommainSite.sessionStorage';
    mainSite.oneShotAllTimer();
  } else {
    window.addEventListener('storage', thisClass.onTransferSymmetricKey, false);
    mainSite.localStorage.removeItem('heloEncryption');
    setTimeout(function() {
      thisClass.initializing = false; thisClass.initSecureSession();
    }, 2000);
  }
}
RSAEncryption.prototype = new Encryption();
RSAEncryption.prototype.constructor = RSAEncryption;

/*
 * ##################################################### End Encryption #####################################################
 */

/*
 * ##################################################### Start IscWebService #####################################################
 */

var ERROR_ID = {
  NOT_AUTHORIZED: '235',
  ENCRYPTION_EXPCTED: '237',
  NO_UPLOADSLOT: '243',
  WAITING_FOR_DATA: '244'
}
function IscWebService(command, value, onResponse, keepAlive) {
  keepAlive = keepAlive | false;
  if (!mainSite.requestsEnabled) {
    return;
  }
  var msg;
  if (value) {
    msg = {
      command: command,
      data: value
    };
  } else {
    msg = {
      command: command
    };
  }
  if (keepAlive)
    msg.keepAlive = true;
  var onReadyStateFunction = function(response) {
    onResponse(response);
  };
  var onFail = function(xhttpstatus) {
    setTimeout(function() {
      onResponse(undefined);
      if (mainSite.modalWaitForContent && !document.body.contains(mainSite.modalWaitForContent) && !mainSite.rebootBecauseOfAnUpdate) {
        // connection error detected
        DisplayError();
        mainSite.connectionError = true;
      }
    },
      250)
  };
  var xhttp = new XMLHttpRequest();
  xhttp.open("POST", "/api", true);
  xhttp.setRequestHeader("Content-type", "application/json");
  xhttp.timeout = 60000;
  xhttp.onreadystatechange = function() {
    if (xhttp.readyState == 4) {
      if (xhttp.status == 200 || xhttp.status == 201) {
        if (msg.command == 'initSecureSession') {
          onReadyStateFunction(xhttp.response);
          return;
        }
        var data = undefined;
        try {
          data = JSON.parse(encryption.decrypt(xhttp.response));
        } catch (SyntaxError) {
          onReadyStateFunction(undefined);
          return;
        }
        /*
                try {
                  var message = {request: JSON.stringify(msg), response: JSON.stringify(data), responseRaw: xhttp.response };
                  console.dir(message);
                } catch (exception) {
                  console.log("Could not stringify received data!");
                }
        */
        if (data.error) {
          switch (data.id) {
            case ERROR_ID.NOT_AUTHORIZED:
              mainSite.abortAllTimer();
              mainSite.show('LoginPage');
              onReadyStateFunction(data);
              return;
            case ERROR_ID.ENCRYPTION_EXPCTED:
              mainSite.abortAllTimer();
              new RSAEncryption();
              onReadyStateFunction(data);
              return;
          }
        }
        if (mainSite.modalWaitForContent && document.body.contains(mainSite.modalWaitForContent)) {
          document.body.removeChild(mainSite.modalWaitForContent);
          if (mainSite.connectionError) {
            location.reload(true);
          }
        }
        onReadyStateFunction(data);
      } else {
        onFail(xhttp.status);
      }
    }
  };
  xhttp.onerror = function(e) {
    onFail();
  };
  xhttp.send(encryption.encrypt(JSON.stringify(msg)));
}
/*
 * ##################################################### End IscWebService #####################################################
 */

/*
 * ##################################################### Start Helper Functions #####################################################
 */

function createGlyphIconSpan(name, color) {
  var glyphSpan = document.createElement('span');
  var glyphString = "glyphicons ";
  if (color === 'white') {
    glyphString += "white " + name;
  } else {
    glyphString += "black " + name;
  }
  glyphSpan.setAttribute('class', glyphString);
  return glyphSpan;
}

function createGlyphIconButton(name, color) {
  var glyphSpan = document.createElement('button');
  var glyphString = "button--xsm glyphicons " + name;
  glyphSpan.setAttribute('class', glyphString);
  return glyphSpan;
}


/*
 * ##################################################### End Helper Functions #####################################################
 *//*###################################################### begin of www/web/ChangePassword.js #############################################*/
/*
 * ######################################## Start ChangePasswordPage ########################################
 */
function ChangePasswordPage() {
  if (!(this instanceof ChangePasswordPage)) {
    return new ChangePasswordPage();
  }
  PageTemplate.call(this);
  var thisClass = this;
  this.visible = false;
  this.contentSection = undefined;
  this.dataBindings = [];
  this.prepare = function() {
    IscWebService('setKeepAlive', '', function(response) {});
    if (!thisClass.contentSection) {
      thisClass.contentSection = document.createElement('div');
      var header = document.createElement('h3');
      header.setAttribute('class', 'h3');
      header.appendChild(document.createTextNode(i18n.translate('change_password')));
      thisClass.contentSection.appendChild(header);
      var paragraph = document.createElement('p');
      if (i18n.translate('this_will_not_affect_password_for') != 'this_will_not_affect_password_for' && i18n.translate('this_will_not_affect_password_for') != '') {
        paragraph.appendChild(document.createTextNode(i18n.translate('this_will_not_affect_password_for')));
        if (i18n.translate('webportalurl') != 'webportalurl' && i18n.translate('webportalurl') != '') {
          var alink = document.createElement('a');
          alink.setAttribute('href', i18n.translate('webportalurl'));
          alink.appendChild(document.createTextNode(i18n.translate('webportalurl')));
          paragraph.appendChild(alink);
        }
        paragraph.appendChild(document.createTextNode('.'));
      }
      thisClass.contentSection.appendChild(paragraph);
      thisClass.contentSection.appendChild(document.createElement('br'));
      var formPasswordForm = document.createElement('form');
      formPasswordForm.setAttribute('class', 'passwordform');

      var minPasswordLength = 6;
      var maxPasswordLength = 40;
      var passwordPattern = '.{' + minPasswordLength + ',' + maxPasswordLength + '}';

      var pCurrentPassword = document.createElement('p');
      var labelCurrentPassword = document.createElement('label');
      labelCurrentPassword.setAttribute('id', 'translate_oldpassword');
      labelCurrentPassword.setAttribute('for', 'oldPassword');
      labelCurrentPassword.appendChild(document.createTextNode(i18n.translate('current_password')));
      pCurrentPassword.appendChild(labelCurrentPassword);
      var inputCurrentPassword = document.createElement('input');
      inputCurrentPassword.setAttribute('type', 'password');
      inputCurrentPassword.setAttribute('id', 'oldPassword');
      inputCurrentPassword.setAttribute('pattern', passwordPattern);
      inputCurrentPassword.setAttribute('maxlength', '40');
      inputCurrentPassword.setAttribute('required', '');
      inputCurrentPassword.setAttribute('autofocus', '');
      pCurrentPassword.appendChild(inputCurrentPassword);
      formPasswordForm.appendChild(pCurrentPassword);

      thisClass.setFocus = function() {
        inputCurrentPassword.focus();
      }

      var pNewPassword0 = document.createElement('p');
      var labelNewPassword0 = document.createElement('label');
      labelNewPassword0.setAttribute('id', 'translate_oldpassword0');
      labelNewPassword0.setAttribute('for', 'newPassword0');
      labelNewPassword0.appendChild(document.createTextNode(i18n.translate('new_password_MINPASSWORDLENGTH_MAXPASSWORDLENGTH').replace(/MINPASSWORDLENGTH|MAXPASSWORDLENGTH/gi,
        function(subst) {
          switch (subst) {
            case 'MINPASSWORDLENGTH':
              return minPasswordLength;
            case 'MAXPASSWORDLENGTH':
              return maxPasswordLength;
          }
        })));
      pNewPassword0.appendChild(labelNewPassword0);
      var inputNewPassword0 = document.createElement('input');
      inputNewPassword0.setAttribute('type', 'password');
      inputNewPassword0.setAttribute('id', 'newPassword0');
      inputNewPassword0.setAttribute('pattern', passwordPattern);
      inputNewPassword0.setAttribute('maxlength', '40');
      inputNewPassword0.setAttribute('required', '');
      pNewPassword0.appendChild(inputNewPassword0);
      formPasswordForm.appendChild(pNewPassword0);

      var pNewPassword1 = document.createElement('p');
      var labelNewPassword1 = document.createElement('label');
      labelNewPassword1.setAttribute('id', 'translate_newpassword1');
      labelNewPassword1.setAttribute('for', 'newPassword1');
      labelNewPassword1.appendChild(document.createTextNode(i18n.translate('new_password_again')));
      pNewPassword1.appendChild(labelNewPassword1);
      var inputNewPassword1 = document.createElement('input');
      inputNewPassword1.setAttribute('type', 'password');
      inputNewPassword1.setAttribute('id', 'newPassword1');
      inputNewPassword1.setAttribute('pattern', passwordPattern);
      inputNewPassword1.setAttribute('maxlength', '40');
      inputNewPassword1.setAttribute('required', '');
      pNewPassword1.appendChild(inputNewPassword1);
      formPasswordForm.appendChild(pNewPassword1);

      var pButtonSubmit = document.createElement('p');
      var buttonSubmit = document.createElement('button');
      buttonSubmit.setAttribute('type', 'submit');
      buttonSubmit.setAttribute('class', 'button--xsm');
      buttonSubmit.appendChild(document.createTextNode(i18n.translate('submit')));
      pButtonSubmit.appendChild(buttonSubmit);
      formPasswordForm.appendChild(pButtonSubmit);

      formPasswordForm.onsubmit = function(event) {
        event.preventDefault();
        if (!event.target.checkValidity()) {
          return;
        }
        if (mainSite.authentication == undefined || mainSite.sessionStorage.getItem('authkeyVer') == null
          || mainSite.sessionStorage.getItem('salt') == null
          || mainSite.sessionStorage.getItem('username') == null) {
          mainSite.show('LoginPage');
          return;
        }
        var setError = function(message) {
          document.getElementById('errors').firstChild.nodeValue = i18n.translate(message);
        };
        if (inputNewPassword0.value !== inputNewPassword1.value) {
          setError('new_password_not_match');
          return;
        }
        var username = mainSite.sessionStorage.getItem('username');
        var oldSalt = mainSite.sessionStorage.getItem('salt');
        IscWebService('getNewPasswordSalt', {
          'username': username,
          'oldSalt': oldSalt
        }, function(response) {
          if (response === undefined || response.error) {
            DisplayError(response);
            return;
          } else {
            var username = mainSite.sessionStorage.getItem('username');
            var authkeyFunction = mainSite.authentication.getAuthkeyfunction(mainSite.sessionStorage.getItem('authkeyVer'));
            var oldHash = authkeyFunction(inputCurrentPassword, mainSite.sessionStorage.getItem('salt'));
            var oldHashSalted = mainSite.authentication.computeAuthToken(oldHash, response.data.newPasswordSalt);
            var newHash = authkeyFunction(inputNewPassword1, response.data.newPasswordSalt);
            mainSite.sessionStorage.setItem('newSalt', response.data.newPasswordSalt);
            IscWebService('writeNewPasswordHash', {
              'username': username,
              'version': mainSite.sessionStorage.getItem('authkeyVer'),
              'newSalt': response.data.newPasswordSalt,
              'oldHash': oldHashSalted,
              'newHash': newHash
            },
              function(response) {
                if (response === undefined || response.error) {
                  DisplayError(response);
                  return;
                } else {
                  new ModalConfirmDialogOk(i18n.translate('change_password'), i18n.translate('password_changed')).prepare();
                  formPasswordForm.reset();
                  mainSite.sessionStorage.setItem('salt', mainSite.sessionStorage.getItem('newSalt'));
                  mainSite.sessionStorage.removeItem('newSalt');

                }
              });
          }
        });
      };
      thisClass.contentSection.appendChild(formPasswordForm);
      var pErrors = document.createElement('p');
      pErrors.setAttribute('id', 'errors');
      pErrors.appendChild(document.createTextNode(''));
      thisClass.contentSection.appendChild(pErrors);
    }
    mainSite.main.appendChild(thisClass.contentSection);
    thisClass.requestData();
    thisClass.update();
    thisClass.setFocus();
  };
  this.setFocus = undefined;

  this.requestData = function() {
    mainSite.timer.getDeviceInfo.oneShot();
  };
  this.update = function() {
    //update data in site
    for (var i = 0; i < thisClass.dataBindings.length; i++) {
      thisClass.dataBindings[i]();
    }
  };
}
ChangePasswordPage.prototype = new PageTemplate();
ChangePasswordPage.prototype.constructor = ChangePasswordPage;
/*
 * ######################################## End ChangePasswordPage ########################################
 */
/*###################################################### end of www/web/ChangePassword.js #############################################*/
/*###################################################### begin of www/web/FirmwareUpdatePage.js #############################################*/
/*
 * ##################################################### Start FirmwareUpdatePage #####################################################
 */
function FirmwareUpdatePage() {
  if (!(this instanceof FirmwareUpdatePage)) {
    return new FirmwareUpdatePage();
  }
  PageTemplate.call(this);
  var thisClass = this;
  this.updateProcess = undefined;
  this.isStartUpdatePossible = true;
  this.firmwareUpdateInfo = undefined;
  this.prepare = function() {
    IscWebService('setKeepAlive', '', function(response) {});
    thisClass.isStartUpdatePossible = true;
    if (!thisClass.contentSection) {
      thisClass.contentSection = document.createElement('div');
      var h3OnlineUpdate = document.createElement('h3');
      h3OnlineUpdate.setAttribute('class', 'h3');
      h3OnlineUpdate.appendChild(document.createTextNode(i18n.translate('online_update')));
      thisClass.contentSection.appendChild(h3OnlineUpdate);
      var h4CurrentFirmware = document.createElement('h4');
      h4CurrentFirmware.setAttribute('class', 'h4');
      var h4CurrentFirmwareText = document.createTextNode('');
      h4CurrentFirmware.appendChild(h4CurrentFirmwareText);
      thisClass.dataBindings.push(
        function() {
          if (mainSite.deviceInfo) {
            h4CurrentFirmwareText.nodeValue = i18n.translate('current_version_VERSION').replace('VERSION', mainSite.deviceInfo.CurrentFirmwareVersion);
          }
        });
      thisClass.contentSection.appendChild(h4CurrentFirmware);
      var h4NewFirmware = document.createElement('h4');
      thisClass.contentSection.appendChild(h4NewFirmware);
      var h4NewFirmwareText = document.createTextNode('');
      h4NewFirmware.appendChild(h4NewFirmwareText);

      var buttonPerformUpdate = document.createElement('button');
      buttonPerformUpdate.setAttribute('class', 'button--xsm');
      buttonPerformUpdate.setAttribute('hidden', '');
      buttonPerformUpdate.appendChild(document.createTextNode(i18n.translate('perform_update')));
      buttonPerformUpdate.onclick = thisClass.startOnlineUpdate;
      var pDescription = document.createElement('p');
      pDescription.setAttribute('hidden', '');
      var pDescriptionText = document.createTextNode('');
      pDescription.appendChild(pDescriptionText);
      thisClass.contentSection.appendChild(pDescription);
      var pWarnMessage = document.createElement('p');
      pWarnMessage.setAttribute('hidden', '');
      var pWarnMessageText = document.createTextNode('');
      pWarnMessage.appendChild(pWarnMessageText);
      thisClass.contentSection.appendChild(pWarnMessage);

      thisClass.contentSection.appendChild(buttonPerformUpdate);
      this.dataBindings.push(function() {
        if (thisClass.isFirmwareUpdateInfoPending()) {
          h4NewFirmwareText.nodeValue = i18n.translate('update_info_pending');
          return;
        }
        if (!thisClass.isFirmwareUpdateServerAvailable()) {
          h4NewFirmwareText.nodeValue = i18n.translate('update_server_unavailable');
          return;
        }
        if (!thisClass.isFirmwareAvailable()) {
          h4NewFirmwareText.nodeValue = i18n.translate('no_newer_version'); //i18n.translate('no_firmware_available');
          return;
        }
        if (thisClass.isNewerFirmwareAvailable()) {
          h4NewFirmwareText.nodeValue = i18n.translate('no_newer_version');
          return;
        }
        h4NewFirmwareText.nodeValue = i18n.translate('new_version_available_VERSION').replace('VERSION', thisClass.firmwareUpdateInfo.firmwareVersion);
        buttonPerformUpdate.removeAttribute('hidden');
        pDescription.removeAttribute('hidden');
        pDescriptionText.nodeValue = '';
        if (thisClass.firmwareUpdateInfo.description) {
          if (thisClass.firmwareUpdateInfo.description[i18n.language]) {
            pDescriptionText.nodeValue = thisClass.firmwareUpdateInfo.description[i18n.language];
          } else {
            pDescriptionText.nodeValue = thisClass.firmwareUpdateInfo.description.en;
          }
        }
        if (thisClass.firmwareUpdateInfo.incompatibleFirmware) {
          pWarnMessage.removeAttribute('hidden');
          pWarnMessage.setAttribute('class', 'alert alert--error');
          pWarnMessageText.nodeValue = i18n.translate('new_incompatible_functionality');
          buttonPerformUpdate.onclick = function() {
            new InfoMessage('new_incompatible_functionality', thisClass.startOnlineUpdate).prepare();
          };
        } else if (thisClass.firmwareUpdateInfo.newFeatures) {
          pWarnMessage.removeAttribute('hidden');
          pWarnMessage.setAttribute('class', 'alert alert--warning');
          pWarnMessageText.nodeValue = i18n.translate('new_compatible_firmware');
          buttonPerformUpdate.onclick = function() {
            new InfoMessage('new_compatible_firmware', thisClass.startOnlineUpdate).prepare();
          };
        } else {
          pWarnMessage.setAttribute('hidden', '');
        }
      });
      if (thisClass.isLocalUpdateAllowed()) {
        thisClass.contentSection.appendChild(document.createElement('br'));
        thisClass.contentSection.appendChild(document.createElement('br'));
        var h3LocalUpdate = document.createElement('h3');
        h3LocalUpdate.setAttribute('class', 'h3');
        h3LocalUpdate.appendChild(document.createTextNode(i18n.translate('local_update')));
        thisClass.contentSection.appendChild(h3LocalUpdate);
        var h4UploadFirmware = document.createElement('h4');
        h4UploadFirmware.setAttribute('class', 'h4');
        h4UploadFirmware.appendChild(document.createTextNode(i18n.translate('upload_firmware_file')));
        thisClass.contentSection.appendChild(h4UploadFirmware);
        var formLocalUpdate = document.createElement('form');
        var divLocalUpdate = document.createElement('div');
        divLocalUpdate.setAttribute('class', 'upload');
        var inputFileUpload = document.createElement('input');
        inputFileUpload.setAttribute('class', 'fileupload');
        inputFileUpload.setAttribute('type', 'file');
        inputFileUpload.setAttribute('accept', 'application/zip');
        var chosen_file = document.createTextNode(' ' + i18n.translate('no_file_chosen'));
        var buttonFileUpload = document.createElement('button');
        buttonFileUpload.setAttribute('class', 'button--xsm');
        buttonFileUpload.appendChild(document.createTextNode(i18n.translate('choose_file')));
        buttonFileUpload.onclick = function(event) {
          event.preventDefault();
          inputFileUpload.click();
        };
        divLocalUpdate.appendChild(inputFileUpload);
        divLocalUpdate.appendChild(buttonFileUpload);
        divLocalUpdate.appendChild(chosen_file);
        formLocalUpdate.appendChild(divLocalUpdate);
        formLocalUpdate.appendChild(document.createElement('br'));
        var pLocalUpdateInfo = document.createElement('p');
        pLocalUpdateInfo.setAttribute('hidden', '');
        var pLocalUpdateInfoText = document.createTextNode(i18n.translate('local_update_compatibility_warning'));
        pLocalUpdateInfo.setAttribute('class', 'text_hint');
        pLocalUpdateInfo.appendChild(pLocalUpdateInfoText);
        formLocalUpdate.appendChild(pLocalUpdateInfo);
        var buttonFirmwareUpdate = document.createElement('button');
        buttonFirmwareUpdate.setAttribute('class', 'button--xsm');
        inputFileUpload.onchange = function() {
          if (inputFileUpload.files.length == 0) {
            chosen_file.nodeValue = ' ' + i18n.translate('no_file_chosen');
            buttonFirmwareUpdate.setAttribute('disabled', '');
            pLocalUpdateInfo.setAttribute('hidden', '');
            return false;
          }
          chosen_file.nodeValue = ' ' + inputFileUpload.files[0].name;
          if (thisClass.isStartUpdatePossible) buttonFirmwareUpdate.removeAttribute('disabled');
          pLocalUpdateInfo.removeAttribute('hidden');
          return true;
        };
        buttonFirmwareUpdate.setAttribute('disabled', '');
        buttonFirmwareUpdate.appendChild(document.createTextNode(i18n.translate('perform_update')));
        buttonFirmwareUpdate.onclick = function(event) {
          buttonPerformUpdate.setAttribute('disabled', '');
          event.preventDefault();
          IscWebService('doFirmwareUpdate', {
            'request': 'initlocalupload'
          }, function(response) {
            if (response == undefined || response.error) {
              DisplayError(response);
              return;
            }
            thisClass.upload(inputFileUpload);
          });
        };
        formLocalUpdate.appendChild(buttonFirmwareUpdate);
        thisClass.contentSection.appendChild(formLocalUpdate);
      }
      thisClass.dataBindings.push(function() {
        if (!thisClass.isStartUpdatePossible) {
          buttonPerformUpdate.setAttribute('disabled', '');
          buttonFirmwareUpdate.setAttribute('disabled', '');
        }
      });
    }
    mainSite.main.appendChild(thisClass.contentSection);
    thisClass.requestData();
    thisClass.update();
  };

  this.isFirmwareUpdateInfoPending = function() {
    return true;
  };
  this.isFirmwareUpdateServerAvailable = function() {
    return true;
  };
  this.isFirmwareAvailable = function() {
    if (thisClass.firmwareUpdateInfo && thisClass.firmwareUpdateInfo.firmwareVersion) {
      return true;
    }
    return false;
  }

  this.isNewerFirmwareAvailable = function() {
    if (thisClass.firmwareUpdateInfo == undefined) {
      return false;
    }
    if (thisClass.firmwareUpdateInfo.firmwareVersion == mainSite.deviceInfo.CurrentFirmwareVersion) {
      return true;
    }
    return false;
  }
  this.isLocalUpdateAllowed = function() {
    return true;
  }

  this.startOnlineUpdate = function() {
    IscWebService('doFirmwareUpdate', {
      'request': 'startonlineupdate'
    }, function(response) {
      if (response == undefined || response.error) {
        DisplayError(response);
        return;
      }
      mainSite.timer.firmwareupdateStatus.timeout = INTERVAL.TWOSECONDS;
      mainSite.timer.firmwareupdateStatus.resetTimeout();
    })
  }

  this.upload = function(inputFileUpload) {
    var uploadSessiontimer = new TimedRequest(INTERVAL.MINUTE, 'setKeepAlive', '', function() {}, thisClass);
    uploadSessiontimer.resetTimeout();
    var xhr = new XMLHttpRequest();
    var dialog = new UploadProgress();
    dialog.prepare();
    dialog.setCallbackFunction(function(returnVal) {
      if (!returnVal) {
        thisClass.updateProcess = undefined;
        xhr.abort();
      }
    });
    xhr.onreadystatechange = function() {
      if (xhr.readyState == 4) {
        if (xhr.status == 200 || xhr.status == 201) {
          var decrypted = encryption.decrypt(xhr.response);
          var response = JSON.parse(decrypted);
          if (JSON.stringify(response) == '{}') {
            dialog.setComplete();
            uploadSessiontimer.abortTimeout();
          }
          if (response && response.error) {
            DisplayError(response);
          }
        } else {
          dialog.transferFailed();
        }
        uploadSessiontimer.abortTimeout();
        mainSite.timer.firmwareupdateStatus.timeout = INTERVAL.TWOSECONDS;
        mainSite.timer.firmwareupdateStatus.resetTimeout();
      }
    };
    xhr.open('POST', '/api/upload', true);
    xhr.upload.onprogress = dialog.setProgress;
    xhr.onerror = dialog.transferCanceled;
    var formData = new FormData();
    formData.append('file', inputFileUpload.files[0]);
    xhr.setRequestHeader('FileSize', inputFileUpload.files[0].size);
    xhr.setRequestHeader('FileTarget', 'FWUpdate');
    xhr.onerror = dialog.transferFailed;
    xhr.onabort = dialog.transferCanceled;
    xhr.send(formData);
  }

  this.startLocalUpdate = function() {
    IscWebService('doFirmwareUpdate', {
      'request': 'startlocalupdate'
    }, function(response) {
      if (response == undefined || response.error) {
        DisplayError(response);
        return;
      }
      mainSite.timer.firmwareupdateStatus.timeout = INTERVAL.TWOSECONDS;
      mainSite.timer.firmwareupdateStatus.resetTimeout();
    })
  }

  this.setFirmwareUpdateStatus = function(response) {
    if (response == undefined) {
      setTimeout(mainSite.timer.firmwareupdateStatus.oneShot, INTERVAL.SECOND);
      mainSite.timer.firmwareupdateStatus.timeout = INTERVAL.MINUTE;
      thisClass.isStartUpdatePossible = true;
      return;
    }
    if (response.error) {
      if (response.id == ERROR_ID.ENCRYPTION_EXPCTED || response.id == ERROR_ID.NOT_AUTHORIZED) {
        setTimeout(mainSite.timer.firmwareupdateStatus.oneShot, INTERVAL.SECOND);
      }
      mainSite.timer.firmwareupdateStatus.timeout = INTERVAL.MINUTE;
      thisClass.updateProcess = undefined;
      thisClass.isStartUpdatePossible = true;
      mainSite.timer.firmwareupdateStatus.timeout = INTERVAL.MINUTE;
      return;
    }
    if (response.data.status == 'IDLE') {
      thisClass.updateProcess = undefined;
      thisClass.isStartUpdatePossible = true;
      mainSite.timer.firmwareupdateStatus.setKeepAlive(false);
      mainSite.timer.firmwareupdateStatus.timeout = INTERVAL.MINUTE;
      return;
    } else if (response.data.status == 'MAINTENANCE') {
      thisClass.updateProcess = undefined;
      thisClass.isStartUpdatePossible = false;
      mainSite.timer.firmwareupdateStatus.setKeepAlive(false);
      mainSite.timer.firmwareupdateStatus.timeout = INTERVAL.MINUTE;
      new ModalConfirmDialogOk(i18n.translate('firmware_update'), i18n.translate('error_maintenance_pending')).prepare();
      return;
    }
    mainSite.timer.firmwareupdateStatus.timeout = INTERVAL.TWOSECONDS;
    if (thisClass.updateProcess == undefined && response.data.status != 'SUCCESS') {
      thisClass.updateProcess = new UpdateProcess(thisClass);
      thisClass.updateProcess.prepare();
      thisClass.isStartUpdatePossible = false;
    }
    if (thisClass.updateProcess) thisClass.updateProcess.setProgress(response.data);
  }

  this.updateInfoOnlineInfoInterval = INTERVAL.SECOND;
  thisClass.setFirmwareUpdateInfo = function(response) {
    if (response == undefined) {
      setTimeout(mainSite.timer.firmwareupdateInfo.oneShot, thisClass.updateInfoOnlineInfoInterval *= 2);
      return;
    }
    if (response.error) {
      if (response.id == ERROR_ID.WAITING_FOR_DATA) {
        setTimeout(mainSite.timer.firmwareupdateInfo.oneShot, thisClass.updateInfoOnlineInfoInterval *= 2);
        thisClass.isFirmwareUpdateInfoPending = function() {
          if (thisClass.updateInfoOnlineInfoInterval < INTERVAL.MINUTE) {
            setTimeout(mainSite.timer.firmwareupdateInfo.oneShot, thisClass.updateInfoOnlineInfoInterval *= 2);
          }
          return true;
        };
        return;
      }
      thisClass.isFirmwareUpdateInfoPending = function() {
        return false;
      };
      thisClass.isFirmwareUpdateServerAvailable = function() {
        return false;
      };
      thisClass.firmwareUpdateInfo = undefined;
      return;
    }
    thisClass.isFirmwareUpdateInfoPending = function() {
      return false;
    };
    thisClass.isFirmwareUpdateServerAvailable = function() {
      return true;
    };
    thisClass.firmwareUpdateInfo = response.data;
  }


  this.requestData = function() {
    if (!mainSite.timer.firmwareupdateStatus) {
      mainSite.timer.firmwareupdateStatus = new TimedRequest(INTERVAL.MINUTE, 'getFirmwareUpdate', {
        'request': 'status'
      }, thisClass.setFirmwareUpdateStatus, thisClass);
      mainSite.timer.firmwareupdateStatus.addCallbackFunction(thisClass.update);
    } else {
      mainSite.timer.firmwareupdateStatus.timeout = INTERVAL.MINUTE;
      mainSite.timer.firmwareupdateStatus.addCallbackFunction(thisClass.update);
    }
    mainSite.timer.firmwareupdateStatus.resetTimeout();
    mainSite.timer.firmwareupdateStatus.oneShot();

    if (!mainSite.timer.firmwareupdateInfo) {
      mainSite.timer.firmwareupdateInfo = new TimedRequest(INTERVAL.NONE, 'getFirmwareUpdate', {
        'request': 'infoonline'
      }, thisClass.setFirmwareUpdateInfo, thisClass);
      mainSite.timer.firmwareupdateInfo.addCallbackFunction(thisClass.update);
    } else {
      mainSite.timer.firmwareupdateInfo.timeout = INTERVAL.NONE;
      mainSite.timer.firmwareupdateInfo.addCallbackFunction(thisClass.update);
    }
    mainSite.timer.firmwareupdateInfo.oneShot();
    mainSite.timer.getDeviceInfo.oneShot();

  };
  this.update = function() {
    for (var i = 0; i < thisClass.dataBindings.length; i++) {
      thisClass.dataBindings[i]();
    }
  };
}
FirmwareUpdatePage.prototype = new PageTemplate();
FirmwareUpdatePage.prototype.constructor = FirmwareUpdatePage;
/*
 * ##################################################### End FirmwareUpdatePage #####################################################
 */

/*
 * ##################################################### Start UploadProgress #####################################################
 */

function UploadProgress() {
  if (!(this instanceof UploadProgress)) {
    return new UploadProgress();
  }
  ModalProgressDialog.call(this, i18n.translate('update_progress'), i18n.translate('uploading_firmware') + '. ' + i18n.translate('do_not_close_until'));
  var thisClass = this;
  this.id = 'FirmwareUploadProgress';
  var parentPrepare = thisClass.prepare;
  this.prepare = function() {
    parentPrepare();
    var cancelUl = document.createElement('ul');
    var cancelLi = document.createElement('li');
    var cancelButton = document.createElement('button');
    cancelButton.setAttribute('class', 'button--xsm');
    cancelButton.setAttribute('column', '2');
    cancelButton.onclick = thisClass.onCancel;
    cancelButton.appendChild(document.createTextNode(i18n.translate('btn_cancel')));
    cancelLi.appendChild(cancelButton);
    cancelUl.appendChild(cancelLi);
    thisClass.modalFooter.appendChild(cancelUl);
    thisClass.updateProgress(0, i18n.translate('uploading_firmware') + '. ' + i18n.translate('do_not_close_until'));
  }
  this.onCancel = function() {
    thisClass.callbackFunction(false);
    IscWebService('resetUploadSlot', '', function() {});
    thisClass.close();
  };
  this.setProgress = function(evt) {
    if (evt.lengthComputable) {
      var percentComplete = 100 * (evt.loaded / evt.total);
      if (percentComplete < 100) {
        thisClass.updateProgress(percentComplete, i18n.translate('uploading_firmware') + '. ' + i18n.translate('do_not_close_until'));
      } else {
        if (thisClass.processingSignal == undefined) {
          thisClass.processingSignal = 0;
          thisClass.processing = function() {
            if (mainSite.currentModalDialog == thisClass) {
              thisClass.processingSignal++;
              if (thisClass.processingSignal == 100) {
                thisClass.processingSignal = 0;
              }
              thisClass.updateProgress(thisClass.processingSignal, i18n.translate('processing_firmware') + ' ' + i18n.translate('do_not_close_until'));
              setTimeout(thisClass.processing, 1150 + thisClass.processingSignal);
            }
          }
          thisClass.processing();
        }
      }
    }
  };
  this.processingSignal = undefined;
  this.processing = function() {};
  this.setComplete = function() {
    thisClass.updateProgress(100, i18n.translate('uploading_firmware_complete'));
  };
  this.transferFailed = function(evt) {
    IscWebService('resetUploadSlot', '', function() {});
    var dialog = new ModalConfirmDialogOk(i18n.translate('firmware_update_error'), i18n.translate('hint_reboot_after_error'));
    dialog.prepare();

  };
  this.transferCanceled = function(evt) {
    IscWebService('resetUploadSlot', '', function() {});
    thisClass.close();
  };
}
UploadProgress.prototype = new ModalProgressDialog();
UploadProgress.prototype.constructor = UploadProgress;
/*
 * ##################################################### End UploadProgress #####################################################
 */
/*
 * ##################################################### Start InfoMessage #####################################################
 */

function InfoMessage(infoMessage, onOkFunction) {
  if (!(this instanceof InfoMessage)) {
    return new InfoMessage();
  }
  var onOkFunction = onOkFunction;
  ModalConfirmDialogYesNo.call(this, i18n.translate('really_update'), i18n.translate(infoMessage))
  var thisClass = this;
  this.id = 'InfoMessage';
  this.setCallbackFunction(function(returnVal) {
    if (returnVal) {
      onOkFunction();
    }
  });
}
RebootDevice.prototype = new ModalConfirmDialogYesNo();
RebootDevice.prototype.constructor = RebootDevice;
/*
 * ##################################################### End InfoMessage #####################################################
 */

/*
* ##################################################### Start UpdateProcess #####################################################
*/

function UpdateProcess(firmwareUpdatePage) {
  if (!(this instanceof UpdateProcess)) {
    return new UpdateProcess();
  }
  ModalProgressDialog.call(this, i18n.translate('update_progress'), i18n.translate('download_firmware'));
  this.id = 'FirmwareUpdateProgress';
  var thisClass = this;
  this.firmwareUpdatePage = firmwareUpdatePage;
  this.setCallbackFunction(function(returnVal) {
    if (returnVal) {
      thisClass.firmwareUpdatePage.updateProcess = undefined;
      var waitForReboot = new WaitForReboot();
      setTimeout(waitForReboot.prepare, 1000);
    }
  });
  this.onOk = function() {
    thisClass.callbackFunction(true);
  };
  this.setProgress = function(data) {
    switch (data.status) {
      case 'MAINTENANCE':
        var errorMessage = i18n.translate('error_maintenance_pending');
      case 'LOCKED':
      case 'ERROR':
        mainSite.timer.firmwareupdateStatus.setKeepAlive(false);
        mainSite.timer.firmwareupdateStatus.timeout = INTERVAL.MINUTE;
        thisClass.firmwareUpdatePage.updateProcess = undefined;
        IscWebService('resetUploadSlot', '', function() {});
        var dialog = new ModalConfirmDialogOk(i18n.translate('firmware_update_error'), i18n.translate('hint_reboot_after_error'));
        dialog.prepare();
        return;
      case 'SUCCESS':
        mainSite.timer.firmwareupdateStatus.setKeepAlive(false);
        mainSite.timer.firmwareupdateStatus.timeout = INTERVAL.MINUTE;
        thisClass.firmwareUpdatePage.updateProcess = undefined;
        setTimeout(thisClass.onOk, 10000);
        thisClass.updateProgress(101, i18n.translate('restart_device'));
        return;
      case 'UPLOADING':
        mainSite.timer.firmwareupdateStatus.setKeepAlive(true);
        mainSite.timer.firmwareupdateStatus.timeout = INTERVAL.TWOSECONDS;
        thisClass.updateProgress(data.progress, i18n.translate('processing_firmware'));
        return;
      case 'DOWNLOADING':
        mainSite.timer.firmwareupdateStatus.setKeepAlive(true);
        mainSite.timer.firmwareupdateStatus.timeout = INTERVAL.TWOSECONDS;
        thisClass.updateProgress(data.progress, i18n.translate('download_firmware'));
        return;
      case 'INSTALLING':
        mainSite.timer.firmwareupdateStatus.setKeepAlive(true);
        mainSite.timer.firmwareupdateStatus.timeout = INTERVAL.TWOSECONDS;
        thisClass.updateProgress(data.progress, i18n.translate('updating_files'));
        return;
      case 'IDLE':
        mainSite.timer.firmwareupdateStatus.setKeepAlive(false);
        mainSite.timer.firmwareupdateStatus.timeout = INTERVAL.MINUTE;
        thisClass.firmwareUpdatePage.updateProcess = undefined;
        IscWebService('resetUploadSlot', '', function() {});
        var dialog = new ModalConfirmDialogOk(i18n.translate('firmware_update_error'), i18n.translate('hint_reboot_after_error'));
        dialog.prepare();
        return;
    }
  };
}
UpdateProcess.prototype = new ModalProgressDialog();
UpdateProcess.prototype.constructor = UpdateProcess;
/*
 * ##################################################### End UpdateProcess #####################################################
 *//*###################################################### end of www/web/FirmwareUpdatePage.js #############################################*/
/*###################################################### begin of www/web/Licenses.js #############################################*/
/*
 * ######################################## Start LicensesPage ########################################
 */
function LicensesPage() {
  if (!(this instanceof LicensesPage)) {
    return new LicensesPage();
  }
  PageTemplate.call(this);
  var thisClass = this;
  this.visible = false;
  this.contentSection = undefined;
  this.dataBindings = [];
  this.licenseText = undefined;
  this.currentLicenseText = undefined;
  this.prepare = function() {
    IscWebService('setKeepAlive', '', function(response) {});
    if (!thisClass.contentSection) {
      thisClass.contentSection = document.createElement('div');
      var header = document.createElement('h3');
      header.setAttribute('class', 'h3');
      header.appendChild(document.createTextNode(i18n.translate('licenses')));
      thisClass.contentSection.appendChild(header);
      var pUsedLicenses = document.createElement('p');
      var usedLicenses = document.createTextNode('');
      pUsedLicenses.appendChild(usedLicenses);
      thisClass.contentSection.appendChild(pUsedLicenses);
      var div = document.createElement('div');
      thisClass.contentSection.appendChild(div);
      thisClass.dataBindings.push(function() {
        if (thisClass.licenseText) {
          usedLicenses.nodeValue = i18n.translate('license_info');
          for (var i = 0; i < thisClass.licenseText.software_packages.length; i++) {
            thisClass.licenseText.software_packages[i].printLicense(div);
          }
        }
      });
      thisClass.setFocus = function() {};
    }
    mainSite.main.appendChild(thisClass.contentSection);
    thisClass.requestData();
    thisClass.update();
    thisClass.setFocus();
  };
  this.setFocus = undefined;

  this.setOldLicenseText = function(response) {
    thisClass.licenseText = JSON.parse(response);
    window.licenses = thisClass.licenseText.licenses;
    for (var i = 0; i < thisClass.licenseText.software_packages.length; i++) {
      thisClass.licenseText.software_packages[i].__proto__ = SoftwarePackageOld.prototype;
      thisClass.licenseText.software_packages[i].page = thisClass;
      var path = thisClass.licenseText.software_packages[i].license.split('.');
      var result = thisClass.licenseText;
      for (var j = 0; j < path.length; j++) {
        if (result == undefined)
          break;
        result = result[path[j]];
      }
      if (result) {
        thisClass.licenseText.software_packages[i].license = result;
      }
    }
    thisClass.update();
  };


  this.getOldLicenses = function() {
    var xhr = new XMLHttpRequest();
    xhr.onreadystatechange = function() {
      if (xhr.readyState == 4) {
        if (xhr.status == 200 || xhr.status == 201) {
          thisClass.setOldLicenseText(xhr.response);
        }
      }
    };
    xhr.open('GET', '/licenses.json', true);
    xhr.timeout = 1000;
    xhr.send();
  };

  this.setLicenseText = function(response) {
    thisClass.licenseText = JSON.parse(response);
    window.licenses = thisClass.licenseText.licenses;
    for (var i = 0; i < thisClass.licenseText.software_packages.length; i++) {
      thisClass.licenseText.software_packages[i].__proto__ = SoftwarePackage.prototype;
      thisClass.licenseText.software_packages[i].page = thisClass;
    }
    thisClass.update();
  };

  this.getLicenses = function() {
    var xhr = new XMLHttpRequest();
    xhr.onreadystatechange = function() {
      if (xhr.readyState == 4) {
        if (xhr.status == 200 || xhr.status == 201) {
          thisClass.setLicenseText(xhr.response);
        }
        if (xhr.status == 404) {
          thisClass.getOldLicenses();
        }
      }
    };
    xhr.open('GET', '/manifest.json', true);
    xhr.timeout = 1000;
    xhr.send();
  };

  this.requestData = function() {
    thisClass.getLicenses();
    mainSite.timer.getDeviceInfo.oneShot();
  };
  this.update = function() {
    //update data in site
    for (var i = 0; i < thisClass.dataBindings.length; i++) {
      thisClass.dataBindings[i]();
    }
  };
}
LicensesPage.prototype = new PageTemplate();
LicensesPage.prototype.constructor = LicensesPage;
/*
 * ######################################## End LicensesPage ########################################
 */

function SoftwarePackageOld() {
  this.name = undefined;
  this.version = undefined;
  this.source = undefined;
  this.license = undefined;
  this.copyright = undefined;
  this.table = undefined;
  this.page = undefined;
}

SoftwarePackageOld.prototype.printLicense = function(parentElement) {
  if (this.table)
    return;
  this.table = document.createElement('table');
  this.table.setAttribute('class', 'table--borderOuter license');
  var tbody = document.createElement('tbody');
  this.appendRow(tbody, i18n.translate('software_package'), document.createTextNode(this.name));
  this.appendRow(tbody, i18n.translate('version'), document.createTextNode(this.version));
  var link = document.createElement('a');
  link.setAttribute('href', this.source);
  link.setAttribute('target', 'new');
  link.appendChild(document.createTextNode(this.source));
  this.appendRow(tbody, i18n.translate('source'), link);
  this.appendRow(tbody, i18n.translate('copyright'), document.createTextNode(this.copyright));
  this.appendRow(tbody, i18n.translate('license'), this.getLicenseText());
  this.table.appendChild(tbody)
  parentElement.appendChild(this.table);
}

SoftwarePackageOld.prototype.getLicenseText = function() {
  var p = document.createElement('p');
  p.appendChild(document.createTextNode((this.license.short_title ? this.license.short_title : this.license)));
  if (this.license.link) {
    var preLicense = document.createElement('pre');
    preLicense.setAttribute('class', 'license');
    preLicense.onclick = function(event) {
      if (preLicense.getAttribute('class').match(/grow/i) == null) {
        preLicense.setAttribute('class', 'license grow');
      } else {
        preLicense.setAttribute('class', 'license');
      }
    };
    var codeLicense = document.createElement('code');
    var licenseText = document.createTextNode('');
    codeLicense.appendChild(licenseText);
    preLicense.appendChild(codeLicense);
    p.appendChild(preLicense);

    var xhr = new XMLHttpRequest();
    xhr.onreadystatechange = function() {
      if (xhr.readyState == 4) {
        if (xhr.status == 200 || xhr.status == 201) {
          if (xhr.response) {
            licenseText.nodeValue = xhr.response;
          }
        }
      }
    };
    xhr.open('GET', this.license.link, true);
    xhr.timeout = 1000;
    xhr.send();
  }
  return p;
}

SoftwarePackageOld.prototype.appendRow = function(parentElement, label, valueElement) {
  var tr1 = document.createElement('tr');
  tr1.setAttribute('class', 'show-smallscreen');
  var td1Label = document.createElement('td');
  td1Label.appendChild(document.createTextNode(label + ':'));
  tr1.appendChild(td1Label);
  parentElement.appendChild(tr1);
  var tr = document.createElement('tr');
  var tdLabel = document.createElement('td');
  tdLabel.appendChild(document.createTextNode(label + ':'));
  tdLabel.setAttribute('class', 'hide-smallscreen');
  var tdValue = document.createElement('td');
  tdValue.appendChild(valueElement);
  tr.appendChild(tdLabel);
  tr.appendChild(tdValue);
  parentElement.appendChild(tr);
}

/*
 * ######################################## Begin SoftwareLicense2 ########################################
 */

function SoftwarePackage() {
  this.license_files = undefined;
  this.name = undefined;
  this.source = undefined;
  this.source_archive = undefined;
  this.version = undefined;
  this.license = undefined;
  this.table = undefined;
  this.page = undefined;
}

SoftwarePackage.prototype.printLicense = function(parentElement) {
  if (this.table)
    return;
  this.table = document.createElement('table');
  this.table.setAttribute('class', 'table--borderOuter license');
  var tbody = document.createElement('tbody');
  this.appendRow(tbody, i18n.translate('software_package'), document.createTextNode(this.name));
  this.appendRow(tbody, i18n.translate('version'), document.createTextNode(this.version));
  var link = document.createElement('a');
  link.setAttribute('href', this.source + '/' + this.source_archive);
  link.setAttribute('target', 'new');
  link.appendChild(document.createTextNode(this.source));
  if (this.source) this.appendRow(tbody, i18n.translate('source'), link);
  this.appendRow(tbody, i18n.translate('license'), this.getLicenseTexts());
  this.table.appendChild(tbody)
  parentElement.appendChild(this.table);
}

SoftwarePackage.prototype.getLicenseText = function(license_file) {
  var preLicense = document.createElement('pre');
  preLicense.setAttribute('class', 'license');
  preLicense.onclick = function(event) {
    if (preLicense.getAttribute('class').match(/grow/i) == null) {
      preLicense.setAttribute('class', 'license grow');
    } else {
      preLicense.setAttribute('class', 'license');
    }
  };
  var codeLicense = document.createElement('code');
  var licenseText = document.createTextNode('');
  codeLicense.appendChild(licenseText);
  preLicense.appendChild(codeLicense);

  var xhr = new XMLHttpRequest();
  xhr.onreadystatechange = function() {
    if (xhr.readyState == 4) {
      if (xhr.status == 200 || xhr.status == 201) {
        licenseText.nodeValue += license_file + '\n\n';
        if (xhr.response) {
          licenseText.nodeValue += xhr.response;
        }
      }
    }
  };
  console.log('./licenses/' + this.name + '-' + this.version + '/' + license_file);
  xhr.open('GET', './licenses/' + this.name + '-' + this.version + '/' + license_file, true);
  xhr.timeout = 1000;
  xhr.send();
  return preLicense;
}
SoftwarePackage.prototype.getLicenseTexts = function() {
  var p = document.createElement('p');
  p.appendChild(document.createTextNode((this.license)));
  if (this.license_files) {
    var license_files = this.license_files.replace(/\.\//g, '').split(" ");
    for (var i = 0; i < license_files.length; i++) {
      p.appendChild(this.getLicenseText(license_files[i]));
    }
  }
  return p;
}

SoftwarePackage.prototype.appendRow = function(parentElement, label, valueElement) {
  var tr1 = document.createElement('tr');
  tr1.setAttribute('class', 'show-smallscreen');
  var td1Label = document.createElement('td');
  td1Label.appendChild(document.createTextNode(label + ':'));
  tr1.appendChild(td1Label);
  parentElement.appendChild(tr1);
  var tr = document.createElement('tr');
  var tdLabel = document.createElement('td');
  tdLabel.appendChild(document.createTextNode(label + ':'));
  tdLabel.setAttribute('class', 'hide-smallscreen');
  var tdValue = document.createElement('td');
  tdValue.appendChild(valueElement);
  tr.appendChild(tdLabel);
  tr.appendChild(tdValue);
  parentElement.appendChild(tr);
}
/*###################################################### end of www/web/Licenses.js #############################################*/
/*###################################################### begin of www/web/LoginPage.js #############################################*/
MainSite.prototype.authentication = undefined;

/*
 * ##################################################### Start LoginPage #####################################################
 */
function LoginPage() {
  if (!(this instanceof LoginPage)) {
    return new LoginPage();
  }
  PageTemplate.call(this);
  var thisClass = this;
  this.visible = false;
  this.contentSection = undefined;
  this.dataBindings = [];
  thisClass.redirectTarget = undefined;
  mainSite.abortAllTimer();
  this.prepare = function() {
    thisClass.redirectTarget = location.hash;
    if (thisClass.redirectTarget.length > 1 && thisClass.redirectTarget != '#LogoutPage') {
      thisClass.redirectTarget = thisClass.redirectTarget.slice(1);
      if (mainSite.pages[this.redirectTarget] == undefined) {
        thisClass.redirectTarget = "StatusPage";
      }

    } else {
      if (mainSite.homepage !== undefined) {
        thisClass.redirectTarget = "#";
      } else {
        thisClass.redirectTarget = "StatusPage";
      }
    }
    if (!thisClass.contentSection) {
      thisClass.contentSection = document.createElement('div');
      var header = document.createElement('h2');
      header.appendChild(document.createTextNode(i18n.translate('welcome')));
      thisClass.contentSection.appendChild(header);
      var divAuthenticationError = document.createElement('p');
      divAuthenticationError.appendChild(document.createTextNode(''));
      thisClass.contentSection.appendChild(divAuthenticationError);
      var formLoginForm = document.createElement('form');
      formLoginForm.setAttribute('id', 'login_form');
      formLoginForm.setAttribute('class', 'login');

      var pUsername = document.createElement('p');
      var labelUsername = document.createElement('label');
      labelUsername.setAttribute('for', 'username');
      labelUsername.appendChild(document.createTextNode(i18n.translate('local_username')));
      pUsername.appendChild(labelUsername);
      var inputUsername = document.createElement('input');
      inputUsername.setAttribute('type', 'text');
      inputUsername.setAttribute('id', 'username');
      inputUsername.setAttribute('maxlength', '30');
      inputUsername.setAttribute('autofocus', '');
      inputUsername.oninput = function(evt) {
        divAuthenticationError.firstChild.nodeValue = ''
      };
      pUsername.appendChild(inputUsername);
      formLoginForm.appendChild(pUsername);

      var pPassword = document.createElement('p');
      var labelPassword = document.createElement('label');
      labelPassword.setAttribute('for', 'password');
      labelPassword.appendChild(document.createTextNode(i18n.translate('password')));
      pPassword.appendChild(labelPassword);
      var inputPassword = document.createElement('input');
      inputPassword.setAttribute('type', 'password');
      inputPassword.setAttribute('id', 'password');
      inputPassword.setAttribute('maxlength', '40');
      inputPassword.oninput = function(evt) {
        divAuthenticationError.firstChild.nodeValue = ''
      };
      pPassword.appendChild(inputPassword);
      formLoginForm.appendChild(pPassword);

      var pButtonSubmit = document.createElement('p');
      var buttonSubmit = document.createElement('button');
      buttonSubmit.setAttribute('type', 'submit');
      buttonSubmit.setAttribute('class', 'button--xsm');
      buttonSubmit.setAttribute('autocomplete', 'off'); //autocomplete = "off" is a workaround for a Firefox bug : FF remembers whether the button was disabled across page loads.
      buttonSubmit.setAttribute('id', 'loginbutton');
      buttonSubmit.appendChild(document.createTextNode(i18n.translate('login')));
      pButtonSubmit.appendChild(buttonSubmit);
      formLoginForm.appendChild(pButtonSubmit);

      thisClass.contentSection.appendChild(formLoginForm);

      thisClass.setFocus = function() {
        inputUsername.focus();
      }

      thisClass.setFailed = function() {
        divAuthenticationError.firstChild.nodeValue = i18n.translate('authentication_failed');
        buttonSubmit.removeAttribute('disabled');
      }


      buttonSubmit.onclick = function(event) {
        // Stop form from submitting normally
        event.preventDefault();
        mainSite.authentication = new Authentication(inputUsername, inputPassword, thisClass.redirectTarget, thisClass.setFailed, function() {
          thisClass.contentSection = null;
        });
        buttonSubmit.setAttribute('disabled', '');
        mainSite.authentication.authenticateStart();
      };
    }
    mainSite.main.appendChild(thisClass.contentSection);
    thisClass.requestData();
    thisClass.update();
    thisClass.setFocus();
  };
  this.setFocus = undefined;
  this.setFailed = undefined;

  this.requestData = function() {};
  this.update = function() {};
}
LoginPage.prototype = new PageTemplate();
LoginPage.prototype.constructor = LoginPage;
/*
 * ##################################################### Start LoginPage #####################################################
 */
/*
 * ##################################################### End LogoutPage #####################################################
 */
function LogoutPage() {
  if (!(this instanceof LogoutPage)) {
    return new LogoutPage();
  }
  PageTemplate.call(this);
  var thisClass = this;
  this.visible = false;
  this.closeSession = function() {
    mainSite.sessionStorage.clear();
    location.hash = '#';
    mainSite.localStorage.removeItem('doCloseSession');
    location.reload();
  };
  this.prepare = function() {
    mainSite.authentication = undefined;
    IscWebService('doCloseSession', '', thisClass.closeSession);
  }
  this.onDoCloseSession = function(event) {
    if (event.key === 'doCloseSession') {
      thisClass.closeSession();
    }
  };
  window.addEventListener('storage', thisClass.onDoCloseSession, false);
}
LogoutPage.prototype = new PageTemplate();
LogoutPage.prototype.constructor = LogoutPage;
/*
 * ##################################################### End LogoutPage #####################################################
 */
/*
 * ##################################################### Start Authentication #####################################################
 */
function Authentication(usernameTxtFld, passwordTxtFld, redirectTarget, setFailed, resetLoginForm) {
  var thisClass = this;
  this.cipher = undefined;
  this.decipher = undefined;
  this.authToken = mainSite.sessionStorage.getItem("authToken");
  this.username = usernameTxtFld;
  this.passwordTxtFld = passwordTxtFld;
  this.salt = undefined;
  this.authkeyVer = undefined;
  this.redirectTarget = redirectTarget;
  this.setFailed = setFailed;
  this.resetLoginForm = resetLoginForm;
  this.authenticateStart = function() {
    mainSite.sessionStorage.setItem("username", thisClass.username.value);
    IscWebService('getPasswordSalt', {
      'username': thisClass.username.value
    }, thisClass.onAuthenticateStartResult);

  };

  this.onAuthenticateStartResult = function(response) {
    if (response == undefined) {
      DisplayError(repsonse);
      return;
    }
    if (response.error) {
      if (response.id == ERROR_ID.ENCRYPTION_EXPCTED) {
        setTimeout(thisClass.authenticateStart, 100);
        return;
      }
      thisClass.setFailed();
      return;
    }
    var authkeyVer = response.data.version;
    thisClass.salt = response.data.salt;
    thisClass.authkeyVer = authkeyVer;
    mainSite.sessionStorage.setItem('salt', response.data.salt);
    mainSite.sessionStorage.setItem('authkeyVer', response.data.version);
    var authkeyFunction = thisClass.getAuthkeyfunction(authkeyVer);
    var authkey = authkeyFunction(thisClass.passwordTxtFld, response.data.salt);
    thisClass.authToken = thisClass.computeAuthToken(authkey, response.data.sessionSalt);
    if (encryption.isActivated()) {
      var cipher = forge.cipher.createCipher(AES_CIPHER, forge.util.hexToBytes(thisClass.authToken));
      var iv = forge.random.getBytesSync(IV_LENGTH);
      cipher.start({
        iv: iv
      });
      cipher.update(forge.util.createBuffer(response.data.sessionSalt));
      cipher.finish();
      var token = forge.util.bytesToHex(iv) + cipher.output.toHex();
      IscWebService('doAuthenticateSession', {
        'token': token,
        'username': thisClass.username.value
      }, thisClass.onAuthenticateFinishResult);
      return;
    }
    mainSite.sessionStorage.setItem("sessionSalt", response.data.sessionSalt);
    IscWebService('doAuthenticateSession', {
      'token': thisClass.authToken,
      'username': thisClass.username.value
    }, thisClass.onAuthenticateFinishResult);
  };

  this.parseHexString = function(str) {
    var result = [];
    while (str.length >= 8) {
      result.push(parseInt(str.substring(0, 8), 16));
      str = str.substring(8, str.length);
    }
    return result;
  };

  this.onAuthenticateFinishResult = function(response) {
    if (response == undefined || response.error) {
      thisClass.setFailed();
      return;
    }
    if (encryption.isActivated()) {
      encryption.updateKey(thisClass.authToken);
    }
    setTimeout(thisClass.redirect, 100);
  };

  this.redirect = function() {
    mainSite.show(thisClass.redirectTarget);
    setTimeout(mainSite.oneShotAllTimer, 200);
    thisClass.resetLoginForm();
  };

  this.getAuthkeyfunction = function(authkeyVer) {
    switch (authkeyVer) {
      case "1":
        return thisClass.authkeyFunction1;
    }
    return function() {
      return '0';
    };
  }

  this.authkeyFunction1 = function(passwordTxtFld, salt) {
    var pwsha256hasher = forge.md.sha256.create();
    pwsha256hasher.update(passwordTxtFld.value);
    var pwhash = pwsha256hasher.digest().toHex();
    var authkeysha256hasher = forge.md.sha256.create();
    authkeysha256hasher.update(pwhash + "+" + salt);
    return authkeysha256hasher.digest().toHex();
  }

  this.computeAuthToken = function(authkey, sessionSalt) {
    var tokensha256hasher = forge.md.sha256.create();
    tokensha256hasher.update(authkey + "+" + sessionSalt);
    return tokensha256hasher.digest().toHex();
  }

}
/*
 * ##################################################### End Authentication #####################################################
 *//*###################################################### end of www/web/LoginPage.js #############################################*/
/*###################################################### begin of www/web/NetworkSettings.js #############################################*/
/*
 * ######################################## Start NetworkSettingsPage ########################################
 */
function NetworkSettingsPage() {
  if (!(this instanceof NetworkSettingsPage)) {
    return new NetworkSettingsPage();
  }
  PageTemplate.call(this);
  var thisClass = this;
  this.visible = false;
  this.contentSection = undefined;
  this.dataBindings = [];
  this.ipSettingsFormEnabled = false;
  this.ntpSettingsFormEnabled = false;
  this.prepare = function() {
    IscWebService('setKeepAlive', '', function(response) {});
    if (!thisClass.contentSection) {
      if (thisClass.ipSettingsFormEnabled) {
        thisClass.contentSection = document.createElement('div');
        var header = document.createElement('h3');
        header.setAttribute('class', 'h3');
        header.appendChild(document.createTextNode(i18n.translate('change_settings')));
        thisClass.contentSection.appendChild(header);
        thisClass.contentSection.appendChild(document.createElement('br'));
        var ipSettingsForm = document.createElement('form');
        ipSettingsForm.setAttribute('class', 'settings');

        var ipSettingsFieldSet = document.createElement('fieldset');
        var ipSettingsHeader = document.createElement('legend');
        ipSettingsHeader.appendChild(document.createTextNode(i18n.translate('ipsettingsheader')));
        ipSettingsFieldSet.appendChild(ipSettingsHeader);
        var paragraph = document.createElement('p');
        paragraph.setAttribute('class', 'text_hint');
        paragraph.appendChild(document.createTextNode(i18n.translate('settings_additional_hint')));
        ipSettingsFieldSet.appendChild(paragraph);
        var pDhcp = document.createElement('p');
        var labelDhcp = document.createElement('label');
        labelDhcp.setAttribute('class', 'checkbox');
        labelDhcp.setAttribute('for', 'dhcp');
        labelDhcp.appendChild(document.createTextNode(i18n.translate('dhcp')));
        var inputDhcp = document.createElement('input');
        inputDhcp.setAttribute('type', 'checkbox');
        thisClass.setFocus = function() {
          inputDhcp.focus();
        }

        var ipSettings = document.createElement('p');
        pDhcp.appendChild(inputDhcp);
        pDhcp.appendChild(labelDhcp);
        ipSettingsFieldSet.appendChild(pDhcp);

        var inputIpAddress = thisClass.appendIPInputTextfieldTo(ipSettings, 'ipaddress');
        var inputSubnetmask = thisClass.appendIPInputTextfieldTo(ipSettings, 'subnetmask');
        var inputGateway = thisClass.appendIPInputTextfieldTo(ipSettings, 'gateway');
        var inputNameServer = thisClass.appendIPInputTextfieldTo(ipSettings, 'nameserver_opt');
        inputNameServer.setAttribute('title', i18n.translate('nameserver_hint'));
        ipSettingsFieldSet.appendChild(ipSettings);

        var pButtonIPSettingsSubmit = document.createElement('p');
        var submitipsettings = document.createElement('button');
        submitipsettings.setAttribute('type', 'submit');
        submitipsettings.setAttribute('class', 'button--xsm');
        submitipsettings.setAttribute('disabled', '');
        submitipsettings.appendChild(document.createTextNode(i18n.translate('submit')));
        pButtonIPSettingsSubmit.appendChild(submitipsettings);
        ipSettingsFieldSet.appendChild(pButtonIPSettingsSubmit);
        ipSettingsForm.appendChild(ipSettingsFieldSet);

        inputIpAddress.oninput = inputSubnetmask.oninput = inputGateway.oninput = inputNameServer.oninput = function(event) {
          if (submitipsettings.hasAttribute('disabled')) submitipsettings.removeAttribute('disabled');
        };

        inputDhcp.onclick = function(event) {
          if (mainSite.deviceInfo) {
            inputIpAddress.value = mainSite.deviceInfo.IpAddress;
            inputIpAddress.disabled = inputDhcp.checked;
            inputIpAddress.removeAttribute('class');

            inputSubnetmask.value = mainSite.deviceInfo.SubnetMask;
            inputSubnetmask.disabled = inputDhcp.checked;
            inputSubnetmask.removeAttribute('class');

            inputGateway.value = mainSite.deviceInfo.DefaultGateway;
            inputGateway.disabled = inputDhcp.checked;
            inputGateway.removeAttribute('class');

            inputNameServer.value = mainSite.deviceInfo.NameServer;
            inputNameServer.disabled = inputDhcp.checked;
            inputNameServer.removeAttribute('class');

            if (submitipsettings.hasAttribute('disabled')) submitipsettings.removeAttribute('disabled');
          }
        };

        ipSettingsForm.addEventListener('submit', function(event) {
          // Stop form from submitting normally
          event.preventDefault();
          if (event.target.checkValidity()) {
            var ipChanged = (mainSite.deviceInfo.IpAddress != inputIpAddress.value);
            var data = '';
            if (inputDhcp.checked) {
              data = {
                Dhcp: true
              };
            } else {
              data = {
                Dhcp: false,
                IpAddress: inputIpAddress.value,
                SubnetMask: inputSubnetmask.value,
                DefaultGateway: inputGateway.value,
              };
              if (inputNameServer.value != mainSite.deviceInfo.NameServer && inputNameServer.value != '') {
                data.NameServer = inputNameServer.value;
              }
            }
            inputIpAddress.disabled = true;
            inputSubnetmask.disabled = true;
            inputGateway.disabled = true;
            inputNameServer.disabled = true;
            submitipsettings.disabled = true;
            var enableInput = function() {
              inputIpAddress.disabled = false;
              inputSubnetmask.disabled = false;
              inputGateway.disabled = false;
              inputNameServer.disabled = false;
              submitipsettings.disabled = false;
            };
            new ModalSpinnerDialog(i18n.translate('change_settings'), i18n.translate('device_unavailable') + ' ' + i18n.translate('wait_or_try_reopen')).prepare();
            IscWebService('setIpConfig', data, function(response) {
              if (response == undefined) {
                enableInput();
                if (!inputDhcp.checked) {
                  new ModalSpinnerDialog(i18n.translate('change_settings'), i18n.translate('device_unavailable') + ' ' + i18n.translate('wait_or_try_reopen')).prepare();
                  setTimeout(open('http://' + inputIpAddress.value + '/index.html', '_self'), 10000);
                } else {
                  new ModalConfirmDialogOk(i18n.translate('change_settings'), i18n.translate('device_unavailable') + ' ' + i18n.translate('try_reopen')).prepare();
                }
              } else if (response.error) {
                enableInput();
                DisplayError(response);

                if (response.id == '203') {
                  inputIpAddress.setAttribute('class', 'input--error');
                  inputIpAddress.oninput = function() {
                    this.removeAttribute('class'); this.removeAttribute('oninput');
                  };
                }
                if (response.id == '201') {
                  inputSubnetmask.setAttribute('class', 'input--error');
                  inputSubnetmask.oninput = function() {
                    this.removeAttribute('class'); this.removeAttribute('oninput');
                  };
                }
                if (response.id == '202') {
                  inputGateway.setAttribute('class', 'input--error');
                  inputGateway.oninput = function() {
                    this.removeAttribute('class'); this.removeAttribute('oninput');
                  };
                }
                if (response.id == '204') {
                  inputNameServer.setAttribute('class', 'input--error');
                  inputNameServer.oninput = function() {
                    this.removeAttribute('class'); this.removeAttribute('oninput');
                  };
                }
              } else {
                var waitForIpChanged = new ModalSpinnerDialog(i18n.translate('change_settings'), i18n.translate('ip_changed_wait'))
                waitForIpChanged.prepare();
                setTimeout(function() {
                  mainSite.timer.getNetworkSettings.oneShot();
                  waitForIpChanged.showDone(i18n.translate('ip_changed'));
                }, 5000);
              }
            }
            );
          }
        }
        );
        thisClass.contentSection.appendChild(ipSettingsForm);
        thisClass.dataBindings.push(function() {
          if (mainSite.deviceInfo) {
            inputDhcp.disabled = false;
            inputDhcp.checked = mainSite.deviceInfo.Dhcp;
            inputIpAddress.value = mainSite.deviceInfo.IpAddress;
            inputIpAddress.disabled = mainSite.deviceInfo.Dhcp;
            inputSubnetmask.value = mainSite.deviceInfo.SubnetMask;
            inputSubnetmask.disabled = mainSite.deviceInfo.Dhcp;
            inputGateway.value = mainSite.deviceInfo.DefaultGateway;
            inputGateway.disabled = mainSite.deviceInfo.Dhcp;
            inputNameServer.value = mainSite.deviceInfo.NameServer;
            inputNameServer.disabled = mainSite.deviceInfo.Dhcp;
            submitipsettings.disabled = true;
          }
        });
      }

      /* NTP Begin */
      if (thisClass.ntpSettingsFormEnabled) {

        var ntpSettingsFieldSet = document.createElement('fieldset');
        var ntpsettingsform = document.createElement('form');

        var ipSettingsHeader = document.createElement('legend');
        ipSettingsHeader.appendChild(document.createTextNode(i18n.translate('ntpsettingsheader')));
        ntpSettingsFieldSet.appendChild(ipSettingsHeader);

        var ntpP = document.createElement('p');
        var ntpLabel = document.createElement('label');
        ntpLabel.setAttribute('class', 'checkbox');
        ntpLabel.setAttribute('for', 'ntp');
        ntpLabel.appendChild(document.createTextNode(i18n.translate('ntp')));
        var ntpInput = document.createElement('input');
        ntpInput.setAttribute('type', 'checkbox');
        ntpInput.setAttribute('id', 'ntp');

        var ntpSettings = document.createElement('p');

        ntpP.appendChild(ntpInput);
        ntpP.appendChild(ntpLabel);
        ntpSettingsFieldSet.appendChild(ntpP);

        var ntpServerP = document.createElement('p');
        var ntpServerLabel = document.createElement('label');
        ntpServerLabel.setAttribute('for', 'ntpserver');
        ntpServerLabel.appendChild(document.createTextNode(i18n.translate('ntpserver')));
        var ntpServerInput = document.createElement('input');
        ntpServerInput.setAttribute('type', 'text');
        ntpServerInput.setAttribute('id', 'ntpserver');
        ntpServerP.appendChild(ntpServerLabel);
        ntpServerP.appendChild(ntpServerInput);
        ntpSettings.appendChild(ntpServerP);

        var ntpIntervalP = document.createElement('p');
        var ntpIntervalLabel = document.createElement('label');
        ntpIntervalLabel.setAttribute('for', 'ntpinterval');
        ntpIntervalLabel.appendChild(document.createTextNode(i18n.translate('ntpinterval') + ' (0-60 ' + i18n.translate('uom_min') + ')'));
        var ntpIntervalInput = document.createElement('input');
        ntpIntervalInput.setAttribute('type', 'text');
        ntpIntervalInput.setAttribute("pattern", "^([1-9]|[1-5][0-9]|60)$");
        ntpIntervalInput.setAttribute('id', 'ntpinterval');
        ntpIntervalP.appendChild(ntpIntervalLabel);
        ntpIntervalP.appendChild(ntpIntervalInput);
        ntpSettings.appendChild(ntpIntervalP);


        ntpSettingsFieldSet.appendChild(ntpSettings);

        var submitButton = document.createElement('button');
        submitButton.setAttribute('type', 'submit');
        submitButton.setAttribute('class', 'button--xsm');
        submitButton.setAttribute('disabled', '');

        submitButton.appendChild(document.createTextNode(i18n.translate('submit')));

        ntpIntervalInput.oninput = function(event) {
          submitButton.removeAttribute('disabled');
        };
        ntpServerInput.oninput = function(event) {
          submitButton.removeAttribute('disabled');
        };

        ntpInput.onclick = function(event) {
          submitButton.removeAttribute('disabled');
          ntpServerInput.value = mainSite.deviceInfo.NtpServerAddress;
          ntpServerInput.disabled = !this.checked;
          ntpIntervalInput.value = mainSite.deviceInfo.NtpInterval;
          ntpIntervalInput.disabled = !this.checked;
        };

        ntpSettingsFieldSet.appendChild(submitButton);
        ntpsettingsform.appendChild(ntpSettingsFieldSet);
        ntpsettingsform.addEventListener('submit', function(event) {
          // Stop form from submitting normally
          event.preventDefault();
          if (event.target.checkValidity()) {
            var data = '';
            if (!ntpInput.checked) {
              data = {
                Ntp: false
              };
            } else {
              data = {
                Ntp: true,
                NtpServerAddress: ntpServerInput.value,
                NtpInterval: ntpIntervalInput.value,
              };
            }
            IscWebService('setNtpConfig', data, function(response) {
              if (response == undefined) {
                new ModalConfirmDialogOk(i18n.translate('something_wrong'), i18n.translate('device_unavailable')).prepare();
              } else if (response.error) {
                DisplayError(response);
              } else {
                new ModalConfirmDialogOk(i18n.translate('ntpsettingsheader'), i18n.translate('ntp_changed')).prepare();
                setTimeout(function() {
                  mainSite.timer.getNetworkSettings
                }, 5000);
              }
            }
            );
          }
        }
        );

        thisClass.dataBindings.push(function() {
          if (mainSite.deviceInfo) {
            submitButton.disabled = true;
            ntpInput.checked = mainSite.deviceInfo.Ntp;
            ntpServerInput.value = mainSite.deviceInfo.NtpServerAddress;
            ntpServerInput.disabled = !mainSite.deviceInfo.Ntp;
            ntpIntervalInput.value = mainSite.deviceInfo.NtpInterval;
            ntpIntervalInput.disabled = !mainSite.deviceInfo.Ntp;
          }
        });

        thisClass.contentSection.appendChild(ntpsettingsform);
      }
      /* NTP End */

    }
    mainSite.main.appendChild(thisClass.contentSection);
    thisClass.requestData();
    thisClass.update();
    thisClass.setFocus();
  };
  this.setFocus = undefined;

  this.appendIPInputTextfieldTo = function(parentElem, id) {
    var inputPatternIP = '^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$';
    var pElem = document.createElement('p');
    var ipLabel = document.createElement('label');
    ipLabel.setAttribute('for', id);
    ipLabel.appendChild(document.createTextNode(i18n.translate(id)));
    var ipInput = document.createElement('input');
    ipInput.setAttribute('type', 'text')
    ipInput.setAttribute('id', id);
    ipInput.setAttribute('pattern', inputPatternIP);

    pElem.appendChild(ipLabel);
    pElem.appendChild(ipInput);
    parentElem.appendChild(pElem);
    return ipInput;
  }


  this.requestData = function() {
    mainSite.timer.getDeviceInfo.oneShot();
    if (!mainSite.timer.getNetworkSettings) {
      mainSite.timer.getNetworkSettings = new TimedRequest(INTERVAL.NONE, 'getDeviceInfo', '', mainSite.setDeviceInfo, thisClass);
    } else {
      mainSite.timer.getNetworkSettings.timeout = INTERVAL.NONE;
    }
    mainSite.timer.getNetworkSettings.addCallbackFunction(thisClass.update);
    mainSite.timer.getNetworkSettings.oneShot();
  };
  this.update = function() {
    //update data in site
    for (var i = 0; i < thisClass.dataBindings.length; i++) {
      thisClass.dataBindings[i]();
    }
  };
}
NetworkSettingsPage.prototype = new PageTemplate();
NetworkSettingsPage.prototype.constructor = NetworkSettingsPage;
/*
 * ######################################## End NetworkSettingsPage ########################################
 */
/*###################################################### end of www/web/NetworkSettings.js #############################################*/
