1#!/usr/bin/env python3
2
3import json
4import argparse
5import copy
6
7
8def hash_key(key):
9    if isinstance(key, list):
10        return "list_" + "".join(key)
11    else:
12        return key
13
14
15def parse_furnter(om_objs, palette, conflicts):
16    for map_key, map_val in om_objs.items():
17        if isinstance(map_val, list) and len(map_val) == 1:
18            map_val = map_val[0]
19        pal_val = palette.get(map_key, "")
20        if not pal_val:
21            palette[map_key] = map_val
22        elif pal_val != map_val:
23            map_hash = hash_key(map_val)
24            pal_hash = hash_key(pal_val)
25            conflicts.setdefault(map_key, {})
26            conflicts[map_key].setdefault(
27                map_hash, {"val": map_val, "count": 0})
28            conflicts[map_key].setdefault(
29                pal_hash, {"val": pal_val, "count": 0})
30            conflicts[map_key][map_hash]["count"] += 1
31            conflicts[map_key][pal_hash]["count"] += 1
32
33
34def decide_conflicts(palette, conflicts):
35    for con_key, conflict in conflicts.items():
36        most_val = ""
37        most_count = -1
38        for _, data in conflict.items():
39            if data["count"] > most_count:
40                most_count = data["count"]
41                most_val = data["val"]
42        palette[con_key] = most_val
43
44
45def resolve_conflicts(om_objs, palette, conflicts):
46    temp_objs = copy.deepcopy(om_objs)
47    for map_key in om_objs:
48        map_val = om_objs[map_key]
49        if isinstance(map_val, list) and len(map_val) == 1:
50            map_val = map_val[0]
51        pal_val = palette.get(map_key, "")
52        if pal_val == map_val:
53            del temp_objs[map_key]
54    return temp_objs
55
56
57args = argparse.ArgumentParser(
58    description="Read all the terrain and furniture definitions from a "
59                "mapgen .json file and move them into a palette file.  "
60                "Symbols with multiple definitions put the most common "
61                "definition in the the palette and leave the others in "
62                "the mapgen file.")
63args.add_argument("mapgen_source", action="store",
64                  help="specify json file to convert to palette.")
65args.add_argument("palette_name", action="store",
66                  help="specify the name of the resulting palette.")
67args.add_argument("palette_path", action="store",
68                  help="specify the folder for the palette.")
69argsDict = vars(args.parse_args())
70
71mapgen = []
72mapgen_source = argsDict.get("mapgen_source", "")
73palette_name = argsDict.get("palette_name", "")
74palette_source = \
75    argsDict.get("palette_path", "") + "/" + palette_name + ".json"
76if mapgen_source.endswith(".json"):
77    try:
78        with open(mapgen_source) as mapgen_file:
79            mapgen += json.load(mapgen_file)
80    except FileNotFoundError:
81        exit("Failed: could not find {}".format(mapgen_source))
82else:
83    exit("Failed: invalid mapgen file name {}".format(mapgen_source))
84
85furn_pal = {}
86furn_conflicts = {}
87ter_pal = {}
88ter_conflicts = {}
89
90# first pass, go through and find all the existing terrains and furnitures and
91# any conflicts
92for om_tile in mapgen:
93    om_object = om_tile.get("object", {})
94    om_furn = om_object.get("furniture", {})
95    parse_furnter(om_furn, furn_pal, furn_conflicts)
96    om_ter = om_object.get("terrain", {})
97    parse_furnter(om_ter, ter_pal, ter_conflicts)
98
99# if there are conflicts, pick the most common version for the palette
100if furn_conflicts:
101    decide_conflicts(furn_pal, furn_conflicts)
102if ter_conflicts:
103    decide_conflicts(ter_pal, ter_conflicts)
104
105# second pass, remove entries in the palette
106for om_tile in mapgen:
107    om_object = om_tile.get("object", {})
108    om_object.setdefault("palettes", [])
109    om_object["palettes"].append(palette_name)
110    if om_object.get("furniture"):
111        if furn_conflicts:
112            om_furn = om_object.get("furniture", {})
113            om_furn_final = resolve_conflicts(om_furn, furn_pal,
114                                              furn_conflicts)
115            if om_furn_final:
116                om_object["furniture"] = om_furn_final
117            else:
118                del om_object["furniture"]
119        else:
120            del om_object["furniture"]
121
122    if om_object.get("terrain"):
123        if ter_conflicts:
124            om_ter = om_object.get("terrain", {})
125            om_ter_final = resolve_conflicts(om_ter, ter_pal, ter_conflicts)
126            if om_ter_final:
127                om_object["terrain"] = om_ter_final
128            else:
129                del om_object["terrain"]
130        else:
131            del om_object["terrain"]
132
133with open(mapgen_source, 'w') as mapgen_file:
134    mapgen_file.write(json.dumps(mapgen, indent=2))
135
136palette_json = [
137    {
138        "type": "palette",
139        "id": palette_name,
140        "furniture": furn_pal,
141        "terrain": ter_pal
142    }
143]
144
145with open(palette_source, 'w') as palette_file:
146    palette_file.write(json.dumps(palette_json, indent=2))
147
148#print("furniture palette {}".format(json.dumps(furn_pal, indent=2)))
149#print("terrain palette {}".format(json.dumps(ter_pal, indent=2)))
150