blob: 06a04aef83af381058455478ff724246c42b4119 [file] [log] [blame]
Stephane Barbarie4a2564d2018-07-26 11:02:58 -04001package model
2
3import (
4 "bytes"
5 "crypto/md5"
6 "fmt"
7 "reflect"
8 "sort"
9)
10
11var (
12 RevisionCache = make(map[string]interface{})
13)
14
15type Revision struct {
16 Config *DataRevision
17 Children map[string][]*Revision
18 Hash string
19 branch *Branch
20 WeakRef string
21}
22
23func NewRevision(branch *Branch, data interface{}, children map[string][]*Revision) *Revision {
24 cr := &Revision{}
25 cr.branch = branch
26 cr.Config = NewDataRevision(data)
27 cr.Children = children
28 cr.finalize()
29
30 return cr
31}
32
33func (cr *Revision) finalize() {
34 cr.Hash = cr.hashContent()
35
36 if _, exists := RevisionCache[cr.Hash]; !exists {
37 RevisionCache[cr.Hash] = cr
38 }
39 if _, exists := RevisionCache[cr.Config.Hash]; !exists {
40 RevisionCache[cr.Config.Hash] = cr.Config
41 } else {
42 cr.Config = RevisionCache[cr.Config.Hash].(*DataRevision)
43 }
44}
45
46func (cr *Revision) hashContent() string {
47 var buffer bytes.Buffer
48 var childrenKeys []string
49
50 if cr.Config != nil {
51 buffer.WriteString(cr.Config.Hash)
52 }
53
54 for key, _ := range cr.Children {
55 childrenKeys = append(childrenKeys, key)
56 }
57 sort.Strings(childrenKeys)
58
59 if cr.Children != nil && len(cr.Children) > 0 {
60 // Loop through sorted Children keys
61 for _, key := range childrenKeys {
62 for _, child := range cr.Children[key] {
63 buffer.WriteString(child.Hash)
64 }
65 }
66 }
67
68 return fmt.Sprintf("%x", md5.Sum(buffer.Bytes()))[:12]
69}
70
71func (cr *Revision) getData() interface{} {
72 if cr.Config == nil {
73 return nil
74 }
75 return cr.Config.Data
76}
77
78func (cr *Revision) getNode() *Node {
79 return cr.branch.node
80}
81
82func (cr *Revision) getType() reflect.Type {
83 // TODO: what is this returning really?
84 return reflect.TypeOf(cr.getData())
85}
86
87func (cr *Revision) clearHash() {
88 cr.Hash = ""
89}
90
91func (cr *Revision) Get(depth int) interface{} {
92 originalData := cr.getData()
93 data := Clone(originalData)
94
95 if depth > 0 {
96 for fieldName, field := range ChildrenFields(cr.getType()) {
97 if field.IsContainer {
98 for _, rev := range cr.Children[fieldName] {
99 childData := rev.Get(depth - 1)
100 childDataHolder := GetAttributeValue(data, fieldName, 0)
101 // TODO: merge with childData
102 fmt.Printf("data:%+v, dataHolder:%+v", childData, childDataHolder)
103 }
104 } else {
105 rev := cr.Children[fieldName][0]
106 childData := rev.Get(depth - 1)
107 childDataHolder := GetAttributeValue(data, fieldName, 0)
108 // TODO: merge with childData
109 fmt.Printf("data:%+v, dataHolder:%+v", childData, childDataHolder)
110 }
111 }
112 }
113 return data
114}
115
116func (cr *Revision) UpdateData(data interface{}, branch *Branch) *Revision {
117 newRev := Clone(cr).(*Revision)
118 newRev.branch = branch
119 newRev.Config = data.(*DataRevision)
120 newRev.finalize()
121
122 return newRev
123}
124
125func (cr *Revision) UpdateChildren(name string, children []*Revision, branch *Branch) *Revision {
126 newChildren := Clone(cr.Children).(map[string][]*Revision)
127 newChildren[name] = children
128 newRev := Clone(cr).(*Revision)
129 newRev.branch = branch
130 newRev.Children = newChildren
131 newRev.finalize()
132
133 return newRev
134}
135
136func (cr *Revision) UpdateAllChildren(children map[string][]*Revision, branch *Branch) *Revision {
137 newRev := Clone(cr).(*Revision)
138 newRev.branch = branch
139 newRev.Children = children
140 newRev.finalize()
141
142 return newRev
143}