1import weakref
2
3
4class StrWithExplicit(str):
5
6    # def __init__(self, object):
7    #     super().__init__(object)
8    #     self.explicit = ""
9
10    @property
11    def int(self):
12        return int(self or "0")
13
14
15class ImplicitConfig:
16    def __init__(self, config, settings):
17        self._values = {}
18        self._config = config
19        self._settings = settings
20
21        # self.__setattr__ = self.__setattr__function
22
23    def items(self):
24        return self._values.items()
25
26    def get(self, key, default=""):
27        value = self._values.get(key, default)
28        explicit = self._config[key]
29        # print(explicit)
30        if not explicit:
31            explicit = self._settings[key]
32        if value:
33            result = StrWithExplicit(value)
34        else:
35            result = StrWithExplicit(explicit)
36        result.explicit = explicit
37        return result
38
39    def __getitem__(self, item):
40        result = self.get(item)
41        # print("get", item, repr(result))
42        return result
43
44    def __setitem__(self, key, value):
45        # print("setitem", key, value)
46        if not value:
47            value = ""
48        else:
49            value = str(value)
50        self._values[key] = value
51
52    def __getattr__(self, item):
53        result = self.get(item)
54        # print("get", item, repr(result))
55        return result
56        # print("getattr", item)
57        # if item == "_values":
58        #     return getattr(self, "_values")
59        # return self.get(item)
60
61    def __setattr__(self, key, value):
62        if key.startswith("_"):
63            self.__dict__[key] = value
64        else:
65            self[key] = value
66
67
68class NoParent:
69    def __call__(self):
70        return None
71
72    # def __nonzero__(self):
73    #     return False
74
75
76class Item:
77    def __init__(self, text, active=True):
78        self.text = text
79        self.extra = ""
80        # self.parent = parent
81        self._active = active
82        self.represents = []
83        self.parent = NoParent()
84        self.children = []
85
86    # def set_parent(self, item):
87    #     self.parent = item
88
89    @property
90    def active(self):
91        return self._active
92
93    def add(self, child):
94        child.parent = weakref.ref(self)
95        self.children.append(child)
96
97    def __str__(self):
98        return " + {0}".format(self.text)
99
100
101class ContainerItem(Item):
102    """This item is only active if it has children."""
103
104    @property
105    def active(self):
106        # print("active???", self, len(self.children))
107        # return True
108        return len(self.children) > 0
109
110
111class InactiveItem(Item):
112    def __init__(self, text):
113        super().__init__(text, active=False)
114
115    def __str__(self):
116        return " ( {0} )".format(self.text)
117
118
119class Model:
120    def __init__(self, show_all=False):
121        self.items = []
122        self.show_all = show_all
123
124    def add(self, item):
125        # if item.active or self.show_all:
126        if True:
127            if item.parent:
128                for i in range(len(self.items) - 1, -1, -1):
129                    if (
130                        self.items[0].parent == item.parent
131                        or self.items[0] == item.parent
132                    ):
133                        self.items.insert(i + 1, item)
134                        break
135                else:
136                    self.items.append(item)
137            else:
138                self.items.append(item)
139        return item
140
141    def remove(self, item):
142        self.items.remove(item)
143        return item
144
145    def last_item(self):
146        return self.items[-1]
147
148
149def normalize(value):
150    n = ""
151    for c in value.lower():
152        if c in "abcdefghijklmnopqrstuvwxyz0123456789+":
153            n += c
154    return n
155
156
157def create_joystick_port_item(c, num: int) -> Item:
158    # FIXME: retrieve uae_ option
159    mode = c.get("joystick_port_{0}_mode".format(num))
160    if mode == "nothing":
161        item = InactiveItem("Joystick Port {0}".format(num))
162    else:
163        item = Item("Joystick Port {0}".format(num))
164        # if mode == "joystick":
165        #     device_text = "[J]"
166        # elif mode == "mouse":
167        #     device_text = "[M]"
168        # elif mode == "cd32_gamepad":
169        #     device_text = "[C]"
170        # else:
171        #     device_text = "[?]"
172        # # FIXME: auto-calculated device
173        # device = c.get("joystick_port_{0}".format(num))
174        # if not device:
175        #     device = "???"
176        # device_text += " " + device
177        # device_item = Item(device_text)
178        # item.add(device_item)
179    return item
180
181
182def create_slirp_item(c):
183    implementation = c.uae_slirp_implementation
184    if implementation == "auto":
185        name = "Auto"
186    elif implementation == "none":
187        name = "None"
188    elif implementation == "builtin":
189        name = "Built-in"
190    elif implementation == "qemu":
191        name = "QEMU"
192    else:
193        name = implementation
194    slirp_item = Item("Slirp ({})".format(name))
195
196    if c.uae_slirp_ports:
197        slirp_ports_item = Item("Ports: " + c.uae_slirp_ports)
198        slirp_item.add(slirp_ports_item)
199    if c.uae_slirp_redir:
200        slirp_redirect_item = Item("Redirect: " + c.uae_slirp_redir)
201        slirp_item.add(slirp_redirect_item)
202
203    return slirp_item
204
205
206def create_model(c, show_all=False):
207    model = Model(show_all=show_all)
208
209    # if c.ntsc_mode:
210    #     model_item = Item(c.int_model_name + " NTSC")
211    # else:
212    #     model_item = Item(c.int_model_name + " PAL")
213    # model_item.represents = ["amiga_model", "ntsc_mode"]
214    # model.add(model_item)
215
216    text = c.int_chipset_name
217    if c.uae_chipset_compatible != "-":
218        text += " ({0})".format(c.uae_chipset_compatible)
219    if c.ntsc_mode:
220        text += " NTSC"
221    else:
222        text += " PAL"
223    chipset_item = Item(text)
224    chipset_item.represents = [
225        "uae_chipset",
226        "uae_chipset_compatible",
227        "ntsc_mode",
228    ]
229    model.add(chipset_item)
230
231    if c.uae_chipset == "aga":
232        text = "Alice (AGA)"
233        if c.ntsc_mode:
234            text += " NTSC"
235        else:
236            text += " PAL"
237        # alice_item = Item(text)
238        # chipset_item.add(alice_item)
239        # lisa_item = Item("Lisa (AGA)")
240        # chipset_item.add(lisa_item)
241        # paula_item = Item("Paula (AGA)")
242        # chipset_item.add(paula_item)
243    else:
244        # http://en.wikipedia.org/wiki/MOS_Technology_Agnus
245        if c.uae_chipset in ["ecs_agnus", "ecs"]:
246            text = "Agnus (ECS)"
247        else:
248            text = "Agnus"
249        if c.ntsc_mode:
250            text += " NTSC"
251        else:
252            text += " PAL"
253        # agnus_item = Item(text)
254        # chipset_item.add(agnus_item)
255        # if c.uae_chipset in ["ecs_denise", "ecs"]:
256        #     denise_item = Item("Denise (ECS)")
257        # else:
258        #     denise_item = Item("Denise")
259        # chipset_item.add(denise_item)
260        # if c.uae_chipset in ["ecs"]:
261        #     paula_item = Item("Paula")
262        # else:
263        #     paula_item = Item("Paula")
264        # chipset_item.add(paula_item)
265
266    # if c.kickstart_file:
267    #     kickstart_item = Item("Custom Kickstart [FIXME]")
268    # else:
269    #     kickstart_item = Item("Default Kickstart [FIXME]")
270    kickstart_item = Item(
271        "Kickstart {} Rev {}".format(
272            c.int_kickstart_version, c.int_kickstart_revision
273        )
274    )
275    model.add(kickstart_item)
276
277    if c.int_kickstart_ext_sha1 == "5bef3d628ce59cc02a66e6e4ae0da48f60e78f7f":
278        kickstart_ext_item = Item("CD32 Extended ROM")
279    elif (
280        c.int_kickstart_ext_sha1 == "7ba40ffa17e500ed9fed041f3424bd81d9c907be"
281    ):
282        kickstart_ext_item = Item("CDTV Extended ROM")
283    else:
284        kickstart_ext_item = InactiveItem("Extended ROM")
285    model.add(kickstart_ext_item)
286
287    # if c.uae_cd32cd == "true":
288    #     akiko_item = Item("Akiko Chip")
289    #     # chipset_item.add(akiko_item)
290    #     model.add(akiko_item)
291
292    jit_text = " [JIT]" if c.jit_compiler == "1" else ""
293    cpu_item = Item("MC" + c.int_cpu_name + jit_text)
294    cpu_item.represents = ["cpu", "uae_cpu_model"]  # FIXME: uae_cpu_type
295
296    if c.int_accelerator_name:
297        item = Item("{0}".format(c.int_accelerator_name))
298        accelerator_item = model.add(item)
299    else:
300        accelerator_item = InactiveItem("No Accelerator")
301        model.add(accelerator_item)
302    accelerator_item.represents = ["accelerator", "uae_cpuboard_type"]
303
304    if accelerator_item.active:
305        accelerator_item.add(cpu_item)
306    else:
307        model.add(cpu_item)
308
309    if accelerator_item.active:
310        if c.int_ppc_model:
311            item = Item("PowerPC {0}".format(c.int_ppc_model))
312            accelerator_item.add(item)
313
314        # model.remove(cpu_item)
315        # cpu_item.set_parent(accelerator_item)
316        # model.add(cpu_item)
317
318        if c.int_cpuboardmem1_size:
319            size = "{0} MB".format(
320                int(c.int_cpuboardmem1_size) // (1024 * 1024)
321            )
322            item = Item("{0} RAM".format(size))
323            item.represents = ["uae_cpuboard1mem_size"]
324            accelerator_item.add(item)
325
326        item = Item("ROM/Flash [FIXME]")
327        item.represents = ["accelerator_rom"]
328        accelerator_item.add(item)
329
330        if c.uae_cpuboard_type == "CyberStormPPC":
331            # FIXME: other too?
332            accelerator_scsi_item = Item("CyberStorm SCSI")
333            accelerator_item.add(accelerator_scsi_item)
334
335    if int(c.uae_mmu_model):
336        mmu_item = Item("{0} MMU".format(c.uae_mmu_model))
337    else:
338        mmu_item = InactiveItem("No MMU")
339    cpu_item.represents = ["mmu_model"]
340    cpu_item.add(mmu_item)
341
342    if int(c.uae_fpu_model):
343        fpu_item = Item("{0} FPU".format(c.uae_fpu_model))
344    else:
345        fpu_item = InactiveItem("No FPU")
346        # fpu_item.set_parent(cpu_item)
347    fpu_item.represents = ["fpu_model"]
348    if c.uae_fpu_model == c.uae_cpu_model:
349        cpu_item.add(fpu_item)
350    else:
351        model.add(fpu_item)
352
353    if int(c.int_chipmem_size) % (1024 * 1024) == 0:
354        size = "{0} MB".format(int(c.int_chipmem_size) // (1024 * 1024))
355    else:
356        size = "{0} KB".format(int(c.int_chipmem_size) // 1024)
357    chipmem_item = Item("{0} Chip RAM".format(size))
358    chipmem_item.represents = ["chip_memory", "uae_chipmem_size"]
359    model.add(chipmem_item)
360
361    if int(c.int_mbresmem_low_size):
362        size = "{0} MB".format(int(c.int_mbresmem_low_size) // (1024 * 1024))
363        item = Item("{0} Fast RAM".format(size))
364    else:
365        item = InactiveItem("No Fast RAM")
366    item.extra = "Motherboard"
367    item.represents = ["uae_a3000mem_size"]
368    model.add(item)
369
370    trapdoor_item = ContainerItem("Trapdoor Slot")
371    zorro_ii_item = ContainerItem("Zorro II Bus")
372    zorro_iii_item = ContainerItem("Zorro III Bus")
373
374    flatten = True
375
376    if int(c.int_bogomem_size):
377        if int(c.int_bogomem_size) % (1024 * 1024) == 0:
378            size = "{0} MB".format(int(c.int_bogomem_size) // (1024 * 1024))
379        else:
380            size = "{0} KB".format(int(c.int_bogomem_size) // 1024)
381        bogomem_item = Item("{0} Slow RAM".format(size))
382    else:
383        bogomem_item = InactiveItem("No Slow RAM")
384    bogomem_item.represents = ["slow_memory", "uae_bogomem_size"]
385    if flatten:
386        bogomem_item.extra = "Trapdoor"
387        model.add(bogomem_item)
388    else:
389        trapdoor_item.add(bogomem_item)
390
391    if int(c.int_fastmem_size):
392        if int(c.int_fastmem_size) % (1024 * 1024) == 0:
393            size = "{0} MB".format(int(c.int_fastmem_size) // (1024 * 1024))
394        else:
395            size = "{0} KB".format(int(c.int_fastmem_size) // 1024)
396        # fastmem_item = Item("{0} Zorro II Fast RAM".format(size))
397        fastmem_item = Item("{0} Fast RAM".format(size))
398    else:
399        fastmem_item = InactiveItem("No Zorro II Fast RAM")
400    fastmem_item.represents = ["fast_memory", "uae_fastmem_size"]
401    if flatten:
402        fastmem_item.extra = "Zorro II"
403        model.add(fastmem_item)
404    else:
405        zorro_ii_item.add(fastmem_item)
406
407    if int(c.int_z3fastmem_size):
408        size = "{0} MB".format(int(c.int_z3fastmem_size) // (1024 * 1024))
409        # z3fastmem_item = Item("{0} Zorro III Fast RAM".format(size))
410        z3fastmem_item = Item("{0} Fast RAM".format(size))
411    else:
412        z3fastmem_item = InactiveItem("No Zorro III Fast RAM")
413    z3fastmem_item.represents = ["zorro_iii_memory", "uae_z3mem_size"]
414    if flatten:
415        z3fastmem_item.extra = "Zorro III"
416        model.add(z3fastmem_item)
417    else:
418        zorro_iii_item.add(z3fastmem_item)
419
420    if c.uae_rtc != "none":
421        rtc_item = Item("{0} RTC".format(c.uae_rtc))
422    else:
423        rtc_item = InactiveItem("No Real Time Clock")
424    rtc_item.represents = ["uae_rtc"]
425    if bogomem_item.active and c.uae_rtc == "MSM6242B":
426        if flatten:
427            # bogomem_item.add(rtc_item)
428            model.add(rtc_item)
429        else:
430            trapdoor_item.add(rtc_item)
431    else:
432        model.add(rtc_item)
433
434    if c.uae_cd32fmv == "true":
435
436        fmv_item = Item("CD32 FMV Module")
437        model.add(fmv_item)
438
439        fmv_rom_item = Item("CD32 FMV ROM")
440        fmv_item.add(fmv_rom_item)
441
442    model.add(trapdoor_item)
443    model.add(zorro_ii_item)
444    model.add(zorro_iii_item)
445
446    # resident_item = ContainerItem("Resident Libraries")
447    # model.add(resident_item)
448    resident_item = model
449
450    if c.int_uae_boot_rom == "true":
451        uae_boot_rom_item = Item("UAE Boot ROM")
452        resident_item.add(uae_boot_rom_item)
453
454        uae_resource_item = Item("UAE uae.resource")
455        uae_boot_rom_item.add(uae_resource_item)
456
457        if c.uae_bsdsocket_emu == "true":
458            bsdsocket_item = Item("UAE bsdsocket.library")
459        else:
460            bsdsocket_item = InactiveItem("No bsdsocket.library")
461        bsdsocket_item.represents = ["bsdsocket_library", "uae_bsdsocket_emu"]
462        resident_item.add(bsdsocket_item)
463
464        if c.uae_native_code == "true":
465            uaenative_library_item = Item("UAE uaenative.library")
466        else:
467            uaenative_library_item = InactiveItem("No uaenative.library")
468        uaenative_library_item.represents = [
469            "uaenative.library",
470            "uae_native_code",
471        ]
472        resident_item.add(uaenative_library_item)
473
474        if c.uae_sana2 == "true":
475            uaenet_device_item = Item("UAE uaenet.device")
476        else:
477            uaenet_device_item = InactiveItem("No uaenet.device")
478        uaenet_device_item.represents = ["uae_sana2"]
479        resident_item.add(uaenet_device_item)
480
481    # if c.uae_a2065:
482    #     a2065_item = Item("A2065 [Network Card]")
483    #     a2065_item.represents = ["uae_a2065"]
484    #     zorro_ii_item.add(a2065_item)
485    #
486    #     if c.uae_a2065 == "slirp":
487    #         slirp_item = create_slirp_item(c)
488    #         a2065_item.add(slirp_item)
489
490    if c.uae_gfxcard_type:
491        graphics_card_item = Item(
492            "{} {} MB".format(c.int_graphics_card_name, c.uae_gfxcard_size)
493        )
494        if flatten:
495            if c.int_graphics_card_bus == "zorro-ii":
496                graphics_card_item.extra = "Zorro II"
497            elif c.int_graphics_card_bus == "zorro-iii":
498                graphics_card_item.extra = "Zorro III"
499            model.add(graphics_card_item)
500        elif c.int_graphics_card_bus == "zorro-ii":
501            zorro_ii_item.add(graphics_card_item)
502        elif c.int_graphics_card_bus == "zorro-iii":
503            zorro_iii_item.add(graphics_card_item)
504        else:
505            model.add(graphics_card_item)
506
507    if c.uae_toccata == "true":
508        sound_card_item = Item("Toccata")
509        sound_card_item.represents = ["sound_card", "uae_toccata"]
510        if flatten:
511            sound_card_item.extra = "Zorro II"
512            model.add(sound_card_item)
513        else:
514            zorro_ii_item.add(sound_card_item)
515
516    if c.uae_a2065:
517        network_card_item = Item("A2065")
518        network_card_item.represents = ["network_card", "uae_a2065"]
519        if flatten:
520            network_card_item.extra = "Zorro II"
521            model.add(network_card_item)
522        else:
523            zorro_ii_item.add(network_card_item)
524
525    joystick_port_0_item = create_joystick_port_item(c, 0)
526    joystick_port_1_item = create_joystick_port_item(c, 1)
527    joystick_port_2_item = create_joystick_port_item(c, 2)
528    joystick_port_3_item = create_joystick_port_item(c, 3)
529
530    model.add(joystick_port_0_item)
531    model.add(joystick_port_1_item)
532    # parallel_port_item = Item("Parallel Port")
533
534    if joystick_port_2_item.active or joystick_port_3_item.active:
535        parallel_port_item = Item("Parallel Port Joystick Adapter")
536        model.add(parallel_port_item)
537        parallel_port_item.add(joystick_port_2_item)
538        parallel_port_item.add(joystick_port_3_item)
539    else:
540        parallel_port_item = InactiveItem("No Parallel Port Device")
541        model.add(parallel_port_item)
542
543    for i in range(4):
544        drive_type = getattr(c, "uae_floppy{0}type".format(i))
545        if drive_type == "0":
546            description = '3.5" DD'
547        elif drive_type == "1":
548            description = '3.5" HD'
549        elif drive_type == "2":
550            description = '5.25" SD'
551        elif drive_type == "3":
552            description = '3.5" DD (ESCOM)'
553        else:
554            description = None
555        if description:
556            drive_item = Item(
557                "{0} Floppy Drive [DF{1}]".format(description, i)
558            )
559        else:
560            drive_item = InactiveItem("No Floppy Drive [DF{0}]".format(i))
561        drive_item.represents = [
562            "floppy_drive_{0}".format(i),
563            "uae_df{0}type".format(i),
564        ]
565        model.add(drive_item)
566        # path = getattr(c, "uae_floppy{0}".format(i))
567        # if path:
568        #     name = os.path.basename(path)
569        #     disk_item = Item(name)
570        #     drive_item.add(disk_item)
571
572    return model
573