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