1/*
2 * Copyright 2006, Haiku.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Stephan A��mus <superstippi@gmx.de>
7 */
8
9#include "PropertyObject.h"
10
11#include <stdio.h>
12
13#include <ByteOrder.h>
14#include <Message.h>
15#include <OS.h>
16
17#include "Int64Property.h"
18#include "Property.h"
19
20#ifndef DEBUG
21#	define DEBUG 0
22#endif
23
24// constructor
25PropertyObject::PropertyObject()
26	: fProperties(16)
27{
28}
29
30// constructor
31PropertyObject::PropertyObject(const PropertyObject& other)
32	: fProperties(16)
33{
34	Assign(other);
35}
36
37// destructor
38PropertyObject::~PropertyObject()
39{
40	DeleteProperties();
41}
42
43// #pragma mark -
44
45// Archive
46status_t
47PropertyObject::Archive(BMessage* into) const
48{
49	if (!into)
50		return B_BAD_VALUE;
51
52	status_t ret = B_OK;
53
54	int32 count = CountProperties();
55	for (int32 i = 0; i < count; i++) {
56		Property* p = PropertyAtFast(i);
57
58		unsigned id = B_HOST_TO_BENDIAN_INT32(p->Identifier());
59		char idString[5];
60		sprintf(idString, "%.4s", (const char*)&id);
61		idString[4] = 0;
62
63		BString value;
64		p->GetValue(value);
65		ret = into->AddString(idString, value.String());
66		if (ret < B_OK)
67			return ret;
68	}
69	return ret;
70}
71
72// Unarchive
73status_t
74PropertyObject::Unarchive(const BMessage* archive)
75{
76	if (!archive)
77		return B_BAD_VALUE;
78
79	SuspendNotifications(true);
80
81	int32 count = CountProperties();
82	for (int32 i = 0; i < count; i++) {
83		Property* p = PropertyAtFast(i);
84
85		unsigned id = B_HOST_TO_BENDIAN_INT32(p->Identifier());
86		char idString[5];
87		sprintf(idString, "%.4s", (const char*)&id);
88		idString[4] = 0;
89
90		const char* value;
91		if (archive->FindString(idString, &value) == B_OK)
92			if (p->SetValue(value))
93				Notify();
94	}
95
96	SuspendNotifications(false);
97
98	return B_OK;
99}
100
101// #pragma mark -
102
103// AddProperty
104bool
105PropertyObject::AddProperty(Property* property)
106{
107	if (!property)
108		return false;
109
110#if DEBUG
111	if (FindProperty(property->Identifier())) {
112		debugger("PropertyObject::AddProperty() -"
113				 "property with same ID already here!\n");
114		return false;
115	}
116
117	// debugging
118	if (fProperties.HasItem((void*)property)) {
119		debugger("PropertyObject::AddProperty() - property id "
120				 "changed unexpectedly\n");
121		return false;
122	}
123#endif
124
125	if (fProperties.AddItem((void*)property)) {
126		Notify();
127		return true;
128	}
129
130	return false;
131}
132
133// PropertyAt
134Property*
135PropertyObject::PropertyAt(int32 index) const
136{
137	return (Property*)fProperties.ItemAt(index);
138}
139
140// PropertyAtFast
141Property*
142PropertyObject::PropertyAtFast(int32 index) const
143{
144	return (Property*)fProperties.ItemAtFast(index);
145}
146
147// CountProperties
148int32
149PropertyObject::CountProperties() const
150{
151	return fProperties.CountItems();
152}
153
154// #pragma mark -
155
156// FindProperty
157Property*
158PropertyObject::FindProperty(uint32 propertyID) const
159{
160	int32 count = fProperties.CountItems();
161	for (int32 i = 0; i < count; i++) {
162		Property* p = (Property*)fProperties.ItemAtFast(i);
163		if (p->Identifier() == propertyID)
164			return p;
165	}
166	return NULL;
167}
168
169//HasProperty
170bool
171PropertyObject::HasProperty(Property* property) const
172{
173	return fProperties.HasItem((void*)property);
174}
175
176// ContainsSameProperties
177bool
178PropertyObject::ContainsSameProperties(const PropertyObject& other) const
179{
180	bool equal = false;
181	int32 count = CountProperties();
182	if (count == other.CountProperties()) {
183		equal = true;
184		for (int32 i = 0; i < count; i++) {
185			Property* ownProperty = PropertyAtFast(i);
186			Property* otherProperty = other.PropertyAtFast(i);
187			if (ownProperty->Identifier() != otherProperty->Identifier()) {
188				equal = false;
189				break;
190			}
191		}
192	}
193	return equal;
194}
195
196// Assign
197status_t
198PropertyObject::Assign(const PropertyObject& other)
199{
200	DeleteProperties();
201
202	int32 count = other.fProperties.CountItems();
203	for (int32 i = 0; i < count; i++) {
204		Property* p = (Property*)other.fProperties.ItemAtFast(i);
205		Property* clone = p->Clone();
206		if (!AddProperty(clone)) {
207			delete clone;
208			fprintf(stderr, "PropertyObject::Assign() - no memory for "
209							"cloning properties!\n");
210			return B_NO_MEMORY;
211		}
212	}
213
214	return B_OK;
215}
216
217// DeleteProperties
218void
219PropertyObject::DeleteProperties()
220{
221	int32 count = fProperties.CountItems();
222	for (int32 i = 0; i < count; i++)
223		delete (Property*)fProperties.ItemAtFast(i);
224	fProperties.MakeEmpty();
225	Notify();
226}
227
228// DeleteProperty
229bool
230PropertyObject::DeleteProperty(uint32 propertyID)
231{
232	int32 count = fProperties.CountItems();
233	for (int32 i = 0; i < count; i++) {
234		Property* p = (Property*)fProperties.ItemAtFast(i);
235		if (p->Identifier() == propertyID) {
236			if (fProperties.RemoveItem(i)) {
237				Notify();
238				delete p;
239				return true;
240			}
241			break;
242		}
243	}
244	return false;
245}
246
247// ValueChanged
248void
249PropertyObject::ValueChanged(uint32 propertyID)
250{
251	Notify();
252}
253
254// #pragma mark -
255
256// SetValue
257bool
258PropertyObject::SetValue(uint32 propertyID, const char* value)
259{
260	if (Property* p = FindProperty(propertyID)) {
261		if (p->SetValue(value)) {
262			ValueChanged(propertyID);
263			return true;
264		}
265	}
266	return false;
267}
268
269// GetValue
270bool
271PropertyObject::GetValue(uint32 propertyID, BString& value) const
272{
273	if (Property* p = FindProperty(propertyID)) {
274		p->GetValue(value);
275		return true;
276	}
277	return false;
278}
279
280// #pragma mark - int32
281
282// SetValue
283bool
284PropertyObject::SetValue(uint32 propertyID, int32 value)
285{
286	IntProperty* p = dynamic_cast<IntProperty*>(FindProperty(propertyID));
287	if (p && p->SetValue(value)) {
288		ValueChanged(propertyID);
289		return true;
290	}
291	return false;
292}
293
294// Value
295int32
296PropertyObject::Value(uint32 propertyID, int32 defaultValue) const
297{
298	if (IntProperty* p = dynamic_cast<IntProperty*>(FindProperty(propertyID)))
299		return p->Value();
300	return defaultValue;
301}
302
303// #pragma mark - int64
304
305// SetValue
306bool
307PropertyObject::SetValue(uint32 propertyID, int64 value)
308{
309	Int64Property* p = dynamic_cast<Int64Property*>(FindProperty(propertyID));
310	if (p && p->SetValue(value)) {
311		ValueChanged(propertyID);
312		return true;
313	}
314	return false;
315}
316
317// Value
318int64
319PropertyObject::Value(uint32 propertyID, int64 defaultValue) const
320{
321	if (Int64Property* p = dynamic_cast<Int64Property*>(FindProperty(propertyID)))
322		return p->Value();
323	return defaultValue;
324}
325
326// #pragma mark - float
327
328// SetValue
329bool
330PropertyObject::SetValue(uint32 propertyID, float value)
331{
332	FloatProperty* p = dynamic_cast<FloatProperty*>(FindProperty(propertyID));
333	if (p && p->SetValue(value)) {
334		ValueChanged(propertyID);
335		return true;
336	}
337	return false;
338}
339
340// Value
341float
342PropertyObject::Value(uint32 propertyID, float defaultValue) const
343{
344	if (FloatProperty* p = dynamic_cast<FloatProperty*>(FindProperty(propertyID)))
345		return p->Value();
346	return defaultValue;
347}
348
349// #pragma mark - bool
350
351// SetValue
352bool
353PropertyObject::SetValue(uint32 propertyID, bool value)
354{
355	BoolProperty* p = dynamic_cast<BoolProperty*>(FindProperty(propertyID));
356	if (p && p->SetValue(value)) {
357		ValueChanged(propertyID);
358		return true;
359	}
360	return false;
361}
362
363// Value
364bool
365PropertyObject::Value(uint32 propertyID, bool defaultValue) const
366{
367	if (BoolProperty* p = dynamic_cast<BoolProperty*>(FindProperty(propertyID)))
368		return p->Value();
369	return defaultValue;
370}
371
372
373