ES6: Port state to ES6

Change-Id: I8f58774ba468ebc47a4a6a3ad923d1b55f2bdae0
diff --git a/dev/js/src-lib/state/state.js b/dev/js/src-lib/state/state.js
new file mode 100644
index 0000000..dfc72d4
--- /dev/null
+++ b/dev/js/src-lib/state/state.js
@@ -0,0 +1,126 @@
+/**
+ * Create a state object, that can have a single value
+ * (mostly boolean) and multiple objects associated to it.
+ * Whenever the state changes, all objects are informed
+ * by their setState() method of the value change.
+ *
+ * @author Nils Diewald
+ */
+/*
+ * TODO:
+ *   Require names for states, that should be quite short, so they
+ *   can easily be serialized and kept between page turns (via cookie
+ *   and/or query param)
+ */
+
+export default class State {
+
+  /**
+   * Constructor
+   */
+  constructor (values) {
+      this._init(values);
+  }
+
+
+  // Initialize
+  _init (values) {
+      const t = this;
+      t._assoc = [];
+      if (values == undefined) {
+        t.values = [false,true];
+      }
+      else if (Array.isArray(values)) {
+        t.values = values;
+      }
+      else {
+        t.values = [values];
+      }
+      return t;
+  }
+
+
+  /**
+   * Associate the state with some objects.
+   */
+  associate (obj) {
+
+      // Check if the object has a setState() method
+      if (obj.hasOwnProperty("setState")) {
+
+        this._assoc.push(obj);
+        if (this.value != undefined) {
+          obj.setState(this.value);
+        };
+      } else {
+        console.log("Object " + obj + " has no setState() method");
+      }
+  }
+
+
+  /**
+   * Set the state to a certain value.
+   * This will set the state to all associated objects as well.
+   */
+  set (value) {
+      if (value != this.value) {
+        this.value = value;
+        this._assoc.forEach(i => i.setState(value));
+      };
+  }
+
+
+  /**
+   * Set the state to a default value.
+   * This will only be set, if no other value is set yet.
+   */
+  setIfNotYet (value) {
+      if (this.value == undefined) {
+        this.set(value);
+      };
+  }
+
+
+  /**
+   * Get the state value
+   */
+  get () {
+      if (this.value == undefined) {
+        this.value = this.values[0];
+      };
+
+      return this.value;
+  }
+
+
+  /**
+   * Get the number of associated objects
+   */
+  associates () {
+      return this._assoc.length;
+  }
+
+
+  /**
+   * Clear all associated objects
+   */
+  clear () {
+      return this._assoc = [];
+  }
+
+
+  /**
+   * Roll to the next value.
+   * This may be used for toggling.
+   */
+  roll () {
+      let next = 0;
+      for (let i = 0; i < this.values.length - 1; i++) {
+        if (this.get() == this.values[i]) {
+          next = i+1;
+          break;
+        };
+      };
+      this.set(this.values[next]);
+  }
+}