initial commit, lordsawar source, slightly modified
[lordsawar] / src / shieldsetlist.cpp
1 //  Copyright (C) 2008, 2009 Ben Asselstine
2 //
3 //  This program is free software; you can redistribute it and/or modify
4 //  it under the terms of the GNU General Public License as published by
5 //  the Free Software Foundation; either version 3 of the License, or
6 //  (at your option) any later version.
7 //
8 //  This program is distributed in the hope that it will be useful,
9 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
10 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 //  GNU Library General Public License for more details.
12 //
13 //  You should have received a copy of the GNU General Public License
14 //  along with this program; if not, write to the Free Software
15 //  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 
16 //  02110-1301, USA.
17
18 #include <iostream>
19 #include <expat.h>
20 #include "rectangle.h"
21 #include <sigc++/functors/mem_fun.h>
22
23 #include "shieldsetlist.h"
24 #include "shieldset.h"
25 #include "File.h"
26 #include "defs.h"
27 #include "ucompose.hpp"
28
29 using namespace std;
30
31 #define debug(x) {cerr<<__FILE__<<": "<<__LINE__<<": "<<x<<endl<<flush;}
32 //#define debug(x)
33
34 Shieldsetlist* Shieldsetlist::s_instance = 0;
35
36 Shieldsetlist* Shieldsetlist::getInstance()
37 {
38     if (!s_instance)
39         s_instance = new Shieldsetlist();
40
41     return s_instance;
42 }
43
44 void Shieldsetlist::deleteInstance()
45 {
46     if (s_instance)
47       delete s_instance;
48
49     s_instance = 0;
50 }
51
52
53 void Shieldsetlist::loadShieldsets(std::list<std::string> shieldsets)
54 {
55     for (std::list<std::string>::const_iterator i = shieldsets.begin(); 
56          i != shieldsets.end(); i++)
57       {
58         Shieldset *shieldset = loadShieldset(*i);
59         if (!shieldset)
60           continue;
61         add(shieldset);
62       }
63 }
64
65 Shieldsetlist::Shieldsetlist()
66 {
67     // load all shieldsets
68     std::list<std::string> shieldsets = Shieldset::scanSystemCollection();
69     loadShieldsets(shieldsets);
70     shieldsets = Shieldset::scanUserCollection();
71     loadShieldsets(shieldsets);
72
73 }
74
75 Shieldsetlist::~Shieldsetlist()
76 {
77   for (iterator it = begin(); it != end(); it++)
78     delete (*it);
79 }
80
81 std::list<std::string> Shieldsetlist::getNames() const
82 {
83   std::list<std::string> names;
84   for (const_iterator it = begin(); it != end(); it++)
85     names.push_back((*it)->getName());
86   return names;
87 }
88 std::string Shieldsetlist::getShieldsetDir(std::string name) const
89 {
90   DirMap::const_iterator it = d_dirs.find(name);
91   if (it == d_dirs.end())
92     return "";
93   else
94     return (*it).second;
95 }
96
97 Shieldset* Shieldsetlist::loadShieldset(std::string name)
98 {
99   debug("Loading shieldset " <<File::get_basename(File::get_dirname(name)));
100
101   Shieldset *shieldset = Shieldset::create(name);
102   if (!shieldset)
103     return NULL;
104
105   if (shieldset->validate() == false)
106     {
107       cerr << "Error!  shieldset: `" << shieldset->getName() << 
108         "' is invalid.  Skipping." << endl;
109       delete shieldset;
110       return NULL;
111     }
112
113   if (d_shieldsetids.find(shieldset->getId()) != d_shieldsetids.end())
114     {
115       Shieldset *s = (*d_shieldsetids.find(shieldset->getId())).second;
116       cerr << "Error!  shieldset: `" << shieldset->getName() << 
117         "' shares a duplicate shieldset id with `" << s->getConfigurationFile() 
118         << "'.  Skipping." << endl;
119       delete shieldset;
120       return NULL;
121     }
122     
123   return shieldset;
124 }
125
126 void Shieldsetlist::add(Shieldset *shieldset)
127 {
128   std::string subdir = File::get_basename(shieldset->getDirectory());
129   push_back(shieldset);
130   shieldset->setSubDir(subdir);
131   d_dirs[shieldset->getName()] = subdir;
132   d_shieldsets[subdir] = shieldset;
133   d_shieldsetids[shieldset->getId()] = shieldset;
134 }
135         
136 Gdk::Color Shieldsetlist::getColor(guint32 shieldset, guint32 owner) const
137 {
138   Shieldset *s = getShieldset(shieldset);
139   if (!s)
140     return Gdk::Color("black");
141   return s->getColor(owner);
142 }
143
144 ShieldStyle *Shieldsetlist::getShield(guint32 shieldset, guint32 type, guint32 colour) const
145 {
146   Shieldset *s = getShieldset(shieldset);
147   if (!s)
148     return NULL;
149   return s->lookupShieldByTypeAndColour(type, colour);
150 }
151
152 void Shieldsetlist::instantiateImages()
153 {
154   for (iterator it = begin(); it != end(); it++)
155     (*it)->instantiateImages();
156 }
157
158 void Shieldsetlist::uninstantiateImages()
159 {
160   for (iterator it = begin(); it != end(); it++)
161     (*it)->uninstantiateImages();
162 }
163         
164 Shieldset *Shieldsetlist::getShieldset(guint32 id)  const
165
166   ShieldsetIdMap::const_iterator it = d_shieldsetids.find(id);
167   if (it == d_shieldsetids.end())
168     return NULL;
169   return (*it).second;
170 }
171
172 Shieldset *Shieldsetlist::getShieldset(std::string dir) const
173
174   ShieldsetMap::const_iterator it = d_shieldsets.find(dir);
175   if (it == d_shieldsets.end())
176     return NULL;
177   return (*it).second;
178 }
179
180 bool Shieldsetlist::addToPersonalCollection(Shieldset *shieldset, std::string &new_subdir, guint32 &new_id)
181 {
182   //do we already have this one?
183       
184   if (getShieldset(shieldset->getSubDir()) == getShieldset(shieldset->getId()) 
185       && getShieldset(shieldset->getSubDir()) != NULL)
186     {
187       shieldset->setDirectory(getShieldset(shieldset->getId())->getDirectory());
188       return true;
189     }
190
191   //if the subdir conflicts with any other subdir, then change it.
192   if (getShieldset(shieldset->getSubDir()) != NULL)
193     {
194       bool found = false;
195       for (int count = 0; count < 100; count++)
196         {
197           new_subdir = String::ucompose("%1%2", shieldset->getSubDir(), count);
198           if (getShieldset(new_subdir) == NULL)
199             {
200               found = true;
201               break;
202             }
203         }
204       if (found == false)
205         return false;
206       shieldset->setSubDir(new_subdir);
207     }
208   else
209     new_subdir = shieldset->getSubDir();
210
211   //if the id conflicts with any other id, then change it
212   if (getShieldset(shieldset->getId()) != NULL)
213     {
214       new_id = Shieldsetlist::getNextAvailableId(shieldset->getId());
215       shieldset->setId(new_id);
216     }
217   else
218     new_id = shieldset->getId();
219
220   //make the directory where the shieldset is going to live.
221   std::string directory = 
222     File::getUserShieldsetDir() + shieldset->getSubDir() + "/";
223
224   if (File::create_dir(directory) == false)
225     return false;
226
227   //okay now we copy the image files into the new directory 
228   std::list<std::string> files;
229   shieldset->getFilenames(files);
230   for (std::list<std::string>::iterator it = files.begin(); it != files.end();
231        it++)
232     File::copy(shieldset->getFile(*it), directory + *it);
233
234   //save out the shieldset file
235   shieldset->setDirectory(directory);
236   XML_Helper helper(shieldset->getConfigurationFile(), std::ios::out, false);
237   shieldset->save(&helper);
238   helper.close();
239   return true;
240 }
241
242 int Shieldsetlist::getNextAvailableId(int after)
243 {
244   std::list<guint32> ids;
245   std::list<std::string> shieldsets = Shieldset::scanSystemCollection();
246   for (std::list<std::string>::const_iterator i = shieldsets.begin(); 
247        i != shieldsets.end(); i++)
248     {
249       Shieldset *shieldset = Shieldset::create(*i);
250       if (shieldset != NULL)
251         {
252           ids.push_back(shieldset->getId());
253           delete shieldset;
254         }
255     }
256   shieldsets = Shieldset::scanUserCollection();
257   for (std::list<std::string>::const_iterator i = shieldsets.begin(); 
258        i != shieldsets.end(); i++)
259     {
260       Shieldset *shieldset = Shieldset::create(*i);
261       if (shieldset != NULL)
262         {
263           ids.push_back(shieldset->getId());
264           delete shieldset;
265         }
266     }
267   for (guint32 i = after + 1; i < 1000000; i++)
268     {
269       if (find(ids.begin(), ids.end(), i) == ids.end())
270         return i;
271     }
272   return -1;
273 }