1/*
2 * Copyright (C) 2010-2013 Robert Ancell
3 *
4 * This program is free software: you can redistribute it and/or modify it under
5 * the terms of the GNU General Public License as published by the Free Software
6 * Foundation, either version 2 of the License, or (at your option) any later
7 * version. See http://www.gnu.org/copyleft/gpl.html the full text of the
8 * license.
9 */
10
11public class Slot : Object
12{
13    public int x;
14    public int y;
15    public int layer;
16
17    public Slot (int x, int y, int layer)
18    {
19        this.x = x;
20        this.y = y;
21        this.layer = layer;
22    }
23}
24
25private static int compare_slots (Slot a, Slot b)
26{
27    /* Sort lowest to highest */
28    var dl = a.layer - b.layer;
29    if (dl != 0)
30        return dl;
31
32    /* Sort diagonally, top left to bottom right */
33    var dx = a.x - b.x;
34    var dy = a.y - b.y;
35    if (dx > dy)
36        return -1;
37    if (dx < dy)
38        return 1;
39
40    return 0;
41}
42
43public class Map : Object
44{
45    public string? name = null;
46    public string? score_name = null;
47    public List<Slot> slots = null;
48
49    public Map.test ()
50    {
51        name = "Test";
52        score_name = "test";
53        slots.append (new Slot (0, 0, 0));
54        slots.append (new Slot (2, 0, 0));
55        slots.append (new Slot (2, 0, 1));
56        slots.append (new Slot (4, 0, 0));
57        slots.append (new Slot (0, 2, 0));
58        slots.append (new Slot (2, 2, 0));
59        slots.append (new Slot (2, 2, 1));
60        slots.append (new Slot (4, 2, 0));
61    }
62
63    public Map.builtin ()
64    {
65        name = "Easy";
66        score_name = "easy";
67        slots.append (new Slot (13, 7, 4));
68        slots.append (new Slot (12, 8, 3));
69        slots.append (new Slot (14, 8, 3));
70        slots.append (new Slot (12, 6, 3));
71        slots.append (new Slot (14, 6, 3));
72        slots.append (new Slot (10, 10, 2));
73        slots.append (new Slot (12, 10, 2));
74        slots.append (new Slot (14, 10, 2));
75        slots.append (new Slot (16, 10, 2));
76        slots.append (new Slot (10, 8, 2));
77        slots.append (new Slot (12, 8, 2));
78        slots.append (new Slot (14, 8, 2));
79        slots.append (new Slot (16, 8, 2));
80        slots.append (new Slot (10, 6, 2));
81        slots.append (new Slot (12, 6, 2));
82        slots.append (new Slot (14, 6, 2));
83        slots.append (new Slot (16, 6, 2));
84        slots.append (new Slot (10, 4, 2));
85        slots.append (new Slot (12, 4, 2));
86        slots.append (new Slot (14, 4, 2));
87        slots.append (new Slot (16, 4, 2));
88        slots.append (new Slot (8, 12, 1));
89        slots.append (new Slot (10, 12, 1));
90        slots.append (new Slot (12, 12, 1));
91        slots.append (new Slot (14, 12, 1));
92        slots.append (new Slot (16, 12, 1));
93        slots.append (new Slot (18, 12, 1));
94        slots.append (new Slot (8, 10, 1));
95        slots.append (new Slot (10, 10, 1));
96        slots.append (new Slot (12, 10, 1));
97        slots.append (new Slot (14, 10, 1));
98        slots.append (new Slot (16, 10, 1));
99        slots.append (new Slot (18, 10, 1));
100        slots.append (new Slot (8, 8, 1));
101        slots.append (new Slot (10, 8, 1));
102        slots.append (new Slot (12, 8, 1));
103        slots.append (new Slot (14, 8, 1));
104        slots.append (new Slot (16, 8, 1));
105        slots.append (new Slot (18, 8, 1));
106        slots.append (new Slot (8, 6, 1));
107        slots.append (new Slot (10, 6, 1));
108        slots.append (new Slot (12, 6, 1));
109        slots.append (new Slot (14, 6, 1));
110        slots.append (new Slot (16, 6, 1));
111        slots.append (new Slot (18, 6, 1));
112        slots.append (new Slot (8, 4, 1));
113        slots.append (new Slot (10, 4, 1));
114        slots.append (new Slot (12, 4, 1));
115        slots.append (new Slot (14, 4, 1));
116        slots.append (new Slot (16, 4, 1));
117        slots.append (new Slot (18, 4, 1));
118        slots.append (new Slot (8, 2, 1));
119        slots.append (new Slot (10, 2, 1));
120        slots.append (new Slot (12, 2, 1));
121        slots.append (new Slot (14, 2, 1));
122        slots.append (new Slot (16, 2, 1));
123        slots.append (new Slot (18, 2, 1));
124        slots.append (new Slot (2, 14, 0));
125        slots.append (new Slot (4, 14, 0));
126        slots.append (new Slot (6, 14, 0));
127        slots.append (new Slot (8, 14, 0));
128        slots.append (new Slot (10, 14, 0));
129        slots.append (new Slot (12, 14, 0));
130        slots.append (new Slot (14, 14, 0));
131        slots.append (new Slot (16, 14, 0));
132        slots.append (new Slot (18, 14, 0));
133        slots.append (new Slot (20, 14, 0));
134        slots.append (new Slot (22, 14, 0));
135        slots.append (new Slot (24, 14, 0));
136        slots.append (new Slot (6, 12, 0));
137        slots.append (new Slot (8, 12, 0));
138        slots.append (new Slot (10, 12, 0));
139        slots.append (new Slot (12, 12, 0));
140        slots.append (new Slot (14, 12, 0));
141        slots.append (new Slot (16, 12, 0));
142        slots.append (new Slot (18, 12, 0));
143        slots.append (new Slot (20, 12, 0));
144        slots.append (new Slot (4, 10, 0));
145        slots.append (new Slot (6, 10, 0));
146        slots.append (new Slot (8, 10, 0));
147        slots.append (new Slot (10, 10, 0));
148        slots.append (new Slot (12, 10, 0));
149        slots.append (new Slot (14, 10, 0));
150        slots.append (new Slot (16, 10, 0));
151        slots.append (new Slot (18, 10, 0));
152        slots.append (new Slot (20, 10, 0));
153        slots.append (new Slot (22, 10, 0));
154        slots.append (new Slot (0, 7, 0));
155        slots.append (new Slot (2, 8, 0));
156        slots.append (new Slot (4, 8, 0));
157        slots.append (new Slot (6, 8, 0));
158        slots.append (new Slot (8, 8, 0));
159        slots.append (new Slot (10, 8, 0));
160        slots.append (new Slot (12, 8, 0));
161        slots.append (new Slot (14, 8, 0));
162        slots.append (new Slot (16, 8, 0));
163        slots.append (new Slot (18, 8, 0));
164        slots.append (new Slot (20, 8, 0));
165        slots.append (new Slot (22, 8, 0));
166        slots.append (new Slot (24, 8, 0));
167        slots.append (new Slot (2, 6, 0));
168        slots.append (new Slot (4, 6, 0));
169        slots.append (new Slot (6, 6, 0));
170        slots.append (new Slot (8, 6, 0));
171        slots.append (new Slot (10, 6, 0));
172        slots.append (new Slot (12, 6, 0));
173        slots.append (new Slot (14, 6, 0));
174        slots.append (new Slot (16, 6, 0));
175        slots.append (new Slot (18, 6, 0));
176        slots.append (new Slot (20, 6, 0));
177        slots.append (new Slot (22, 6, 0));
178        slots.append (new Slot (24, 6, 0));
179        slots.append (new Slot (4, 4, 0));
180        slots.append (new Slot (6, 4, 0));
181        slots.append (new Slot (8, 4, 0));
182        slots.append (new Slot (10, 4, 0));
183        slots.append (new Slot (12, 4, 0));
184        slots.append (new Slot (14, 4, 0));
185        slots.append (new Slot (16, 4, 0));
186        slots.append (new Slot (18, 4, 0));
187        slots.append (new Slot (20, 4, 0));
188        slots.append (new Slot (22, 4, 0));
189        slots.append (new Slot (6, 2, 0));
190        slots.append (new Slot (8, 2, 0));
191        slots.append (new Slot (10, 2, 0));
192        slots.append (new Slot (12, 2, 0));
193        slots.append (new Slot (14, 2, 0));
194        slots.append (new Slot (16, 2, 0));
195        slots.append (new Slot (18, 2, 0));
196        slots.append (new Slot (20, 2, 0));
197        slots.append (new Slot (2, 0, 0));
198        slots.append (new Slot (4, 0, 0));
199        slots.append (new Slot (6, 0, 0));
200        slots.append (new Slot (8, 0, 0));
201        slots.append (new Slot (10, 0, 0));
202        slots.append (new Slot (12, 0, 0));
203        slots.append (new Slot (14, 0, 0));
204        slots.append (new Slot (16, 0, 0));
205        slots.append (new Slot (18, 0, 0));
206        slots.append (new Slot (20, 0, 0));
207        slots.append (new Slot (22, 0, 0));
208        slots.append (new Slot (24, 0, 0));
209        slots.append (new Slot (26, 7, 0));
210        slots.append (new Slot (28, 7, 0));
211    }
212
213    public uint width
214    {
215        get
216        {
217            var w = 0;
218            foreach (var slot in slots)
219            {
220                if (slot.x > w)
221                    w = slot.x;
222            }
223
224            /* Width is x location of right most tile and the width of that tile (2 units) */
225            return w + 2;
226        }
227    }
228
229    public uint height
230    {
231        get
232        {
233            var h = 0;
234            foreach (var slot in slots)
235            {
236                if (slot.y > h)
237                    h = slot.y;
238            }
239
240            /* Height is x location of bottom most tile and the height of that tile (2 units) */
241            return h + 2;
242        }
243    }
244}
245
246public class MapLoader : Object
247{
248    public List<Map> maps = null;
249    private Map map;
250    private int layer_z = 0;
251
252    public void load (string filename) throws Error
253    {
254        string data;
255        size_t length;
256        FileUtils.get_contents (filename, out data, out length);
257
258        var parser = MarkupParser ();
259        parser.start_element = start_element_cb;
260        parser.end_element = end_element_cb;
261        parser.text = null;
262        parser.passthrough = null;
263        parser.error = null;
264        var parse_context = new MarkupParseContext (parser, 0, this, null);
265        try
266        {
267            parse_context.parse (data, (ssize_t) length);
268        }
269        catch (MarkupError e)
270        {
271        }
272    }
273
274    private string? get_attribute (string[] attribute_names, string[] attribute_values, string name, string? default = null)
275    {
276        for (var i = 0; attribute_names[i] != null; i++)
277        {
278            if (attribute_names[i].down () == name)
279                return attribute_values[i];
280        }
281
282        return default;
283    }
284
285    private double get_attribute_d (string[] attribute_names, string[] attribute_values, string name, double default = 0.0)
286    {
287        var a = get_attribute (attribute_names, attribute_values, name);
288        if (a == null)
289            return default;
290        else
291            return double.parse (a);
292    }
293
294    private void start_element_cb (MarkupParseContext context, string element_name, string[] attribute_names, string[] attribute_values) throws MarkupError
295    {
296        /* Identify the tag. */
297        switch (element_name.down ())
298        {
299        case "mahjongg":
300            break;
301
302        case "map":
303            map = new Map ();
304            map.name = get_attribute (attribute_names, attribute_values, "name", "");
305            map.score_name = get_attribute (attribute_names, attribute_values, "scorename", "");
306            break;
307
308        case "layer":
309            layer_z = (int) get_attribute_d (attribute_names, attribute_values, "z");
310            break;
311
312        case "row":
313            var x1 = (int) (get_attribute_d (attribute_names, attribute_values, "left") * 2);
314            var x2 = (int) (get_attribute_d (attribute_names, attribute_values, "right") * 2);
315            var y = (int) (get_attribute_d (attribute_names, attribute_values, "y") * 2);
316            var z = (int) get_attribute_d (attribute_names, attribute_values, "z", layer_z);
317            for (; x1 <= x2; x1 += 2)
318                map.slots.append (new Slot (x1, y, z));
319            break;
320
321        case "column":
322            var x = (int) (get_attribute_d (attribute_names, attribute_values, "x") * 2);
323            var y1 = (int) (get_attribute_d (attribute_names, attribute_values, "top") * 2);
324            var y2 = (int) (get_attribute_d (attribute_names, attribute_values, "bottom") * 2);
325            var z = (int) get_attribute_d (attribute_names, attribute_values, "z", layer_z);
326            for (; y1 <= y2; y1 += 2)
327                map.slots.append (new Slot (x, y1, z));
328            break;
329
330        case "block":
331            var x1 = (int) (get_attribute_d (attribute_names, attribute_values, "left") * 2);
332            var x2 = (int) (get_attribute_d (attribute_names, attribute_values, "right") * 2);
333            var y1 = (int) (get_attribute_d (attribute_names, attribute_values, "top") * 2);
334            var y2 = (int) (get_attribute_d (attribute_names, attribute_values, "bottom") * 2);
335            var z = (int) get_attribute_d (attribute_names, attribute_values, "z", layer_z);
336            for (; x1 <= x2; x1 += 2)
337                for (var y = y1; y <= y2; y += 2)
338                    map.slots.append (new Slot (x1, y, z));
339            break;
340
341        case "tile":
342            var x = (int) (get_attribute_d (attribute_names, attribute_values, "x") * 2);
343            var y = (int) (get_attribute_d (attribute_names, attribute_values, "y") * 2);
344            var z = (int) get_attribute_d (attribute_names, attribute_values, "z", layer_z);
345            map.slots.append (new Slot (x, y, z));
346            break;
347        }
348    }
349
350    private void end_element_cb (MarkupParseContext context, string element_name) throws MarkupError
351    {
352        switch (element_name.down ())
353        {
354        case "map":
355            var n_slots = map.slots.length ();
356            if (map.name != null && map.score_name != null && n_slots <= 144 && n_slots % 2 == 0)
357                maps.append (map);
358            else
359                warning ("Invalid map");
360            map = null;
361            break;
362
363        case "layer":
364            layer_z = 0;
365            break;
366        }
367    }
368}
369