Reference
  Util\Color.txt
  Util\Input.txt
  Util\WindowFrame.txt
  Util\Audio.txt
End Reference

Import StdUtilLib
  Math = MathUtil
  String = StringUtil
End Import

Import StdWindow
  Wnd = Window
End Import


''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'General Controls
'
'Information Window
'-DoModalInfoWindow
'-CreateInfoWindow
'-GetInfoWindowCell
'-CloseInfoWindow
'
'Input Box
'-DoInputBox
'
'Message Window
'-DoMsg
'-DoMsgEx
'
'Simple Menu
'-DoSimpleMenu
'
'Menu
'-DoMenu
'
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''


''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'Information Window
'
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

'The following CreateXxx() procedures return a handle of control.
'The last element is a panel used as the frame window.

Procedure GetFrameWindow(hCtrl)
  Return hCtrl[hCtrl.Count]
End Procedure

Procedure DestroyControl(hCtrl)
  hCtrl[hCtrl.Count].Dispose()
End Procedure

Procedure CreateEmptyInfoWindow(x, y, width, height, columns, rows)
  Dim items = CreateArrayList(columns)
  For i = 1 To columns
    items[i] = CreateArrayList(rows)
  Next
  Return CreateInfoWindow(x, y, width, height, columns, rows, items)
End Procedure

Procedure CreateInfoWindow(x, y, width, height, columns, rows, items)

  Dim hInfoWnd = CreateArrayList(columns + 1)
  Dim panel = CreateWindow(x, y, width, height)
  hInfoWnd[hInfoWnd.Count] = panel

  Dim cellWidth = panel.Width / columns
  Dim cellHeight = [F_SYS].LineHeight 'panel.Height / rows

  For x = 1 To columns
    Dim align = 0 'LEFT
    If x % 2 = 0 Then align = 2 'RIGHT
    Dim cells = CreateArrayList(rows)
    For y = 1 To rows
      Dim text = items[x][y]
      If text = Nothing Then text = ""
      Dim lbl = Wnd.CreateLabel((x - 1) * cellWidth, (y - 1) * cellHeight, _
        cellWidth, [F_SYS].LineHeight, 1, align, [F_SYS], Color.LightGray, text)
      panel.Add(lbl)
      cells[y] = lbl
    Next
    hInfoWnd[x] = cells
  Next

  Return hInfoWnd

End Procedure

Procedure GetInfoWindowCell(hInfoWnd, column, row)
  Return hInfoWnd[column][row]
End Procedure

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'Input Box
'
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

Procedure CreateInputBox(x, y, width, height, maxChars, chars, chars_in_list, defaultText)
  Dim label = Wnd.CreateLabel(0, 0, [F_SYS], Color.LightGray, defaultText)
  Dim panel = CreateWindow(x, y, width, height)
  panel.Add(label)
  Return {maxChars, chars, chars_in_list, label, panel}
End Procedure

Procedure ProcessInputBox(hInputBox)

  Dim maxChars = hInputBox[1]
  Dim chars = hInputBox[2]
  Dim chars_in_list = hInputBox[3]
  Dim label = hInputBox[4]
  Dim panel = GetFrameWindow(hInputBox)
  Dim text = label.Text

  Dim hCharList = CreateMenu(panel.X + panel.Width, panel.Y, _
    70, [F_SYS].LineHeight * (chars_in_list + 2), Nothing, Nothing, _
    Nothing, chars, Nothing, 1)

  Do
    Dim the_char_index = ProcessMenu(hCharList)
    If 1 <= the_char_index AndAlso the_char_index <= chars.Count - 1 Then
      If text.Length < maxChars Then
        text += chars[the_char_index]
      Else
        text = String.Substring(text, 1, text.Length - 1) + chars[the_char_index]
      End If
    ElseIf the_char_index = 0 Then
      If text.Length > 0 Then
        text = String.Substring(text, 1, text.Length - 1)
      Else
        text = Nothing
        Exit Do
      End If
    ElseIf the_char_index = chars.Count Then 'char of end is selected
      Exit Do
    End If
    label.Text = text
  Loop

  DestroyControl(hCharList)

  Sleep(0)
  Return text

End Procedure

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'Message Window
'
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

Procedure CreateDefaultMsgWindow(msgs, page_time) '17 chars and 4 lines
  Dim ss = GetScreenSize()
  Return CreateMsgWindow((ss.X - 576) / 2, ss.Y - 160, 576, 140, msgs, page_time)
End Procedure

Procedure CreateMsgWindow(x, y, width, height, msgs, page_time)
  Return {msgs, page_time, CreateWindow(x, y, width, height)}
End Procedure

Procedure ProcessMsgWindow(hMsgWnd)

  Dim msgs = hMsgWnd[1]
  Dim page_time = hMsgWnd[2]
  Dim panel = GetFrameWindow(hMsgWnd)
  Dim firstLineIndex = 1
  Dim lastLineIndex = Math.Min(firstLineIndex + 3, msgs.Count)
  For i = firstLineIndex To lastLineIndex
    panel.Add(Wnd.CreateLabel( _
      0, (i - firstLineIndex) * [F_MSG].LineHeight * 3 / 2, [F_MSG], _
      Color.LightGray, msgs[i]))
  Next

  Do
    If page_time = 0 Then
      WaitForOKOrCancel()
    Else
      Sleep(page_time)
    End If
    If lastLineIndex = msgs.Count Then Exit Do
    Dim label_count = lastLineIndex - firstLineIndex + 1
    Do While label_count > 0
      Dim label = panel.Children[panel.Children.Count]        
      panel.Remove(label)
      label.Dispose()
      label_count -= 1
    Loop
    firstLineIndex += 4
    lastLineIndex = Math.Min(firstLineIndex + 3, msgs.Count)
    For i = firstLineIndex To lastLineIndex
      panel.Add(Wnd.CreateLabel( _
        0, (i - firstLineIndex) * [F_MSG].LineHeight * 3 / 2, [F_MSG], _
        Color.LightGray, msgs[i]))
    Next i
  Loop

  Sleep(0)
  Return

End Procedure

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'Menu
'
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

Procedure CreateMenu(wndX, wndY, wndWidth, wndHeight, _
  scProc, scParam, caption, names, values, index)

  Dim panel = CreateWindow(wndX, wndY, wndWidth, wndHeight)
  Dim tw = panel.Width - [F_SYS].LineHeight
  Dim maxItemsInPage = panel.ClientHeight / [F_SYS].LineHeight - 1
  Dim maxPage = 0

  Dim label_cursor = Wnd.CreateLabel( _
    0, [F_SYS].LineHeight, [F_SYS], Color.Gray, String.Chr(0x25B6))
  panel.Add(label_cursor)

  Dim label_caption = Nothing
  If caption <> Nothing Then
    label_caption = Wnd.CreateLabel( _
      0, 0, tw + [F_SYS].LineHeight, [F_SYS].LineHeight, 1, 0, [F_SYS], Color.LightGray, caption)
    panel.Add(label_caption)
    If names <> Nothing Then
      maxPage = (names.Count - 1) / maxItemsInPage + 1
    Else
      maxPage = (values.Count - 1) / maxItemsInPage + 1
    End If
  Else
    maxItemsInPage += 1
    If names <> Nothing Then
      maxPage = (names.Count - 1) / maxItemsInPage + 1
    Else
      maxPage = (values.Count - 1) / maxItemsInPage + 1
    End If
    If maxPage > 1 Then
      maxItemsInPage -= 1
      If names <> Nothing Then
        maxPage = (names.Count - 1) / maxItemsInPage + 1
      Else
        maxPage = (values.Count - 1) / maxItemsInPage + 1
      End If
    End If
  End If

  Dim label_page = Nothing
  If maxPage > 1 Then
    label_page = Wnd.CreateLabel( _
    0, 0, tw + [F_SYS].LineHeight, [F_SYS].LineHeight, 1, 2, [F_SYS], Color.LightGray, "")
    panel.Add(label_page)
  End If

  Return {index, scProc, scParam, names, values, _
    label_cursor, label_caption, label_page, CreateList(), panel}

End Procedure

Procedure ProcessMenu(hMenu)

  Dim selected = hMenu[1]
  Dim scProc = hMenu[2]
  Dim scParam = hMenu[3]
  Dim names = hMenu[4]
  Dim values = hMenu[5]
  Dim label_cursor = hMenu[6]
  Dim label_caption = hMenu[7]
  Dim label_page = hMenu[8]
  Dim labels = hMenu[9]
  Dim panel = hMenu[10]

  Dim items_count = 0
  If names <> Nothing Then
    items_count = names.Count
  Else
    items_count = values.Count
  End If

  Dim has_title = 1
  If label_caption = Nothing AndAlso label_page = Nothing Then has_title = 0

  Dim maxItemsInPage = panel.ClientHeight / [F_SYS].LineHeight - has_title
  Dim maxPage = (items_count - 1) / maxItemsInPage + 1

  Dim prev_selected = 0
  Dim iStart = 0 '1
  Dim iEnd = 0 'Math.Min(maxItemsInPage, items_count)

  Do
    Sleep(0)
    Dim curr = GetInputState()
    Dim diff = (GetPreviousInputState() Xor curr) And curr
    If TestInput(diff, Buttons.Up) Then
      If iStart < selected Then selected -= 1 Else selected = iEnd
      hMenu[1] = selected
    ElseIf TestInput(diff, Buttons.Down) Then
      If selected < iEnd Then selected += 1 Else selected = iStart
      hMenu[1] = selected
    ElseIf TestInput(diff, Buttons.Left) Then
      If 1 < iStart Then
        selected -= maxItemsInPage
        hMenu[1] = selected
      End If
    ElseIf TestInput(diff, Buttons.Right) Then
      If iEnd < items_count Then
        selected = Math.Min(items_count, selected + maxItemsInPage)
        hMenu[1] = selected
      End If
    ElseIf TestInput(diff, Buttons.A) AndAlso items_count > 0 Then
      PlayAudio(Sound.Kettei)
      Exit Do
    ElseIf TestInput(diff, Buttons.B) Then
      selected = 0
      Exit Do
    End If
    If selected < iStart OrElse iEnd < selected Then
      For i = 1 To labels.Count
        panel.Remove(labels[i])
        labels[i].Dispose()
      Next i
      labels.Clear()
      iStart = (selected - 1) / maxItemsInPage * maxItemsInPage + 1
      iEnd = Math.Min(iStart + maxItemsInPage - 1, items_count)
      Dim tw = panel.Width - [F_SYS].LineHeight
      Dim currentPage = (selected - 1) / maxItemsInPage + 1
      If maxPage > 1 Then
        If currentPage = 1 Then
          If currentPage < maxPage Then label_page.Text = " >" Else label_page.Text = "  "
        Else
          If currentPage < maxPage Then label_page.Text = "<>" Else label_page.Text = "< "
        End If
      End If
      For i = iStart To iEnd
        Dim ty = (i - iStart + has_title) * [F_SYS].LineHeight
        If names <> Nothing Then
          panel.Add(Wnd.CreateLabel([F_SYS].LineHeight, ty, tw, [F_SYS].LineHeight, 1, 0, _
            [F_SYS], Color.LightGray, names[i]))
          labels.Add(panel.Children[panel.Children.Count])
        End If
        If values <> Nothing Then
          panel.Add(Wnd.CreateLabel([F_SYS].LineHeight, ty, tw, [F_SYS].LineHeight, 1, 2, _
            [F_SYS], Color.LightGray, values[i]))
          labels.Add(panel.Children[panel.Children.Count])
        End If
      Next
    End If
    label_cursor.Y = (selected - iStart + has_title) * [F_SYS].LineHeight
    If prev_selected <> selected Then
      If scProc <> Nothing Then
        Call(scProc, selected, scParam)
      End If
    End If
    prev_selected = selected
  Loop

  Sleep(0)
  Return selected

End Procedure

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'Specialized Controls
'
'Yes/No
'-YesNo
'
'Katakana Input Box
'-InputKatakana
'
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''


''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'Yes/No
'
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

Procedure DoYesNo()
  Dim hMenu = CreateMenu(600, 200, 70, 50, Nothing, Nothing, _
    Nothing, {"Oui", "Non"}, Nothing, 1)
  Dim result = ProcessMenu(hMenu)
  DestroyControl(hMenu)
  Return result = 1
End Procedure

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'Katakana Input Box
'
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

Procedure InputKatakana(default_text, max_chars)
  Dim hInputWnd = CreateInputBox(250, 200, max_chars * 20, 30, max_chars, { _
    "ア", "イ", "ウ", "エ", "オ", _
    "カ", "キ", "ク", "ケ", "コ", _
    "サ", "シ", "ス", "セ", "ソ", _
    "タ", "チ", "ツ", "テ", "ト", _
    "ナ", "ニ", "ヌ", "ネ", "ノ", _
    "ハ", "ヒ", "フ", "ヘ", "ホ", _
    "マ", "ミ", "ム", "メ", "モ", _
    "ヤ", "ユ", "ヨ", "ヰ", "ヱ", _
    "ラ", "リ", "ル", "レ", "ロ", _
    "ワ", "ヲ", "ン", "ヴ", "ー", _
    "ガ", "ギ", "グ", "ゲ", "ゴ", _
    "ザ", "ジ", "ズ", "ゼ", "ゾ", _
    "ダ", "ヂ", "ヅ", "デ", "ド", _
    "バ", "ビ", "ブ", "ベ", "ボ", _
    "パ", "ピ", "プ", "ペ", "ポ", _
    "ァ", "ィ", "ゥ", "ェ", "ォ", _
    "ャ", "ュ", "ョ", "ッ", "　", _
    "Oui"}, 5, default_text)
  Dim result = ProcessInputBox(hInputWnd)
  DestroyControl(hInputWnd)
  Return result
End Procedure

Procedure DoMsg()
  Dim hMsgWnd = CreateDefaultMsgWindow(GetArguments(), 0)
  ProcessMsgWindow(hMsgWnd)
  DestroyControl(hMsgWnd)
End Procedure

Procedure DoMsgV(msgs)
  Dim hMsgWnd = CreateDefaultMsgWindow(msgs, 0)
  ProcessMsgWindow(hMsgWnd)
  DestroyControl(hMsgWnd)
End Procedure

Procedure DoMsgT(msgs, page_time)
  Dim hMsgWnd = CreateDefaultMsgWindow(msgs, page_time)
  ProcessMsgWindow(hMsgWnd)
  DestroyControl(hMsgWnd)
End Procedure

Procedure DoYesNoMsg()
  Dim hMsgWnd = CreateDefaultMsgWindow(GetArguments(), 0)
  ProcessMsgWindow(hMsgWnd)
  Dim result = DoYesNo()
  DestroyControl(hMsgWnd)
  Return result
End Procedure

Procedure HanToZen(word) 'all chars must be a part of ASCII.
  Dim result = ""
  For i = 1 To String.Len(word)
    result += String.Chr(String.Asc(String.Substring(word, i)) + 0xFEE0)
  Next
  Return result
End Procedure

Procedure MoneyStr(amount)
  Return HanToZen(amount) + [RVII].MoneyUnit
End Procedure
