blob: 07c3388f9845dca70c758711ed40534b2377ffd3 [file] [log] [blame]
khenaidoobf6e7bb2018-08-14 22:27:29 -04001/*
2 * Copyright 2018-present Open Networking Foundation
3
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7
8 * http://www.apache.org/licenses/LICENSE-2.0
9
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Stephane Barbarie4a2564d2018-07-26 11:02:58 -040016package model
17
18import (
19 "bytes"
20 "crypto/md5"
21 "fmt"
22 "reflect"
23 "sort"
24)
25
26var (
27 RevisionCache = make(map[string]interface{})
28)
29
30type Revision struct {
31 Config *DataRevision
32 Children map[string][]*Revision
33 Hash string
34 branch *Branch
35 WeakRef string
36}
37
38func NewRevision(branch *Branch, data interface{}, children map[string][]*Revision) *Revision {
39 cr := &Revision{}
40 cr.branch = branch
41 cr.Config = NewDataRevision(data)
42 cr.Children = children
43 cr.finalize()
44
45 return cr
46}
47
48func (cr *Revision) finalize() {
49 cr.Hash = cr.hashContent()
50
51 if _, exists := RevisionCache[cr.Hash]; !exists {
52 RevisionCache[cr.Hash] = cr
53 }
54 if _, exists := RevisionCache[cr.Config.Hash]; !exists {
55 RevisionCache[cr.Config.Hash] = cr.Config
56 } else {
57 cr.Config = RevisionCache[cr.Config.Hash].(*DataRevision)
58 }
59}
60
61func (cr *Revision) hashContent() string {
62 var buffer bytes.Buffer
63 var childrenKeys []string
64
65 if cr.Config != nil {
66 buffer.WriteString(cr.Config.Hash)
67 }
68
69 for key, _ := range cr.Children {
70 childrenKeys = append(childrenKeys, key)
71 }
72 sort.Strings(childrenKeys)
73
74 if cr.Children != nil && len(cr.Children) > 0 {
75 // Loop through sorted Children keys
76 for _, key := range childrenKeys {
77 for _, child := range cr.Children[key] {
78 buffer.WriteString(child.Hash)
79 }
80 }
81 }
82
83 return fmt.Sprintf("%x", md5.Sum(buffer.Bytes()))[:12]
84}
85
86func (cr *Revision) getData() interface{} {
87 if cr.Config == nil {
88 return nil
89 }
90 return cr.Config.Data
91}
92
93func (cr *Revision) getNode() *Node {
94 return cr.branch.node
95}
96
97func (cr *Revision) getType() reflect.Type {
98 // TODO: what is this returning really?
99 return reflect.TypeOf(cr.getData())
100}
101
102func (cr *Revision) clearHash() {
103 cr.Hash = ""
104}
105
106func (cr *Revision) Get(depth int) interface{} {
107 originalData := cr.getData()
108 data := Clone(originalData)
109
110 if depth > 0 {
111 for fieldName, field := range ChildrenFields(cr.getType()) {
112 if field.IsContainer {
113 for _, rev := range cr.Children[fieldName] {
114 childData := rev.Get(depth - 1)
115 childDataHolder := GetAttributeValue(data, fieldName, 0)
116 // TODO: merge with childData
117 fmt.Printf("data:%+v, dataHolder:%+v", childData, childDataHolder)
118 }
119 } else {
120 rev := cr.Children[fieldName][0]
121 childData := rev.Get(depth - 1)
122 childDataHolder := GetAttributeValue(data, fieldName, 0)
123 // TODO: merge with childData
124 fmt.Printf("data:%+v, dataHolder:%+v", childData, childDataHolder)
125 }
126 }
127 }
128 return data
129}
130
131func (cr *Revision) UpdateData(data interface{}, branch *Branch) *Revision {
132 newRev := Clone(cr).(*Revision)
133 newRev.branch = branch
134 newRev.Config = data.(*DataRevision)
135 newRev.finalize()
136
137 return newRev
138}
139
140func (cr *Revision) UpdateChildren(name string, children []*Revision, branch *Branch) *Revision {
141 newChildren := Clone(cr.Children).(map[string][]*Revision)
142 newChildren[name] = children
143 newRev := Clone(cr).(*Revision)
144 newRev.branch = branch
145 newRev.Children = newChildren
146 newRev.finalize()
147
148 return newRev
149}
150
151func (cr *Revision) UpdateAllChildren(children map[string][]*Revision, branch *Branch) *Revision {
152 newRev := Clone(cr).(*Revision)
153 newRev.branch = branch
154 newRev.Children = children
155 newRev.finalize()
156
157 return newRev
158}