from ctypes import *
from ctypes import POINTER as _P

from .sdlconstants import *

# -------- Init -------- #

# -------- Version -------- #

class SDL_version(Structure):
    _fields_ = [("major", c_uint8), ("minor", c_uint8), ("patch", c_uint8)]

# -------- Other -------- #

HWND = c_void_p
HDC = c_void_p
HINSTANCE = c_void_p

class _wininfo(Structure):
    _fields_ = [("window", HWND), ("hdc", HDC), ("hinstance", HINSTANCE)]

class _winrtinfo(Structure):
    _fields_ = [("window", c_void_p)]

class _x11info(Structure):
    """Window information for X11."""
    _fields_ = [("display", c_void_p), ("window", c_ulong)]

class _dfbinfo(Structure):
    _fields_ = [("dfb", c_void_p), ("window", c_void_p), ("surface", c_void_p)]

class _cocoainfo(Structure):
    _fields_ = [("window", c_void_p)]

class _uikitinfo(Structure):
    _fields_ = [("window", c_void_p), ("framebuffer", c_uint32), ("colorbuffer", c_uint32), ("resolveFramebuffer", c_uint32)]

class _wl(Structure):
    _fields_ = [("display", c_void_p), ("surface", c_void_p), ("shell_surface", c_void_p), ("egl_window", c_void_p),
                ("xdg_surface", c_void_p), ("xdg_toplevel", c_void_p), ("xdg_popup", c_void_p), ("xdg_positioner", c_void_p)]

class _mir(Structure):
    _fields_ = [("connection", c_void_p), ("surface", c_void_p)]

class _android(Structure):
    _fields_ = [("window", c_void_p), ("surface", c_void_p)]

class _os2(Structure):
    _fields_ = [("hwnd", HWND), ("hwndFrame", HWND)]

class _vivante(Structure):
    _fields_ = [("display", c_void_p), ("window", c_void_p)]

class _kmsdrm(Structure):
    _fields_ = [("dev_index", c_int), ("drm_fd", c_int), ("gbm_dev", c_void_p)]

class _info(Union):
    _fields_ = [("win", _wininfo), ("winrt", _winrtinfo), ("x11", _x11info), ("dfb", _dfbinfo), ("cocoa", _cocoainfo), ("uikit", _uikitinfo),
                ("wl", _wl), ("mir", _mir), ("android", _android), ("os2", _os2), ("vivante", _vivante), ("kmsdrm", _kmsdrm), ("dummy", (c_uint8 * 64))]

class SDL_SysWMinfo(Structure):
    _fields_ = [("version", SDL_version), ("subsystem", c_int), ("info", _info)]

class _hidden(Union):
    pass

class SDL_RWops(Structure):
    pass

_sdlsize = CFUNCTYPE(c_int64, _P(SDL_RWops))
_sdlseek = CFUNCTYPE(c_int64, _P(SDL_RWops), c_int64, c_int)
_sdlread = CFUNCTYPE(c_size_t, _P(SDL_RWops), c_void_p, c_size_t, c_size_t)
_sdlwrite = CFUNCTYPE(c_size_t, _P(SDL_RWops), c_void_p, c_size_t, c_size_t)
_sdlclose = CFUNCTYPE(c_int, _P(SDL_RWops))
SDL_RWops._fields_ = [
    ("size", _sdlsize),
    ("seek", _sdlseek),
    ("read", _sdlread),
    ("write", _sdlwrite),
    ("close", _sdlclose),
    ("type", c_uint32),
    ("hidden", _hidden),
]

class SDL_Locale(Structure):
    _fields_ = [("_language", c_char_p), ("_country", c_char_p)]

    @property
    def language(self):
        return self._language.decode() if self._language is not None else self._language

    @property
    def country(self):
        return self._country.decode() if self._country is not None else self._country

# -------- Audio -------- #

# -------- Video -------- #

class SDL_Point(Structure):
    _fields_ = [("x", c_int), ("y", c_int)]

    def __init__(self, x=0, y=0):
        super(SDL_Point, self).__init__()
        self.x, self.y = x, y

    def __repr__(self):
        return f"SDL_Point(x={self.x}, y={self.y})"

    def __copy__(self):
        return SDL_Point(self.x, self.y)

class SDL_FPoint(Structure):
    _fields_ = [("x", c_float), ("y", c_float)]

    def __init__(self, x=0.0, y=0.0):
        super(SDL_FPoint, self).__init__()
        self.x, self.y = x, y

    def __repr__(self):
        return f"SDL_FPoint(x={self.x}, y={self.y})"

    def __copy__(self):
        return SDL_FPoint(self.x, self.y)

class SDL_Rect(Structure):
    _fields_ = [("x", c_int), ("y", c_int), ("w", c_int), ("h", c_int)]

    def __init__(self, x=0, y=0, w=0, h=0):
        super(SDL_Rect, self).__init__()
        self.x, self.y, self.w, self.h = x, y, w, h

    def __repr__(self):
        return f"SDL_Rect(x={self.x}, y={self.y}, w={self.w}, h={self.h})"

    def __copy__(self):
        return SDL_Rect(self.x, self.y, self.w, self.h)

class SDL_FRect(Structure):
    _fields_ = [("x", c_float), ("y", c_float), ("w", c_float), ("h", c_float)]

    def __init__(self, x=0.0, y=0.0, w=0.0, h=0.0):
        super(SDL_FRect, self).__init__()
        self.x, self.y, self.w, self.h = x, y, w, h

    def __repr__(self):
        return f"SDL_FRect(x={self.x}, y={self.y}, w={self.w}, h={self.h})"

    def __copy__(self):
        return SDL_FRect(self.x, self.y, self.w, self.h)

# -- Pixels -- #

class SDL_Color(Structure):
    _fields_ = [("r", c_uint8), ("g", c_uint8), ("b", c_uint8), ("a", c_uint8)]

    def __init__(self, r=255, g=255, b=255, a=255):
        super(SDL_Color, self).__init__()
        self.r, self.g, self.b, self.a = r, g, b, a

    def __repr__(self):
        return "SDL_Color(r=%d, g=%d, b=%d, a=%d)" % (self.r, self.g, self.b, self.a)

    def __copy__(self):
        return SDL_Color(self.r, self.g, self.b, self.a)

class SDL_Palette(Structure):
    _fields_ = [("ncolors", c_int), ("colors", _P(SDL_Color)), ("version", c_uint32), ("refcount", c_int)]

class SDL_PixelFormat(Structure):
    pass

SDL_PixelFormat._fields_ = [
    ("format", c_uint32), ("palette", _P(SDL_Palette)), ("BitsPerPixel", c_uint8), ("BytesPerPixel", c_uint8), ("padding", c_uint8 * 2),
    ("Rmask", c_uint32), ("Gmask", c_uint32), ("Bmask", c_uint32), ("Amask", c_uint32), ("Rloss", c_uint8), ("Gloss", c_uint8), ("Bloss", c_uint8),
    ("Aloss", c_uint8), ("Rshift", c_uint8), ("Gshift", c_uint8), ("Bshift", c_uint8), ("Ashift", c_uint8), ("refcount", c_int), ("next", _P(SDL_PixelFormat))]

# -- Surface -- #

class SDL_Surface(Structure):
    _fields_ = [("flags", c_uint32), ("format", _P(SDL_PixelFormat)), ("w", c_int), ("h", c_int), ("pitch", c_int),
                ("pixels", c_void_p), ("userdata", c_void_p), ("list_blitmap", c_void_p), ("refcount", c_int)]

# -- Window -- #

class SDL_Window(c_void_p):
    pass

class SDL_DisplayMode(Structure):
    _fields_ = [("format", c_uint32),
                ("w", c_int),
                ("h", c_int),
                ("refresh_rate", c_int),
                ("driverdata", c_void_p)
                ]

    def __init__(self, format_=0, w=0, h=0, refresh_rate=0):
        super(SDL_DisplayMode, self).__init__()
        self.format = format_
        self.w = w
        self.h = h
        self.refresh_rate = refresh_rate

    def __repr__(self):
        s = "SDL_DisplayMode({0}x{1} @ {2}Hz)"
        return s.format(self.w, self.h, self.refresh_rate)

    def __eq__(self, mode):
        return self.format == mode.format and self.w == mode.w and \
            self.h == mode.h and self.refresh_rate == mode.refresh_rate

    def __ne__(self, mode):
        return self.format != mode.format or self.w != mode.w or \
            self.h != mode.h or self.refresh_rate != mode.refresh_rate

class SDL_WindowShapeParams(Union):
    _fields_ = [("binarizationCutoff", c_uint8), ("colorKey", SDL_Color)]

class SDL_WindowShapeMode(Structure):
    _fields_ = [("mode", c_int), ("parameters", SDL_WindowShapeParams)]

    def __init__(self, mode=ShapeModeDefault, parameters=SDL_WindowShapeParams()):
        super(SDL_WindowShapeMode, self).__init__()
        self.mode, self.parameters = mode, parameters

# -- Render -- #

class SDL_RendererInfo(Structure):
    _fields_ = [
        ("name", c_char_p),
        ("flags", c_uint32),
        ("num_texture_formats", c_uint32),
        ("texture_formats", c_uint32 * 16),
        ("max_texture_width", c_int),
        ("max_texture_height", c_int),
    ]

class SDL_Renderer(c_void_p):
    pass

class SDL_Texture(c_void_p):
    pass

# -------- MessageBox -------- #

class SDL_MessageBoxButtonData(Structure):
    _fields_ = [("flags", Uint32), ("buttonid", c_int), ("text", c_char_p)]

class SDL_MessageBoxColor(Structure):
    _fields_ = [("r", Uint8), ("g", Uint8), ("b", Uint8)]

class SDL_MessageBoxColorScheme(Structure):
    _fields_ = [("colors", (SDL_MessageBoxColor * SDL_MESSAGEBOX_COLOR_MAX))]

class SDL_MessageBoxData(Structure):
    _fields_ = [
        ("flags", Uint32),
        ("window", _P(SDL_Window)),
        ("title", c_char_p),
        ("message", c_char_p),
        ("numbuttons", c_int),
        ("buttons", _P(SDL_MessageBoxButtonData)),
        ("colorScheme", _P(SDL_MessageBoxColorScheme)),
    ]

# -------- Events -------- #
# -- Touch -- #

class SDL_Finger(Structure):
    _fields_ = [("id", SDL_FingerID), ("x", c_float), ("y", c_float), ("pressure", c_float)]

# -- Mouse -- #

class SDL_Cursor(c_void_p):
    pass

# -- Joystick -- #

class SDL_JoystickGUID(Structure):
    _fields_ = [("data", (c_uint8 * 16))]

class SDL_Joystick(c_void_p):
    pass

class SDL_VirtualJoystickDesc(Structure):
    _fields_ = [
        ("version", c_uint16),
        ("type", c_uint16),
        ("naxes", c_uint16),
        ("nbuttons", c_uint16),
        ("nhats", c_uint16),
        ("vendor_id", c_uint16),
        ("product_id", c_uint16),
        ("padding", c_uint16),
        ("button_mask", c_uint32),
        ("axis_mask", c_uint32),
        ("name", c_char_p),
        ("userdata", c_void_p),
        ("Update", CFUNC_Update),
        ("SetPlayerIndex", CFUNC_SetPlayerIndex),
        ("Rumble", CFUNC_Rumble),
        ("RumbleTriggers", CFUNC_RumbleTriggers),
        ("SetLED", CFUNC_SetLED),
        ("SendEffect", CFUNC_SendEffect),
    ]

# -- Controller -- #

class _gchat(Structure):
    _fields_ = [("hat", c_int), ("hat_mask", c_int)]

class _gcvalue(Union):
    _fields_ = [("button", c_int), ("axis", c_int), ("hat", _gchat)]

class SDL_GameControllerButtonBind(Structure):
    _fields_ = [("bindType", SDL_GameControllerBindType), ("value", _gcvalue)]

class SDL_GameController(c_void_p):
    pass

# -- Events -- #

class SDL_CommonEvent(Structure):
    _fields_ = [("type", c_uint32), ("timestamp", c_uint32)]

class SDL_DisplayEvent(Structure):
    _fields_ = [
        ("type", c_uint32),
        ("timestamp", c_uint32),
        ("display", c_uint32),
        ("event", c_uint8),
        ("padding1", c_uint8),
        ("padding2", c_uint8),
        ("padding3", c_uint8),
        ("data1", c_int32),
    ]

class SDL_WindowEvent(Structure):
    _fields_ = [
        ("type", c_uint32),
        ("timestamp", c_uint32),
        ("windowID", c_uint32),
        ("event", c_uint8),
        ("padding1", c_uint8),
        ("padding2", c_uint8),
        ("padding3", c_uint8),
        ("data1", c_int32),
        ("data2", c_int32),
    ]

class SDL_Keysym(Structure):
    _fields_ = [("sym", SDL_Keycode), ("mod", c_uint16), ("unused", c_uint32)]

class SDL_KeyboardEvent(Structure):
    _fields_ = [
        ("type", c_uint32),
        ("timestamp", c_uint32),
        ("windowID", c_uint32),
        ("state", c_uint8),
        ("repeat", c_uint8),
        ("padding2", c_uint8),
        ("padding3", c_uint8),
        ("keysym", SDL_Keysym),
    ]

class SDL_TextEditingEvent(Structure):
    _fields_ = [
        ("type", c_uint32),
        ("timestamp", c_uint32),
        ("windowID", c_uint32),
        ("text", (c_char * SDL_TEXTEDITINGEVENT_TEXT_SIZE)),
        ("start", c_int32),
        ("length", c_int32),
    ]

class SDL_TextEditingExtEvent(Structure):
    _fields_ = [
        ("type", c_uint32),
        ("timestamp", c_uint32),
        ("windowID", c_uint32),
        ("text", c_char_p),
        ("start", c_int32),
        ("length", c_int32),
    ]

class SDL_TextInputEvent(Structure):
    _fields_ = [("type", c_uint32), ("timestamp", c_uint32), ("windowID", c_uint32), ("text", (c_char * SDL_TEXTINPUTEVENT_TEXT_SIZE))]

class SDL_MouseMotionEvent(Structure):
    _fields_ = [
        ("type", c_uint32),
        ("timestamp", c_uint32),
        ("windowID", c_uint32),
        ("which", c_uint32),
        ("state", c_uint32),
        ("x", c_int32),
        ("y", c_int32),
        ("xrel", c_int32),
        ("yrel", c_int32),
    ]

class SDL_MouseButtonEvent(Structure):
    _fields_ = [
        ("type", c_uint32),
        ("timestamp", c_uint32),
        ("windowID", c_uint32),
        ("which", c_uint32),
        ("button", c_uint8),
        ("state", c_uint8),
        ("clicks", c_uint8),
        ("padding1", c_uint8),
        ("x", c_int32),
        ("y", c_int32),
    ]

class SDL_MouseWheelEvent(Structure):
    _fields_ = [
        ("type", c_uint32),
        ("timestamp", c_uint32),
        ("windowID", c_uint32),
        ("which", c_uint32),
        ("x", c_int32),
        ("y", c_int32),
        ("direction", c_uint32),
        ("preciseX", c_float),
        ("preciseY", c_float),
        ("mouseX", c_int32),
        ("mouseY", c_int32)
    ]

class SDL_JoyAxisEvent(Structure):
    _fields_ = [
        ("type", c_uint32),
        ("timestamp", c_uint32),
        ("which", SDL_JoystickID),
        ("axis", c_uint8),
        ("padding1", c_uint8),
        ("padding2", c_uint8),
        ("padding3", c_uint8),
        ("value", c_int16),
        ("padding4", c_uint16),
    ]

class SDL_JoyBallEvent(Structure):
    _fields_ = [
        ("type", c_uint32),
        ("timestamp", c_uint32),
        ("which", SDL_JoystickID),
        ("ball", c_uint8),
        ("padding1", c_uint8),
        ("padding2", c_uint8),
        ("padding3", c_uint8),
        ("xrel", c_int16),
        ("yrel", c_int16),
    ]

class SDL_JoyHatEvent(Structure):
    _fields_ = [
        ("type", c_uint32),
        ("timestamp", c_uint32),
        ("which", SDL_JoystickID),
        ("hat", c_uint8),
        ("value", c_uint8),
        ("padding1", c_uint8),
        ("padding2", c_uint8),
    ]

class SDL_JoyButtonEvent(Structure):
    _fields_ = [
        ("type", c_uint32),
        ("timestamp", c_uint32),
        ("which", SDL_JoystickID),
        ("button", c_uint8),
        ("state", c_uint8),
        ("padding1", c_uint8),
        ("padding2", c_uint8),
    ]

class SDL_JoyDeviceEvent(Structure):
    _fields_ = [("type", c_uint32), ("timestamp", c_uint32), ("which", c_int32)]

class SDL_JoyBatteryEvent(Structure):
    _fields_ = [("type", c_uint32), ("timestamp", c_uint32), ("which", SDL_JoystickID), ("level", SDL_JoystickPowerLevel)]

class SDL_ControllerAxisEvent(Structure):
    _fields_ = [
        ("type", c_uint32),
        ("timestamp", c_uint32),
        ("which", SDL_JoystickID),
        ("axis", c_uint8),
        ("padding1", c_uint8),
        ("padding2", c_uint8),
        ("padding3", c_uint8),
        ("value", c_int16),
        ("padding4", c_uint16),
    ]

class SDL_ControllerButtonEvent(Structure):
    _fields_ = [
        ("type", c_uint32),
        ("timestamp", c_uint32),
        ("which", SDL_JoystickID),
        ("button", c_uint8),
        ("state", c_uint8),
        ("padding1", c_uint8),
        ("padding2", c_uint8),
    ]

class SDL_ControllerDeviceEvent(Structure):
    _fields_ = [("type", c_uint32), ("timestamp", c_uint32), ("which", c_int32)]

class SDL_ControllerTouchpadEvent(Structure):
    _fields_ = [
        ("type", c_uint32),
        ("timestamp", c_uint32),
        ("which", SDL_JoystickID),
        ("touchpad", c_int32),
        ("finger", c_int32),
        ("x", c_float),
        ("y", c_float),
        ("pressure", c_float),
    ]

class SDL_ControllerSensorEvent(Structure):
    _fields_ = [
        ("type", c_uint32),
        ("timestamp", c_uint32),
        ("which", SDL_JoystickID),
        ("sensor", c_int32),
        ("data", c_float * 3),
        ("timestamp_us", c_uint64)
    ]

class SDL_AudioDeviceEvent(Structure):
    _fields_ = [
        ("type", c_uint32),
        ("timestamp", c_uint32),
        ("which", c_uint32),
        ("iscapture", c_uint8),
        ("padding1", c_uint8),
        ("padding2", c_uint8),
        ("padding3", c_uint8),
    ]

class SDL_TouchFingerEvent(Structure):
    _fields_ = [
        ("type", c_uint32),
        ("timestamp", c_uint32),
        ("touchId", SDL_TouchID),
        ("fingerId", SDL_FingerID),
        ("x", c_float),
        ("y", c_float),
        ("dx", c_float),
        ("dy", c_float),
        ("pressure", c_float),
        ("windowID", c_uint32)
    ]

class SDL_MultiGestureEvent(Structure):
    _fields_ = [
        ("type", c_uint32),
        ("timestamp", c_uint32),
        ("touchId", SDL_TouchID),
        ("dTheta", c_float),
        ("dDist", c_float),
        ("x", c_float),
        ("y", c_float),
        ("numFingers", c_uint16),
        ("padding", c_uint16),
    ]

class SDL_DollarGestureEvent(Structure):
    _fields_ = [
        ("type", c_uint32),
        ("timestamp", c_uint32),
        ("touchId", SDL_TouchID),
        ("gestureId", SDL_GestureID),
        ("numFingers", c_uint32),
        ("error", c_float),
        ("x", c_float),
        ("y", c_float),
    ]

class SDL_DropEvent(Structure):
    _fields_ = [("type", c_uint32), ("timestamp", c_uint32), ("file", c_char_p), ("windowID", c_uint32)]

class SDL_SensorEvent(Structure):
    _fields_ = [("type", c_uint32), ("timestamp", c_uint32), ("which", c_int32), ("data", (c_float * 6)), ("timestamp_us", c_uint64)]

class SDL_QuitEvent(Structure):
    _fields_ = [("type", c_uint32), ("timestamp", c_uint32)]

class SDL_OSEvent(Structure):
    _fields_ = [("type", c_uint32), ("timestamp", c_uint32)]

class SDL_UserEvent(Structure):
    _fields_ = [
        ("type", c_uint32),
        ("timestamp", c_uint32),
        ("windowID", c_uint32),
        ("code", c_int32),
        ("data1", c_void_p),
        ("data2", c_void_p),
    ]

class SDL_Event(Union):
    _fields_ = [
        ("type", c_uint32),
        ("common", SDL_CommonEvent),
        ("display", SDL_DisplayEvent),
        ("window", SDL_WindowEvent),
        ("key", SDL_KeyboardEvent),
        ("edit", SDL_TextEditingEvent),
        ("editExt", SDL_TextEditingExtEvent),
        ("text", SDL_TextInputEvent),
        ("motion", SDL_MouseMotionEvent),
        ("button", SDL_MouseButtonEvent),
        ("wheel", SDL_MouseWheelEvent),
        ("jaxis", SDL_JoyAxisEvent),
        ("jball", SDL_JoyBallEvent),
        ("jhat", SDL_JoyHatEvent),
        ("jbutton", SDL_JoyButtonEvent),
        ("jdevice", SDL_JoyDeviceEvent),
        ("jbattery", SDL_JoyBatteryEvent),
        ("caxis", SDL_ControllerAxisEvent),
        ("cbutton", SDL_ControllerButtonEvent),
        ("cdevice", SDL_ControllerDeviceEvent),
        ("ctouchpad", SDL_ControllerTouchpadEvent),
        ("csensor", SDL_ControllerSensorEvent),
        ("adevice", SDL_AudioDeviceEvent),
        ("sensor", SDL_SensorEvent),
        ("quit", SDL_QuitEvent),
        ("user", SDL_UserEvent),
        ("tfinger", SDL_TouchFingerEvent),
        ("mgesture", SDL_MultiGestureEvent),
        ("dgesture", SDL_DollarGestureEvent),
        ("drop", SDL_DropEvent),
        ("padding", (c_uint8 * (56 if sizeof(c_void_p) <= 8 else (3 * sizeof(c_void_p)) if sizeof(c_void_p) > 16 else 64))),
    ]

# -------- Image -------- #

class IMG_Animation(Structure):
    _fields_ = [("w", c_int), ("h", c_int), ("count", c_int), ("frames", _P(_P(SDL_Surface))), ("delays", _P(c_int))]
