' ************************************************
'  Adapted from: Amort.bas by Kevin Diggins(MrBCX)
'  ported to Oxygenbasic (simplified)     
' ************************************************
'  AMORT is a small loan amortization program 
' ************************************************

$ filename "Amort-Demo.exe"

'uses rtl32
'uses rtl64

uses winutil

! sprintf lib "msvcrt.dll" (char *buffer, const char *format, ...) as sys

typedef sys control

% DS_MODALFRAME=128
% SS_NOTIFY = 256
% SS_LEFT = 0

% LVS_EX_GRIDLINES 1 
% LVS_EX_FULLROWSELECT  0x0020
% LVM_SETEXTENDEDLISTVIEWSTYLE 0x1036
% LVCF_TEXT=4
% LVM_SETCOLUMN = 4122
% LVM_SETCOLUMNWIDTH=4126
% LVSCW_AUTOSIZE  -1
% LVSCW_AUTOSIZE_USEHEADER = -2
% LVM_DELETEALLITEMS = 4105
% LVIF_TEXT=1
% LVM_INSERTITEM=4103
% LVCF_FMT 1
% LVCF_WIDTH 2
% LVCF_SUBITEM 8
% LVCFMT_LEFT = 0
% LVM_INSERTCOLUMN = 4123
% LVS_REPORT = 1
% LVS_SHAREIMAGELISTS = 64
% LVS_EDITLABELS = 512
% LVM_SETITEMTEXT = 4142


% HDI_FORMAT = 4
% HDF_STRING = 16384
% HDM_SETITEM = 4612
% HDF_LEFT = 0
% HDF_RIGHT = 1


type LVCOLUMN
  uint  mask
  int   fmt
  int   cx
  char* pszText
  int   cchTextMax
  int   iSubItem
  int   iImage
  int   iOrder
  int   cxMin
  int   cxDefault
  int   cxIdeal 
end type
typedef LVCOLUMN LV_COLUMN

type LVITEM 
  uint   mask
  int    iItem
  int    iSubItem
  uint   state
  uint   stateMask
  char*  pszText
  int    cchTextMax
  int    iImage       // index of the list view item's icon
  sys    lParam       // 32-bit value to associate with item
  int    iIndent
  int    iGroupId
  uint   cColumns
  uint   *puColumns
  int    *piColFmt
  int    iGroup
end type
typedef LVITEM LV_ITEM

type HDITEM 
  uint     mask 
  int      cxy
  char*    pszText
  sys      hbm
  int      cchTextMax
  int      fmt
  sys      lParam
  int      iImage
  int      iOrder
'#if (_WIN32_IE >= 0x0500)
  uint     type_    'type
  sys      pvFilter 'LPVOID
'#endif /* _WIN32_IE >= 0x0500 */
'#if (_WIN32_WINNT >= 0x0600)
  uint     state
'#endif /* _WIN32_WINNT >= 0x0600 */ 
end type
typedef HDITEM HD_ITEM


macro ListView_DeleteAllItems(hwnd) (SendMessage(hwnd, LVM_DELETEALLITEMS, 0, 0))
macro ListView_InsertItem(hwnd,pitem) (SendMessage(hwnd, LVM_INSERTITEM,0, pitem))
macro ListView_InsertColumn(hwnd,iCol,pcol) (SendMessage(hwnd, LVM_INSERTCOLUMN, iCol, pcol))
macro ListView_SetItemText(hwnd,i,iSubItem_,pszText_) 
  LV_ITEM _ms_lvi
  _ms_lvi.iSubItem = iSubItem_
  _ms_lvi.pszText = pszText_
  SendMessage((hwnd),LVM_SETITEMTEXT, i, &_ms_lvi)
end macro 

    ' create a structure of INITCOMMONCONTROLSEX
    INITCOMMONCONTROLSEXt iccex
    iccex.dwSize=sizeof(iccex)
    'Register Common Controls
    iccex.dwICC= 0xffff
    InitCommonControlsEx(&iccex)

GLOBAL Input1  AS CONTROL
GLOBAL Input2  AS CONTROL
GLOBAL Input3  AS CONTROL
GLOBAL Label1  AS CONTROL
GLOBAL Label2  AS CONTROL
GLOBAL Label3  AS CONTROL
GLOBAL Label4  AS CONTROL
GLOBAL Button1 AS CONTROL
GLOBAL LView1  AS CONTROL

SUB Set_ColumnText(ByVal hWnd AS sys, ByVal Column as int, ByVal Text$ as string)
   LOCAL lvc AS LV_COLUMN
   lvc.mask = LVCF_TEXT
   lvc.pszText = Text$
   SendMessage(hWnd, LVM_SETCOLUMN, Column, &lvc)
   SendMessage(LView1, LVM_SETCOLUMNWIDTH, Column, LVSCW_AUTOSIZE_USEHEADER)
END SUB

SUB LV_Reset(ByVal LView AS CONTROL, ByVal Columns as int, ByVal Rows as int)
   LOCAL lvItem AS LV_ITEM
   LOCAL i as int
   ListView_DeleteAllItems(LView)
   for i = 1 to Rows
     lvItem.mask = LVIF_TEXT
     lvItem.pszText = " "
     lvItem.iSubItem = 0
     ListView_InsertItem(LView1, &lvItem)
   next   
END SUB

SUB LV_Justify(ByVal LV AS sys, ByVal Column as int , ByVal JustifyType as int)
   LOCAL hHeader AS LONG
   LOCAL hdi AS HD_ITEM
   '*******************************************
   % HDF_LEFT = 0    'JustifyType
   % HDF_RIGHT = 1    'JustifyType
   % HDF_CENTER = 2    'JustifyType
   '*******************************************
   % LVM_FIRST = 4096
   % LVM_GETHEADER = LVM_FIRST + 31
   '*******************************************
   hHeader = SendMessage(LV, LVM_GETHEADER, 0, 0)
   hdi.mask = HDI_FORMAT
   hdi.pszText = " "
   hdi.fmt = HDF_STRING OR JustifyType
   SendMessage(hHeader, HDM_SETITEM, Column, &hdi)
END SUB

FUNCTION INTEREST_PAYMENT(ByVal i AS DOUBLE, ByVal Balance AS DOUBLE) AS DOUBLE
   FUNCTION =(i/12/100) * Balance
END FUNCTION
   
FUNCTION Payment(ByVal i AS DOUBLE, ByVal np AS DOUBLE, ByVal pv AS DOUBLE, ByVal fv AS DOUBLE) AS DOUBLE
   DIM q1 AS DOUBLE
   DIM ir AS DOUBLE
   ir = i / 12 / 100
   q1 = POW(1 + ir, np)
   FUNCTION =((ir *(fv + q1 * pv))/(-1 + q1))
END FUNCTION

function Set_Text(sys hWnd, string Text) as int
  return SetWindowText(hWnd,Text)
end function

function Get_Text(sys hWnd) as string
  int tmpint
  tmpint = 1 + GetWindowTextLength(hWnd)
  static string strtmp = nuls * 1024
  GetWindowText(hWnd, strtmp, tmpint) 
  return strtmp
end function


SUB FillListView() 
   '==========================
   DIM Amount AS DOUBLE
   DIM Interest AS DOUBLE
   DIM Years AS DOUBLE
   DIM Pmt AS DOUBLE
   DIM Int_Payment AS DOUBLE
   DIM Prin_Payment AS DOUBLE
   DIM lvItem AS LV_ITEM
   DIM SumPrinc AS DOUBLE
   DIM SumInt AS DOUBLE
   DIM z AS int
   char buff[32]
   '==========================
 
   Amount =   VAL(GET_TEXT(Input1))
   Interest = VAL(GET_TEXT(Input2))
   Years =    VAL(GET_TEXT(Input3))
   Pmt = Payment(Interest, Years * 12, Amount, 0)
 
   LV_Reset(LView1, 4, Years * 12)
 
   Set_ColumnText(LView1, 0, "Payment")
   Set_ColumnText(LView1, 1, "Interest")
   Set_ColumnText(LView1, 2, "Principal")
   Set_ColumnText(LView1, 3, "Balance")
 
   FOR z = 1 TO Years * 12
     Int_Payment = INTEREST_PAYMENT(Interest, Amount)
     Prin_Payment = Pmt - INTEREST_PAYMENT(Interest, Amount)
     SumPrinc = SumPrinc + Prin_Payment
     SumInt = SumInt + Int_Payment
     string z1=str(z)
     ListView_SetItemText(LView1, z - 1, 0, z1)
     sprintf(buff, "%0.2lf", Int_Payment)
     ListView_SetItemText(LView1, z - 1, 1, buff)     
     sprintf(buff, "%.2f", Prin_Payment)
     ListView_SetItemText(LView1, z - 1, 2, buff)
     Amount = Amount - Prin_Payment
     sprintf(buff, "%.2f", Amount)
     ListView_SetItemText(LView1, z - 1, 3, buff)
   NEXT
 
   ListView_SetItemText(LView1, z, 3, " ")  ' add a line at the bottom
 
   FOR z = 0 TO 3
     SendMessage(LView1, LVM_SETCOLUMNWIDTH, z, LVSCW_AUTOSIZE_USEHEADER)
   NEXT
 
   LV_Justify(LView1, 0, HDF_LEFT)
   LV_Justify(LView1, 1, HDF_RIGHT)
   LV_Justify(LView1, 2, HDF_RIGHT)
   LV_Justify(LView1, 3, HDF_RIGHT)
 
   SET_TEXT(Label3, str(SumPrinc,2))
   SET_TEXT(Label4, str(SumInt,2))
END SUB

******************************************************************************

sys hInstance=inst
MainWindow 400,460, DS_MODALFRAME OR WS_POPUP OR WS_CAPTION OR WS_SYSMENU

function WndProc(sys hwnd, uMsg, wParam, lParam) as sys callback
 
    select uMsg
    case WM_CREATE
        SetWindowText(hwnd, "Amortization Schedule in Oxygenbasic")

        Input1=CreateWindowEx(WS_EX_CLIENTEDGE,"edit","8000",WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_LEFT | ES_AUTOHSCROLL, 272,  6, 92, 28, hwnd,0,hinstance,0)
        Input2=CreateWindowEx(WS_EX_CLIENTEDGE,"edit","9.25",WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_LEFT | ES_AUTOHSCROLL, 272, 36, 92, 28, hwnd,0,hinstance,0)
        Input3=CreateWindowEx(WS_EX_CLIENTEDGE,"edit","3",WS_CHILD | WS_VISIBLE | WS_TABSTOP | ES_LEFT | ES_AUTOHSCROLL, 272, 66, 92, 28, hwnd,0,hinstance,0)
        Label1=CreateWindowEx(0,"static","Principal",WS_CHILD | SS_NOTIFY | SS_LEFT | WS_VISIBLE, 10, 104, 80, 28, hwnd,0,hinstance,0)
        Label2=CreateWindowEx(0,"static","Interest",WS_CHILD | SS_NOTIFY | SS_LEFT | WS_VISIBLE,  10, 130, 80, 28, hwnd,0,hinstance,0)
        Label3=CreateWindowEx(0,"static","",WS_CHILD | SS_NOTIFY | SS_LEFT | WS_VISIBLE, 100, 104, 80, 28, hwnd,0,hinstance,0)
        Label4=CreateWindowEx(0,"static","",WS_CHILD | SS_NOTIFY | SS_LEFT | WS_VISIBLE, 100,130, 80, 28, hwnd,0,hinstance,0)
        Button1=CreateWindowEx(WS_EX_STATICEDGE,"button","Calc",WS_CHILD | WS_VISIBLE | BS_MULTILINE | BS_PUSHBUTTON | WS_TABSTOP, 280,104, 80, 28, hwnd, 101, hinstance, 0)

        LV_COLUMN lvCol =
            { LVCF_FMT|LVCF_WIDTH|LVCF_TEXT|LVCF_SUBITEM, LVCFMT_LEFT, 65, "", 0, 0 }
        LView1=CreateWindowEx(WS_EX_CLIENTEDGE,"SysListView32",0,WS_CHILD | WS_TABSTOP |
                                         WS_VISIBLE | LVS_REPORT |
                                         LVS_SHAREIMAGELISTS | LVS_EDITLABELS | WS_BORDER, 10, 160, 300, 246, hwnd, 0, hinstance, 0)
        int Style=LVS_EX_GRIDLINES | LVS_EX_FULLROWSELECT
        SendMessage(LView1, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, Style)
        lvCol.iSubItem=0
        while lvCol.iSubItem<15
           ListView_InsertColumn(LView1, 0, lvCol)
           lvCol.iSubItem+=1     
        wend

        CreateWindowEx(0,"static","Loan Amount",  WS_CHILD | SS_NOTIFY | SS_LEFT | WS_VISIBLE, 10, 14, 126, 22, hwnd,0,hinstance,0)
        CreateWindowEx(0,"static","Interest Rate",WS_CHILD | SS_NOTIFY | SS_LEFT | WS_VISIBLE, 10, 44, 126, 22, hwnd,0,hinstance,0)
        CreateWindowEx(0,"static","No. of Years", WS_CHILD | SS_NOTIFY | SS_LEFT | WS_VISIBLE, 10, 72, 192, 22, hwnd,0,hinstance,0)

        Set_ColumnText(LView1, 0, "Payment")
        Set_ColumnText(LView1, 1, "Interest")
        Set_ColumnText(LView1, 2, "Principal")
        Set_ColumnText(LView1, 3, "Balance")
               
        SetFocus(Input1)
        RedrawWindow(hwnd)
        ShowWindow(hwnd)

    case WM_COMMAND
        if LOWORD(wParam) = 101 then 'Calc
           FillListView()
        end if   

    case WM_CLOSE
        DestroyWindow(hwnd)
           
    case WM_DESTROY
        PostQuitMessage(0)
           
    case else
        return DefWindowProc(hwnd, uMsg, wParam, lParam)

    end select

    return 0
end function