from typing import Any, List, Optional, TypeVar, Callable, Type, cast
from uuid import UUID


T = TypeVar("T")


def from_list(f: Callable[[Any], T], x: Any) -> List[T]:
    assert isinstance(x, list)
    return [f(y) for y in x]


def to_class(c: Type[T], x: Any) -> dict:
    assert isinstance(x, c)
    return cast(Any, x).to_dict()


def from_str(x: Any) -> str:
    assert isinstance(x, str)
    return x


def from_int(x: Any) -> int:
    assert isinstance(x, int) and not isinstance(x, bool)
    return x


def from_none(x: Any) -> Any:
    assert x is None
    return x


def from_union(fs, x):
    for f in fs:
        try:
            return f(x)
        except:
            pass
    assert False


class WelcomeCustomFields:
    pass

    def __init__(self, ) -> None:
        pass

    @staticmethod
    def from_dict(obj: Any) -> 'WelcomeCustomFields':
        assert isinstance(obj, dict)
        return WelcomeCustomFields()

    def to_dict(self) -> dict:
        result: dict = {}
        return result


class Target:
    entity_iid: UUID
    layer_iid: UUID
    level_iid: UUID
    world_iid: UUID

    def __init__(self, entity_iid: UUID, layer_iid: UUID, level_iid: UUID, world_iid: UUID) -> None:
        self.entity_iid = entity_iid
        self.layer_iid = layer_iid
        self.level_iid = level_iid
        self.world_iid = world_iid

    @staticmethod
    def from_dict(obj: Any) -> 'Target':
        assert isinstance(obj, dict)
        entity_iid = UUID(obj.get("entityIid"))
        layer_iid = UUID(obj.get("layerIid"))
        level_iid = UUID(obj.get("levelIid"))
        world_iid = UUID(obj.get("worldIid"))
        return Target(entity_iid, layer_iid, level_iid, world_iid)

    def to_dict(self) -> dict:
        result: dict = {}
        result["entityIid"] = str(self.entity_iid)
        result["layerIid"] = str(self.layer_iid)
        result["levelIid"] = str(self.level_iid)
        result["worldIid"] = str(self.world_iid)
        return result


class ButtonCustomFields:
    targets: List[Target]

    def __init__(self, targets: List[Target]) -> None:
        self.targets = targets

    @staticmethod
    def from_dict(obj: Any) -> 'ButtonCustomFields':
        assert isinstance(obj, dict)
        targets = from_list(Target.from_dict, obj.get("targets"))
        return ButtonCustomFields(targets)

    def to_dict(self) -> dict:
        result: dict = {}
        result["targets"] = from_list(lambda x: to_class(Target, x), self.targets)
        return result


class Button:
    id: str
    iid: UUID
    layer: str
    x: int
    y: int
    width: int
    height: int
    color: int
    custom_fields: ButtonCustomFields

    def __init__(self, id: str, iid: UUID, layer: str, x: int, y: int, width: int, height: int, color: int, custom_fields: ButtonCustomFields) -> None:
        self.id = id
        self.iid = iid
        self.layer = layer
        self.x = x
        self.y = y
        self.width = width
        self.height = height
        self.color = color
        self.custom_fields = custom_fields

    @staticmethod
    def from_dict(obj: Any) -> 'Button':
        assert isinstance(obj, dict)
        id = from_str(obj.get("id"))
        iid = UUID(obj.get("iid"))
        layer = from_str(obj.get("layer"))
        x = from_int(obj.get("x"))
        y = from_int(obj.get("y"))
        width = from_int(obj.get("width"))
        height = from_int(obj.get("height"))
        color = from_int(obj.get("color"))
        custom_fields = ButtonCustomFields.from_dict(obj.get("customFields"))
        return Button(id, iid, layer, x, y, width, height, color, custom_fields)

    def to_dict(self) -> dict:
        result: dict = {}
        result["id"] = from_str(self.id)
        result["iid"] = str(self.iid)
        result["layer"] = from_str(self.layer)
        result["x"] = from_int(self.x)
        result["y"] = from_int(self.y)
        result["width"] = from_int(self.width)
        result["height"] = from_int(self.height)
        result["color"] = from_int(self.color)
        result["customFields"] = to_class(ButtonCustomFields, self.custom_fields)
        return result


class DoorCustomFields:
    locked_with: Optional[str]

    def __init__(self, locked_with: Optional[str]) -> None:
        self.locked_with = locked_with

    @staticmethod
    def from_dict(obj: Any) -> 'DoorCustomFields':
        assert isinstance(obj, dict)
        locked_with = from_union([from_none, from_str], obj.get("lockedWith"))
        return DoorCustomFields(locked_with)

    def to_dict(self) -> dict:
        result: dict = {}
        result["lockedWith"] = from_union([from_none, from_str], self.locked_with)
        return result


class Door:
    id: str
    iid: UUID
    layer: str
    x: int
    y: int
    width: int
    height: int
    color: int
    custom_fields: DoorCustomFields

    def __init__(self, id: str, iid: UUID, layer: str, x: int, y: int, width: int, height: int, color: int, custom_fields: DoorCustomFields) -> None:
        self.id = id
        self.iid = iid
        self.layer = layer
        self.x = x
        self.y = y
        self.width = width
        self.height = height
        self.color = color
        self.custom_fields = custom_fields

    @staticmethod
    def from_dict(obj: Any) -> 'Door':
        assert isinstance(obj, dict)
        id = from_str(obj.get("id"))
        iid = UUID(obj.get("iid"))
        layer = from_str(obj.get("layer"))
        x = from_int(obj.get("x"))
        y = from_int(obj.get("y"))
        width = from_int(obj.get("width"))
        height = from_int(obj.get("height"))
        color = from_int(obj.get("color"))
        custom_fields = DoorCustomFields.from_dict(obj.get("customFields"))
        return Door(id, iid, layer, x, y, width, height, color, custom_fields)

    def to_dict(self) -> dict:
        result: dict = {}
        result["id"] = from_str(self.id)
        result["iid"] = str(self.iid)
        result["layer"] = from_str(self.layer)
        result["x"] = from_int(self.x)
        result["y"] = from_int(self.y)
        result["width"] = from_int(self.width)
        result["height"] = from_int(self.height)
        result["color"] = from_int(self.color)
        result["customFields"] = to_class(DoorCustomFields, self.custom_fields)
        return result


class ItemCustomFields:
    type: str

    def __init__(self, type: str) -> None:
        self.type = type

    @staticmethod
    def from_dict(obj: Any) -> 'ItemCustomFields':
        assert isinstance(obj, dict)
        type = from_str(obj.get("type"))
        return ItemCustomFields(type)

    def to_dict(self) -> dict:
        result: dict = {}
        result["type"] = from_str(self.type)
        return result


class Item:
    id: str
    iid: UUID
    layer: str
    x: int
    y: int
    width: int
    height: int
    color: int
    custom_fields: ItemCustomFields

    def __init__(self, id: str, iid: UUID, layer: str, x: int, y: int, width: int, height: int, color: int, custom_fields: ItemCustomFields) -> None:
        self.id = id
        self.iid = iid
        self.layer = layer
        self.x = x
        self.y = y
        self.width = width
        self.height = height
        self.color = color
        self.custom_fields = custom_fields

    @staticmethod
    def from_dict(obj: Any) -> 'Item':
        assert isinstance(obj, dict)
        id = from_str(obj.get("id"))
        iid = UUID(obj.get("iid"))
        layer = from_str(obj.get("layer"))
        x = from_int(obj.get("x"))
        y = from_int(obj.get("y"))
        width = from_int(obj.get("width"))
        height = from_int(obj.get("height"))
        color = from_int(obj.get("color"))
        custom_fields = ItemCustomFields.from_dict(obj.get("customFields"))
        return Item(id, iid, layer, x, y, width, height, color, custom_fields)

    def to_dict(self) -> dict:
        result: dict = {}
        result["id"] = from_str(self.id)
        result["iid"] = str(self.iid)
        result["layer"] = from_str(self.layer)
        result["x"] = from_int(self.x)
        result["y"] = from_int(self.y)
        result["width"] = from_int(self.width)
        result["height"] = from_int(self.height)
        result["color"] = from_int(self.color)
        result["customFields"] = to_class(ItemCustomFields, self.custom_fields)
        return result


class PlayerCustomFields:
    ammo: int
    life: int

    def __init__(self, ammo: int, life: int) -> None:
        self.ammo = ammo
        self.life = life

    @staticmethod
    def from_dict(obj: Any) -> 'PlayerCustomFields':
        assert isinstance(obj, dict)
        ammo = from_int(obj.get("ammo"))
        life = from_int(obj.get("life"))
        return PlayerCustomFields(ammo, life)

    def to_dict(self) -> dict:
        result: dict = {}
        result["ammo"] = from_int(self.ammo)
        result["life"] = from_int(self.life)
        return result


class Player:
    id: str
    iid: UUID
    layer: str
    x: int
    y: int
    width: int
    height: int
    color: int
    custom_fields: PlayerCustomFields

    def __init__(self, id: str, iid: UUID, layer: str, x: int, y: int, width: int, height: int, color: int, custom_fields: PlayerCustomFields) -> None:
        self.id = id
        self.iid = iid
        self.layer = layer
        self.x = x
        self.y = y
        self.width = width
        self.height = height
        self.color = color
        self.custom_fields = custom_fields

    @staticmethod
    def from_dict(obj: Any) -> 'Player':
        assert isinstance(obj, dict)
        id = from_str(obj.get("id"))
        iid = UUID(obj.get("iid"))
        layer = from_str(obj.get("layer"))
        x = from_int(obj.get("x"))
        y = from_int(obj.get("y"))
        width = from_int(obj.get("width"))
        height = from_int(obj.get("height"))
        color = from_int(obj.get("color"))
        custom_fields = PlayerCustomFields.from_dict(obj.get("customFields"))
        return Player(id, iid, layer, x, y, width, height, color, custom_fields)

    def to_dict(self) -> dict:
        result: dict = {}
        result["id"] = from_str(self.id)
        result["iid"] = str(self.iid)
        result["layer"] = from_str(self.layer)
        result["x"] = from_int(self.x)
        result["y"] = from_int(self.y)
        result["width"] = from_int(self.width)
        result["height"] = from_int(self.height)
        result["color"] = from_int(self.color)
        result["customFields"] = to_class(PlayerCustomFields, self.custom_fields)
        return result


class Entities:
    door: List[Door]
    item: List[Item]
    button: List[Button]
    player: List[Player]

    def __init__(self, door: List[Door], item: List[Item], button: List[Button], player: List[Player]) -> None:
        self.door = door
        self.item = item
        self.button = button
        self.player = player

    @staticmethod
    def from_dict(obj: Any) -> 'Entities':
        assert isinstance(obj, dict)
        door = from_list(Door.from_dict, obj.get("Door"))
        item = from_list(Item.from_dict, obj.get("Item"))
        button = from_list(Button.from_dict, obj.get("Button"))
        player = from_list(Player.from_dict, obj.get("Player"))
        return Entities(door, item, button, player)

    def to_dict(self) -> dict:
        result: dict = {}
        result["Door"] = from_list(lambda x: to_class(Door, x), self.door)
        result["Item"] = from_list(lambda x: to_class(Item, x), self.item)
        result["Button"] = from_list(lambda x: to_class(Button, x), self.button)
        result["Player"] = from_list(lambda x: to_class(Player, x), self.player)
        return result


class NeighbourLevel:
    level_iid: UUID
    dir: str

    def __init__(self, level_iid: UUID, dir: str) -> None:
        self.level_iid = level_iid
        self.dir = dir

    @staticmethod
    def from_dict(obj: Any) -> 'NeighbourLevel':
        assert isinstance(obj, dict)
        level_iid = UUID(obj.get("levelIid"))
        dir = from_str(obj.get("dir"))
        return NeighbourLevel(level_iid, dir)

    def to_dict(self) -> dict:
        result: dict = {}
        result["levelIid"] = str(self.level_iid)
        result["dir"] = from_str(self.dir)
        return result


class Welcome:
    identifier: str
    unique_identifer: UUID
    x: int
    y: int
    width: int
    height: int
    bg_color: str
    neighbour_levels: List[NeighbourLevel]
    custom_fields: WelcomeCustomFields
    layers: List[str]
    entities: Entities

    def __init__(self, identifier: str, unique_identifer: UUID, x: int, y: int, width: int, height: int, bg_color: str, neighbour_levels: List[NeighbourLevel], custom_fields: WelcomeCustomFields, layers: List[str], entities: Entities) -> None:
        self.identifier = identifier
        self.unique_identifer = unique_identifer
        self.x = x
        self.y = y
        self.width = width
        self.height = height
        self.bg_color = bg_color
        self.neighbour_levels = neighbour_levels
        self.custom_fields = custom_fields
        self.layers = layers
        self.entities = entities

    @staticmethod
    def from_dict(obj: Any) -> 'Welcome':
        assert isinstance(obj, dict)
        identifier = from_str(obj.get("identifier"))
        unique_identifer = UUID(obj.get("uniqueIdentifer"))
        x = from_int(obj.get("x"))
        y = from_int(obj.get("y"))
        width = from_int(obj.get("width"))
        height = from_int(obj.get("height"))
        bg_color = from_str(obj.get("bgColor"))
        neighbour_levels = from_list(NeighbourLevel.from_dict, obj.get("neighbourLevels"))
        custom_fields = WelcomeCustomFields.from_dict(obj.get("customFields"))
        layers = from_list(from_str, obj.get("layers"))
        entities = Entities.from_dict(obj.get("entities"))
        return Welcome(identifier, unique_identifer, x, y, width, height, bg_color, neighbour_levels, custom_fields, layers, entities)

    def to_dict(self) -> dict:
        result: dict = {}
        result["identifier"] = from_str(self.identifier)
        result["uniqueIdentifer"] = str(self.unique_identifer)
        result["x"] = from_int(self.x)
        result["y"] = from_int(self.y)
        result["width"] = from_int(self.width)
        result["height"] = from_int(self.height)
        result["bgColor"] = from_str(self.bg_color)
        result["neighbourLevels"] = from_list(lambda x: to_class(NeighbourLevel, x), self.neighbour_levels)
        result["customFields"] = to_class(WelcomeCustomFields, self.custom_fields)
        result["layers"] = from_list(from_str, self.layers)
        result["entities"] = to_class(Entities, self.entities)
        return result


def welcome_from_dict(s: Any) -> Welcome:
    return Welcome.from_dict(s)


def welcome_to_dict(x: Welcome) -> Any:
    return to_class(Welcome, x)
