3e913df5e969bb5925bca64585a7964f73164bcf
[lordsawar] / src / citysetlist.cpp
1 // Copyright (C) 2008 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 <algorithm>
20 #include <expat.h>
21 #include "rectangle.h"
22 #include <sigc++/functors/mem_fun.h>
23
24 #include "citysetlist.h"
25 #include "ucompose.hpp"
26 #include "File.h"
27 #include "defs.h"
28
29 using namespace std;
30
31 #define debug(x) {cerr<<__FILE__<<": "<<__LINE__<<": "<<x<<endl<<flush;}
32 //#define debug(x)
33
34 Citysetlist* Citysetlist::s_instance = 0;
35
36 Citysetlist* Citysetlist::getInstance()
37 {
38     if (!s_instance)
39         s_instance = new Citysetlist();
40
41     return s_instance;
42 }
43
44 void Citysetlist::deleteInstance()
45 {
46     if (s_instance)
47       delete s_instance;
48
49     s_instance = 0;
50 }
51
52 void Citysetlist::loadCitysets(std::list<std::string> citysets)
53 {
54     for (std::list<std::string>::const_iterator i = citysets.begin(); 
55          i != citysets.end(); i++)
56       {
57         Cityset *cityset = loadCityset(*i);
58         if (!cityset)
59           continue;
60
61         add(cityset);
62       }
63 }
64
65 Citysetlist::Citysetlist()
66 {
67     // load all citysets
68     std::list<std::string> citysets = Cityset::scanSystemCollection();
69     loadCitysets(citysets);
70     citysets = Cityset::scanUserCollection();
71     loadCitysets(citysets);
72
73 }
74
75 Citysetlist::~Citysetlist()
76 {
77   for (iterator it = begin(); it != end(); it++)
78     delete (*it);
79 }
80
81 std::list<std::string> Citysetlist::getNames()
82 {
83   std::list<std::string> names;
84   for (iterator it = begin(); it != end(); it++)
85     names.push_back((*it)->getName());
86   return names;
87 }
88
89 std::list<std::string> Citysetlist::getNames(guint32 tilesize)
90 {
91   std::list<std::string> names;
92   for (iterator it = begin(); it != end(); it++)
93     if ((*it)->getTileSize() == tilesize)
94       names.push_back((*it)->getName());
95   return names;
96 }
97
98 Cityset *Citysetlist::loadCityset(std::string name)
99 {
100   debug("Loading cityset " <<File::get_basename(File::get_dirname(name)));
101
102   Cityset *cityset = Cityset::create(name);
103   if (!cityset)
104     return NULL;
105     
106   if (cityset->validate() == false)
107     {
108       cerr << "Error!  cityset: `" << cityset->getName() << 
109         "' is invalid.  Skipping." << endl;
110       delete cityset;
111       return NULL;
112     }
113
114   if (d_citysetids.find(cityset->getId()) != d_citysetids.end())
115     {
116       Cityset *c = (*d_citysetids.find(cityset->getId())).second;
117       cerr << "Error!  cityset: `" << cityset->getName() << 
118         "' shares a duplicate cityset id with `" << c->getConfigurationFile() 
119         << "'.  Skipping." << endl;
120       delete cityset;
121       return NULL;
122     }
123
124   if (d_citysetids.find(cityset->getId()) != d_citysetids.end())
125     {
126       Cityset *c = (*d_citysetids.find(cityset->getId())).second;
127       cerr << "Error!  cityset: `" << cityset->getName() << 
128         "' has a duplicate cityset id with `" << c->getConfigurationFile() << 
129         "'.  Skipping." << endl;
130       delete cityset;
131       return NULL;
132     }
133   return cityset;
134 }
135
136 void Citysetlist::add(Cityset *cityset)
137 {
138   std::string subdir = File::get_basename(cityset->getDirectory());
139   push_back(cityset);
140   cityset->setSubDir(subdir);
141   d_dirs[String::ucompose("%1 %2", cityset->getName(), cityset->getTileSize())] = subdir;
142   d_citysets[subdir] = cityset;
143   d_citysetids[cityset->getId()] = cityset;
144 }
145
146 void Citysetlist::getSizes(std::list<guint32> &sizes)
147 {
148   for (iterator i = begin(); i != end(); i++)
149     {
150       if (find (sizes.begin(), sizes.end(), (*i)->getTileSize()) == sizes.end())
151         sizes.push_back((*i)->getTileSize());
152     }
153 }
154
155 std::string Citysetlist::getCitysetDir(std::string name, guint32 tilesize)
156 {
157   return d_dirs[String::ucompose("%1 %2", name, tilesize)];
158 }
159 void Citysetlist::instantiateImages()
160 {
161   for (iterator it = begin(); it != end(); it++)
162     (*it)->instantiateImages();
163 }
164 void Citysetlist::uninstantiateImages()
165 {
166   for (iterator it = begin(); it != end(); it++)
167     (*it)->uninstantiateImages();
168 }
169         
170 Cityset *Citysetlist::getCityset(guint32 id) 
171
172   if (d_citysetids.find(id) == d_citysetids.end())
173     return NULL;
174   return d_citysetids[id];
175 }
176         
177 Cityset *Citysetlist::getCityset(std::string dir) 
178
179   if (d_citysets.find(dir) == d_citysets.end())
180     return NULL;
181   return d_citysets[dir];
182 }
183 bool Citysetlist::addToPersonalCollection(Cityset *cityset, std::string &new_subdir, guint32 &new_id)
184 {
185   //do we already have this one?
186   if (getCityset(cityset->getSubDir()) == getCityset(cityset->getId()) &&
187       getCityset(cityset->getSubDir()) != NULL)
188     {
189       cityset->setDirectory(getCityset(cityset->getId())->getDirectory());
190       return true;
191     }
192
193   //if the subdir conflicts with any other subdir, then change it.
194   if (getCityset(cityset->getSubDir()) != NULL)
195     {
196       bool found = false;
197       for (int count = 0; count < 100; count++)
198         {
199           new_subdir = String::ucompose("%1%2", cityset->getSubDir(), count);
200           if (getCityset(new_subdir) == NULL)
201             {
202               found = true;
203               break;
204             }
205         }
206       if (found == false)
207         return false;
208       cityset->setSubDir(new_subdir);
209     }
210   else
211     new_subdir = cityset->getSubDir();
212
213   //if the id conflicts with any other id, then change it
214   if (getCityset(cityset->getId()) != NULL)
215     {
216       new_id = Citysetlist::getNextAvailableId(cityset->getId());
217       cityset->setId(new_id);
218     }
219   else
220     new_id = cityset->getId();
221
222   //make the directory where the cityset is going to live.
223   std::string directory = 
224     File::getUserCitysetDir() + cityset->getSubDir() + "/";
225
226   if (File::create_dir(directory) == false)
227     return false;
228
229   //okay now we copy the image files into the new directory 
230   std::list<std::string> files;
231   cityset->getFilenames(files);
232   for (std::list<std::string>::iterator it = files.begin(); it != files.end();
233        it++)
234     File::copy(cityset->getFile(*it), directory + *it);
235
236   //save out the cityset file
237   cityset->setDirectory(directory);
238   XML_Helper helper(cityset->getConfigurationFile(), std::ios::out, false);
239   cityset->save(&helper);
240   helper.close();
241   return true;
242 }
243
244 int Citysetlist::getNextAvailableId(int after)
245 {
246   std::list<guint32> ids;
247   std::list<std::string> citysets = Cityset::scanSystemCollection();
248   //there might be IDs in invalid armysets.
249   for (std::list<std::string>::const_iterator i = citysets.begin(); 
250        i != citysets.end(); i++)
251     {
252       Cityset *cityset = Cityset::create(*i);
253       if (cityset != NULL)
254         {
255           ids.push_back(cityset->getId());
256           delete cityset;
257         }
258     }
259   citysets = Cityset::scanUserCollection();
260   for (std::list<std::string>::const_iterator i = citysets.begin(); 
261        i != citysets.end(); i++)
262     {
263       Cityset *cityset = Cityset::create(*i);
264       if (cityset != NULL)
265         {
266           ids.push_back(cityset->getId());
267           delete cityset;
268         }
269     }
270   for (guint32 i = after + 1; i < 1000000; i++)
271     {
272       if (find(ids.begin(), ids.end(), i) == ids.end())
273         return i;
274     }
275   return -1;
276 }