<?php 
// vim: ts=2 sw=2

set_include_path(get_include_path() . PATH_SEPARATOR . '../../app');

include_once "base_controller.php";

class DataServiceConfig extends BaseController {
  protected function signinRequired() {
    return true;
  }

  protected function adminRequired() {
    return true;
  }

  public function doAjaxGet() {
    $action = 'load_config';
    if (isset($_GET['action']))
      $action = $_GET['action'];

    $response = array();
    if ($action == "status")
      $this->handleServiceStatusQuery();
    else if ($action == 'load_config')
      $this->handleDataMappingQuery();
    else
      $this->renderAjaxError($response, "invalid action: " . $action);
  }

  public function doAjaxPost() {
    $response = array();
    $action = "save_config";
    if (isset($_POST['action']))
      $action = $_POST['action']; 
    
    if ($action == "save_config") {
      $curPath = dirname(__FILE__);

      $config_data = $this->getInputData('config_data', false);
      $filename = build_file_path($curPath, "data_mapping_config.json");
      file_put_contents($filename, $config_data);

      $mapping_data = $this->getInputData('mapping_data', false);
      $filename = build_file_path($curPath, "data_mapping.json");
      if (file_put_contents($filename, $mapping_data)) {
        execCmd('ln -sf '.$filename.' /etc/mqtt-service.json')
        $pfName = platformName();
        if ($pfName == "FS") {
          // if monit service exists, then use it; otherwise use init script
          `[ -e /usr/bin/monit ] && /usr/bin/monit restart mqtt-service || /etc/init.d/S91mqtt-service restart`
        } else if ($pfName == "FW") {
          `[ -e /usr/bin/monit ] && /usr/bin/monit restart mqtt-service || /etc/init.d/mqtt-service restart`
        } else {
          $this->renderAjaxError($response, "current platform is not supported");
        }
        $this->renderAjaxSuccess($response);
      }
      else
        $this->renderAjaxError($response, "can not write config data to file: " . $filename);
    } else
      $this->renderAjaxError($response, "invalid action: " . $action);
  }

  protected function handleServiceStatusQuery() {
    $response = array();
    $pfName = platformName();
    if ($pfName == 'FS')
      $cmd = "/bin/sh /etc/init.d/S91mqtt-service status";
    else if ($pfName == 'FW')
      $cmd = "/bin/sh -c 'source /etc/init.d/mqtt-service && service_status'";
    else
      $this->renderAjaxError($response, "platform is not supported");
        
    $output = array();
    $return = '';
    $last_line = exec($cmd, $output, $return)
    if ($return != '0')
      $response['service_status'] = 'unknown';
    else {
      if (preg_match('/mqtt-service dead but pid file exists/', $last_line)
        || preg_match('/mqtt-service is stopped/', $last_line))
        $response['service_status'] = 'stopped';
      else if (preg_match('/mqtt-service \(pid \d+\) is running.../', $last_line))
        $response['service_status'] = 'started';
      else
        $response['service_status'] = 'error';
    }
    $this->renderAjaxSuccess($response);
  }

  protected function handleDataMappingQuery() {
    $response = array();
    $response['data'] = array();

    $response['data']['certs_dir'] = build_file_path(dirname(__FILE__), "uploads", "certs");
    $filename = "data_mapping.json";
    if (file_exists($filename))
      $response['data']['mapping_data'] = file_get_contents($filename); 

    $filename = "data_mapping_config.json";
    if (file_exists($filename))
      $response['data']['config_data'] = file_get_contents($filename); 

    $this->renderAjaxSuccess2($response);
  }
}

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

?>
<!DOCTYPE html>
<html>
  <head>
    <eta charset="utf-8" />
    <title>Data Service Config</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="../../js/jstree/themes/default/style.min.css" media="screen" />

    <link rel="stylesheet" href="css/data_service_config.css" media="screen" />
  </head>
  <body>
    <div class="container" id="data_service_config_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>
          <service-status id="service_status" />
          <!-- <button class="btn btn&#45;primary pull&#45;right">New Profile</button> -->
        </div>
      </div>

      <!-- <h3 class='text&#45;center'>Data Service Config</h3>  -->
      <div class="row">
        <alert></alert>
        <template v-for="sec in sections">
          <component :is="sec.sec_id" class="tab-pane" :class="{hide: active_sec_id != sec.sec_id}" :ref="sec.sec_id"></component>
        </template>
        <button type="button" class="btn btn-primary btn-large pull-right" @click="saveConfig">Save</button>
      </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="gcp_iot_core_template">
      <form class="form-horizontal">
        <div class="control-group">
          <label class="control-label"><strong>GCP IoT Core</strong></label>
        </div>
        <div class="control-group" :class="{error: name_error.length > 0}">
          <label class="control-label" for="inputName">Broker Name:</label>
          <div class="controls">
            <input type="text" id="inputName" placeholder="Broker Name" v-model.trim="name">
            <span class="help-inline" v-show="name_error.length > 0">{{ name_error }}</span>
          </div>
        </div>
        <div class="control-group" :class="{error: project_id_error.length > 0}">
          <label class="control-label" for="inputProjectID">Project ID:</label>
          <div class="controls">
            <input type="text" id="inputProjectID" placeholder="Project ID" v-model.trim="config.project_id">
            <span class="help-inline" v-show="project_id_error.length > 0">{{ project_id_error }}</span>
          </div>
        </div>
        <div class="control-group" :class="{error: registry_id_error.length > 0}">
          <label class="control-label" for="inputRegistryID">Registry ID:</label>
          <div class="controls">
            <input type="text" id="inputRegistryID" placeholder="Registry ID" v-model.trim="config.registry_id">
            <span class="help-inline" v-show="registry_id_error.length > 0">{{ registry_id_error }}</span>
          </div>
        </div>
        <div class="control-group" :class="{error: device_id_error.length > 0}">
          <label class="control-label" for="inputDeviceID">Device ID:</label>
          <div class="controls">
            <input type="text" id="inputDeviceID" placeholder="Device ID" v-model.trim="config.device_id">
            <span class="help-inline" v-show="device_id_error.length > 0">{{ device_id_error }}</span>
          </div>
        </div>
        <div class="control-group" :class="{error: region_error.length > 0}">
          <label class="control-label" for="inputRegion">Region:</label>
          <div class="controls">
            <select id="inputRegion" v-model="config.region">
              <option value="us-central1">us-central1</option>
              <option value="europe-west1">europe-west1</option>
              <option value="asia-east1">asia-east1</option>
            </select>
            <span class="help-inline" v-show="region_error.length > 0">{{ region_error }}</span>
          </div>
        </div>

        <div class="control-group">
          <label class="control-label"><strong>SSL/TLS</strong></label>
        </div>

        <div class="control-group" :class="{error: ca_file_error.length > 0}">
          <label class="control-label" for="inputCAFile">CA File:</label>
          <div class="controls">
            <div class="input-append">
              <input type="text" id="inputCAFile" placeholder="CA File (click to change)" v-model="config.ca_file" @click="changeCAFile" readonly class='default-cursor span11'>
              <button class="btn btn-link" type="button" @click="config.ca_file=''"><i class="icon-remove"></i></button>
            </div>
            <span class="help-inline" v-show="ca_file_error.length > 0">{{ ca_file_error }}</span>
          </div>
        </div>
        <div class="control-group" :class="{error: cert_file_error.length > 0}">
          <label class="control-label" for="inputCertFile">Certificate File:</label>
          <div class="controls">
            <div class="input-append">
              <input type="text" id="inputCertFile" placeholder="Client Certificate File (click to change)" v-model="config.cert_file" @click="changeClientCertFile" readonly class='default-cursor span11'>
              <button class="btn btn-link" type="button" @click="config.cert_file=''"><i class="icon-remove"></i></button>
            </div>
            <span class="help-inline" v-show="cert_file_error.length > 0">{{ cert_file_error }}</span>
          </div>
        </div>
        <div class="control-group" :class="{error: key_file_error.length > 0}">
          <label class="control-label" for="inputKeyFile">Key File:</label>
          <div class="controls">
            <div class="input-append">
              <input type="text" id="inputKeyFile" placeholder="Key File (click to change)" v-model="config.key_file" @click="changeKeyFile" readonly class='default-cursor span11'>
              <button class="btn btn-link" type="button" @click="config.key_file=''"><i class="icon-remove"></i></button>
            </div>
            <span class="help-inline" v-show="key_file_error.length > 0">{{ key_file_error }}</span>
          </div>
        </div>

        <div class="control-group">
          <label class="control-label"><strong>Publish Interval</strong></label>
        </div>
        <div class="control-group" :class="{error: events_interval_error.length > 0}">
          <label class="control-label" for="inputEventInterval">Publish Interval:</label>
          <div class="controls">
            <input type="number" id="inputEventInterval" placeholder="How often to publish data" v-model.number="config.events_interval">
            <span class="help-inline" v-show="events_interval_error.length > 0">{{ events_interval_error }}</span>
          </div>
        </div>

        <div class="control-group">
          <div class="controls">
            <button type="submit" class="btn btn-success" @click.prevent="onSaveLocal">Ok</button>
            <button class="btn" @click.prevent="onReset">Reset</button>
          </div>
        </div>
      </form>
    </script>

    <script type="text/x-template" id="mqtt-template">
      <form class="form-horizontal">
        <div class="control-group">
          <label class="control-label"><strong>General MQTT</strong></label>
        </div>
        <div class="control-group" :class="{error: name_error.length > 0}">
          <label class="control-label" for="inputName">Broker Name:</label>
          <div class="controls">
            <input type="text" id="inputName" placeholder="Broker Name" v-model.trim="name">
            <span class="help-inline" v-show="name_error.length > 0">{{ name_error }}</span>
          </div>
        </div>
        <div class="control-group" :class="{error: host_error.length > 0}">
          <label class="control-label" for="inputHost">Host:</label>
          <div class="controls">
            <input type="text" id="inputHost" placeholder="MQTT Broker Host" v-model.trim="config.mqtt_host">
            <span class="help-inline" v-show="host_error.length > 0">{{ host_error }}</span>
          </div>
        </div>
        <div class="control-group" :class="{error: port_error.length > 0}">
          <label class="control-label" for="inputPort">Port:</label>
          <div class="controls">
            <input type="text" id="inputPort" placeholder="MQTT Broker Port" v-model.number="config.mqtt_port">
            <span class="help-inline" v-show="port_error.length > 0">{{ port_error }}</span>
          </div>
        </div>
        <div class="control-group" :class="{error: client_id_error.length > 0}">
          <label class="control-label" for="inputClientId">Client ID:</label>
          <div class="controls">
            <input type="text" id="inputClientId" placeholder="Client ID" v-model.trim="config.mqtt_client_id">
            <span class="help-inline" v-show="client_id_error.length > 0">{{ client_id_error }}</span>
          </div>
        </div>
        <div class="control-group" :class="{error: user_error.length > 0}">
          <label class="control-label" for="inputUserName">User:</label>
          <div class="controls">
            <input type="text" id="inputUserName" placeholder="User" v-model.trim="config.mqtt_user" autocomplete="nope">
            <span class="help-inline" v-show="user_error.length > 0">{{ user_error }}</span>
          </div>
        </div>
        <div class="control-group" :class="{error: passwd_error.length > 0}">
          <label class="control-label" for="inputPassword">Password:</label>
          <div class="controls">
            <input id="inputPassword" type="password" placeholder="Password" v-model.trim="config.mqtt_passwd" autocomplete="nope">
            <span class="help-inline" v-show="passwd_error.length > 0">{{ passwd_error }}</span>
          </div>
        </div>
        <div class="control-group">
          <label class="control-label" for="inputQoS">QoS:</label>
          <div class="controls">
            <select id="inputQoS" v-model="config.mqtt_qos">
              <option value="0">QoS0</option>
              <option value="1">QoS1</option>
              <option value="2">QoS2</option>
            </select>
          </div>
        </div>

        <div class="control-group">
          <label class="control-label"><strong>SSL/TLS</strong></label>
        </div>

        <div class="control-group">
          <div class="controls">
            <label class="checkbox">
              <input type="checkbox" id="inputEnableTls" v-model="tls_enabled">Enable TLS
            </label>
          </div>
        </div>
        <div class="control-group" :class="{error: ca_file_error.length > 0}">
          <label class="control-label" for="inputCAFile">CA File:</label>
          <div class="controls">
            <div class="input-append">
              <input type="text" id="inputCAFile" placeholder="CA File (click to change)" v-model="config.ca_file" @click="changeCAFile" readonly class='default-cursor span11'>
              <button class="btn btn-link" type="button" @click="config.ca_file=''"><i class="icon-remove"></i></button>
            </div>
            <span class="help-inline" v-show="ca_file_error.length">Invalid CA File</span>
          </div>
        </div>
        <div class="control-group" :class="{error: cert_file_error.length > 0}">
          <label class="control-label" for="inputCertFile">Certificate File:</label>
          <div class="controls">
            <div class="input-append">
              <input type="text" id="inputCertFile" placeholder="Client Certificate File (click to change)" v-model="config.cert_file" @click="changeClientCertFile" readonly class='default-cursor span11'>
              <button class="btn btn-link" type="button" @click="config.cert_file=''"><i class="icon-remove"></i></button>
            </div>
            <span class="help-inline" v-show="cert_file_error.length > 0">{{ cert_file_error }}</span>
          </div>
        </div>
        <div class="control-group" :class="{error: key_file_error.length > 0}">
          <label class="control-label" for="inputKeyFile">Key File:</label>
          <div class="controls">
            <div class="input-append">
              <input type="text" id="inputKeyFile" placeholder="Key File (click to change)" v-model="config.key_file" @click="changeKeyFile" readonly class='default-cursor span11'>
              <button class="btn btn-link" type="button" @click="config.key_file=''"><i class="icon-remove"></i></button>
            </div>
            <span class="help-inline" v-show="key_file_error.length">{{ key_file_error }}</span>
          </div>
        </div>

        <div class="control-group">
          <label class="control-label"><strong>Publish Interval</strong></label>
        </div>
        <div class="control-group" :class="{error: events_interval_error.length > 0}">
          <label class="control-label" for="inputEventInterval">Publish Interval:</label>
          <div class="controls">
            <input type="number" id="inputEventInterval" placeholder="How often to publish data" v-model.number="config.events_interval">
            <span class="help-inline" v-show="events_interval_error.length">{{ events_interval_error }}</span>
          </div>
        </div>
        <div class="control-group">
          <div class="controls">
            <button type="submit" class="btn btn-success" @click.prevent="onSaveLocal">Ok</button>
            <button class="btn" @click.prevent="onReset">Reset</button>
          </div>
        </div>
      </form>
    </script>

    <script type="text/x-template" id="aws_iot_core_template">
      <form class="form-horizontal">
        <div class="control-group">
          <label class="control-label"><strong>AWS IoT Core</strong></label>
        </div>
        <div class="control-group" :class="{error: name_error.length > 0}">
          <label class="control-label" for="inputName">Broker Name:</label>
          <div class="controls">
            <input type="text" id="inputName" placeholder="Broker Name" v-model.trim="name">
            <span class="help-inline" v-show="name_error.length > 0">{{ name_error }}</span>
          </div>
        </div>

        <div class="control-group" :class="{error: host_error.length > 0}">
          <label class="control-label" for="inputHost">Endpoint:</label>
          <div class="controls">
            <input type="text" id="inputHost" placeholder="MQTT Endpoint" v-model.trim="config.mqtt_host">
            <span class="help-inline" v-show="host_error.length > 0">{{ host_error }}</span>
          </div>
        </div>
        <div class="control-group" :class="{error: client_id_error.length > 0}">
          <label class="control-label" for="inputClientId">Client ID:</label>
          <div class="controls">
            <input type="text" id="inputClientId" placeholder="Client ID" v-model.trim="config.mqtt_client_id">
            <span class="help-inline" v-show="client_id_error.length > 0">{{ client_id_error }}</span>
          </div>
        </div>
        <div class="control-group">
          <label class="control-label" for="inputQoS">QoS:</label>
          <div class="controls">
            <select id="inputQoS" v-model="config.mqtt_qos">
              <option value="0">QoS0</option>
              <option value="1">QoS1</option>
            </select>
          </div>
        </div>

        <div class="control-group">
          <label class="control-label"><strong>SSL/TLS</strong></label>
        </div>

        <div class="control-group" :class="{error: ca_file_error.length > 0}">
          <label class="control-label" for="inputCAFile">CA File:</label>
          <div class="controls">
            <div class="input-append">
              <input type="text" id="inputCAFile" placeholder="CA File (click to change)" v-model="config.ca_file" @click="changeCAFile" readonly class='default-cursor span11'>
              <button class="btn btn-link" type="button" @click="config.ca_file=''"><i class="icon-remove"></i></button>
            </div>
            <span class="help-inline" v-show="ca_file_error.length > 0">{{ ca_file_error }}</span>
          </div>
        </div>
        <div class="control-group" :class="{error: cert_file_error.length > 0}">
          <label class="control-label" for="inputCertFile">Certificate File:</label>
          <div class="controls">
            <div class="input-append">
              <input type="text" id="inputCertFile" placeholder="Client Certificate File (click to change)" v-model="config.cert_file" @click="changeClientCertFile" readonly class='default-cursor span11'>
              <button class="btn btn-link" type="button" @click="config.cert_file=''"><i class="icon-remove"></i></button>
            </div>
            <span class="help-inline" v-show="cert_file_error.length > 0">{{ cert_file_error }}</span>
          </div>
        </div>
        <div class="control-group" :class="{error: key_file_error.length > 0}">
          <label class="control-label" for="inputKeyFile">Key File:</label>
          <div class="controls">
            <div class="input-append">
              <input type="text" id="inputKeyFile" placeholder="Key File (click to change)" v-model="config.key_file" @click="changeKeyFile" readonly class='default-cursor span11'>
              <button class="btn btn-link" type="button" @click="config.key_file=''"><i class="icon-remove"></i></button>
            </div>
            <span class="help-inline" v-show="key_file_error.length > 0">{{ key_file_error }}</span>
          </div>
        </div>

        <div class="control-group">
          <label class="control-label"><strong>Publish Interval</strong></label>
        </div>
        <div class="control-group" :class="{error: events_interval_error.length > 0}">
          <label class="control-label" for="inputEventInterval">Publish Interval:</label>
          <div class="controls">
            <input type="number" id="inputEventInterval" placeholder="How often to publish data" v-model.number="config.events_interval">
            <span class="help-inline" v-show="events_interval_error.length > 0">{{ events_interval_error }}</span>
          </div>
        </div>

        <div class="control-group">
          <div class="controls">
            <button type="submit" class="btn btn-success" @click.prevent="onSaveLocal">Ok</button>
            <button class="btn" @click.prevent="onReset">Reset</button>
          </div>
        </div>
      </form>
    </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 type="text/x-template" id="device_data_panel_template">
      <div id="deviceDataPanel" class='well well-small'>
        <h4 class="center">Device Data Tree</h4>
        <div id="deviceDataTree" class="row scrollable-content"></div>
        <p class="tree-btns">
          <button class="btn btn-mini" type="button" @click="addObjectToSchema">Add</button>
        </p>
      </div>
    </script>
    
    <script type="text/x-template" id="data_schema_panel_template">
      <div class='well well-small'>
        <h4 class="center">Cloud Data Tree</h4>
        <div id="dataSchemaTree" class="row scrollable-content"></div>
        <p class="tree-btns">
          <button class="btn btn-mini" type="button" @click="newNode">New</button>
          <button class="btn btn-mini" type="button" @click="newTopicTree">New Topic Tree</button>
          <button class="btn btn-mini btn-info" type="button" @click="editNode">Edit</button>
          <button class="btn btn-mini btn-danger" type="button" @click="removeNode">Delete</button>
        </p>

        <odal-dialog :title="newTopicTreeMode ? 'New Topic Tree' : 'Edit Topic'" v-on:submitChange="newTopicTreeMode ? createTopicTreeNode() : changeTopicTreeNode()">
          <div v-if="availableTopicNames.length > 0" class="control-group">
            <label class="control-label">Topic:</label>
            <div class="controls">
              <select v-model="selectedTopicName">
                <option v-for="topicName in availableTopicNames" :value="topicName">{{topicName}}</option>
                <!-- <option value="NoMQTTTopic">NoMQTTTopic</option> -->
              </select>
            </div>
          </div>
          <div v-else class="alert alert-block">
            There is no topics available, please create more topics from TopicManager first.
          </div>
        </modal-dialog>
      </div>
    </script>

    <script type="text/x-template" id="property_list_panel_template">
      <div class="comp-data-box">
        <button type="button" class="btn btn-fullwidth" data-toggle="collapse" :data-target="'#' + objDataUniqueDomID(objData.path)" @click="boxOpened = !boxOpened"><i :class="boxBtnClass"></i> {{ objData.path }}</button>
        <div :id="objDataUniqueDomID(objData.path)" class="collapse in">
        <table class="table table-striped table-hover table-condensed">
          <thead>
            <tr>
              <th></th>
              <th>Label</th>
              <th>Value</th>
              <th class="operation-box">Operations</th>
            </tr>
          </thead>
          <tbody>
              <tr v-for='(slot, index) in objData.slots'>
                <td  @click='slot.enabled = !slot.enabled'><input type='checkbox' v-model='slot.enabled'></td>
                <td><input type='text' class='input-small' v-model='slot.label' :disabled="!slot.enabled"></td>
                <td><input type='text' class='input-small' v-model='slot.value' :disabled="!slot.enabled"></td>
                <td class="operation-box">
                  <button class="btn btn-mini btn-danger btn-link" type="button" @click="objData.slots.splice(index, 1)">Delete</button>
                </td>
              </tr>
          </tbody>
        </table>
        <div class="comp-btn-group">
          <button class="btn btn-mini btn-success" id="newPropertyBtn" type="button" @click="addProperty">New</button>
          <button class="btn btn-mini" type="button" @click="selectAll">Select All</button>
          <button class="btn btn-mini btn-inverse" type="button" @click="inverseSelect">Inverse Select</button>
          <button class="btn btn-mini btn-warning" type="button" @click="selectNone">Select None</button>
          <button class="btn btn-mini btn-danger pull-right" type="button" @click="deleteSelectedSlot">Del Selected</button>
          <button id="delCompBtn" class="btn btn-mini btn-danger pull-right" type="button" @click="$emit('remove')">Del Comp</button>
        </div>
        </div>
      </div>
    </script>

    <script type="text/x-template" id="node_schema_panel_template">
      <div class='well well-small'>
        <h4 class="center">Cloud Tree Node Schema</h4>
        <div class="row scrollable-content">
          <table class="table table-striped table-hover table-condensed">
            <thead>
              <tr>
                <th></th>
                <th>Label</th>
                <th>Binding</th>
              </tr>
            </thead>
            <tbody>
              <template v-for='objData in objDataList'>
              <tr v-for='(slotData, index) in objData.slots' v-show="slotData.visible">
                <td><input type='radio' :value="slotData.uid" v-model='selectedSlotUID'></td>
                <td><input type='text' class='input-small' v-model='slotData.label' 
                  :disabled="selectedSlotUID!=slotData.uid" :class="{error: errorSlotUID == slotData.uid}"></td>
                <td><a v-if="commonBindingPath.length > 0" href="#" data-toggle="tooltip" :title="bindingTooltip(slotData)">...</a>/{{ shortBindingPath(slotData) }}</td>
              </tr>
              </template>
            </tbody>
          </table>
        </div>
        <div class="row" id="nodeBtnSection">
          <!-- 
          <button class="btn btn-mini" type="button" @click="selectAll">Select All</button>
          <button class="btn btn-mini btn-inverse" type="button" @click="inverseSelect">Inverse Select</button>
          <button class="btn btn-mini btn-warning" type="button" @click="selectNone">Select None</button>
          <button class="btn btn-mini btn-danger pull-right" type="button" @click="deleteSelectedSlot">Del Selected</button>
          -->
          <transition name="fade" mode="out-in">
          <button class="btn btn-mini" type="button" :key="editMode" @click="saveNodeSchema">{{ editMode ? 'Update' : 'Add' }}</button>
          </transition>
        </div>
      </div>
    </script>

    <script type="text/x-template" id="name_replacement_preprocessor_template">
      <div> 
        <form class="form-inline">
          <label>When slot's name is :</label>
          <input type='text' class='input-small' v-model='payload.old_name' :disabled="!enabled"></td>
          <label> then rename it to :</label>
          <input type='text' class='input-small' v-model='payload.new_name' :disabled="!enabled"></td>
          <a v-if="tooltip && tooltip.length > 0" v-once class="pull-right" href="#" data-toggle="tooltip" data-placement="top" :title="tooltip"><i class="icon-question-sign"></i></a>
        </form>
      </div>
    </script>

    <script type="text/x-template" id="preselect_preprocessor_template">
      <div>
        <form class="form-inline">
          <label>Preselect slot when its name match :</label>
          <input type='text' class='input-small' :disabled="!enabled"></td>
          <a v-if="tooltip && tooltip.length > 0" v-once class="pull-right" href="#" data-toggle="tooltip" data-placement="top" :title="tooltip"><i class="icon-question-sign"></i></a>
        </form>
      </div>
    </script>

    <script type="text/x-template" id="schema_preview_panel_template">
      <div class='row' >
        <div class="alert alert-info">
          <button type='button' class='close' data-dismiss='alert'>x</button>
          <strong>Note:</strong> all property values (number, boolean, string etc) are fake, only for demo purpose.
        </div>
        <schema-preview-entry v-for="(schema_json, index) in schema_jsons" :key='index' :topic='schema_json[0]' :json='schema_json[1]'></schema-preview-entry>
      </div>
    </script>

    <script type="text/x-template" id="preprocessor_list_template">
      <div class='row scrollable-content' >
        <div id='preprocessorBtnGroup' class='btn-group dropdown pull-right'>
          <a class='btn dropdown-toggle' data-toggle='dropdown' href='#'>
            Add New Preprocessor
            <span class='caret'></span>
          </a>
          <ul class="dropdown-menu">
            <li v-for="preprocessor in type_list">
              <a href="#" @click.prevent="addPreprocessorElem(preprocessor)"><i :class="preprocessor.icon"></i> {{ preprocessor.label }}</a>
            </li>
          </ul>
        </div>
        <table class="table table-striped table-hover">
          <thead>
            <tr>
              <th></th>
              <th></th>
              <th>Preprocessor</th>
              <th class="operation-box">Operation</th>
            </tr>
          </thead>
          <tbody>
            <tr v-for='(inst, index) in instance_list'>
              <td  @click='inst.enabled = !inst.enabled'>
                <input type='checkbox' v-model='inst.enabled'>
              </td>
              <td> <i :class="iconFromComp(inst.component)"></i> </td>
              <td>
                <component :is="inst.component" ref="preprocessor" :payload="inst.payload" :enabled="inst.enabled"></component>
              </td>
              <td class="operation-box">
                <button class="btn btn-mini btn-link" type="button" @click="instance_list.push(_.clone(inst))">Clone</button>
                <button class="btn btn-mini btn-danger btn-link" type="button" @click="instance_list.splice(index, 1)">Delete</button>
              </td>
            </tr>
          </tbody>
        </table>
      </div>
    </script>

    <script type="text/x-template" id="data_mapping_template">
      <div class='row tabbable'>
        <ul class="nav nav-tabs">
          <li v-for="tab in tabs" v-once :class="{ active : tab.id == active_tab_id }"><a :href="'#' + tab.id" :data-tab-id='tab.id' data-toggle='tab' @click='onShowTab'>{{ tab.label }}</a></li>
        </ul>
        <div class='row tab-content'>
          <div :id='tabs[0].id' class='row tab-pane' :class="{ active: tabs[0].id == active_tab_id }" >
            <data-schema-panel id="dataSchemaPanel" ref="dataSchemaPanel" class="split" 
              v-on:nodeChanged="onNodeChanged">
            </data-schema-panel>
            <node-schema-panel id="nodeSchemaPanel" ref="nodeSchemaPanel" class="split" 
              v-on:nodeSchemaUpdated="onNodeSchemaUpdated" v-on:objectAdded="onObjectAdded" >
            </node-schema-panel>
            <device-data-panel id="deviceDataPanel" ref="deviceDataPanel" class="split" v-on:objectsToSchema="addObjectsToSchema" ></device-data-panel>
          </div>
          <schema-preview-panel :id='tabs[1].id' ref="schemaPreviewPanel" class='tab-pane' :class="{ active: tabs[1].id == active_tab_id }" :schema_jsons="previewJsons"></schema-preview-panel>
          <preprocess-list-panel :id='tabs[2].id' ref="preprocessorListPanel" class='tab-pane' :class="{ active: tabs[2].id == active_tab_id }"></preprocess-list-panel>
        </div>
      </div>
    </script>

    <script type="text/x-template" id="broker_manager_template">
      <div class="row-fluid" v-cloak>
        <div id="broker_list" class="span6">
          <table class="table table-striped table-hover table-bordered">
            <thead>
              <tr>
                <sortable-table-header :sortField="sortField" fieldName="name" @sortBy="sortBy"></sortable-table-header>
                <sortable-table-header :sortField="sortField" fieldName="type" @sortBy="sortBy"></sortable-table-header>
              </tr>
            </thead>
            <tbody>
              <tr v-for="broker in brokerList" @click="activeBroker=broker" :class="{info:activeBroker && activeBroker.uniqueKey==broker.uniqueKey}">
                <td>{{broker.name}}</td>
                <td>{{broker.type | typeLabel}}</td>
              </tr>
            </tbody>
          </table>
          <div class="pull-right">
            <button class="btn" type="button" @click="addBroker">Add</button>
            <button class="btn" type="button" @click="cloneBroker" :disabled="activeBroker==null">Clone</button>
            <button class="btn btn-danger" type="button" @click="deleteBroker" :disabled="activeBroker==null">Delete</button>
          </div>
        </div>
        <div id="broker_detail" class="well span6">
          <keep-alive>
          <component v-if="activeBroker != null" :is="activeBroker.type" :key="activeBroker.uniqueKey" 
            :brokerName="activeBroker.name" :configData="activeBroker.config" :nameError="nameError"
            @brokerUpdated="onBrokerUpdated" ></component>
          </keep-alive>
        </div>

        <odal-dialog title="New Broker" :error="newBroker.error.length != 0" v-on:submitChange="createBroker">
          <div class="control-group" :class="{error: !isNewNameValid(newBroker.name)}">
            <label class="control-label" for="inputBrokerName">Name:</label>
            <div class="controls">
              <input type="text" id="inputBrokerName" placeholder="Broker's Name" v-model.trim="newBroker.name" autofocus>
              <span class="help-inline" v-show="newBroker.error.length != 0">{{newBroker.error}}</span>
            </div>
          </div>
          <div class="control-group">
            <label class="control-label">Type:</label>
            <div class="controls">
              <select v-model="newBroker.type">
                <option v-for="type in brokerTypeList" :value="type">{{type | typeLabel}}</option>
              </select>
            </div>
          </div>
        </modal-dialog>
      </div>
    </script>

    <script type="text/x-template" id="sortable_table_header_template">
      <th @click="ascendingSort = !ascendingSort">
        <slot>
        {{fieldName | capitalize}}
        </slot>
        <a v-show="sortField == fieldName" class="pull-right" href="#"><i :class="[ascendingSort ? 'icon-chevron-down' : 'icon-chevron-up']"></i></a>
      </th>
    </script>
    
    <script type="text/x-template" id="gcp_iot_core_topic_template">
      <form class="form-horizontal">
        <div class="control-group">
          <label class="control-label"><strong>GCP IoT Core Topic</strong></label>
        </div>
        <div class="control-group" :class="{error: name_error.length > 0}">
          <label class="control-label" for="inputTopicName">Topic Name:</label>
          <div class="controls">
            <input type="text" id="inputTopicName" placeholder="Topic Name" v-model.trim="name">
            <span class="help-inline" v-show="name_error.length > 0">{{ name_error }}</span>
          </div>
        </div>
        <div class="control-group">
          <label class="control-label">Topic Path:</label>
          <div class="controls">
            <input type="text" placeholder="Topic Path" :value="path" readonly>
          </div>
        </div>

        <div class="control-group">
          <div class="controls">
            <button type="submit" class="btn btn-success" @click.prevent="onSaveLocal">Ok</button>
            <button class="btn" @click.prevent="onReset">Reset</button>
          </div>
        </div>
      </form>
    </script>

    <script type="text/x-template" id="mqtt_topic_template">
      <form class="form-horizontal">
        <div class="control-group">
          <label class="control-label"><strong>MQTT Topic</strong></label>
        </div>
        <div class="control-group" :class="{error: name_error.length > 0}">
          <label class="control-label" for="inputTopicName">Topic Name:</label>
          <div class="controls">
            <input type="text" id="inputTopicName" placeholder="Topic Name" v-model.trim.lazy="name">
            <span class="help-inline" v-show="name_error.length > 0">{{ name_error }}</span>
          </div>
        </div>
        <div class="control-group" :class="{error: path_error.length > 0}">
          <label class="control-label" for="inputTopicPath">Topic Path:</label>
          <div class="controls">
            <input type="text" id="inputTopicPath" placeholder="Topic Path" v-model.trim="config.path">
            <span class="help-inline" v-show="path_error.length > 0">{{ path_error }}</span>
          </div>
        </div>

        <div class="control-group">
          <div class="controls">
            <button type="submit" class="btn btn-success" @click.prevent="onSaveLocal">Ok</button>
            <button class="btn" @click.prevent="onReset">Reset</button>
          </div>
        </div>
      </form>
    </script>

    <script type="text/x-template" id="aws_iot_core_topic_template">
      <form class="form-horizontal">
        <div class="control-group">
          <label class="control-label"><strong>AWS IoT Core Topic</strong></label>
        </div>
        <div class="control-group" :class="{error: name_error.length > 0}">
          <label class="control-label" for="inputTopicName">Topic Name:</label>
          <div class="controls">
            <input type="text" id="inputTopicName" placeholder="Topic Name" v-model.trim.lazy="name">
            <span class="help-inline" v-show="name_error.length > 0">{{ name_error }}</span>
          </div>
        </div>
        <div class="control-group" :class="{error: path_error.length > 0}">
          <label class="control-label" for="inputTopicPath">Topic Path:</label>
          <div class="controls">
            <input type="text" id="inputTopicPath" placeholder="Topic Path" v-model.trim="config.path">
            <span class="help-inline" v-show="path_error.length > 0">{{ path_error }}</span>
          </div>
        </div>

        <div class="control-group">
          <div class="controls">
            <button type="submit" class="btn btn-success" @click.prevent="onSaveLocal">Ok</button>
            <button class="btn" @click.prevent="onReset">Reset</button>
          </div>
        </div>
      </form>
    </script>

    <script type="text/x-template" id="topic_manager_template">
      <div class="row-fluid" v-cloak>
        <div id="topic_list" class="span6">
          <table class="table table-striped table-hover table-bordered">
            <thead>
              <tr>
                <sortable-table-header :sortField="sortField" fieldName="name" @sortBy="sortBy"></sortable-table-header>
                <sortable-table-header :sortField="sortField" fieldName="broker" @sortBy="sortBy"></sortable-table-header>
              </tr>
            </thead>
            <tbody>
              <tr v-for="topic in topicList" @click="activeTopic=topic" :class="{info: activeTopic && activeTopic.uniqueKey==topic.uniqueKey}">
                <td>{{topic.name}}</td>
                <td>{{topic.broker}}</td>
              </tr>
            </tbody>
          </table>
          <div class="pull-right">
            <button class="btn" type="button" @click="addTopic">Add</button>
            <button class="btn btn-danger" type="button" @click="deleteTopic">Delete</button>
          </div>
        </div>
        <div id="topic_detail" class="well span6">
          <keep-alive>
          <component v-if="activeTopic != null && activeTopic.broker != null" :is="activeTopicType" :key="activeTopic.uniqueKey" 
            :topicName="activeTopic.name" :configData="activeTopic.config" :nameError="nameError" :broker="activeTopic.broker"
            @topicUpdated="onTopicUpdated" ></component>
          </keep-alive>
        </div>

        <odal-dialog title="New Topic" :error="newTopic.error.length != 0" v-on:submitChange="createTopic">
          <div v-if="brokerList.length > 0">
            <div class="control-group" :class="{error: !isNewNameValid(newTopic.name)}">
              <label class="control-label" for="inputNewTopicName">Name:</label>
              <div class="controls">
                <input type="text" id="inputNewTopicName" placeholder="Topic's Name" v-model.trim="newTopic.name" autofocus>
                <span class="help-inline" v-show="newTopic.error.length != 0">{{newTopic.error}}</span>
              </div>
            </div>
            <div class="control-group">
              <label class="control-label">Broker:</label>
              <div class="controls">
                <select v-model="newTopic.broker">
                  <option v-for="broker in brokerList" :value="broker.name">{{broker.name}}</option>
                </select>
              </div>
            </div>
          </div>
          <div v-else class="alert alert-block">
            There is no broker available, please create some broker from BrokerManager first.
          </div>
        </modal-dialog>
      </div>
    </script>

    <script type="text/x-template" id="modal_dialog_template">
      <div class="modal hide fade">
        <div class="modal-header">
          <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
          <h3>{{title}}</h3>
        </div>
        <div class="modal-body">
          <form class="form-horizontal" @submit.prevent="onSubmit">
            <slot></slot>
          </form>
        </div>
        <div class="modal-footer">
          <slot name="buttons">
            <button class="btn btn-primary" @click="onSubmit">Save</button>
            <button class="btn" data-dismiss="modal" aria-hidden="true">Cancel</button>
          </slot>
        </div>
      </div>
    </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>
    <script type="text/javascript" src="../../js/renderjson.js"></script>

    <script type="text/javascript" src="../../js/vue.js"></script>
    <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>

    <!-- used by data mapping -->
    <script type="text/javascript" src="../../js/split.min.js"></script>
    <script type="text/javascript" src="../../js/jstree/jstree.min.js"></script>

    <script type="text/javascript" src="js/data_service_config.js"></script>

  </body>
  </html>