;****************************************
; Creates and manages MRU lists.
; This file was written very quick, so
; it will be commented later. Maybe...
;****************************************


struct TMRUList
  .capacity dd ?
  .count    dd ?
  label .data dword
ends


proc CreateNewMRUList, .count
begin
        mov     eax, [.count]
        lea     eax, [4*eax+sizeof.TMRUList]  ; Two additional cells for capacity and count.

        stdcall GetMem, eax
        pushd   [.count]
        popd    [eax+TMRUList.capacity]      ; capacity of the MRU list.
        return
endp


proc AddToMRUList, .ptrList, .hString
begin
        push    esi ebx

        mov     esi, [.ptrList]
        mov     ebx, [esi+TMRUList.count]    ; the count of MRU items.

.search:
        dec     ebx
        js      .notfound
        stdcall StrCompNoCase, [esi+4*ebx+sizeof.TMRUList], [.hString]
        jnc     .search

; Found
        pushd   [esi+4*ebx+sizeof.TMRUList]   ; The found one.
.move:
        inc     ebx
        cmp     ebx, [esi+TMRUList.count]
        je      .save

        pushd   [esi+4*ebx+8]
        popd    [esi+4*ebx+4]
        jmp     .move

.save:
        popd    [esi+4*ebx+4]   ; Move to the top.
        pop     ebx esi
        return

.notfound:
        mov     ebx, [esi+TMRUList.count]    ; Count
        cmp     ebx, [esi+TMRUList.capacity] ; Capacity
        jl      .insertlast

        stdcall RemoveFromMRUList, [.ptrList], 0
        dec     ebx

.insertlast:
        stdcall StrDup, [.hString]
        mov     [esi+4*ebx+8], eax      ; On the last free place
        inc     dword [esi+TMRUList.count]

        pop     ebx esi
        return
endp


proc RemoveFromMRUList, .ptrList, .iItem
begin
        push    esi ebx

        mov     esi, [.ptrList]
        mov     ebx, [.iItem]
        cmp     ebx, [esi+4]      ; Count
        jae     .finish

        dec     dword [esi+4]
        stdcall StrDel, [esi+4*ebx+8]

.shift:
        cmp     ebx, [esi+4]
        je      .zero

        pushd   [esi+4*ebx+12]
        popd    [esi+4*ebx+8]
        inc     ebx
        jmp     .shift
.zero:
        mov     dword [esi+4*ebx+8], 0        ; Zero the last element.

.finish:
        pop     ebx esi
        return
endp


proc ValidateMRUList, .ptrList, .ptrCallback
begin
        push    esi ebx
        mov     esi, [.ptrList]
        mov     ebx, [esi+4]    ; count;

.checkloop:
        dec     ebx
        js      .endcheck
        stdcall [.ptrCallback], [esi+4*ebx+8]      ; Check from the end to the begin
        jnc     .checkloop
        stdcall RemoveFromMRUList, [.ptrList], ebx
        jmp     .checkloop

.endcheck:
        pop     ebx esi
        return
endp


proc DestroyMRUList, .ptrList
begin
        push    esi ebx
        mov     esi, [.ptrList]
        mov     ebx, [esi+4]      ; Count

.freestrings:
        dec     ebx
        js      .freelist
        stdcall StrDel, [esi+4*ebx+8]
        jmp     .freestrings

.freelist:
        stdcall FreeMem, esi
        pop     ebx esi
        return
endp



proc SaveMRUToIni, .ptrList, .hIniName, .hSection
begin
        push    ebx esi edi
        mov     esi, [.ptrList]

        stdcall StrNew
        mov     edx, eax

        xor     ebx, ebx

.itemsloop:
        cmp     ebx, [esi+TMRUList.count]
        jae     .enditems

        stdcall StrDup, [esi+4*ebx+TMRUList.data]
        stdcall StrSetQuotes, eax, ','

        test    ebx, ebx
        jz      @f
        stdcall StrCharCat, edx, ','
@@:
        stdcall StrCat, edx, eax
        stdcall StrDel, eax

        inc     ebx
        jmp     .itemsloop


.enditems:
        stdcall CfgSetStr, [.hIniName], [.hSection], cMRUkey, edx
        stdcall StrDel, edx
        pop     edi esi ebx
        return
endp


cMRUkey  text  'Items'



proc LoadMRUFromIni, .capacity, .hIniName, .hSection
.count  dd ?
begin
        push    esi edi ebx

        stdcall CreateNewMRUList, [.capacity]
        mov     esi, eax

        stdcall CfgGetStr, [.hIniName], [.hSection], cMRUkey
        jc      .finish

        push    eax
        stdcall StrSplitList, eax, ',', FALSE
        mov     edi, eax

        xor     ecx, ecx

.add_loop:
        cmp     ecx, [edi+TArray.count]
        jae     .end_add

        stdcall StrClipQuotes, [edi+4*ecx+TArray.array]
        stdcall AddToMRUList, esi, [edi+4*ecx+TArray.array]

        inc     ecx
        jmp     .add_loop

.end_add:
        stdcall ListFree, edi, StrDel

.finish:
        mov     eax, esi
        pop     ebx edi esi
        return
endp




proc FillMRUMenu, .hMenu, .ptrList, .ItemID, .fromSeparator
.mii  MENUITEMINFO
begin
        push    esi edi ebx

        mov     [.mii.cbSize], sizeof.MENUITEMINFO
        mov     [.mii.fMask], MIIM_TYPE or MIIM_ID

        xor     edi, edi

        invoke  GetMenuItemCount, [.hMenu]
        mov     ebx, eax
        test    ebx, ebx
        jz      .endscan

.scanloop:
        lea     ecx, [.mii]
        invoke  GetMenuItemInfoW, [.hMenu], edi, TRUE, ecx
        cmp     [.mii.fType], MF_SEPARATOR
        jne     .next
        dec     [.fromSeparator]
        jz      .delloop
.next:
        inc     edi
        cmp     edi, ebx
        jae     .endscan
        jmp     .scanloop

; found needed separator, delete to the next separator.
.delloop:
        invoke  DeleteMenu, [.hMenu], edi, MF_BYPOSITION
        dec     ebx
        cmp     edi, ebx
        jae     .endscan

        lea     ecx, [.mii]
        invoke  GetMenuItemInfoW, [.hMenu], edi, TRUE, ecx
        cmp     [.mii.fType], MF_SEPARATOR
        jne     .delloop

.endscan:
        mov     [.mii.fType], MFT_STRING

        mov     esi, [.ptrList]
        xor     ebx, ebx
        mov     eax, [esi+4]
        add     [.ItemID], eax
        stc                     ; One for the separator.
        adc     [.ItemID], edi
.loop:
        cmp     ebx, [esi+4]
        jae     .endinsert

        stdcall utf8ToWideChar, [esi+4*ebx+8]
        mov     [.mii.dwTypeData], eax

;        stdcall StrPtr, [esi+4*ebx+8]
;        mov     [.mii.dwTypeData], eax

        dec     [.ItemID]
        push    [.ItemID]
        pop     [.mii.wID]

        lea     eax, [.mii]
        invoke  InsertMenuItemW, [.hMenu], edi, TRUE, eax

        stdcall FreeMem, [.mii.dwTypeData]

        inc     ebx
        jmp     .loop

.endinsert:
; Put separator at the begin.
        mov     [.mii.fMask], MIIM_TYPE
        mov     [.mii.fType], MFT_SEPARATOR
        mov     [.mii.wID], NULL
        lea     eax, [.mii]
        invoke  InsertMenuItemW, [.hMenu], edi, TRUE, eax

.finish:
        pop     ebx edi esi
        return
endp




