VOL-1027 : Initial commit of voltha 2.0 data model

Change-Id: Ib8006de1af2166281ccf1c9d7c2b9156991bf4e4
diff --git a/db/model/root.go b/db/model/root.go
new file mode 100644
index 0000000..722fc94
--- /dev/null
+++ b/db/model/root.go
@@ -0,0 +1,213 @@
+package model
+
+import (
+	"encoding/hex"
+	"encoding/json"
+	"fmt"
+	"github.com/google/uuid"
+	"reflect"
+)
+
+type Root struct {
+	*Node
+	DirtyNodes            map[string]*Node
+	KvStore               *Backend
+	Loading               bool
+	RevisionClass         interface{}
+	Callbacks             []func() interface{}
+	NotificationCallbacks []func() interface{}
+}
+
+func NewRoot(initialData interface{}, kvStore *Backend, revisionClass interface{}) *Root {
+	root := &Root{}
+	root.KvStore = kvStore
+	root.DirtyNodes = make(map[string]*Node)
+	root.Loading = false
+	if kvStore != nil /*&& FIXME: RevisionClass is a subclass of PersistedConfigRevision */ {
+		revisionClass = reflect.TypeOf(PersistedRevision{})
+	}
+	root.RevisionClass = revisionClass
+	root.Callbacks = []func() interface{}{}
+	root.NotificationCallbacks = []func() interface{}{}
+
+	root.Node = NewNode(root, initialData, false, "")
+
+	return root
+}
+
+func (r *Root) makeRevision(branch *Branch, data interface{}, children map[string][]*Revision) *Revision {
+
+	return &Revision{}
+}
+
+func (r *Root) makeTxBranch() string {
+	txid_bin, _ := uuid.New().MarshalBinary()
+	txid := hex.EncodeToString(txid_bin)[:12]
+	r.DirtyNodes[txid] = r.Node
+	r.Node.makeTxBranch(txid)
+	return txid
+}
+
+func (r *Root) deleteTxBranch(txid string) {
+	for _, dirtyNode := range r.DirtyNodes {
+		dirtyNode.deleteTxBranch(txid)
+	}
+	delete(r.DirtyNodes, txid)
+}
+
+func (r *Root) foldTxBranch(txid string) {
+	// TODO: implement foldTxBranch
+	// if err := r.Node.mergeTxBranch(txid, dryRun=true); err != nil {
+	//   r.deleteTxBranch(txid)
+	// } else {
+	//   r.Node.mergeTxBranch(txid)
+	//   r.executeCallbacks()
+	// }
+}
+
+func (r *Root) executeCallbacks() {
+	for len(r.Callbacks) > 0 {
+		callback := r.Callbacks[0]
+		r.Callbacks = r.Callbacks[1:]
+		callback()
+	}
+	for len(r.NotificationCallbacks) > 0 {
+		callback := r.NotificationCallbacks[0]
+		r.NotificationCallbacks = r.NotificationCallbacks[1:]
+		callback()
+	}
+}
+
+func (r *Root) noCallbacks() bool {
+	return len(r.Callbacks) == 0
+}
+
+func (r *Root) addCallback(callback func() interface{}) {
+	r.Callbacks = append(r.Callbacks, callback)
+}
+func (r *Root) addNotificationCallback(callback func() interface{}) {
+	r.NotificationCallbacks = append(r.NotificationCallbacks, callback)
+}
+
+func (r *Root) Update(path string, data interface{}, strict bool, txid string, makeBranch t_makeBranch) *Revision {
+	var result *Revision
+	// FIXME: the more i look at this... i think i need to implement an interface for Node & root
+
+	if makeBranch == nil {
+		// TODO: raise error
+	}
+
+	if r.noCallbacks() {
+		// TODO: raise error
+	}
+
+	if txid != "" {
+		//dirtied := r.DirtyNodes[txid]
+
+		trackDirty := func(node *Node) *Branch {
+			//dirtied.Add(Node)
+			return node.makeTxBranch(txid)
+		}
+		result = r.Node.Update(path, data, strict, txid, trackDirty)
+	} else {
+		result = r.Node.Update(path, data, strict, "", nil)
+	}
+
+	r.executeCallbacks()
+
+	return result
+}
+
+func (r *Root) Add(path string, data interface{}, txid string, makeBranch t_makeBranch) *Revision {
+	var result *Revision
+	// FIXME: the more i look at this... i think i need to implement an interface for Node & root
+
+	if makeBranch == nil {
+		// TODO: raise error
+	}
+
+	if r.noCallbacks() {
+		// TODO: raise error
+	}
+
+	if txid != "" {
+		//dirtied := r.DirtyNodes[txid]
+
+		trackDirty := func(node *Node) *Branch {
+			//dirtied.Add(Node)
+			return node.makeTxBranch(txid)
+		}
+		result = r.Node.Add(path, data, txid, trackDirty)
+	} else {
+		result = r.Node.Add(path, data, "", nil)
+	}
+
+	r.executeCallbacks()
+
+	return result
+}
+
+func (r *Root) Remove(path string, txid string, makeBranch t_makeBranch) *Revision {
+	var result *Revision
+	// FIXME: the more i look at this... i think i need to implement an interface for Node & root
+
+	if makeBranch == nil {
+		// TODO: raise error
+	}
+
+	if r.noCallbacks() {
+		// TODO: raise error
+	}
+
+	if txid != "" {
+		//dirtied := r.DirtyNodes[txid]
+
+		trackDirty := func(node *Node) *Branch {
+			//dirtied.Add(Node)
+			return node.makeTxBranch(txid)
+		}
+		result = r.Node.Remove(path, txid, trackDirty)
+	} else {
+		result = r.Node.Remove(path, "", nil)
+	}
+
+	r.executeCallbacks()
+
+	return result
+}
+
+func (r *Root) Load(rootClass interface{}) *Root {
+	//fakeKvStore := &Backend{}
+	//root := NewRoot(rootClass, fakeKvStore, PersistedRevision{})
+	//r.KvStore = KvStore
+	r.loadFromPersistence(rootClass)
+	return r
+}
+
+func (r *Root) LoadLatest(hash string) {
+	r.Node.LoadLatest(r.KvStore, hash)
+}
+
+type rootData struct {
+	Latest string            `json:GetLatest`
+	Tags   map[string]string `json:Tags`
+}
+
+func (r *Root) loadFromPersistence(rootClass interface{}) {
+	var data rootData
+
+	r.Loading = true
+	blob, _ := r.KvStore.Get("root")
+
+	if err := json.Unmarshal(blob.Value.([]byte), &data); err != nil {
+		fmt.Errorf("problem to unmarshal blob - error:%s\n", err.Error())
+	}
+
+	for tag, hash := range data.Tags {
+		r.Node.LoadLatest(r.KvStore, hash)
+		r.Node.Tags[tag] = r.Node.Latest()
+	}
+
+	r.Node.LoadLatest(r.KvStore, data.Latest)
+	r.Loading = false
+}