1/*
2 * Copyright 2012-2016, Rene Gollent, rene@gollent.com.
3 * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
4 * Distributed under the terms of the MIT License.
5 */
6
7#include "ValueNodeManager.h"
8
9#include "AutoLocker.h"
10
11#include "model/Thread.h"
12#include "StackFrame.h"
13#include "Team.h"
14#include "TypeHandlerRoster.h"
15#include "ValueNode.h"
16#include "Variable.h"
17#include "VariableValueNodeChild.h"
18
19
20ValueNodeManager::ValueNodeManager(bool addFrameNodes)
21	:
22	fAddFrameNodes(addFrameNodes),
23	fContainer(NULL),
24	fStackFrame(NULL),
25	fThread(NULL)
26{
27	SetStackFrame(NULL, NULL);
28}
29
30
31ValueNodeManager::~ValueNodeManager()
32{
33	SetStackFrame(NULL, NULL);
34}
35
36
37status_t
38ValueNodeManager::SetStackFrame(Thread* thread,
39	StackFrame* stackFrame)
40{
41	if (fContainer != NULL) {
42		AutoLocker<ValueNodeContainer> containerLocker(fContainer);
43
44		fContainer->RemoveListener(this);
45
46		fContainer->RemoveAllChildren();
47		containerLocker.Unlock();
48		fContainer->ReleaseReference();
49		fContainer = NULL;
50	}
51
52	fStackFrame = stackFrame;
53	fThread = thread;
54
55	if (fStackFrame == NULL)
56		return B_OK;
57
58	fContainer = new(std::nothrow) ValueNodeContainer;
59	if (fContainer == NULL)
60		return B_NO_MEMORY;
61
62	status_t error = fContainer->Init();
63	if (error != B_OK) {
64		delete fContainer;
65		fContainer = NULL;
66		return error;
67	}
68
69	AutoLocker<ValueNodeContainer> containerLocker(fContainer);
70
71	fContainer->AddListener(this);
72
73	if (fStackFrame != NULL && fAddFrameNodes) {
74		for (int32 i = 0; Variable* variable = fStackFrame->ParameterAt(i);
75				i++) {
76			_AddNode(variable);
77		}
78
79		for (int32 i = 0; Variable* variable
80				= fStackFrame->LocalVariableAt(i); i++) {
81			_AddNode(variable);
82		}
83	}
84
85	return B_OK;
86}
87
88
89bool
90ValueNodeManager::AddListener(ValueNodeContainer::Listener* listener)
91{
92	return fListeners.AddItem(listener);
93}
94
95
96void
97ValueNodeManager::RemoveListener(ValueNodeContainer::Listener* listener)
98{
99	fListeners.RemoveItem(listener);
100}
101
102
103void
104ValueNodeManager::ValueNodeChanged(ValueNodeChild* nodeChild,
105	ValueNode* oldNode, ValueNode* newNode)
106{
107	if (fContainer == NULL)
108		return;
109
110	AutoLocker<ValueNodeContainer> containerLocker(fContainer);
111
112	for (int32 i = fListeners.CountItems() - 1; i >= 0; i--)
113		fListeners.ItemAt(i)->ValueNodeChanged(nodeChild, oldNode, newNode);
114
115	if (oldNode != NULL && !newNode->ChildCreationNeedsValue())
116		newNode->CreateChildren(fThread->GetTeam()->GetTeamTypeInformation());
117}
118
119
120void
121ValueNodeManager::ValueNodeChildrenCreated(ValueNode* node)
122{
123	if (fContainer == NULL)
124		return;
125
126	for (int32 i = fListeners.CountItems() - 1; i >= 0; i--)
127		fListeners.ItemAt(i)->ValueNodeChildrenCreated(node);
128}
129
130
131void
132ValueNodeManager::ValueNodeChildrenDeleted(ValueNode* node)
133{
134	if (fContainer == NULL)
135		return;
136
137	for (int32 i = fListeners.CountItems() - 1; i >= 0; i--)
138		fListeners.ItemAt(i)->ValueNodeChildrenDeleted(node);
139}
140
141
142void
143ValueNodeManager::ValueNodeValueChanged(ValueNode* valueNode)
144{
145	if (fContainer == NULL)
146		return;
147
148	AutoLocker<ValueNodeContainer> containerLocker(fContainer);
149
150	// check whether we know the node
151	ValueNodeChild* nodeChild = valueNode->NodeChild();
152	if (nodeChild == NULL)
153		return;
154
155	if (valueNode->ChildCreationNeedsValue()
156		&& !valueNode->ChildrenCreated()) {
157		status_t error = valueNode->CreateChildren(
158			fThread->GetTeam()->GetTeamTypeInformation());
159		if (error == B_OK) {
160			for (int32 i = 0; i < valueNode->CountChildren(); i++) {
161				ValueNodeChild* child = valueNode->ChildAt(i);
162				_CreateValueNode(child);
163				AddChildNodes(child);
164			}
165		}
166	}
167
168	for (int32 i = fListeners.CountItems() - 1; i >= 0; i--)
169		fListeners.ItemAt(i)->ValueNodeValueChanged(valueNode);
170}
171
172
173void
174ValueNodeManager::_AddNode(Variable* variable)
175{
176	// create the node child for the variable
177	ValueNodeChild* nodeChild = new (std::nothrow) VariableValueNodeChild(
178		variable);
179	BReference<ValueNodeChild> nodeChildReference(nodeChild, true);
180	if (nodeChild == NULL || !fContainer->AddChild(nodeChild)) {
181		delete nodeChild;
182		return;
183	}
184
185	// automatically add child nodes for the top level nodes
186	AddChildNodes(nodeChild);
187}
188
189
190status_t
191ValueNodeManager::_CreateValueNode(ValueNodeChild* nodeChild)
192{
193	if (nodeChild->Node() != NULL)
194		return B_OK;
195
196	// create the node
197	ValueNode* valueNode;
198	status_t error;
199	if (nodeChild->IsInternal()) {
200		error = nodeChild->CreateInternalNode(valueNode);
201	} else {
202		error = TypeHandlerRoster::Default()->CreateValueNode(nodeChild,
203			nodeChild->GetType(), NULL, valueNode);
204	}
205
206	if (error != B_OK)
207		return error;
208
209	nodeChild->SetNode(valueNode);
210	valueNode->ReleaseReference();
211
212	return B_OK;
213}
214
215
216status_t
217ValueNodeManager::AddChildNodes(ValueNodeChild* nodeChild)
218{
219	AutoLocker<ValueNodeContainer> containerLocker(fContainer);
220
221	// create a value node for the value node child, if doesn't have one yet
222	ValueNode* valueNode = nodeChild->Node();
223	if (valueNode == NULL) {
224		status_t error = _CreateValueNode(nodeChild);
225		if (error != B_OK)
226			return error;
227		valueNode = nodeChild->Node();
228	}
229
230	// check if this node requires child creation
231	// to be deferred until after its location/value have been resolved
232	if (valueNode->ChildCreationNeedsValue())
233		return B_OK;
234
235	// create the children, if not done yet
236	if (valueNode->ChildrenCreated())
237		return B_OK;
238
239	return valueNode->CreateChildren(
240		fThread->GetTeam()->GetTeamTypeInformation());
241}
242