From 78a0d483b8ccbc13dbecfb7cdec0ec7b3fb1822f Mon Sep 17 00:00:00 2001
From: Jake <jake.read@cba.mit.edu>
Date: Fri, 24 May 2019 16:31:25 -0400
Subject: [PATCH] this for inputs and outputs, and now update vs. replace for
 link swapping

---
 README.md                 | 13 ++++--
 hunks/input/string.js     |  4 +-
 hunks/interface/button.js |  8 ++--
 hunks/interface/logger.js |  2 +-
 hunks/link.js             |  9 ++--
 hunks/manager.js          | 13 ++++--
 hunks/template.js         |  4 +-
 hunks/view.js             | 96 +++++++++++++++++++++++----------------
 typeset.js                | 19 ++++----
 view/vdef.js              | 31 ++++++++++---
 10 files changed, 126 insertions(+), 73 deletions(-)

diff --git a/README.md b/README.md
index 5e5a0e5..ae7a048 100644
--- a/README.md
+++ b/README.md
@@ -17,10 +17,17 @@ Native Cuttlefish 'Hunks' are given access to a DOM/div element, making them nic
 - towards a patch loading recipe, you need to consider the link update, that's next ... see if you can just complete the promise 'last' with the og state request,
 - needs a policy,
 
-- check all hunks can load, 
-
 - do load-patch-by-promises
-- do open-up-a-link-to-a-view recipe,
+ - load link, websocket, and change link to have new outputs and inputs
+ - replacedef / evaluatehunk / link, ok, we have to face this
+ - then you can save, then you can load
+
+ok, my thoughts on links adding inputs and outputs
+- go atomic or build complexity:
+ instead of monolithic link, each link io is a hunk, and you can connect them each to the same data port
+- would still like to 
+
+- do open-up-a-link-to-a-view recipe, (req. leap of faith into new drawings, new view)
 - do refresh afterwards, find bootstrap nautilus ...
 - merge on nautilus a serial program ... the link updates, oy oy
 - ponyo
diff --git a/hunks/input/string.js b/hunks/input/string.js
index 93dc474..92238a3 100644
--- a/hunks/input/string.js
+++ b/hunks/input/string.js
@@ -11,10 +11,10 @@ function Strang() {
 
     this.description = 'click pow pow'
 
-    let thruput = new Input('string', 'thru')
+    let thruput = new Input('string', 'thru', this)
     this.inputs.push(thruput)
 
-    let stringOutput = new Output('string', 'string')
+    let stringOutput = new Output('string', 'string', this)
     this.outputs.push(stringOutput)
 
     // this.states.prefix = new State('string', 'prefix', 'LOG:')
diff --git a/hunks/interface/button.js b/hunks/interface/button.js
index 5f03464..b281895 100644
--- a/hunks/interface/button.js
+++ b/hunks/interface/button.js
@@ -9,14 +9,14 @@ import { Hunkify, Input, Output, State } from '../hunks.js'
 function Button() {
     Hunkify(this, 'Button')
 
-    let trigger = new Input('any', 'trigger')
+    let trigger = new Input('any', 'trigger', this)
     this.inputs.push(trigger)
 
-    let onclk = new Output('any', 'onclick')
+    let onclk = new Output('any', 'onclick', this)
     this.outputs.push(onclk)
     /* aspirationally
-    this.outputs.mousedown = new Output('event', 'mousedown')
-    this.outputs.mouseup = new Output('event', 'mouseup')
+    this.outputs.mousedown
+    this.outputs.mouseup 
     */
 
     let strang = new State('string', 'strng', 'start value')
diff --git a/hunks/interface/logger.js b/hunks/interface/logger.js
index 391084d..8fdac88 100644
--- a/hunks/interface/logger.js
+++ b/hunks/interface/logger.js
@@ -9,7 +9,7 @@ import { Hunkify, Input, Output, State } from '../hunks.js'
 function Logger() {
     Hunkify(this, 'Logger')
 
-    let tolog = new Input('any', 'tolog')
+    let tolog = new Input('any', 'tolog', this)
     this.inputs.push(tolog)
 
     let prefix = new State('string', 'prefix', 'LOG:')
diff --git a/hunks/link.js b/hunks/link.js
index f282a14..0bb5ae9 100644
--- a/hunks/link.js
+++ b/hunks/link.js
@@ -104,16 +104,19 @@ function Link() {
   inputList.onChange = (value) => {
     // OK: back up to this ...
     swapLists(value, true)
-    // if OK
-    inputList.set(value)
     // we have to report this ...
     this.mgr.evaluateHunk(this)
+    // if OK
+    inputList.set(value)
   }
 
   outputList.onChange = (value) => {
     swapLists(value, false)
-    outputList.set(value)
     this.mgr.evaluateHunk(this)
+    // this has to follow on, to complete the promise ?
+    // this necessitates that we write a manager-message-buffer on embedded,
+    // and breaks one-program-item-at-a-time rules 
+    outputList.set(value)
   }
 
   /* ---------------------------    ---------------------------- */
diff --git a/hunks/manager.js b/hunks/manager.js
index 6ea08ee..b41deb4 100644
--- a/hunks/manager.js
+++ b/hunks/manager.js
@@ -89,6 +89,7 @@ function Manager() {
         let slat = bytes.length
         bytes.push(HK.CONNECTIONS)
         for(let cn of op.connections){
+          console.log('conn', cn)
           bytes.push(HK.CONNECTION)
           bytes.push(cn.parent.ind)
           bytes.push(cn.findOwnIndex())
@@ -283,8 +284,13 @@ function Manager() {
 
   // this is a utility that hunks can use when they modify themsleves,
 
-  this.serializeAndSendHunk = (hunk) => {
-    let msg = [MK.HUNKALIVE]
+  this.serializeAndSendHunk = (hunk, replace) => {
+    let msg = []
+    if(replace) {
+      msg.push(MK.HUNKREPLACE)
+    } else {
+      msg.push(MK.HUNKALIVE)
+    }
     serializeHunk(hunk, msg)
     writeMessage(msg)
   }
@@ -302,11 +308,10 @@ function Manager() {
   }
 
   // one for updating hunks,
-
   this.evaluateHunk = (hunk) => {
     // input and output lists have probably changed, so there's some work to do.
     // first, we reply with a new definition,
-    this.serializeAndSendHunk(hunk)
+    this.serializeAndSendHunk(hunk, true)
     // on a renewed definition, the view will remove all links associated.
     // now we need to walk inputs and outputs, and message about the links
     // that still exist
diff --git a/hunks/template.js b/hunks/template.js
index a4f55e5..dc0a41d 100644
--- a/hunks/template.js
+++ b/hunks/template.js
@@ -13,10 +13,10 @@ let State = Hunk.State
 function Name() {
     Hunkify(this, 'Name')
 
-    let inA = new Input('type', 'name')
+    let inA = new Input('type', 'name', this)
     this.inputs.push(inA)
 
-    let outB = new Output('type', 'name')
+    let outB = new Output('type', 'name', this)
     this.outputs.push(outB)
 
     let stateItem = new State('type', 'name')
diff --git a/hunks/view.js b/hunks/view.js
index 17f0a54..1e84df8 100644
--- a/hunks/view.js
+++ b/hunks/view.js
@@ -214,7 +214,7 @@ function View() {
             $(evt.target).append(' > requested ... ')
             msgbox.write(`requested one new ${item}`)
             this.requestAddHunk(item).then((def) => {
-              console.log('one hunk as promised', def)
+              //console.log('one hunk as promised', def)
             }).catch((err) => {
               this.changeContextTitle('error, see consoles')
               setTimeout(() => {
@@ -474,49 +474,55 @@ function View() {
     return def
   }
 
+  let updateDef = (spec) => {
+    // update should change names, values, but not types or orders
+    // with an update, we maintain link topology
+    // with a replace, we wipe link topology,
+    // and manager is responsible for updating us with new links
+    console.log('updateDef with this spec:', spec)
+    let cdef = defs[spec.ind]
+    // check name,
+    if (spec.name !== cdef.name) {
+      cdef.updateName(spec.name)
+    }
+    // check states,
+    for (let st in spec.states) {
+      if (spec.states[st].value !== cdef.states[st].value) {
+        cdef.states[st].set(spec.states[st].value)
+      }
+    }
+  } // end update
+
   let replaceDef = (spec) => {
-    // the old boy,
-    console.error('watch out, replacing definitions is pretty well untested')
     let od = defs[spec.ind]
+    // as a rule, when we replace defs, we unhook everything.
+    // the manager (in its wisdom) is responsible for following up by sending us
+    // links that are still alive,
+    // console.log('the od', od)
+    // so first rm those links (this won't properly be tested until program loading, i'd bet)
+    for (let ip in od.inputs) {
+      od.inputs[ip].disconnectAll()
+    }
+    for (let op in od.outputs) {
+      od.outputs[op].disconnectAll()
+    }
+    // that was considerate of the others, but this whole thing is just going to get rm'd, so outputs don't matter
     let mt = dt.readTransform(od.de)
-    // remove, and add new
+    // now we can *eliminate it*
     $(od.de).remove()
-    defs[spec.ind] = null
-    // new baybieee
+    delete defs[spec.ind]
+    // and replace it,
     let nd = new HunkDefinition(spec, this, dt, false)
+    // write-over and cut all connections, we'll receive new ones
+    // ok, ready to place and append,
     dt.writeTransform(nd.de, mt)
+    // add the def's domelement to the view,
     $(this.plane).append(nd.de)
-    // shoebox return
+    // and replace it in the list,
     defs[spec.ind] = nd
-    // delete, and then rekindle outputs (by our new spec)
-    for (let op of od.outputs) {
-      op.disconnectAll()
-    }
-    for(let op of nd.outputs){
-      if (op.specConnections) {
-        for (let sc of op.specConnections) {
-          try {
-            op.connect(defs[sc[0]].inputs[sc[1]])
-          } catch (err) {
-            console.err('cannot reconnect from spec', err)
-            msgbox.write(`err while trying to make links from spec`)
-          }
-        }
-        delete op.specConnections
-      }
-    }
-    // connect (by memory) and then eliminate old refs
-    for (let ip of od.inputs){
-      for(let cn of ip.connections){
-        // connections is an array of outputs, we can connect them by respective index
-        cn.connect(nd.inputs[ip.ind])
-      }
-    }
-    // now we let them go,
-    for(let ip of od.inputs){
-      ip.disconnectAll()
-    }
+    // and re-render
     this.drawLinks()
+    // occasionally useful,
     return nd
   }
 
@@ -694,7 +700,7 @@ function View() {
         msgbox.write('err serializing state change request, see console for that type err')
       }
       promiseThis(msg, (stdef) => {
-        //console.log('promise returns for state change for def', stdef)
+        console.log('promise returns for state change for def', stdef)
         resolve(stdef)
       }, (errmsg) => {
         //console.log('promise rejects for state change bc error', errmsg)
@@ -945,11 +951,25 @@ function View() {
             msgbox.write(`added a new hunk: ${spec.name}`)
           } else {
             if (verbose) console.log('replacing hunk at', spec.ind)
-            nd = replaceDef(spec)
-            msgbox.write(`replaced ${spec.name}_${spec.ind} with a new definition`)
+            nd = updateDef(spec)
+            msgbox.write(`updated ${spec.name}_${spec.ind} with a new definition`)
           }
           if (cbd) cbd.callback(nd)
           break
+        case MK.HUNKREPLACE:
+          // to add inputs or outputs, this is sent, all links are eliminated,
+          // and they are sent again by the manager
+          if (msgverbose) console.log('VIEW MSG is a hunk replacement')
+          let repSpec = specBySerial(msg, inc + 1, false)
+          if (defs[repSpec.ind] === undefined) {
+            console.error('received hunk replace for non existent hunk')
+            console.error('ere is the spec:', repSpec)
+          } else {
+            replaceDef(repSpec)
+            msgbox.write(`replaced ${repSpec.name}_${repSpec.ind} with a new definition`)
+            if (cbd) cbd.callback(nd)
+          }
+          break
         case MK.HUNKSTATECHANGE:
           if (msgverbose) console.log('VIEW MSG is a state change')
           let stchHnkInd = MSGS.readFrom(msg, inc + 1, 'uint16').item
diff --git a/typeset.js b/typeset.js
index b8de570..34626cc 100644
--- a/typeset.js
+++ b/typeset.js
@@ -375,16 +375,17 @@ const MK = {
   REQADDHUNK: 247, // (str) name
   REQNAMECHANGE: 246,
   HUNKALIVE: 245, // (hunkdescription): name, id, inputlist, outputlist, statelist
-  REQSTATECHANGE: 244,
-  HUNKSTATECHANGE: 243,
-  REQRMHUNK: 242, // (str) id
-  HUNKREMOVED: 241, // (str) id
-  REQADDLINK: 240, // (str) id, (str) outname, (str) id, (str) inname
-  LINKALIVE: 239, // (str) id, (str) outname, (str) id, (str) inname
-  REQRMLINK: 238, // (str) id, (str) outname, (str) id, (str) inname
-  LINKREMOVED: 237, // (str) id, (str) outname, (str) id, (str) inname
+  HUNKREPLACE: 244,
+  REQSTATECHANGE: 243,
+  HUNKSTATECHANGE: 242,
+  REQRMHUNK: 241, // (str) id
+  HUNKREMOVED: 240, // (str) id
+  REQADDLINK: 239, // (str) id, (str) outname, (str) id, (str) inname
+  LINKALIVE: 238, // (str) id, (str) outname, (str) id, (str) inname
+  REQRMLINK: 237, // (str) id, (str) outname, (str) id, (str) inname
+  LINKREMOVED: 236, // (str) id, (str) outname, (str) id, (str) inname
   // to id,
-  MSGID: 236
+  MSGID: 235
 }
 
 // hunk description keys,
diff --git a/view/vdef.js b/view/vdef.js
index 7f9816c..60888c1 100644
--- a/view/vdef.js
+++ b/view/vdef.js
@@ -109,7 +109,7 @@ function HunkDefinition(spec, view, dt, debug) {
     }
     $(this.de).append(odom)
   }
-
+  // and states, 
   if (spec.states.length > 0) {
     let sdom = $('<div>').addClass('states')
     for (let st in spec.states) {
@@ -120,19 +120,36 @@ function HunkDefinition(spec, view, dt, debug) {
     $(this.de).append(sdom)
   }
 
+  // UPDATE Index
   this.newInd = (ind) => {
     this.ind = ind
     // and those titles, and ids ...
     $(this.de).attr('id', `${this.name}_${this.ind}`)
     $(title).text(`${this.name}`)
     for (let ip of this.inputs) {
-      ip.newParentInd()
+      ip.onNewParentInfo()
+    }
+    for (let op of this.outputs) {
+      op.onNewParentInfo()
+    }
+    for (let st of this.states) {
+      st.onNewParentInfo()
+    }
+  }
+
+  // UPDATE Name
+  this.updateName = (newName) => {
+    this.name = newName
+    $(this.de).attr('id', `${this.name}_${this.ind}`)
+    $(title).text(`${this.name}`)
+    for (let ip of this.inputs) {
+      ip.onNewParentInfo()
     }
     for (let op of this.outputs) {
-      op.newParentInd()
+      op.onNewParentInfo()
     }
     for (let st of this.states) {
-      st.newParentInd()
+      st.onNewParentInfo()
     }
   }
 
@@ -148,7 +165,7 @@ function InputDefinition(ipspec, ind, def, debug) {
   // a dom element
   this.de = $(`<li>${this.name} (${this.type})</li>`).addClass('input').get(0)
   this.de.id = `${this.parent.name}_${this.parent.ind}_input_${this.name}`
-  this.newParentInd = () => {
+  this.onNewParentInfo = () => {
     this.de.id = `${this.parent.name}_${this.parent.ind}_input_${this.name}`
   }
   // we also keep a list,
@@ -179,7 +196,7 @@ function OutputDefinition(opspec, ind, def, view, dt, debug) {
   // a dom element
   this.de = $(`<li>(${this.type}) ${this.name}</li>`).addClass('output').get(0)
   this.de.id = `${this.parent.name}_${this.parent.ind}_output_${this.name}`
-  this.newParentInd = () => {
+  this.onNewParentInfo = () => {
     this.de.id = `${this.parent.name}_${this.parent.ind}_output_${this.name}`
   }
   // outputs handle all of the dragging-etc
@@ -287,7 +304,7 @@ function StateDefinition(stspec, ind, def, view, debug) {
   // ok,
   this.de = $('<div>' + this.name + " (" + this.type + ")" + '</div>').addClass('stateItem').get(0)
   this.de.id = `${this.parent.name}_${this.parent.ind}_state_${this.name}`
-  this.newParentInd = () => {
+  this.onNewParentInfo = () => {
     this.de.id = `${this.parent.name}_${this.parent.ind}_state_${this.name}`
   }
   // ui for these ... we can just cover the basics of js types because yonder serializations
-- 
GitLab