"""API for ReaExtensions by Julian Sader.

Repo on GitHub: https://github.com/juliansader/ReaExtensions
Theme on ReaperForums: https://forum.cockos.com/showthread.php?t=212174

Module consists of autogenerated members and some "fixed" functions, which
ought to replace autogenerated.
But the "fixed" functions are renamed for avoiding umbiguos behaviour.
For example: instead of MIDIEditor_ArrayAll use MIDIEditor_ArrayAllEx.
"""

import typing as ty
import reapy_boost
import ctypes as ct
if reapy_boost.is_inside_reaper():
    from reapy_boost.additional_api import packp, unpackp, packs_l, unpacks_l
    from reaper_python import _ft
try:
    from ._JS_API_generated import *
    from ._JS_API_generated import VoidPtr
except ImportError:
    from warnings import warn
    warn(
        ImportWarning(
            'JS API still is not generated, or generated incorrectly.'
        )
    )

# initial __all__ is autogenerated, be careful!
__all__: ty.List[str] = [
    "Pointer", "VoidPtr", "LICE_IBitmap", "PCM_source", "AudioWriter",
    "ReaScriptAPI_Version", "Localize", "Mem_Alloc", "Mem_Free",
    "Mem_FromString", "String", "Int", "Byte", "Double",
    "Dialog_BrowseForSaveFile", "Dialog_BrowseForOpenFiles",
    "Dialog_BrowseForFolder", "Window_GetRect", "Window_ScreenToClient",
    "Window_ClientToScreen", "Window_GetClientRect", "Window_GetClientSize",
    "Window_MonitorFromRect", "Window_GetViewportFromRect", "Window_Update",
    "Window_InvalidateRect", "Window_FromPoint", "Window_GetParent",
    "Window_SetParent", "Window_IsChild", "Window_GetRelated",
    "Window_FindChildByID", "Window_SetFocus", "Window_GetFocus",
    "Window_SetForeground", "Window_GetForeground", "Window_Create",
    "Window_EnableMetal", "Window_Enable", "Window_Destroy", "Window_Show",
    "Window_IsVisible", "Window_IsWindow", "Window_FindEx", "Window_Find",
    "Window_FindTop", "Window_FindChild", "Window_ArrayAllChild",
    "Window_ArrayAllTop", "Window_ArrayFind", "Window_ListAllChild",
    "Window_ListAllTop", "Window_ListFind", "MIDIEditor_ListAll",
    "MIDIEditor_ArrayAll", "Window_SetPosition", "Window_Resize",
    "Window_Move", "Window_SetZOrder", "Window_GetLongPtr", "Window_GetLong",
    "Window_SetLong", "Window_SetStyle", "Window_SetOpacity",
    "Window_GetTitle", "Window_SetTitle", "Window_GetClassName",
    "Window_HandleFromAddress", "Window_AddressFromHandle",
    "WindowMessage_Post", "WindowMessage_Send", "WindowMessage_Peek",
    "WindowMessage_Intercept", "WindowMessage_InterceptList",
    "WindowMessage_PassThrough", "WindowMessage_ListIntercepts",
    "WindowMessage_Release", "WindowMessage_ReleaseWindow",
    "WindowMessage_ReleaseAll", "Window_OnCommand", "VKeys_GetState",
    "VKeys_GetDown", "VKeys_GetUp", "VKeys_Intercept", "Mouse_GetState",
    "Mouse_GetCursor", "Mouse_SetPosition", "Mouse_LoadCursor",
    "Mouse_LoadCursorFromFile", "Mouse_SetCursor", "Window_GetScrollInfo",
    "Window_SetScrollPos", "GDI_GetClientDC", "GDI_GetWindowDC",
    "GDI_GetScreenDC", "GDI_ReleaseDC", "GDI_CreateFillBrush", "GDI_CreatePen",
    "GDI_CreateFont", "GDI_SelectObject", "GDI_DeleteObject", "GDI_FillRect",
    "GDI_FillRoundRect", "GDI_FillPolygon", "GDI_FillEllipse",
    "GDI_GetSysColor", "GDI_SetTextBkMode", "GDI_SetTextBkColor",
    "GDI_SetTextColor", "GDI_GetTextColor", "GDI_DrawText", "GDI_SetPixel",
    "GDI_Line", "GDI_Polyline", "GDI_Blit", "GDI_StretchBlit", "Composite",
    "Composite_Unlink", "Composite_ListBitmaps", "Composite_Delay",
    "LICE_CreateBitmap", "LICE_ListAllBitmaps", "LICE_ArrayAllBitmaps",
    "LICE_GetHeight", "LICE_GetWidth", "LICE_GetDC", "LICE_DestroyBitmap",
    "LICE_LoadPNG", "LICE_Blit", "LICE_RotatedBlit", "LICE_ScaledBlit",
    "LICE_IsFlipped", "LICE_Resize", "LICE_Clear", "LICE_CreateFont",
    "LICE_DestroyFont", "LICE_SetFontFromGDI", "LICE_SetFontColor",
    "LICE_SetFontBkColor", "LICE_DrawText", "LICE_DrawChar",
    "LICE_MeasureText", "LICE_GradRect", "LICE_FillRect", "LICE_FillTriangle",
    "LICE_FillPolygon", "LICE_FillCircle", "LICE_Line", "LICE_Bezier",
    "LICE_Arc", "LICE_Circle", "LICE_RoundRect", "LICE_GetPixel",
    "LICE_PutPixel", "LICE_WritePNG", "LICE_WriteJPG", "LICE_LoadJPG",
    "LICE_SetAlphaFromColorMask", "LICE_AlterBitmapHSV", "LICE_AlterRectHSV",
    "LICE_ProcessRect", "Window_AttachTopmostPin", "Window_AttachResizeGrip",
    "ListView_GetItemCount", "ListView_GetSelectedCount",
    "ListView_EnsureVisible", "ListView_GetFocusedItem",
    "ListView_EnumSelItems", "ListView_GetItem", "ListView_GetItemText",
    "ListView_GetItemState", "ListView_ListAllSelItems",
    "Xen_AudioWriter_Create", "Xen_AudioWriter_Destroy",
    "Xen_AudioWriter_Write", "Xen_GetMediaSourceSamples",
    "Xen_StartSourcePreview", "Xen_StopSourcePreview"
]
# This part is where the module __all__ begins
__all__.extend(
    [
        "Window_ArrayAllChildEx",
        "Window_ArrayAllTopEx",
        "Window_ArrayFindEx",
        "MIDIEditor_ArrayAllEx",
        "reaper_array_to_hwnd",
    ]
)


@reapy_boost.inside_reaper()
def create_reaper_array(size: int = 100) -> ct.Structure:

    class ReaperArray(ct.Structure):
        _fields_ = [
            ('size', ct.c_uint32), ('maximum', ct.c_uint32),
            ('values', ct.c_double * size)
        ]

    return ReaperArray(size=0, maximum=size, values=(ct.c_double * size)(0.0))


@reapy_boost.inside_reaper()
def Window_ArrayAllChildEx(
    parentHWND: 'VoidPtr',
    size: int = 100
) -> ty.Tuple[int, ty.Tuple[float, ...]]:
    """
    Finds all child windows of the specified parent.

    Returns:
     * retval:
    The number of windows found; negative if an error occurred.
     * The
    addresses are stored in the provided reaper.array, and can be
    converted to REAPER objects (HWNDs) by the function
    JS_Window_HandleFromAddress.

    Returns
    -------
    ret_value: int
    array: Tuple[float]
    """
    a = _ft['JS_Window_ArrayAllChild']
    f = ct.CFUNCTYPE(ct.c_int, ct.c_void_p, ct.c_void_p)(a)
    array = create_reaper_array(size)
    ret = f(packp("void*", str(parentHWND)), ct.byref(array))
    return int(ret), tuple(array.values)


@reapy_boost.inside_reaper()
def Window_ArrayAllTopEx(
    size: int = 100
) -> ty.Tuple[int, ty.Tuple[float, ...]]:
    """
    Finds all top-level windows.

    Returns:
     * retval: The number of
    windows found; negative if an error occurred.
     * The addresses are
    stored in the provided reaper.array, and can be converted to REAPER
    objects (HWNDs) by the function JS_Window_HandleFromAddress.

    Returns
    -------
    ret_value: int
    array: Tuple[float]
    """
    a = _ft['JS_Window_ArrayAllTop']
    f = ct.CFUNCTYPE(ct.c_int, ct.c_void_p)(a)
    array = create_reaper_array(size)
    ret = f(ct.byref(array))
    return int(ret), tuple(array.values)


@reapy_boost.inside_reaper()
def Window_ArrayFindEx(
    title: str,
    exact: bool,
    size: int = 100,
    encoding: str = "utf-8"
) -> ty.Tuple[int, ty.Tuple[float, ...]]:
    """
    Finds all windows, whether top-level or child, whose titles match the
    specified string.

    Returns:
     * retval: The number of windows found;
    negative if an error occurred.
     * The addresses are stored in the
    provided reaper.array, and can be converted to REAPER objects (HWNDs)
    by the function JS_Window_HandleFromAddress.

    Parameters:
     * exact:
    Match entire title exactly, or match substring of title.

    Returns
    -------
    ret_value: int
    array: Tuple[float]
    """
    a = _ft['JS_Window_ArrayFind']
    f = ct.CFUNCTYPE(ct.c_int, ct.c_char_p, ct.c_byte, ct.c_void_p)(a)
    prot_title = packs_l(title, size=len(title), encoding=encoding)
    array = create_reaper_array(size)
    ret = f(prot_title, ct.c_byte(exact), ct.byref(array))
    return int(ret), tuple(array.values)


@reapy_boost.inside_reaper()
def MIDIEditor_ArrayAllEx(
    size: int = 100,
) -> ty.Tuple[int, ty.Tuple[float, ...]]:
    """
    Finds all open MIDI windows (whether docked or not).

     * retval: The
    number of MIDI editor windows found; negative if an error occurred.
    * The address of each MIDI editor window is stored in the provided
    reaper.array. Each address can be converted to a REAPER object (HWND)
    by the function JS_Window_HandleFromAddress.

    Returns
    -------
    ret_value: int
    array: Tuple[float]
    """
    a = _ft['JS_MIDIEditor_ArrayAll']
    f = ct.CFUNCTYPE(ct.c_int, ct.c_void_p)(a)
    array = create_reaper_array(size)
    ret = f(ct.byref(array))
    return int(ret), tuple(array.values)


@reapy_boost.inside_reaper()
def LICE_LoadPNGEx(filename: str, encoding: str = "utf-8") -> 'VoidPtr':
    """
    Returns a system LICE bitmap containing the PNG.

    Note
    ----
    This is stable version of LoadPNG which provides constant filename
    string size of 2048. God knows, why, but we respect him.

    Returns
    -------
    ret_value: VoidPtr
    """
    a = _ft['JS_LICE_LoadPNG']
    f = ct.CFUNCTYPE(ct.c_void_p, ct.c_char_p)(a)
    prot_filename = packs_l(
        filename,
        # size=len(filename.encode(encoding)),
        size=2048,  # strange need to keep it constant
        encoding=encoding,
    )
    ret = f(prot_filename)
    return VoidPtr(unpackp("void*", ret))


@reapy_boost.inside_reaper()
def reaper_array_to_hwnd(array: ty.Tuple[float, ...]) -> ty.List['VoidPtr']:
    """Transform reaper array to VoidPtr pointers to hwnd.

    Parameters
    ----------
    array : ty.Tuple[float, ...]
        got within *Array funtions

    Returns
    -------
    ty.List[VoidPtr]
    """
    out = list()
    for val in array:
        if val != 0:
            out.append(VoidPtr(int(val)))
    return out
