1/*
2 * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
5
6
7#include "SettingsManager.h"
8
9#include <new>
10
11#include <Directory.h>
12#include <File.h>
13#include <FindDirectory.h>
14
15#include <AutoDeleter.h>
16#include <AutoLocker.h>
17
18#include "TeamSettings.h"
19
20
21static const char* const kSettingsDirPath		= "Debugger";
22static const char* const kGlobalSettingsName	= "Global";
23static const int32 kMaxRecentTeamSettings		= 10;
24
25
26SettingsManager::SettingsManager()
27	:
28	fLock("settings manager"),
29	fRecentTeamSettings(kMaxRecentTeamSettings, true)
30{
31}
32
33
34SettingsManager::~SettingsManager()
35{
36	_Unset();
37}
38
39
40status_t
41SettingsManager::Init()
42{
43	// check the lock
44	status_t error = fLock.InitCheck();
45	if (error != B_OK)
46		return error;
47
48	// get and create our settings directory
49	if (find_directory(B_USER_SETTINGS_DIRECTORY, &fSettingsPath, true) == B_OK
50		&& fSettingsPath.Append(kSettingsDirPath) == B_OK
51		&& create_directory(fSettingsPath.Path(), 0700) == B_OK
52		&& fSettingsPath.Append(kGlobalSettingsName) == B_OK) {
53		// load the settings
54		_LoadSettings();
55	} else {
56		// something went wrong -- clear the path
57		fSettingsPath.Unset();
58	}
59
60	return B_OK;
61}
62
63
64status_t
65SettingsManager::LoadTeamSettings(const char* teamName, TeamSettings& settings)
66{
67	AutoLocker<BLocker> locker(fLock);
68
69	int32 index = _TeamSettingsIndex(teamName);
70	if (index < 0)
71		return B_ENTRY_NOT_FOUND;
72
73	try {
74		settings = *fRecentTeamSettings.ItemAt(index);
75		return B_OK;
76	} catch (std::bad_alloc) {
77		return B_NO_MEMORY;
78	}
79}
80
81
82status_t
83SettingsManager::SaveTeamSettings(const TeamSettings& _settings)
84{
85	AutoLocker<BLocker> locker(fLock);
86
87	TeamSettings* settings;
88	int32 index = _TeamSettingsIndex(_settings.TeamName());
89	if (index >= 0) {
90		settings = fRecentTeamSettings.RemoveItemAt(index);
91	} else {
92		settings = new(std::nothrow) TeamSettings;
93		if (settings == NULL)
94			return B_NO_MEMORY;
95
96		// enforce recent limit
97		while (fRecentTeamSettings.CountItems() >= kMaxRecentTeamSettings)
98			delete fRecentTeamSettings.RemoveItemAt(0);
99
100	}
101	ObjectDeleter<TeamSettings> settingsDeleter(settings);
102
103	try {
104		*settings = _settings;
105		if (!fRecentTeamSettings.AddItem(settings))
106			return B_NO_MEMORY;
107		settingsDeleter.Detach();
108
109		return _SaveSettings();
110	} catch (std::bad_alloc) {
111		return B_NO_MEMORY;
112	}
113}
114
115
116void
117SettingsManager::_Unset()
118{
119	fRecentTeamSettings.MakeEmpty();
120}
121
122
123status_t
124SettingsManager::_LoadSettings()
125{
126	_Unset();
127
128	if (fSettingsPath.Path() == NULL)
129		return B_ENTRY_NOT_FOUND;
130
131	// read the settings file
132	BFile file;
133	status_t error = file.SetTo(fSettingsPath.Path(), B_READ_ONLY);
134	if (error != B_OK)
135		return error;
136
137	BMessage archive;
138	error = archive.Unflatten(&file);
139	if (error != B_OK)
140		return error;
141
142	// unarchive the recent team settings
143	BMessage childArchive;
144	for (int32 i = 0; archive.FindMessage("teamSettings", i, &childArchive)
145			== B_OK; i++) {
146		TeamSettings* settings = new(std::nothrow) TeamSettings;
147		if (settings == NULL)
148			return B_NO_MEMORY;
149
150		error = settings->SetTo(childArchive);
151		if (error != B_OK) {
152			delete settings;
153			continue;
154		}
155
156		if (!fRecentTeamSettings.AddItem(settings)) {
157			delete settings;
158			return B_NO_MEMORY;
159		}
160	}
161
162	return B_OK;
163}
164
165
166status_t
167SettingsManager::_SaveSettings()
168{
169	if (fSettingsPath.Path() == NULL)
170		return B_ENTRY_NOT_FOUND;
171
172	// archive the recent team settings
173	BMessage archive;
174	for (int32 i = 0; TeamSettings* settings = fRecentTeamSettings.ItemAt(i);
175			i++) {
176		BMessage childArchive;
177		status_t error = settings->WriteTo(childArchive);
178		if (error != B_OK)
179			return error;
180
181		error = archive.AddMessage("teamSettings", &childArchive);
182		if (error != B_OK)
183			return error;
184	}
185
186	// open the settings file
187	BFile file;
188	status_t error = file.SetTo(fSettingsPath.Path(),
189		B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE);
190	if (error != B_OK)
191		return error;
192
193	return archive.Flatten(&file);
194}
195
196
197int32
198SettingsManager::_TeamSettingsIndex(const char* teamName) const
199{
200	for (int32 i = 0; TeamSettings* settings = fRecentTeamSettings.ItemAt(i);
201			i++) {
202		if (settings->TeamName() == teamName)
203			return i;
204	}
205
206	return -1;
207}
208