blob: 06a04aef83af381058455478ff724246c42b4119 [file] [log] [blame]
package model
import (
"bytes"
"crypto/md5"
"fmt"
"reflect"
"sort"
)
var (
RevisionCache = make(map[string]interface{})
)
type Revision struct {
Config *DataRevision
Children map[string][]*Revision
Hash string
branch *Branch
WeakRef string
}
func NewRevision(branch *Branch, data interface{}, children map[string][]*Revision) *Revision {
cr := &Revision{}
cr.branch = branch
cr.Config = NewDataRevision(data)
cr.Children = children
cr.finalize()
return cr
}
func (cr *Revision) finalize() {
cr.Hash = cr.hashContent()
if _, exists := RevisionCache[cr.Hash]; !exists {
RevisionCache[cr.Hash] = cr
}
if _, exists := RevisionCache[cr.Config.Hash]; !exists {
RevisionCache[cr.Config.Hash] = cr.Config
} else {
cr.Config = RevisionCache[cr.Config.Hash].(*DataRevision)
}
}
func (cr *Revision) hashContent() string {
var buffer bytes.Buffer
var childrenKeys []string
if cr.Config != nil {
buffer.WriteString(cr.Config.Hash)
}
for key, _ := range cr.Children {
childrenKeys = append(childrenKeys, key)
}
sort.Strings(childrenKeys)
if cr.Children != nil && len(cr.Children) > 0 {
// Loop through sorted Children keys
for _, key := range childrenKeys {
for _, child := range cr.Children[key] {
buffer.WriteString(child.Hash)
}
}
}
return fmt.Sprintf("%x", md5.Sum(buffer.Bytes()))[:12]
}
func (cr *Revision) getData() interface{} {
if cr.Config == nil {
return nil
}
return cr.Config.Data
}
func (cr *Revision) getNode() *Node {
return cr.branch.node
}
func (cr *Revision) getType() reflect.Type {
// TODO: what is this returning really?
return reflect.TypeOf(cr.getData())
}
func (cr *Revision) clearHash() {
cr.Hash = ""
}
func (cr *Revision) Get(depth int) interface{} {
originalData := cr.getData()
data := Clone(originalData)
if depth > 0 {
for fieldName, field := range ChildrenFields(cr.getType()) {
if field.IsContainer {
for _, rev := range cr.Children[fieldName] {
childData := rev.Get(depth - 1)
childDataHolder := GetAttributeValue(data, fieldName, 0)
// TODO: merge with childData
fmt.Printf("data:%+v, dataHolder:%+v", childData, childDataHolder)
}
} else {
rev := cr.Children[fieldName][0]
childData := rev.Get(depth - 1)
childDataHolder := GetAttributeValue(data, fieldName, 0)
// TODO: merge with childData
fmt.Printf("data:%+v, dataHolder:%+v", childData, childDataHolder)
}
}
}
return data
}
func (cr *Revision) UpdateData(data interface{}, branch *Branch) *Revision {
newRev := Clone(cr).(*Revision)
newRev.branch = branch
newRev.Config = data.(*DataRevision)
newRev.finalize()
return newRev
}
func (cr *Revision) UpdateChildren(name string, children []*Revision, branch *Branch) *Revision {
newChildren := Clone(cr.Children).(map[string][]*Revision)
newChildren[name] = children
newRev := Clone(cr).(*Revision)
newRev.branch = branch
newRev.Children = newChildren
newRev.finalize()
return newRev
}
func (cr *Revision) UpdateAllChildren(children map[string][]*Revision, branch *Branch) *Revision {
newRev := Clone(cr).(*Revision)
newRev.branch = branch
newRev.Children = children
newRev.finalize()
return newRev
}