""" Python interface to IProgressDialog """

from __future__ import annotations

__all__ = ['Progress']


import atexit
from ctypes import *
from ctypes.wintypes import *
from typing import Literal

ole32 = oledll.ole32


class GUID(Structure):
    _fields_ = [
        ('', c_ulong),
        ('', c_ushort),
        ('', c_ushort),
        ('', c_ubyte * 8),
    ]

CLSIDFromString = WINFUNCTYPE(HRESULT, LPCWSTR, POINTER(GUID)) \
    (('CLSIDFromString', ole32),      ((1,),    (2,)))
IIDFromString = WINFUNCTYPE(HRESULT, LPCWSTR, POINTER(GUID)) \
    (('IIDFromString', ole32),      ((1,),    (2,)))

CoInitializeEx = WINFUNCTYPE(HRESULT, c_void_p,              DWORD) \
    (('CoInitializeEx', ole32),      ((1, 'reserved', None), (1, 'coinit', 0x00)))
CoCreateInstance = WINFUNCTYPE(HRESULT, POINTER(GUID), c_void_p,           DWORD,             POINTER(GUID), POINTER(LPVOID)) \
    (('CoCreateInstance', ole32),      ((1, 'clsid'),  (1, 'outer', None), (1, 'clsContext'), (1, 'iid'),    (2,)))
CoUninitialize = WINFUNCTYPE(None) \
    (('CoUninitialize', ole32), ())

CLSID_IProgressDialog = CLSIDFromString('{F8383852-FCD3-11D1-A6B9-006097DF5BD4}')
IID_IProgressDialog = IIDFromString('{EBBC7C04-315E-11D2-B62F-006097DF5BD4}')

Release = WINFUNCTYPE(c_ulong) \
    (2, 'Release', ())
StartProgressDialog = WINFUNCTYPE(HRESULT, HWND,                c_void_p,               DWORD,        c_void_p) \
    (3, 'StartProgressDialog',            ((1, 'parent', None), (1, 'reserved1', None), (1, 'flags'), (1, 'reserved2', None)))
StopProgressDialog = WINFUNCTYPE(HRESULT) \
    (4, 'StopProgressDialog', ())
SetTitle = WINFUNCTYPE(HRESULT, c_wchar_p) \
    (5, 'SetTitle',             ((1, 'title'),))
SetProgress = WINFUNCTYPE(HRESULT, DWORD,            DWORD) \
    (8, 'SetProgress',            ((1, 'completed'), (1, 'total')))
SetLine = WINFUNCTYPE(HRESULT, DWORD,          LPCWSTR,       BOOL,                  LPCVOID) \
    (10, 'SetLine',           ((1, 'lineNum'), (1, 'string'), (1, 'compactPath', 0), (1, 'reserved', None)))


CoInitializeEx()
atexit.register(CoUninitialize)


class Progress:
    """ IProgressDialog controller """
    ptr: LPVOID
    _started: bool

    def __init__(self, title: str) -> None:
        self.ptr = cast(CoCreateInstance(clsid=byref(CLSID_IProgressDialog), iid=byref(IID_IProgressDialog), clsContext=0x01), LPVOID)
        SetTitle(self.ptr, title)
        self._started = False

    def start(self) -> None:
        """ Show the progress dialog """
        StartProgressDialog(self.ptr, flags=0x0040)
        self._started = True

    def stop(self) -> None:
        """ Hide the progress dialog """
        StopProgressDialog(self.ptr)
        self._started = False

    def set_progress(self, n: int, m: int) -> None:
        """ Set the current progress to N out of M """
        SetProgress(self.ptr, n, m)

    def set_text(self, line: Literal[1, 2, 3], text: str, *, compact: bool = False) -> None:
        """ Set a line of text by index
        (1 = status, 2 = first detail line, 3 = second detail line) """
        SetLine(self.ptr, lineNum=line, string=text, compactPath=compact)

    def set_status(self, status: str, *, compact: bool = False) -> None:
        """ Set the status line text """
        self.set_text(1, status, compact=compact)

    def set_detail1(self, detail: str, *, compact: bool = False) -> None:
        """ Set the first detail line text """
        self.set_text(2, detail, compact=compact)

    def set_detail2(self, detail: str, *, compact: bool = False) -> None:
        """ Set the second detail line text """
        self.set_text(3, detail, compact=compact)

    def __del__(self) -> None:
        if self.ptr:
            if self._started:
                self.stop()
            Release(self.ptr)
