''dsmplayer.wxb''

Const ID_TIMER_NORM = wxNewId()

Dim normTimer As wxTimer
Dim normPid As Integer
Dim normErrors As Integer
Dim isAnalyze As Integer = FALSE
Dim isNorm As Integer = FALSE
Dim isSearchTag As Integer = FALSE
Dim normCnt As Integer

'create normalize dialog
Sub onNormalize(event As wxCommandEvent)
  Dim explorerMedia As wxGenericDirCtrl = DynamicCast("wxGenericDirCtrl", musicFrame.FindWindowByName("explorermedia"))

  Dim cfg As wxFileConfig = wxFileConfig("", "", playerIni)
  cfg.SetPath("/Normalize")

  Dim sd = New wxDialog(musicFrame, -1, _("Normalize"), wxDefaultPosition, wxSize(1010, 900), wxCAPTION|wxSYSTEM_MENU|wxMINIMIZE_BOX|wxCLOSE_BOX)'|wxSTAY_ON_TOP)
  sd.SetName("normdlg")

  Dim sizeX = sd.GetClientSizeWidth()
  Dim sizeY = sd.GetClientSizeHeight()
'  Dim cfilter = "all Music files|*.aac;*.flac;*.mp3;*.m4a;*.ogg;*.opus;*.wav;*.wv|" &
'  "aac files (*.aac)|*.aac|flac files (*.flac)|*.flac|mp3 files (*.mp3)|*.mp3|m4a files (*.m4a)|*.m4a|ogg files (*.ogg)|*.ogg|opus files (*.opus)|*.opus|wav files (*.wav)|*.wav|wv files (*.wv)|*.wv"

  'currently aac, m4a and wav are not supported
  Dim cfilter = "all Music files|*.flac;*.mp3;*.ogg;*.opus|" &
  "flac files (*.flac)|*.flac|mp3 files (*.mp3)|*.mp3|ogg files (*.ogg)|*.ogg|opus files (*.opus)|*.opus"

  Dim plPanel As wxPanel = wxPanel(sd, -1)
  Dim font As wxFont = wxFont(IIf(ppiH > 100, 8, 9), wxDEFAULT, wxNORMAL, wxNORMAL)
  plPanel.SetFont(font)
  Dim filePath As String = cfg.Read("SourcePath", explorerMedia.GetPath())
  If filePath = "" Then filePath = explorerMedia.GetPath()

  Dim gb As wxGridBagSizer = wxGridBagSizer(3, 3)

  'left side
  Dim filectrl As wxGenericFileCtrl = wxGenericFileCtrl(plPanel, -1, "", "", cFilter, wxFC_OPEN|wxFC_MULTIPLE, wxDefaultPosition, wxSize(sizeX - 130, 300), "batchFileCtrl")
  fileCtrl.SetFilterIndex(0)
  fileCtrl.SetDirectory(filePath)
  gb.AddSpacer(5, 2, wxGBPosition(1, 0))
  gb.AddWindow(fileCtrl, wxGBPosition(1, 1), wxGBSpan(9, 1), 0)

  'controls in the middle
  Dim btn = wxBitmapButton(plPanel, -1, wxArtProvider_GetBitmap(wxART_FOLDER_OPEN, wxART_OTHER, wxSize(16, 16)), wxDefaultPosition, wxSize(30, 30))
  btn.SetToolTip(_("Open a directory"))
  Connect(btn, -1, wxEVT_COMMAND_BUTTON_CLICKED, "onChangeFilePath")
  gb.AddWindow(btn, wxGBPosition(1, 2), wxDefaultSpan, 0)

  Dim cb = wxCheckBox(plPanel, -1, _("Report Mode"))'
  cb.SetName("mode")
  Dim mode = Val(cfg.Read("ReportMode", TRUE))
  cb.SetValue(mode) 
  setReportMode(mode)
  Connect(cb, -1, wxEVT_COMMAND_CHECKBOX_CLICKED, "onReportMode")
  gb.AddWindow(cb, wxGBPosition(2, 2), wxDefaultSpan, 0)

  Dim cb1 = wxCheckBox(plPanel, -1, _("Subdirs"))
  If Val(cfg.Read("IncludeSubs", FALSE)) Then cb1.SetValue(TRUE) 
  cb1.SetName("includeCb")
  gb.AddWindow(cb1, wxGBPosition(3, 2), wxDefaultSpan, 0)
  gb.AddSpacer(1, 3, wxGBPosition(4, 2))

  'buttons right
  btn = wxBitmapButton(plPanel, -1, wxArtProvider_GetBitmap(wxART_PLUS, wxART_OTHER, wxSize(24, 24)), wxDefaultPosition, wxSize(110, 50))
  Connect(btn, -1, wxEVT_COMMAND_BUTTON_CLICKED, "onAddNormFiles")
  btn.SetName("addfiles")
  btn.SetToolTip(_("Add selected files"))
  gb.AddWindow(btn, wxGBPosition(5, 2), wxDefaultSpan, 0)

  btn = wxBitmapButton(plPanel, -1, iList["addAllNorm"], wxDefaultPosition, wxSize(110, 50))
  btn.SetName("addallfiles")
  btn.SetToolTip(_("Add all files"))
  Connect(btn, -1, wxEVT_COMMAND_BUTTON_CLICKED, "onAddAllNormFiles")
  gb.AddWindow(btn, wxGBPosition(6, 2), wxDefaultSpan, 0)

  'create clear button
  btn = wxBitmapButton(plPanel, -1, wxArtProvider_GetBitmap(wxART_NORMAL_FILE, wxART_OTHER, wxSize(24, 24)), wxDefaultPosition, wxSize(110, 50))
  Connect(btn, -1, wxEVT_COMMAND_BUTTON_CLICKED, "onClearAnalyzeList")
  btn.SetName("clearlist")
  btn.SetToolTip(_("Delete task list"))
  gb.AddWindow(btn, wxGBPosition(7, 2), wxDefaultSpan, 0)
  gb.AddSpacer(5, 30, wxGBPosition(8, 2), wxGBSpan(1, 1))

  'create overwrite checkbox
  Dim cb2 = wxCheckBox(plPanel, -1, _("Tag ovr"))
  cb2.SetValue(cfg.Read("OverwriteTags", FALSE)) 
  cb2.SetName("overwrite")
  gb.AddWindow(cb2, wxGBPosition(9, 2), wxDefaultSpan, 0)
  gb.AddSpacer(1, 3, wxGBPosition(10, 1))

  Dim bsizer = wxBoxSizer(wxHORIZONTAL)
  'create analyze loudness button
  Dim analyzeButton = wxButton(plPanel, -1, _("Analyze loudness"), wxDefaultPosition, wxSize(-1, 30))
  Connect(analyzeButton, -1, wxEVT_COMMAND_BUTTON_CLICKED, "onAnalyzeButtonClick")
  analyzeButton.SetName("analyze")
  analyzeButton.SetToolTip(_("Analyze the volume of the files.") &"\n" &_("This has no effect on other actions") &"\n" &_("and is for information purposes only."))
  bSizer.AddWindow(analyzeButton, wxEXPAND, 0)

  'create clear all tags button
  Dim clearButton = wxButton(plPanel, -1, _("Clear all tags"), wxDefaultPosition, wxSize(-1, 30))
  Connect(clearButton, -1, wxEVT_COMMAND_BUTTON_CLICKED, "onClearTags")
  clearButton.SetName("cleartags")
  clearButton.SetToolTip(_("Delete all tags in the files"))
  bSizer.AddWindow(clearButton, wxEXPAND, 0)

  'create clear additional tags button
  Dim clearAButton = wxButton(plPanel, -1, _("Clear ID3v2/additional tags"), wxDefaultPosition, wxSize(-1, 30))
  Connect(clearAButton, -1, wxEVT_COMMAND_BUTTON_CLICKED, "onClearAddTags")
  clearAButton.SetName("clearaddtags")
  clearAButton.SetToolTip(_("Clear ID3v2 and additional tags only") &"\n" &_("Leave the ID3v1 tag"))
  bSizer.AddWindow(clearAButton, wxEXPAND, 0)

  'add ID3v1 tags from filename
  Dim AddButton = wxButton(plPanel, -1, _("Add Tags from filename"), wxDefaultPosition, wxSize(-1, 30))
  Connect(AddButton, -1, wxEVT_COMMAND_BUTTON_CLICKED, "onAddTags")
  AddButton.SetName("addtags")
  AddButton.SetToolTip(_("Add ID3v1 tags from filename.") &"\n" &_("All names must be in the same format."))
  bSizer.AddWindow(AddButton, wxEXPAND, 0)

  'create convert button
  Dim normButton = wxButton(plPanel, -1, _("Start normalize"), wxDefaultPosition, wxSize(-1, 30))
  Connect(normButton, -1, wxEVT_COMMAND_BUTTON_CLICKED, "onNormButtonClick")
  normButton.SetName("normalize")
  normButton.SetToolTip(_("Start normalyze process"))
  bSizer.AddWindow(normButton, wxEXPAND, 0)

  gb.AddSizer(bSizer, wxGBPosition(11, 1), wxGBSpan(1, 2), wxEXPAND)

  'create the listctrl for showing the files an datas
  Dim normCtrl As wxListCtrl = wxListCtrl(plPanel, -1, wxPoint(10, 370), wxSize(-1, sizeY - 400), wxLC_REPORT|wxLC_SINGLE_SEL)
  normCtrl.SetName("normlist")
  normCtrl.InsertColumnInfo(0, _("No."))
  normCtrl.InsertColumnInfo(1, _("File"))
  normCtrl.InsertColumnInfo(2, _("Loudness"), wxLIST_FORMAT_RIGHT)
  normCtrl.InsertColumnInfo(3, _("Tag present"), wxLIST_FORMAT_RIGHT)
  gb.AddWindow(normCtrl, wxGBPosition(12, 1), wxGBSpan(1, 2), wxEXPAND)
  gb.AddSpacer(1, 3, wxGBPosition(13, 1))

  Dim Ok As wxButton = wxButton(plPanel, wxID_OK, _("Close"), wxDefaultPosition, wxSize(-1, 30))
  Ok.SetName("closebtn")
  gb.AddWindow(Ok, wxGBPosition(14, 1), wxGBSpan(1, 2), wxEXPAND)

  plPanel.SetAutoLayout(TRUE)
  plPanel.SetSizerAndFit(gb)

  normCtrl.SetColumnWidth(0, 50)
  normCtrl.SetColumnWidth(1, normCtrl.GetClientSizeWidth() - 265)
  normCtrl.SetColumnWidth(2, 100)
  normCtrl.SetColumnWidth(3, 100)
  sd.ShowModal()

  cfg.SetPath("/Normalize")
  cfg.Write("ReportMode", cb.GetValue())
  cfg.Write("IncludeSubs", cb1.GetValue())
  cfg.Write("SourcePath", fileCtrl.GetDirectory())
  cfg.Write("OverwriteTags", cb2.GetValue())
  sd.Destroy()
End Sub


'add selected files to the listctrl and check for existing gain tag
Sub onAddNormFiles(event As wxCommandEvent)
  Dim ctrl = DynamicCast("wxGenericFileCtrl", wxFindWindowByName("batchFileCtrl"))
  Dim lc = DynamicCast("wxListCtrl", wxFindWindowByName("normlist"))

  Dim allFiles As wxArrayString = ctrl.GetPaths()
  isSearchTag = TRUE
  EnableButtons()
  Dim cnt As Integer = lc.GetItemCount()

  For i = 0 To allFiles.Count() - 1
    If !wxFileName_DirExists(allFiles.Item(i)) Then
      lc.InsertStringItem(cnt, cnt + 1)
      lc.SetStringItem(cnt, 1, allFiles.Item(i))
      checkGainTag(cnt)
      cnt += 1
    End If
  Next

  isSearchTag = FALSE
  isAnalyze = FALSE
  EnableButtons()

  allFiles.Clear()
End Sub


'add all files to the listctrl and check for existing gain tag
Sub onAddAllNormFiles(event As wxCommandEvent)
  isSearchTag = TRUE
  isAnalyze = FALSE
  EnableButtons()

  Dim lc = DynamicCast("wxListCtrl", wxFindWindowByName("normlist"))
  Dim ctrl = DynamicCast("wxGenericFileCtrl", wxFindWindowByName("batchFileCtrl"))
  Dim ictrl = DynamicCast("wxCheckBox", wxFindWindowByName("includeCb"))

  Dim allFiles As wxArrayString = wxArrayString()
  Dim Style As Integer = IIf(iCtrl.GetValue(), wxDIR_FILES|wxDIR_DIRS, wxDIR_FILES)

  Dim wild As wxStringTokenizer = wxStringTokenizer(ctrl.GetWildcard(), "|")
  Dim fIndex As Integer = ctrl.GetFilterIndex()
  Dim cnt As Integer = 0
  Dim filter As String

  For i = 1 To wild.CountTokens()/ 2
    wild.GetNextToken()
    filter = wild.GetNextToken()
    If cnt = fIndex Then Break
    cnt += 1
  Next

  ctrl.SetFocus()
  wild.SetString(filter, ";")

  While TRUE
    wxDir_GetAllFiles(ctrl.GetShownDirectory(), allFiles, wild.GetNextToken(), Style)
    If !wild.CountTokens() Then Break
  Wend

  allFiles.Sort()
  For i = 0 To allFiles.Count() - 1
    lc.InsertStringItem(i, i + 1)
    lc.SetStringItem(i, 1, allFiles.Item(i))
    checkGainTag(i)
  Next

  allFiles.Clear()
  wild.AllowEmpty()

  isSearchTag = FALSE
  EnableButtons()
End Sub


'clear the listctrl
Sub onClearAnalyzeList(event As wxCommandEvent)
  Dim lctrl = DynamicCast("wxListCtrl", wxFindWindowByName("normlist"))
  lctrl.DeleteAllItems()
End Sub


'start analyze process
Sub onAnalyzeButtonClick(event As wxCommandEvent)
  Dim lc = DynamicCast("wxListCtrl", wxFindWindowByName("normlist"))

  isAnalyze = !isAnalyze
  EnableButtons()
 
  If !isAnalyze Then
    isBroken = TRUE
    wxYield()
    If infoPrc Then wxProcess_Kill(infoPrc.GetPid(), wxSIGKILL)

  Else

    If lc.GetItemCount() >= 0 Then
      isBroken = FALSE

      For normCnt = 0 To lc.GetItemCount() - 1
        If lc.GetStringItem(normCnt, 2) = "" Then Break
      Next

      If normCnt < lc.GetItemCount() Then
        'create the timer for getting normalize informations
        normTimer = New wxTimer(musicFrame, ID_TIMER_NORM)
        Connect(musicFrame, ID_TIMER_NORM, wxEVT_TIMER, "onNormTimer")
        normTimer.Start(100)

        phiolaAnalyze()

      Else

        isAnalyze = FALSE
        EnableButtons()
      end if
    End If
  End If
End Sub


'analyze the loudness value for the given item
Sub phiolaAnalyze()
  Dim lc = DynamicCast("wxListCtrl", wxFindWindowByName("normlist"))
  lc.SetStringItem(normCnt, 2, _("analyze..."))
  lc.EnsureVisible(normCnt)

  'execute phiola to get the file informations
  infoPrc = New wxProcess(musicFrame)
  infoPrc.Redirect()
  Connect(infoPrc, wxEVT_END_PROCESS, "onEndAnalyze")
  Dim pid = wxExecute(Chr(34) &phiolaPath &Chr(34) &" info -loudness " &Chr(34) & lc.GetStringItem(normCnt, 1) &Chr(34), wxEXEC_ASYNC, infoPrc)

  If !pid Then
    ~infoPrc
    infoPrc = Nothing
  End If
End Sub


'the analyze process has ended
'check for next file
Sub onEndAnalyze(event As wxProcessEvent)
  Dim lc = DynamicCast("wxListCtrl", wxFindWindowByName("normlist"))
  Dim exitcode = event.GetExitCode()

  'unichar characters in filename are displayerd correctly, but
  'GetPath() from wxGenericFileCtrl or wxDir_GetAllFiles() return an empty string
  'for this reason, an error is generated
  If exitcode > 0 Then
    lc.SetStringItem(normCnt, 2, _("Fehler"))

  Elseif event.GetExitCode()< 0 Then
    lc.SetStringItem(normCnt, 2, "" )

  Elseif lc.GetStringItem(normCnt, 2)= _("analyze...") Then
    lc.SetStringItem(normCnt, 2, "" )
  End If

  normCnt += 1
  infoPrc = Nothing

  If normCnt < lc.GetItemCount() And !isBroken Then
    phiolaAnalyze()

  Else
    normTimer.Stop()
    ~normTimer
    isAnalyze = FALSE
    EnableButtons()
  End If

  wxYield()
End Sub


'read the stream with a timer
Sub onNormTimer(event As wxTimerEvent)
  If !readInfoStream() Then normTimer.Stop()
End Sub


Function readInfoStream()
  If infoPrc And infoPrc.IsInputOpened() Then
    'read the stream
    Dim errStream = infoPrc.GetErrorStream()
    Dim inStream = infoPrc.GetInputStream()

    If inStream And inStream.IsOk() And !isBroken Then

      'use textinputstream to read the lines
      Dim tStream As wxTextInputStream = wxTextInputStream(inStream)
      Dim lc = DynamicCast("wxListCtrl", wxFindWindowByName("normlist"))
      Dim at As Integer
      Dim at1 As Integer
      Dim buffer As String = ""
      Dim frameErr As Integer = FALSE
      Dim cnt As Integer = 0
      Dim IsError As Integer = FALSE
      Dim path As String = LCase(lc.GetStringItem(normCnt, 1))

     'read the error stream
      While infoPrc.IsErrorAvailable()
        errStream.Read(8)
      Wend

      While !inStream.Eof()
        buffer = LCase(tStream.ReadLine())
        If buffer[: 1]= "[" Then
          cnt += 1
          If cnt%100 = 0 Then wxYield()
          Continue
        End If

        If isAnalyze Then
          at = RInstr(buffer, "loudness:")
          If at Then lc.SetStringItem(normCnt, 2, buffer[RInstr(buffer, " ")+ 1: ])

        Elseif isNorm Then
          at1 = InStr(buffer, "error")

          If at1 And (buffer[: 1] != "#") And (at1 < InStr(buffer, "file ")) Then
            errCnt += 1
            IsError = TRUE

            If InStr(buffer, "unsupported") Then
              lc.SetStringItem(normCnt, 3, _("unsupported"))

            Elseif InStr(buffer, "detect file format") Then
              frameErr = TRUE
              lc.SetStringItem(normCnt, 3, "--" )
            End If
          End If
          
          If !IsError Then
            at = RInstr(buffer, "loudness:")
            If at Then lc.SetStringItem(normCnt, 3, buffer[RInstr(buffer, " ")+ 1: ])
          End If
        End If
      Wend

      ~tStream
    End If
  End If

  Return IIf(frameErr, FALSE, TRUE)
End Function


'start the normalite process
Sub onNormButtonClick(event As wxCommandEvent)
  Dim lc = DynamicCast("wxListCtrl", wxFindWindowByName("normlist"))
  isNorm = !isNorm
  EnableButtons()
  errMsg = ""
  errCnt = 0

  If !isNorm Then
    isBroken = TRUE
    wxYield()
    If infoPrc Then wxProcess_Kill(infoPrc.GetPid(), wxSIGKILL)

  Else

    isBroken = FALSE
    normCnt = 0

    If lc.GetItemCount() >= 0 Then
      Dim cb = DynamicCast("wxCheckbox", wxFindWindowByName("overwrite"))
      If !cb.IsChecked() Then
        For normCnt = 0 To lc.GetItemCount() - 1
          If lc.GetStringItem(normCnt, 3) = "--" Then Break
        Next
      End If

      If normCnt < lc.GetItemCount() Then
        normTimer = New wxTimer(musicFrame, ID_TIMER_NORM)
        Connect(musicFrame, ID_TIMER_NORM, wxEVT_TIMER, "onNormTimer")
        normTimer.Start(100)
        phiolaNormalize(normCnt)

      Else

        isNorm = FALSE
        EnableButtons()
      End If
    End If
  End If
End Sub


'analyze and write tag to the file
Sub phiolaNormalize(cnt As Integer)
  Dim lc = DynamicCast("wxListCtrl", wxFindWindowByName("normlist"))
  Dim path As String = lc.GetStringItem(cnt, 1)

  Dim FileName As wxFileName = wxFileName(path)
  Dim IsWritable As Integer = FileName.IsFileWritable()

  If lc.GetStringItem(cnt, 3)= _("unsupported") or !isWritable Then
    If !isWritable Then lc.SetStringItem(cnt, 3, _("read-only"))
    errCnt += 1
    normCnt += 1

    If normCnt <= lc.GetItemCount() - 1 Then
      phiolaNormalize(normCnt)

    Else

      normTimer.Stop()
      ~normTimer
      normTimer = Nothing
      isNorm = FALSE
      EnableButtons()
    End If

    Return
  End If

  lc.SetStringItem(cnt, 3, _("write..."))
  lc.EnsureVisible(cnt)

  'execute phiola to get the file informations
  infoPrc = New wxProcess(musicFrame)
  infoPrc.Redirect()
  Connect(infoPrc, wxEVT_END_PROCESS, "onEndNormalize")

  Dim pid = wxExecute(Chr(34) &phiolaPath &Chr(34) &" tag -rg track_gain " &"\"" &path &"\"", wxEXEC_ASYNC, infoPrc)
  If !pid Then
    ~infoPrc
    infoPrc = Nothing
    lc.SetStringItem(cnt, 3, "--")
  End If
End Sub


'end normalize process
Sub onEndNormalize(event As wxProcessEvent)
  Dim lc = DynamicCast("wxListCtrl", wxFindWindowByName("normlist"))
  Dim exitcode = event.GetExitCode()
  Dim path As String = lc.GetStringItem(normCnt, 1)

  Dim Ok As Integer = readInfoStream()
  If !normTimer.IsRunning() Then Ok = FALSE
  infoPrc = Nothing

  'possibly the timer is stopped in timer event
  If !Ok Then
    Dim dl = wxGenericMessageDialog(Nothing, _("It looks like the file header starts with a corrupted frame.") &"\n" &
    _("Should an attempt be made to correct this?"), wxFileNameFromPath(path), wxYES_NO | wxCANCEL|wxYES_DEFAULT | wxICON_QUESTION|wxDIALOG_NO_PARENT)

    'wxYes = 5103 in wxGenericMessageDialog
    Dim action As Integer = dl.ShowModal()
    If action = 5103 Then
      correctFrames(path)

    Elseif action = 5104 Then
      Ok = TRUE

    Else

      Ok = TRUE
      normcnt = lc.GetItemCount()
    End If
  End If


  If Ok Then
    If exitCode = -1 Then
      lc.SetStringItem(normCnt, 3, "--" )
      normcnt = lc.GetItemCount()
    End If

    normCnt += 1
    If !normTimer.IsRunning() Then normTimer.Start(100)

    If normCnt < lc.GetItemCount() Then
      Dim cb = DynamicCast("wxCheckbox", wxFindWindowByName("overwrite"))
      If !cb.IsChecked() Then
        'check for next empty tag
        While (normCnt < lc.GetItemCount()) And (lc.GetStringItem(normCnt, 3) <> "--")
          normCnt += 1
        Wend
      End If

      If normCnt < lc.GetItemCount() Then
        wxYield()
        phiolaNormalize(normCnt)

      Else
        normTimer.Stop()
        ~normTimer
        normTimer = Nothing
        isNorm = FALSE
        EnableButtons()
      End If

    Else
      normTimer.Stop()
      ~normTimer
      normTimer = Nothing
      isNorm = FALSE
      EnableButtons()
    End If

    If !isNorm Then
      dl = wxGenericMessageDialog(lc, _("Tags written with") &" " &errCnt &" " &_("error(s)") &"\n" &errMsg, _("Write tags"), wxOK|wxICON_INFORMATION|wxSTAY_ON_TOP)
      dl.Raise()
      dl.ShowModal()
    End If
  End If
End Sub


Sub correctFrames(path As String)
  Dim prc = New wxProcess(musicFrame)
  Connect(prc, wxEVT_END_PROCESS, "onEndCorrection")
  prc.Redirect()

  Dim pid = wxExecute(Chr(34) &phiolaPath &Chr(34) &" co -copy " &Chr(34) &path &Chr(34) &" -o " &Chr(34) &wxPathOnly(path) &DELIMITER_CHAR &"temp.mp3" &Chr(34), wxEXEC_ASYNC, prc)

  If !pid Then
    ~prc

  Else

    Dim errStream = prc.GetErrorStream()
    Dim inStream = prc.GetInputStream()

    If inStream And inStream.IsOk() Then
     'read the error stream
      While prc.IsErrorAvailable()
        errStream.Read(1)
      Wend

      'read th real stream
      While !inStream.Eof()
        inStream.Read(1)
      Wend
    End If
  End If
End Sub


Sub onEndCorrection(event As wxProcessEvent)
  Dim lc = DynamicCast("wxListCtrl", wxFindWindowByName("normlist"))
  Dim path As String = lc.GetStringItem(normCnt, 1)
  Dim tempfile As String = wxPathOnly(path) &DELIMITER_CHAR &"temp.mp3"

  Dim Ok = wxRenameFile(tempfile, path)
  If !Ok Then
    If wxFileExists(tempFile) Then Kill(tempFile)
    normCnt += 1
  Else
    errCnt -= 1
  End If

  If !normTimer.IsRunning() Then normTimer.Start(100)
  phiolaNormalize(normCnt)
End Sub


'check for gain tag in the given file
Sub checkGainTag(cnt As Integer)
  Dim lc = DynamicCast("wxListCtrl", wxFindWindowByName("normlist"))
  Dim path As String = lc.GetStringItem(cnt, 1)

  'execute phiola to get the gain tag informations
  infoPrc = New wxProcess(musicFrame)
  infoPrc.Redirect()
  Connect(infoPrc, wxEVT_END_PROCESS, "onEndInfoProcess")

  Dim pid = wxExecute(Chr(34) &phiolaPath &Chr(34) &" info -tags " &"\"" &path &"\"", wxEXEC_ASYNC, infoPrc)
  If !pid Then
    ~infoPrc
    infoPrc = Nothing

  Else

    Dim inStream = infoPrc.GetInputStream()

    'read the stream
    Dim buffer As String = ""
    If inStream And inStream.IsOk() Then
      While !inStream.Eof()
        buffer &= inStream.Read(8)
      Wend
    End If

    If InStr(LCase(buffer), "error") And !InStr(buffer, "[") Then
      lc.SetStringItem(cnt, 3, _("Fehler"))

    Else

      Dim at As Integer = 0
      Dim ext = GetFileFormat(path)
      Dim message As String = ""

      Select Case ext
      Case "m4a", "wav", "aac": at = 0: message = _("unsupported")
      Case "opus": at = RInstr(LCase(buffer), "r128_track_gain")
      Case "mp3", "ogg", "flac": at = RInstr(LCase(buffer), "replaygain_track_gain")
      End Select

      If at Then
        at = InStr(at, buffer, "\t")+ 1
        buffer = Trim(buffer[at: InStr(at + 1, buffer, "\n") - 1])

        Try
          If Right(LCase(buffer), 2)= "db" Then buffer = buffer[: RInstr(buffer, " ") - 1]
          lc.SetStringItem(cnt, 3, extend(buffer))
        Catch
          lc.SetStringItem(cnt, 3, "--")
        End Try

      Elsif message <> "" Then
        lc.SetStringItem(cnt, 3, message)

      Else
        lc.SetStringItem(cnt, 3, "--")
      End If
    End If

    wxYield()
  End If
End Sub


'enable or disable buttons in dialog
Sub EnableButtons()
  Dim btn1 = DynamicCast("wxButton", wxFindWindowByName("addfiles"))
  Dim btn2 = DynamicCast("wxButton", wxFindWindowByName("addallfiles"))
  Dim btn3 = DynamicCast("wxButton", wxFindWindowByName("clearlist"))
  Dim btn4 = DynamicCast("wxButton", wxFindWindowByName("analyze"))
  Dim btn5 = DynamicCast("wxButton", wxFindWindowByName("normalize"))
  Dim btn6 = DynamicCast("wxButton", wxFindWindowByName("cleartags"))
  Dim btn7 = DynamicCast("wxButton", wxFindWindowByName("clearaddtags"))
  Dim btn8 = DynamicCast("wxButton", wxFindWindowByName("addtags"))
  Dim Ok = DynamicCast("wxButton", wxFindWindowByName("closebtn"))

  Dim se As Integer = !(isAnalyze Or isNOrm or isSearchTag)
  btn1.Enable(se)
  btn2.Enable(se)
  btn3.Enable(se)
  btn6.Enable(se)
  btn7.Enable(se)
  btn8.Enable(se)

  If isanalyze Then
    btn4.SetLabel(_("Stop Analyze"))
    btn4.SetBackgroundColour(wxRED)
  Else
    btn4.SetLabel(_("Analyze Loudness"))
    btn4.SetBackgroundColour(wxNullColour)
    btn4.Enable( !(isNOrm or isSearchTag))
  End If

  If isNorm Then
    btn5.SetLabel(_("Stop Normalize"))
    btn5.SetBackgroundColour(wxRED)
  Else
    btn5.SetLabel(_("Start Normalize"))
    btn5.SetBackgroundColour(wxNullColour)
    btn5.Enable( !(isAnalyze Or isSearchTag))
  End If

  Ok.Enable(se)
End Sub


'clear all tags
Sub onClearTags(event As wxCommandEvent)
  Dim lc = DynamicCast("wxListCtrl", wxFindWindowByName("normlist"))
  Dim dl = wxGenericMessageDialog(lc, _("Do you really want to delete all tags?") &"\n" &_("This cannot be undone!") &"\n" &_("You do this at your own risk!") &"\n\n" &
  _("APE tags cannot be deleted and will be ignored!"), _("Attention"), wxYES_NO|wxNO_DEFAULT|wxCENTRE|wxICON_EXCLAMATION)

  'wxYes = 5103 in wxGenericMessageDialog
  If dl.ShowModal() = 5103 Then 

    errMsg = ""
    errCnt = 0
    If busyInfo Then ~busyInfo
    busyInfo = wxBusyInfo(_("Delete tags..."))

    For i = 0 To lc.GetItemCount() - 1
      If clearTag(lc.GetStringItem(i, 1)) Then checkGainTag(i)
    Next
    ~busyInfo
    busyInfo = Nothing

    Dim dl1 = wxGenericMessageDialog(lc, _("Tags deleted with") &" " &errCnt &" " &_("errors") &"\n" &errMsg, _("Delete tags"), wxOK|wxICON_INFORMATION)
    dl1.Raise()
    dl1.ShowModal()
  End If
End Sub


'clear the tag for the given file
Function clearTag(path As String)
  'execute phiola to get the gain tag informations
  infoPrc = New wxProcess(musicFrame)
  infoPrc.Redirect()
  Connect(infoPrc, wxEVT_END_PROCESS, "onEndInfoProcess")

  Dim pid = wxExecute(Chr(34) &phiolaPath &Chr(34) &" tag -clear " &"\"" &path &"\"", wxEXEC_ASYNC, infoPrc)
  If !pid Then
    ~infoPrc
    infoPrc = Nothing

  Else

    Dim inStream = infoPrc.GetInputStream()

    'read the stream
    Dim buffer As String = ""
    If inStream And inStream.IsOk() Then
      While !inStream.Eof()
        buffer&= inStream.Read(1)
      Wend
    End If

    Dim at As Integer = InStr(buffer, "written to file")
    If !at Then
      errCnt += 1
      Dim ext = GetFileFormat(path)

      Select Case ext
      Case "m4a", "wav", "aac"
        If errCnt < 30 Then 
          errMsg &= wxFileNameFromPath(path) &" - " &_("unsupported file format" &"\n")

        Elseif errCnt = 30 Then
          errMsg&= "..."
        End If
      End Select
    End If
  End If

  Return TRUE
End Function


'clear additional tags
'leave ID3v1 tags
Sub onClearAddTags(event As wxCommandEvent)
  Dim dl = wxGenericMessageDialog(Nothing, _("Do you really want to delete ID3v2 and additional tags?") &"\n" &_("This cannot be undone!") &"\n" &_("You do this at your own risk!") &"\n\n" &
  _("APE tags cannot be deleted and will be ignored!"), _("Attention"), wxYES_NO|wxNO_DEFAULT|wxCENTRE|wxICON_EXCLAMATION)

  'wxYes = 5103 in wxGenericMessageDialog
  If dl.ShowModal() = 5103 Then 
    Dim lc = DynamicCast("wxListCtrl", wxFindWindowByName("normlist"))

    errMsg = ""
    errCnt = 0
    If busyInfo Then ~busyInfo
    busyInfo = wxBusyInfo(_("Delete additional tags..."))

    For i = 0 To lc.GetItemCount() - 1
      If lc.GetStringItem(i, 3)<> _("unsupported") Then
        clearAddTag(lc.GetStringItem(i, 1))
        checkGainTag(i)
      End If
    Next

    If busyInfo Then ~busyInfo
    busyInfo = Nothing

    'if phiola can not write to the file, 2 errors occur in one file
    'once when trying to delete the tags and once when trying to write back the id3v1 tags
    If errCnt Then errcnt /= 2

    Dim dl1 = wxGenericMessageDialog(Nothing, _("Tags deleted with") &" " &errCnt &" " &_("errors") &"\n" &errMsg, _("Delete tags"), wxOK|wxICON_INFORMATION|wxDIALOG_NO_PARENT)
    dl1.Raise()
    dl1.ShowModal()
  End If
End Sub


'clear the tags
Sub clearAddTag(path As String)
  'execute phiola to get the tag informations
  infoPrc = New wxProcess(musicFrame)
  infoPrc.Redirect()
  Connect(infoPrc, wxEVT_END_PROCESS, "onEndInfoProcess")

  'read all tag informations
  Dim buffer, aTitle, aArtist, aAlbum, aYear, aTrack, aComment, aGenre, temp As String
  buffer, aTitle, aArtist, aAlbum, aYear, aTrack, aComment, aGenre, temp = readID3Tags(path)

  'clear all tags
  If clearTag(path) Then

  'write back ID3v1 tags
  writeID3v1Tag(aTitle, aArtist, aAlbum, aYear, aTrack, aComment, aGenre, path, FALSE)
  End If
End Sub


'add tags from filename
Sub onaddTags(event As wxCommandEvent)
  Dim dlg = wxDialog(musicFrame, -1, _("Add IDv1 tags from FileName"), wxDefaultPosition, wxSize(630, 400), wxCAPTION)
  Dim w = dlg.GetClientSizeWidth()
  Dim h = dlg.GetClientSizeHeight()
  Dim Ok As wxButton = wxButton(dlg, wxID_OK, _("Ok"), wxPoint(0, h - 30), wxSize(w / 3, 30))
  Dim Apply = wxButton(dlg, wxID_APPLY, _("Test run"), wxPoint(w / 3, h - 30), wxSize(w / 3, 30))
  Connect(Apply, -1, wxEVT_COMMAND_BUTTON_CLICKED, "onTestTags")
  Dim Cancel As wxButton = wxButton(dlg, wxID_CANCEL, _("Cancel"), wxPoint(w / 3 * 2, h - 30), wxSize(w / 3, 30))

  Dim seps As List = ["-", ",", "&", "#", "_"]
  Dim sb1 As wxStaticBox = wxStaticBox(dlg, -1, _("Separator between the information"), wxPoint(10, 10), wxSize(w - 20, 80))
  Dim rb[5]
  rb[1] = wxRadioButton(sb1, wxID_HIGHEST + 4101, Space(3) &Chr(34) &" - " &Chr(34) &Space(2) &_("(Minus)"), wxPoint(10, 25))
  rb[2] = wxRadioButton(sb1, wxID_HIGHEST + 4102, Space(3) &Chr(34) &" , " &Chr(34) &Space(2) &_("(Comma)"), wxPoint(180, 25))
  rb[3] = wxRadioButton(sb1, wxID_HIGHEST + 4103, Space(3) &Chr(34) &" " &"&&" &" " &Chr(34) &Space(2) &_("(And) "), wxPoint(350, 25))
  rb[4] = wxRadioButton(sb1, wxID_HIGHEST + 4104, Space(3) &Chr(34) &" # " &Chr(34) &Space(2) &_("(Rhombus)"), wxPoint(10, 50))
  rb[5] = wxRadioButton(sb1, wxID_HIGHEST + 4105, Space(3) &Chr(34) &" _ " &Chr(34) &Space(2) &_("(Underscore) "), wxPoint(180, 50))
  For i = 1 To seps.Count()
    If fileSep = seps[i] Then rb[i].SetValue(TRUE)
    Connect(rb[i], wxID_HIGHEST + 4100 + i, wxEVT_COMMAND_RADIOBUTTON_SELECTED, "onFileSepSelected")
  Next

  Dim arr As wxArrayString = wxArrayString()
  arr.Add("")
  arr.Add("Album")
  arr.Add("Artist")
  arr.Add("Title")
  arr.Add("Track")
  arr.Add("Year")

  Dim sb2 As wxStaticBox = wxStaticBox(dlg, -1, _("Format of the file name"), wxPoint(10, 100), wxSize(w - 20, 170))
  Dim st = wxStaticText(sb2, -1, _("First place"), wxPoint(10, 32))
  Dim cb1 As wxComboBox = wxComboBox3(sb2, -1, "" , wxPoint(150, 30), wxSize(150, 25), arr , wxCB_DROPDOWN | wxCB_READONLY)
  cb1.SetName("first")
  st = wxStaticText(sb2, -1, _("Second place"), wxPoint(10, 57))
  Dim cb2 As wxComboBox = wxComboBox3(sb2, -1, "" , wxPoint(150, 55), wxSize(150, 25), arr , wxCB_DROPDOWN | wxCB_READONLY)
  cb2.SetName("second")
  st = wxStaticText(sb2, -1, _("Third place"), wxPoint(10, 82))
  Dim cb3 As wxComboBox = wxComboBox3(sb2, -1, "" , wxPoint(150, 80), wxSize(150, 25), arr , wxCB_DROPDOWN | wxCB_READONLY)
  cb3.SetName("third")
  st = wxStaticText(sb2, -1, _("Fourth place"), wxPoint(10, 107))
  Dim cb4 As wxComboBox = wxComboBox3(sb2, -1, "" , wxPoint(150, 105), wxSize(150, 25), arr , wxCB_DROPDOWN | wxCB_READONLY)
  cb4.SetName("fourth")
  st = wxStaticText(sb2, -1, _("Fifth place"), wxPoint(10, 137))
  Dim cb5 As wxComboBox = wxComboBox3(sb2, -1, "" , wxPoint(150, 130), wxSize(150, 25), arr , wxCB_DROPDOWN | wxCB_READONLY)
  cb5.SetName("fifth")

  If dlg.ShowModal()= wxID_OK Then
    Dim lc = DynamicCast("wxListCtrl", wxFindWindowByName("normlist"))
    Dim aTitle, aArtist, aAlbum, aYear, aTrack As String
    Dim aComment As String = ""
    Dim aGenre As String = ""
    Dim path As String
    errCnt = 0
    errMsg = ""

    For i = 0 To lc.GetItemCount() - 1
      path = lc.GetStringItem(i, 1)
      aTitle, aArtist, aAlbum, aYear, aTrack = getFileInfos(wxFileNameFromPath(path))
      writeID3v1Tag(aTitle, aArtist, aAlbum, aYear, aTrack, aComment, aGenre, path, TRUE)
    Next

    Dim dl1 =wxGenericMessageDialog(Nothing, _("Tags created with") &" " &errCnt &" " &_("errors") &"\n" &errMsg, _("Create tags"), wxOK|wxICON_INFORMATION|wxDIALOG_NO_PARENT)
    dl1.Raise()
    dl1.ShowModal()
  End If

  dlg.Destroy()
End Sub


'test writing tags
'show results in a textctrl
Sub onTestTags(event As wxCommandEvent)
  Dim dlg As wxDialog = wxDialog(musicFrame, -1, _("Preview"), wxDefaultPosition, wxSize(700, 500))
  dlg.Center()
  Dim w = dlg.GetClientSizeWidth()
  Dim h = dlg.GetClientSizeHeight()
  Dim Ok As wxButton = wxButton(dlg, wxID_OK, _("Ok"), wxPoint(0, h - 30), wxSize(w, 30))
  Dim tCtrl As wxTextCtrl = wxTextCtrl(dlg, -1, "", wxPoint(0, 0), wxSize(w, h - 30), wxTE_MULTILINE)
  tCtrl.SetName("previewCtrl")

  Dim lc = DynamicCast("wxListCtrl", wxFindWindowByName("normlist"))
  Dim aTitle, aArtist, aAlbum, aYear, aTrack, aCommand, aGenre As String
  Dim cb1 = DynamicCast("wxComboBox", wxFindWindowByName("first"))
  Dim cb2 = DynamicCast("wxComboBox", wxFindWindowByName("second"))
  Dim cb3 = DynamicCast("wxComboBox", wxFindWindowByName("third"))
  Dim cb4 = DynamicCast("wxComboBox", wxFindWindowByName("fourth"))
  Dim cb5 = DynamicCast("wxComboBox", wxFindWindowByName("fifth"))
  Dim path As String

  For i = 0 To lc.GetItemCount() - 1
    path = lc.GetStringItem(i, 1)
    aTitle, aArtist, aAlbum, aYear, aTrack = getFileInfos(wxFileNameFromPath(path))

    tCtrl.AppendText(path &":\n")
    tCtrl.AppendText("Track: " &aTrack &"\n")
    tCtrl.AppendText("Title: " &aTitle &"\n")
    tCtrl.AppendText("Artist: " &aArtist&"\n")
    tCtrl.AppendText("Album: " &aAlbum &"\n")
    tCtrl.AppendText("Year: " &aYear &"\n\n")
  Next

  dlg.ShowModal()
  dlg.Destroy()
End Sub


'get the file infos from the given path
'return the datas for writing the tag
Function getFileInfos(path As String)
  Dim cb[5]
  cb[1] = DynamicCast("wxComboBox", wxFindWindowByName("first"))
  cb[2] = DynamicCast("wxComboBox", wxFindWindowByName("second"))
  cb[3] = DynamicCast("wxComboBox", wxFindWindowByName("third"))
  cb[4] = DynamicCast("wxComboBox", wxFindWindowByName("fourth"))
  cb[5] = DynamicCast("wxComboBox", wxFindWindowByName("fifth"))

  Dim aTitle As String = ""
  Dim aArtist As String = ""
  Dim aAlbum As String = ""
  Dim aYear As String = ""
  Dim aTrack As String = ""
  
  Dim tk As wxArrayString = wxStringTokenize(path, filesep)

  For i = 0 To 4
    Select Case cb[i + 1].GetValue()
    Case "Title": aTitle = Trim(tk.Item(i))
    Case "Album": aAlbum = Trim(tk.Item(i))
    Case "Artist": aArtist = Trim(tk.Item(i))
    Case "Track": aTrack = Trim(tk.Item(i))
    Case "Year": aYear = Trim(tk.Item(i))
    End Select
  Next

  tk.Clear()

  Return aTitle, aArtist, aAlbum, aYear, aTrack
End Function


'extend the normalize value to 6 decimal places
Function extend(num As String)
  Dim at As Integer = InStr(num, ".")
  If !at Then Return num &".000000"

  Dim before = num[: at - 1]
  Dim after = num[at + 1: ]

  While Len(after)< 6
    after &= "0"
  Wend

  Return before &"." &after
End Function
