"""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",
    "AudioWriter",
    "PCM_source",
    "LICE_IBitmap",
    "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
