File: threadcontainer.go

package info (click to toggle)
golang-github-gatherstars-com-jwz 1.4.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 13,744 kB
  • sloc: makefile: 3
file content (154 lines) | stat: -rw-r--r-- 3,536 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
package jwz

// NoThreadableError indicates that the container was not in a valid state when a utility function was called
// against it
//
type NoThreadableError struct {
}

func (e NoThreadableError) Error() string {
	return "Container is not a root (has parent), but contains no Threadable element"
}

// threadContainer  is used to encapsulate a Threadable implementation. It holds some intermediate state used while
// threading.  This is private to the module and is used while performing the threading operation, then discarded.
//
type threadContainer struct {

	// threadable contains the base of the threadable items in this instance of the struct
	//
	threadable Threadable

	// parent shows which threadable item is the parent of this container, which can be nil for a root node
	//
	parent *threadContainer

	// child shows which threadable is the child of this container
	//
	child *threadContainer

	// child shows which threadable is the child of this container
	//
	next *threadContainer

	// forID holds the message id that this container is holding. This is only useful for
	// when we don't ever see the actual email (it is referenced by one email, but we don't
	// have the email as we are parsing a partial set)
	//
	forID string
}

// flush copies the ThreadContainer tree structure down into the underlying
// Threadable elements. I.E. make the IThreadable tree look like
// the ThreadContainer tree.
//
func (tc *threadContainer) flush() error {

	// Only a root node can have no threadable element - if we have a parent, then
	// we are not a root node.
	//
	if tc.parent != nil && tc.threadable == nil {

		return NoThreadableError{}
	}

	tc.parent = nil

	if tc.threadable != nil {
		if tc.child == nil {
			tc.threadable.SetChild(nil)
		} else {
			tc.threadable.SetChild(tc.child.threadable)
		}
	}

	if tc.child != nil {
		_ = tc.child.flush()
		tc.child = nil
	}

	if tc.threadable != nil {
		if tc.next == nil {
			tc.threadable.SetNext(nil)
		} else {
			tc.threadable.SetNext(tc.next.threadable)
		}
	}

	if tc.next != nil {
		_ = tc.next.flush()
		tc.next = nil
	}

	tc.threadable = nil

	return nil
}

// findChild returns true if child is under self's tree.  This is used for detecting circularities in the references header.
//
func (tc *threadContainer) findChild(target *threadContainer) bool {

	if tc.child == nil {
		return false
	} else if tc.child == target {
		return true
	} else {
		return tc.child.findChild(target)
	}
}

// reverseChildren does what it implies and reverses the order of the child elements
//
func (tc *threadContainer) reverseChildren() {

	if tc.child != nil {

		var kid, prev, rest *threadContainer

		// Reverse the children of this one
		//
		prev = nil
		kid = tc.child
		rest = kid.next
		for kid != nil {

			kid.next = prev

			prev = kid
			kid = rest
			if rest != nil {
				rest = rest.next
			}
		}
		tc.child = prev

		// Now reverse the children of this one's children
		//
		for kid = tc.child; kid != nil; kid = kid.next {
			kid.reverseChildren()
		}
	}
}

func (tc *threadContainer) fillDummy(t Threadable) {

	// Only a root node can have no threadable element - if we have a message id, then
	// we are not a root node.
	//
	if tc.threadable == nil && tc.forID != "" {
		tc.threadable = t.MakeDummy(tc.forID)
	}

	// Depth first, but it does not matter
	//
	if tc.child != nil {
		tc.child.fillDummy(t)
	}

	// Simple walk this one, no need to save stack space by following the next chain here
	//
	if tc.next != nil {
		tc.next.fillDummy(t)
	}
}