<?php 

set_include_path(get_include_path() . PATH_SEPARATOR . '../../app');
include_once "base_controller.php";
include_once "utils.php";

class NetworkConfig extends BaseController {
  protected $networkConn = "wired-eth0";

  protected function signinRequired() {
    return true;
  }

  protected function adminRequired() {
    return true;
  }

  protected function parseNMCLIOutput($cmd) {
    $data = array();

    $output = array();
    $return_var = null;
    exec($cmd, $output, $return_var); 

    if ($return_var != 0) {
      error_log("failed to get network settings");
      return "failed to get network settings";
    }

    $uploadsPath = build_file_path(dirname(__FILE__), "uploads", "certs");
    foreach($output as $line) {
      $parts = explode(':', $line, 2);
      if (count($parts) != 2)
        continue;

      $key = $parts[0];
      $val = $parts[1];

      //process file's path
      if (startsWith($val, $uploadsPath))
        $val = substr($val, strlen($uploadsPath)+1);

      $data[$key] = $val;
    }
    return $data;
  }
  private function parseSecuritySettingsForFS($props) {
    $output = parse_ini_file("/etc/NetworkManager/system-connections/{$this->networkConn}", true);
    if(!isset($output['802-1x'])) {
      $msg = "can not find security settings";
      error_log($msg);
      return $msg;
    }

    return $output['802-1x'];
  }

  private function parseSecuritySettingsForFW($props) {
    $settings = array();
    $conf_path = "/etc/wpa_supplicant/wpa_supplicant_wired.conf";
    if (!file_exists($conf_path))
      return $settings;

    $content = file_get_contents($conf_path);
    if (!$content)
      return $settings;

    $lines = explode(PHP_EOL, $content);
    $start = False;
    foreach($lines as $line) {
      if (preg_match("/^\s*network=\{/", $line)) {
        $start = True;
        continue;
      } else if (preg_match("/^\s*\}\s*$/", $line)) {
        $start = False;
        break;
      }

      if (!$start)
        continue;

      //we are in the network block now
      $matches = array();
      if (!preg_match("/^\s*([_a-zA-Z0-9]+)=(.*)$/", $line, $matches))
        continue;

      if (count($matches) != 3) {
        error_log("get invalid config line: " . $line);
        continue;
      }
      $key = trim($matches[1]);
      $val = trim($matches[2], '" ');

      if ($key == 'private_key_passwd')
        $key = 'private_key_password';
      $key = preg_replace('/_/', '-', $key);

      if ($key == 'eap')
        $val = strtolower($val);
      else if ($key == 'phase2') {
        $parts = explode('=', $val);
        if (count($parts) != 2) {
          error_log("invalid phase config: " . $line);
          continue;
        }
        $key = $key . '-' . $parts[0];
        $val = strtolower($parts[1]);
      }

      if (!in_array($key, $props))
        continue;
      
      $settings[$key] = $val;
    }
    return $settings;
  }

  protected function parseSecuritySettings($props) {
    $platform = platformName();
    $settings = NULL;
    if ($platform == "FS")
      $settings = $this->parseSecuritySettingsForFS($props);
    else if ($platform == "FW")
      $settings = $this->parseSecuritySettingsForFW($props);

    if (empty($settings) || is_string($settings))
      return $settings;

    $data = array();
    $uploadsPath = build_file_path(dirname(__FILE__), "uploads", "certs");
    foreach($props as $prop) {
      if (!isset($settings[$prop]))
        continue;

      $val = $settings[$prop];
      if ($prop == "eap")
        $data["802-1x.".$prop] = rtrim($val, ";");
      else {
        //process file's path
        if (startsWith($val, $uploadsPath))
          $val = substr($val, strlen($uploadsPath)+1);
        $data["802-1x.".$prop] = $val;
      }
    }
    return $data;

  }

  public function doAjaxGet() {
    $response = array();
    $data = array();
    $type = $_GET['type'];
    $cmd = null;
    if ($type == "802.1x") {
      $props = array("eap", "identity", "password", "client-cert", "ca-cert", "private-key", "private-key-password", "phase2-auth", "phase2-autheap");
      $data = $this->parseSecuritySettings($props);
      // foreach($props as $prop) {
      //   $props[] = "802-1x." . $prop;
      // }
      // $cmd = "/usr/bin/nmcli -t -m multiline -f " . implode(',', $props) . " connection show '{$this->networkConn}'";
    } else if ($type == "general") {
      $fields = implode(',', array('ipv4.method', 'ipv4.addresses', 'ipv4.gateway', 'ipv4.dns', 'DHCP4'));
      $cmd = "/usr/bin/nmcli -t -m multiline -f {$fields} connection show '{$this->networkConn}'";
      $data = $this->parseNMCLIOutput($cmd);
    } else if ($type == "ipv6") {
      $fields = implode(',', array('ipv6.method', 'ipv6.addresses', 'ipv6.gateway', 'ipv6.dns', 'IP6'));
      $cmd = "/usr/bin/nmcli -t -m multiline -f {$fields} connection show '{$this->networkConn}'";
      $data = $this->parseNMCLIOutput($cmd);
    } else
      $this->renderAjaxError($response, "invalid 'type' parameter");

    if (is_string($data))
      $this->renderAjaxError($response, $data);

    if ($type == "general") {
      $hostname = exec('/usr/bin/nmcli general hostname');
      if (!empty($hostname))
        $data['hostname'] = $hostname;
    }

    if (!empty($data))
      $response['data'] = $data;
    // error_log(print_r($data, TRUE));
    $this->renderAjaxSuccess2($response);
  }

  public function doAjaxPost() {
    $response = array();
    if (!isset($_POST['type']))
      $this->renderAjaxError($response, "type parameter is missing");

    $type = $_POST['type'];
    if ($type == "general")
      $this->saveGeneralNetworkConfig();
    else if ($type == "802.1x")
      $this->saveSecurityNetworkConfig();
    else if ($type == "ipv6")
      $this->saveIPv6NetworkConfig();
    else
      $this->renderAjaxError($response, "invalid type parameter: " . $type);
  }

  protected function saveGeneralNetworkConfig() {
    $response = array();
    if (!isset($_POST['config']))
      $this->renderAjaxError($response, "'config' parameter is missing");

    $config = $_POST['config'];
    $error = '';
    $ipv4 = $config['ipv4'];
    $method = $ipv4['method'];
    $ip = null;
    $cdir = null;
    $gateway = null;
    $dns = null;

    if (isset($config['hostname']))
      $error = $this->odifyHostName($config['hostname']);
    if (empty($error)) {
      if ($method == 'manual') {
        if (empty($ipv4['ip']))
          $this->renderAjaxError($response, "invalid IP address"); 
        if (empty($ipv4['cdir']))
          $this->renderAjaxError($response, "invalid network mask"); 
        if (empty($ipv4['gateway']))
          $this->renderAjaxError($response, "invalid gateway"); 
        $ip = $ipv4['ip'];
        $cdir = $ipv4['cdir'];
        $gateway = $ipv4['gateway'];
        $dns = $ipv4['dns'];
        $error = $this->odifyNetworkSettings($method, $ip."/".$cdir, $gateway, $dns);
      } else if ($ipv4['method'] == 'auto') {
        $error = $this->odifyNetworkSettings($ipv4['method']);
      } else
        $this->renderAjaxError($response, "invalid method value: " . $ipv4['method']);
    }

    if (empty($error)) {
      $this->saveNetworkSettingsForSedona($method, $ip, $cdir, $gateway, $dns);
      $this->reactivateConn();
      $this->renderAjaxSuccess2($response);
    }
    else
      $this->renderAjaxError($response, $error);
  }

  private function isInSameSubnet($addr1, $addr2, $prefixLen) {
    return true;
  }

  protected function saveIPv6NetworkConfig() {
    $response = array();
    if (!isset($_POST['config']))
      $this->renderAjaxError($response, "'config' parameter is missing");

    $error = '';
    $config = $_POST['config'];
    $ipv6 = $config['ipv6'];

    $method = $ipv6['method'];
    $ip = null;
    $prefixLen = 64;
    $gateway = null;
    $dns = null;

    if ($method == 'manual') {
      if (empty($ipv6['ip']))
        $this->renderAjaxError($response, "invalid IPv6 address"); 
      if (empty($ipv6['subnetPrefixLen']))
        $this->renderAjaxError($response, "subnet prefix length is missing"); 
      if (empty($ipv6['gateway']))
        $this->renderAjaxError($response, "invalid gateway"); 

      $ip = $ipv6['ip'];
      $prefixLen = intval($ipv6['subnetPrefixLen']);
      $gateway = $ipv6['gateway'];

      if ($prefixLen < 1 || $prefixLen > 128)
        $this->renderAjaxError($response, "invalid subnet prefix length");

      if (!$this->isInSameSubnet($ip, $gateway, $prefixLen))
        $this->renderAjaxError($response, "IPv6 address and gateway are not in the same subnet");

      $dns = $ipv6['dns'];
      $error = $this->odifyIPv6NetworkSettings($method, $ip."/".$prefixLen, $gateway, $dns);
    } else if ($ipv6['method'] == 'auto') {
      $error = $this->odifyIPv6NetworkSettings($ipv6['method']);
    } else
      $this->renderAjaxError($response, "invalid method value: " . $ipv6['method']);

    if (empty($error)) {
      //TODO: support IPv6 in easyio.config file
      // $this->saveNetworkSettingsForSedona($method, $ip, $cdir, $gateway, $dns);

      $this->reactivateConn();
      $this->renderAjaxSuccess2($response);
    }
    else
      $this->renderAjaxError($response, $error);
  }

  protected function saveSecurityNetworkConfig() {
    $response = array();
    if (!isset($_POST['eap']))
      $this->renderAjaxError($response, "'eap' parameter is missing");
    $eap = $_POST['eap'];

    if (!empty($eap) && !isset($_POST['config']))
      $this->renderAjaxError($response, "'config' parameter is missing");
    
    if (!empty($eap))
      $config = $_POST['config'];
    else
      $config = null;
    $error = $this->odifySecuritySettings($eap, $config);
    if (empty($error)) {
      $this->reactivateConn();
      $this->renderAjaxSuccess2($response);
    } else 
      $this->renderAjaxError($response, $error);
  }

  protected function reactivateConn() {
    // $downCmd = "/usr/bin/nmcli connection down '{$this->networkConn}' >/dev/null 2>&1";
    // $upCmd = "/usr/bin/nmcli connection up '{$this->networkConn}' >/dev/null 2>&1";
    // shell_exec("(sleep 1 && ${downCmd} && ${upCmd}) >/dev/null 2>&1 &");

    // nmcli conn down&up does not work well, especially for 802.1x settings, do system reboot here
    $platform = platformName();
    if ($platform == "FW") {
    } else 
      doReboot(true);
  }

  protected function modifyHostName($hostname) {
    $cmd = "/usr/bin/nmcli general hostname " . escapeshellarg($hostname);
    $output = array();
    $return_var = 0;
    exec($cmd, $output, $return_var)
    if ($return_var == 1) {
      error_log("failed to change hostname to: {$hostname}");
      return "failed to change hostname";
    }
    //update /etc/hostname file
    shell_exec("echo " . escapeshellarg($hostname) . " > /etc/hostname")
  }
  protected function modifyNetworkSettings($method, $ip_address=null, $gateway=null, $dns=null) {
    $cmd = "/usr/bin/nmcli connection modify '{$this->networkConn}' ";
    if ($method == "manual") {
      $cmd = $cmd . " ipv4.method manual"; 
      $cmd = $cmd . " ipv4.address " . escapeshellarg($ip_address); 
      $cmd = $cmd . " ipv4.gateway " . escapeshellarg($gateway); 
      if ($dns)
        $cmd = $cmd . " ipv4.dns " . escapeshellarg($dns); 
      else
        $cmd = $cmd . " ipv4.dns ''"; 
    }
    else if ($method == "auto") {
      $cmd = $cmd . " ipv4.method auto"; 
      $cmd = $cmd . " ipv4.address ''"; 
      $cmd = $cmd . " ipv4.gateway ''"; 
      $cmd = $cmd . " ipv4.dns ''"; 
    }
    else
      return "invalid method value: " . $method;

    $output = array();
    $return_var = 0;
    exec($cmd, $output, $return_var)
    if ($return_var == 1) {
      error_log("failed to change network settings");
      return "failed to change network settings";
    }
  }

  protected function modifyIPv6NetworkSettings($method, $ip_address=null, $gateway=null, $dns=null) {
    $cmd = "/usr/bin/nmcli connection modify '{$this->networkConn}' ";
    if ($method == "manual") {
      $cmd = $cmd . " ipv6.method manual"; 
      $cmd = $cmd . " ipv6.address " . escapeshellarg($ip_address); 
      $cmd = $cmd . " ipv6.gateway " . escapeshellarg($gateway); 
      if ($dns)
        $cmd = $cmd . " ipv6.dns " . escapeshellarg($dns); 
      else
        $cmd = $cmd . " ipv6.dns ''"; 
    }
    else if ($method == "auto") {
      $cmd = $cmd . " ipv6.method auto"; 
      $cmd = $cmd . " ipv6.address ''"; 
      $cmd = $cmd . " ipv6.gateway ''"; 
      $cmd = $cmd . " ipv6.dns ''"; 
    }
    else
      return "invalid method value: " . $method;

    $output = array();
    $return_var = 0;
    exec($cmd, $output, $return_var)
    if ($return_var == 1) {
      error_log("failed to change network settings");
      return "failed to change network settings";
    }
  }
  protected function fullUploadFilePath($relativePath) {
    if (empty($relativePath))
      return '';

    $curPath = dirname(__FILE__);
    return build_file_path($curPath, "uploads", "certs", $relativePath);
  }
  private function modifySecuritySettingsForFS($eap, $settings) {
    $cmd = null;
    if (empty($eap)) {
      //GOTCHA: set 'eap' to empty string doesn't disable 802.1x, have to
      //remove it from conn config file 
      // $cmd = $cmd . " 802-1x.eap ''";
      $cmd = "/bin/sed -i -e '/\[802-1x\]$/,/^$/d' /etc/NetworkManager/system-connections/{$this->networkConn}";
    }

    //clear not used settings and build nmcli command
    if (is_null($cmd)) {
      $cmd = "/usr/bin/nmcli connection modify '{$this->networkConn}' ";
      $props = array("eap", "identity", "password", "client-cert", "ca-cert", "private-key", "private-key-password", "phase2-auth", "phase2-autheap");
      foreach($settings as $setting) {
        $key = $setting[0];
        $val = $setting[1];
        $cmd = $cmd . " 802-1x.{$key} {$val} ";

        if (($found = array_search($key, $props)) !== false) {
            unset($props[$found]);
        }
      }
      foreach($props as $prop) {
        $cmd = $cmd . " 802-1x.{$prop} '' ";
      }
    }

    $output = array();
    $return_var = 0;

    exec($cmd, $output, $return_var)
    error_log("cmd: " . $cmd);

    if ($return_var == 1) {
      error_log("failed to change security settings:" . implode("\n", $output));
      // error_log(print_r($output, TRUE));
      return "failed to change security settings: " .  implode("\n", $output);
    }
  }

  private function modifySecuritySettingsForFW($eap, $settings) {
    $conf_path = "/etc/wpa_supplicant/wpa_supplicant_wired.conf";
    if (empty($eap)) {
      //disable 802.1X 
      unlink($conf_path);
      //TODO: kill wpa_supplicant
      return;
    }
    
    $settings_map = array();
    foreach($settings as $setting) {
      $settings_map[$setting[0]] = trim($setting[1], "'");
    }
    $content = render_template("wpa_supplicant_wired_template.conf", $settings_map);
    if (!file_put_contents($conf_path, $content))
      return "failed to save config to " . $conf_path;

    //TODO: restart wpa_supplicant
  }

  protected function modifySecuritySettings($eap, $config) {
    $settings = array();
    if ($eap == "md5") {
      $settings[] = array("eap", escapeshellarg($eap));
      $settings[] = array("identity", escapeshellarg($config['identity']));
      $settings[] = array("password", escapeshellarg($config['password']));
    } else if ($eap == "tls") {
      $settings[] = array("eap", escapeshellarg($eap));
      $settings[] = array("identity", escapeshellarg($config['identity']));
      if (isset($config['client-cert'])) {
        $certFile = $this->fullUploadFilePath($config['client-cert']);
        $settings[] = array("client-cert", escapeshellarg($certFile));
      }

      if (isset($config['ca-cert'])) {
        $caCertFile = $this->fullUploadFilePath($config['ca-cert']);
        $settings[] = array("ca-cert", escapeshellarg($caCertFile));
      }

      if (isset($config['private-key'])) {
        $keyFile = $this->fullUploadFilePath($config['private-key']);
        if (!empty($keyFile) && isset($config['private-key-password']))
          $settings[] = array("private-key-password", escapeshellarg($config['private-key-password']));
        $settings[] = array("private-key", escapeshellarg($keyFile));
      }
    } else if ($eap == "ttls") {
      $settings[] = array("eap", escapeshellarg($eap));
      $settings[] = array("identity", escapeshellarg($config['identity']));
      $settings[] = array("password", escapeshellarg($config['password']));
      if (isset($config['ca-cert'])) {
        $caCertFile = $this->fullUploadFilePath($config['ca-cert']);
        $settings[] = array("ca-cert", escapeshellarg($caCertFile));
      }

      if (isset($config['phase2-auth']))
        $settings[] = array("phase2-auth", escapeshellarg($config['phase2-auth']));
      else if (isset($config['phase2-autheap']))
        $settings[] = array("phase2-autheap", escapeshellarg($config['phase2-autheap']));

      $settings[] = array("anonymous-identity", escapeshellarg($config['anonymous-identity']));
    } else if ($eap == "peap") {
      $settings[] = array("eap", escapeshellarg($eap));
      $settings[] = array("identity", escapeshellarg($config['identity']));
      $settings[] = array("password", escapeshellarg($config['password']));
      if (isset($config['ca-cert'])) {
        $caCertFile = $this->fullUploadFilePath($config['ca-cert']);
        $settings[] = array("ca-cert", escapeshellarg($caCertFile));
      }

      if (isset($config['phase2-auth']))
        $settings[] = array("phase2-auth", escapeshellarg($config['phase2-auth']));
      else if (isset($config['phase2-autheap']))
        $settings[] = array("phase2-autheap", escapeshellarg($config['phase2-autheap']));

      $settings[] = array("anonymous-identity", escapeshellarg($config['anonymous-identity']));
    } else {
      if (!empty($eap))
        return "invalid eap value: " . $eap;
    }

    $platform = platformName();
    if ($platform == "FS")
      return $this->odifySecuritySettingsForFS($eap, $settings);
    else if ($platform == "FW")
      return $this->odifySecuritySettingsForFW($eap, $settings);
    else
      return "802.1X config is not supported for this platform";
  }

  protected function saveNetworkSettingsForSedona($method, $ip_address, $cdir, $gateway, $dns) {
    $filename = "/mnt/sedona/easyio.config";
    //read old config in 
    $content = file_get_contents($filename); 
    $lines = explode(PHP_EOL, $content);
    $config = array();
    foreach($lines as $line) {
      if (empty($line))
        continue;

      $parts = explode(':', $line, 2);
      if (count($parts) != 2)
        continue;

      $key = $parts[0];
      $val = $parts[1];

      $config[$key] = $val;
    }
    
    if ($method == 'auto')
      $config['DHCP Enabled'] = 'yes';
    else {
      $config['DHCP Enabled'] = 'no';
      $config['IP Address'] = $ip_address;
      $mask = cdir2MaskIP($cdir);
      if ($mask)
        $config['Subnet Mask'] = $mask;
      $config['Gateway'] = $gateway;

      $config['DNS1'] = '';
      $config['DNS2'] = '';
      if ($dns) {
        $dns_list = explode(',', $dns);
        if (count($dns_list) > 0)
          $config['DNS1'] = trim($dns_list[0]);
        if (count($dns_list) > 1)
          $config['DNS2'] = trim($dns_list[1]);
      }
    }
    
    $newLines = array();
    foreach($config as $key => $val) {
      $newLines[] = $key . ':' . $val;
    } 
    file_put_contents($filename, implode(PHP_EOL, $newLines) . PHP_EOL);
  }
}

$controller = new NetworkConfig();
$controller->run();

?>
<!DOCTYPE html>
<html>
  <head>
    <eta charset="utf-8" />
    <title>Network Settings</title>
    <eta name="viewport" content="width=device-width, initial-scale=1.0">

    <link rel="stylesheet" href="../../css/bootstrap.min.css" media="screen" />
    <link rel="stylesheet" href="../../css/dropzone.css" media="screen" />
    <link rel="stylesheet" href="css/network_config.css" media="screen" />
  </head>
  <body>
    <div class="container" id="network_settings_content">
      <div class="navbar">
        <div class="navbar-inner">
          <a class="brand" href="/">EasyIO</a>
          <ul class="nav">
            <li class="divider-vertical"></li>
            <li v-for="sec in sections" :class="{active:isSectionActive(sec)}"><a href="#" @click="active_sec_id=sec.sec_id">{{ sec.name }}</a></li>
          </ul>
          <!-- <button class="btn btn&#45;primary pull&#45;right">New Profile</button> -->
        </div>
      </div>

      <div class="row">
        <alert></alert>
        <keep-alive>
            <component :is="active_sec_id"></component>
        </keep-alive>
      </div>
      <file-selector ref="file_selector_inst" server_url="file_manager.php" ></file-selector>
    </div>

    <!-- component templates -->
    <script type="text/x-template" id="alert-template">
      <div class="alert" :class="label_class" v-show="show">
        <button type="button" class="close" @click="show=false">&times;</button>
        <strong>{{ title }}</strong> {{ msg }}
      </div>
    </script>

    <script type="text/x-template" id="general-network-template">
      <div class="span12">
      <form class="form-horizontal" @submit.prevent="saveGeneralNetworkSettings">
        <div class="control-group" :class="{error:hostnameError}">
          <div class="control-label" for="inputHostName">HostName:</div>
          <div class="controls">
            <input id="inputHostName" type="text" v-model.trim="hostname" readonly>
            <span class="help-inline" v-show="hostnameError">Invalid HostName</span>
          </div>
        </div>
        <div class="control-group">
          <div class="controls">
            <select v-model='currentView'>
              <option v-for="sec in sections" :value="sec.id">{{ sec.name }}</option>
            </select>
          </div>
        </div>
        <div class="control-group" :class="{error:ipError && currentView == 'manual'}">
          <div class="control-label" for="inputIPAddress">IP Address:</div>
          <div class="controls">
            <input id="inputIPAddress" type="text" v-model.trim="ip" :disabled="currentView == 'auto'">
            <span class="help-inline" v-show="ipError && currentView == 'manual'">Invalid IP Address</span>
          </div>
        </div>
        <div class="control-group" :class="{error:netmaskError && currentView == 'manual'}">
          <div class="control-label" for="inputNetMask">Network Mask:</div>
          <div class="controls">
            <input id="inputNetMask" type="text" v-model.trim="netmask" :disabled="currentView== 'auto'">
            <span class="help-inline" v-show="netmaskError && currentView == 'manual'">Invalid Network Mask</span>
          </div>
        </div>
        <div class="control-group" :class="{error:gatewayError && currentView == 'manual'}">
          <div class="control-label" for="inputGateway">Gateway:</div>
          <div class="controls">
            <input id="inputGateway" type="text" v-model.trim="gateway" :disabled="currentView== 'auto'">
            <span class="help-inline" v-show="gatewayError && currentView == 'manual'">Invalid Gateway</span>
          </div>
        </div>

        <div class="control-group" :class="{error:dns1Error && currentView == 'manual'}">
          <div class="control-label" for="inputDNS1">DNS1:</div>
          <div class="controls">
            <input id="inputDNS1" type="text" v-model.trim="dns1" :disabled="currentView== 'auto'">
            <span class="help-inline" v-show="dns1Error && currentView == 'manual'">Invalid DNS</span>
          </div>
        </div>
        <div class="control-group" :class="{error:dns2Error && currentView == 'manual'}">
          <div class="control-label" for="inputDNS2">DNS2:</div>
          <div class="controls">
            <input id="inputDNS2" type="text" v-model.trim="dns2" :disabled="currentView== 'auto'">
            <span class="help-inline" v-show="dns2Error && currentView == 'manual'">Invalid DNS</span>
          </div>
        </div>

        <div class="control-group">
          <div class="controls">
            <button type="submit" class="btn">Save</button>
          </div>
        </div>
      </form>
      </div>
    </script>

    <script type="text/x-template" id="ipv6-network-template">
      <div class="span12">
      <form class="form-horizontal" @submit.prevent="saveIPv6NetworkSettings">
        <div class="control-group">
          <div class="controls">
            <select v-model='currentView'>
              <option v-for="sec in sections" :value="sec.id">{{ sec.name }}</option>
            </select>
          </div>
        </div>
        <template v-if="currentView =='manual'">
        <div class="control-group" :class="{error:ipError && currentView == 'manual'}">
          <div class="control-label" for="inputIPAddress">IP Address:</div>
          <div class="controls">
            <input id="inputIPAddress" type="text" v-model.trim="ip" :disabled="currentView == 'auto'">
            <span class="help-inline" v-show="ipError && currentView == 'manual'">Invalid IP Address</span>
          </div>
        </div>
        <div class="control-group" :class="{error:subnetPrefixLenError && currentView == 'manual'}">
          <div class="control-label" for="inputSubnetPrefixLen">Subnet Prefix Length:</div>
          <div class="controls">
            <input id="inputSubnetPrefixLen" type="number" v-model.number="subnetPrefixLen" :disabled="currentView== 'auto'">
            <span class="help-inline" v-show="subnetPrefixLenError && currentView == 'manual'">Subnet prefix length should be 1 ~ 128 (inclusive).</span>
          </div>
        </div>
        <div class="control-group" :class="{error:gatewayError && currentView == 'manual'}">
          <div class="control-label" for="inputGateway">Gateway:</div>
          <div class="controls">
            <input id="inputGateway" type="text" v-model.trim="gateway" :disabled="currentView== 'auto'">
            <span class="help-inline" v-show="gatewayError && currentView == 'manual'">Invalid Gateway</span>
          </div>
        </div>

        <div class="control-group" :class="{error:dns1Error && currentView == 'manual'}">
          <div class="control-label" for="inputDNS1">DNS1:</div>
          <div class="controls">
            <input id="inputDNS1" type="text" v-model.trim="dns1" :disabled="currentView== 'auto'">
            <span class="help-inline" v-show="dns1Error && currentView == 'manual'">Invalid DNS</span>
          </div>
        </div>
        <div class="control-group" :class="{error:dns2Error && currentView == 'manual'}">
          <div class="control-label" for="inputDNS2">DNS2:</div>
          <div class="controls">
            <input id="inputDNS2" type="text" v-model.trim="dns2" :disabled="currentView== 'auto'">
            <span class="help-inline" v-show="dns2Error && currentView == 'manual'">Invalid DNS</span>
          </div>
        </div>
        </template>

        <template v-else>
        <div class="control-group">
          <div class="control-label">IP Address:</div>
          <div class="controls">
            <p v-for="ip in autoSettings.ipList"> {{ ip }} </p>
          </div>
        </div>
        <div class="control-group">
          <div class="control-label">Gateway:</div>
          <div class="controls">
            <span class="static-label">{{ autoSettings.gateway }} </span>
          </div>
        </div>

        <div class="control-group" >
          <div class="control-label">DNS:</div>
          <div class="controls">
            <p v-for="dns in autoSettings.dnsList"> {{ dns }} </p>
          </div>
        </div>
        </template>

        <div class="control-group">
          <div class="controls">
            <button type="submit" class="btn">Save</button>
          </div>
        </div>
      </form>
      </div>
    </script>
    <script type="text/x-template" id="security-802_1x-md5-template">
      <div class="row security-section">
        <div class="control-group" :class="{error: usernameError}">
          <label class="control-label" for="inputUserName">Username:</label>
          <div class="controls">
            <input id="inputUserName" type="text" placeholder="User Name" v-model.trim='username' :disabled='!enabled'>
            <span class="help-inline" v-show="usernameError">Invalid user name</span>
          </div>   
        </div>
        <div class="control-group" :class="{error: passwordError}">
          <label class="control-label" for="inputPassword">Password:</label>
          <div class="controls">
            <input id="inputPassword" type="password" placeholder="Password" v-model.trim='password' :disabled='!enabled'>
            <span class="help-inline" v-show="passwordError">Invalid password(must >= 8 characters)</span>
          </div>
        </div>
      </div>
    </script>

    <script type="text/x-template" id="security-802_1x-tls-template">
      <div class="row security-section">
        <div class="control-group" :class="{error: identityError}">
          <label class="control-label" for="inputIdentity">Identity:</label>
          <div class="controls">
            <input id="inputIdentity" type="text" placeholder="Identity" v-model.trim='identity' :disabled='!enabled'>
            <span class="help-inline" v-show="identityError">Invalid identity</span>
          </div>   
        </div>
        <div class="control-group" :class="{error: certError}">
          <label class="control-label" for="inputCert">User certificate:</label>
          <div class="controls">
            <input id="inputCert" type="text" placeholder="User Certificate file (click to change)" v-model='cert' @click="changeFile('Choose User Certificate File', 'cert')" readonly class='default-cursor' :disabled='!enabled'>
            <button class="btn btn-link" type="button" @click="cert=''"><i class="icon-remove"></i></button>
            <span class="help-inline" v-show="certError">Invalid User Certificate</span>
          </div>   
        </div>
        <div class="control-group" :class="{error: caCertError}">
          <label class="control-label" for="inputCaCert">CA certificate:</label>
          <div class="controls">
            <input id="inputCaCert" type="text" placeholder="CA Certificate file (click to change)" v-model='caCert' @click="changeFile('Choose CA Certificate File', 'caCert')" readonly class='default-cursor' :disabled='!enabled'>
            <button class="btn btn-link" type="button" @click="caCert=''"><i class="icon-remove"></i></button>
            <span class="help-inline" v-show="caCertError">Invalid CA Certificate</span>
          </div>   
        </div>
        <div class="control-group" :class="{error: keyError}">
          <label class="control-label" for="inputKey">Private key:</label>
          <div class="controls">
            <input id="inputKey" type="text" placeholder="Private Key file (click to change)" v-model='key' @click="changeFile('Choose Private Key File', 'key')" readonly class='default-cursor' :disabled='!enabled'>
            <button class="btn btn-link" type="button" @click="key=''"><i class="icon-remove"></i></button>
            <span class="help-inline" v-show="keyError">Invalid private key</span>
          </div>   
        </div>
        <div class="control-group" :class="{error: keyPasswordError}">
          <label class="control-label" for="inputKeyPassword">Private key password:</label>
          <div class="controls">
            <input id="inputKeyPassword" type="password" placeholder="Private Key password" v-model.trim='keyPassword' :disabled='!enabled'>
            <span class="help-inline" v-show="keyPasswordError">Invalid private key password (must >= 8 characters)</span>
          </div>   
        </div>
      </div>
    </script>

    <script type="text/x-template" id="security-802_1x-ttls-template">
      <div class="row security-section">
        <div class="control-group" :class="{error: anonymousIdentityError}">
          <label class="control-label" for="inputAnanymousIdentity">Ananymous Identity:</label>
          <div class="controls">
            <input id="inputAnanymousIdentity" type="text" placeholder="Anonymous Identity" v-model.trim='anonymousIdentity' :disabled='!enabled'>
            <span class="help-inline" v-show="anonymousIdentityError">Invalid Anonymous identity</span>
          </div>   
        </div>
        <div class="control-group" :class="{error: caCertError}">
          <label class="control-label" for="inputCaCert">CA certificate:</label>
          <div class="controls">
            <input id="inputCaCert" type="text" placeholder="CA Certificate file (click to change)" v-model='caCert' @click="changeFile('Choose CA Certificate File', 'caCert')" readonly class='default-cursor' :disabled='!enabled'>
            <button class="btn btn-link" type="button" @click="caCert=''"><i class="icon-remove"></i></button>
            <span class="help-inline" v-show="caCertError">Invalid CA Certificate</span>
          </div>   
        </div>

        <div class="control-group">
          <label class="control-label">Inner authentication:</label>
          <div class="controls">
            <select v-model="phase2AuthEap" :disabled='!enabled'>
              <option v-for="auth in phase2AuthEapList" :value="auth.toLowerCase()">{{ auth }}</option>
            </select>
          </div>   
        </div>

        <div class="control-group" :class="{error: identityError}">
          <label class="control-label" for="inputUserName">Username:</label>
          <div class="controls">
            <input id="inputUserName" type="text" placeholder="User Name" v-model.trim='identity' :disabled='!enabled'>
            <span class="help-inline" v-show="identityError">Invalid user name</span>
          </div>   
        </div>
        <div class="control-group" :class="{error: passwordError}">
          <label class="control-label" for="inputPassword">Password:</label>
          <div class="controls">
            <input id="inputPassword" type="password" placeholder="Password" v-model.trim='password' :disabled='!enabled'>
            <span class="help-inline" v-show="passwordError">Invalid password(must >= 8 characters)</span>
          </div>
        </div>
      </div>
    </script>

    <script type="text/x-template" id="security-802_1x-peap-template">
      <div class="row security-section">
        <div class="control-group" :class="{error: anonymousIdentityError}">
          <label class="control-label" for="inputAnanymousIdentity">Ananymous Identity:</label>
          <div class="controls">
            <input id="inputAnanymousIdentity" type="text" placeholder="Anonymous Identity" v-model.trim='anonymousIdentity' :disabled='!enabled'>
            <span class="help-inline" v-show="anonymousIdentityError">Invalid Anonymous identity</span>
          </div>   
        </div>
        <div class="control-group" :class="{error: caCertError}">
          <label class="control-label" for="inputCaCert">CA certificate:</label>
          <div class="controls">
            <input id="inputCaCert" type="text" placeholder="CA Certificate file (click to change)" v-model='caCert' @click="changeFile('Choose CA Certificate File', 'caCert')" readonly class='default-cursor' :disabled='!enabled'>
            <button class="btn btn-link" type="button" @click="caCert=''"><i class="icon-remove"></i></button>
            <span class="help-inline" v-show="caCertError">Invalid CA Certificate</span>
          </div>   
        </div>

        <div class="control-group">
          <label class="control-label">Inner authentication:</label>
          <div class="controls">
            <select v-model="phase2Auth" :disabled='!enabled'>
              <option v-for="auth in phase2AuthList" :value="auth.toLowerCase()">{{ auth }}</option>
            </select>
          </div>   
        </div>

        <div class="control-group" :class="{error: identityError}">
          <label class="control-label" for="inputUserName">Username:</label>
          <div class="controls">
            <input id="inputUserName" type="text" placeholder="User Name" v-model.trim='identity' :disabled='!enabled'>
            <span class="help-inline" v-show="identityError">Invalid user name</span>
          </div>   
        </div>
        <div class="control-group" :class="{error: passwordError}">
          <label class="control-label" for="inputPassword">Password:</label>
          <div class="controls">
            <input id="inputPassword" type="password" placeholder="Password" v-model.trim='password' :disabled='!enabled'>
            <span class="help-inline" v-show="passwordError">Invalid password(must >= 8 characters)</span>
          </div>
        </div>
      </div>
    </script>

    <script type="text/x-template" id="security-802_1x-template">
      <div class="offset1 span11">
        <label class="checkbox">
          <input type="checkbox" v-model="enabled">
          Enable 802.1X security
        </label>
        
        <form class="form-horizontal" @submit.prevent="saveSecuritySettings" autocomplete="nope">
          <div class="control-group">
            <div class="control-label" for="securityType">Authentication:</div>
            <div class="controls">
              <select v-model='currentView' id="securityType" :disabled="!enabled">
                <option v-for="sec in sections" :value="sec.id">{{ sec.name }}</option>
              </select>
            </div>
            <keep-alive>
              <component :is="currentView" ref="sub_config_panel" :enabled="enabled" :initialSettings="initialSettings"></component>
            </keep-alive>
          </div>

          <div class="control-group">
            <div class="controls">
              <button type="submit" class="btn">Save</button>
            </div>
          </div>
        </form>
      </div>
    </script>

    <script type="text/x-template" id="file_selector_template">
      <div id="file_selector_modal" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="file_selector_modal_label" aria-hidden="true" >
        <div class="modal-header">
          <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
          <h3 id="file_selector_modal_label">{{ title }}</h3>
        </div>

        <div class="modal-body">
          <div id="file_upload_panel" style="overflow:scroll;">
            <div class="dropzone needsclick dz-clickable">
              <div class="dz-message needsclick">
                Drag and Drop file here or click to upload.
              </div>
            </div>
            <div class="dropzone dropzone-previews">
							<div class="dz-message">{{ previewMsg }}</div>
							<div class="table table-striped files dz-clickable">
							</div>
            </div>
          </div>
        </div>

        <div class="modal-footer">
          <button class="btn btn-primary" @click="saveFilePath">Ok</button>
          <button class="btn" data-dismiss="modal" aria-hidden="true">Close</button>
        </div>
      </div>
    </script>
    <script type="text/x-template" id="file_preview_template">
			<div class="file-row">
				<!-- This is used as the file preview template -->
				<div>
						<span class="preview"><img data-dz-thumbnail /></span>
				</div>
				<div>
						<p class="name" data-dz-name></p>
						<strong class="error text-danger" data-dz-errormessage></strong>
				</div>
				<div>
						<p class="size" data-dz-size></p>
						<div class="progress progress-striped active" role="progressbar" aria-valuemin="0" aria-valuemax="100" aria-valuenow="0">
							<div class="bar bar-success" style="width:0%;" data-dz-uploadprogress></div>
						</div>
				</div>
				<div>
<!--
					<button class="btn btn-primary start">
							<i class="glyphicon glyphicon-upload"></i>
							<span>Start</span>
					</button>
					<button data-dz-remove class="btn btn-warning cancel">
							<i class="glyphicon glyphicon-ban-circle"></i>
							<span>Cancel</span>
					</button>
-->
					<button data-dz-remove class="btn btn-danger delete">
						<i class="glyphicon glyphicon-trash"></i>
						<span>Delete</span>
					</button>
				</div>
			</div>
    </script>

    <script language="javascript" type="text/javascript">
      window.iot_platform = '<?php echo platformName() ?>';
    </script>

    <script type="text/javascript" src="../../js/jquery-1.10.0.min.js"></script>
    <script type="text/javascript" src="../../js/bootstrap.min.js"></script>
    <script type="text/javascript" src="../../js/underscore-min.js"></script>
    <script type="text/javascript" src="../../js/dropzone.js"></script>
    <script type="text/javascript" src="../../js/spin.min.js"></script>

<?php
  if (isset($_GET["dev"])) {
?>
    <script type="text/javascript" src="../../js/vue.js"></script>
<?php
  } else {
?>
    <script type="text/javascript" src="../../js/vue.min.js"></script>
<?php
  }
?>
    <script type="text/javascript" src="../../js/plugin-utils.js"></script>
    <script type="text/javascript" src="../../js/vue-alert-component.js"></script>
    <script type="text/javascript" src="../../js/vue-file-selector-component.js"></script>
    <script type="text/javascript" src="js/network_config.js"></script>
  </body>
</html>