'/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
'// dsmPlayer (duckes simple media player)                                                                      //
'// Licence: GPL                                                                                                //
'// media player for mp3, mp4, aac, ogg, opus, wv, flac, webm, m4a, wav, caf, ts, mpc, ape                      //
'// can play mp4, mov, avi and mkv audio stream from videos without seeking                                     //
'// play internet radio, play internet TV with an external program                                              //
'// dsmPlayer uses phiola for most actions                                                                      //
'// dsmPlayer now use the playlist from Kodinerds IPTV repo on github for radio and tv as a basis:              //
'// https://github.com/jnk22/kodinerds-iptv                                                                     //
'// update playlist from github for radio:                                                                      //
'// https://github.com/iptvroger2022/junguler-m3u-radio                                                         //
'// update playlist from github for tv:                                                                         //
'// https://github.com/iptv-org/iptv                                                                            //
'// https://github.com/Free-TV/IPTV                                                                             //
'/////////////////////////////////////////////////////////////////////////////////////////////////////////////////


Option Explicit

Const ID_EXPLORER_MEDIA = wxNewId(), ID_PLAY_MEDIA = wxNewId(), ID_PAUSE_MEDIA = wxNewId(), 
      ID_STOP_MEDIA = wxNewId(), ID_PREV_MEDIA = wxNewId(), ID_NEXT_MEDIA = wxNewId(), ID_MUTE_MEDIA = wxNewId(), 
      ID_EXIT_PLAYER = wxNewId(), 
      ID_PLAY_WEBRADIO = wxNewId(), ID_PLAY_WEBTV = wxNewId(), ID_PLAY_FILE = wxNewId(), ID_PLAY_PODCAST = wxNewId(), 
      ID_MEDIA_TO_TRAY = wxNewId(), ID_SHUFFLE = wxNewId(), ID_LISTCTRL_MEDIA = wxNewId(), ID_LISTCTRL_TV = wxNewId(), ID_LISTCTRL_PODCAST = wxNewId(), 
      ID_SHOW_TAGS = wxNewId(), ID_CREATE_PLAYLIST = wxNewId(), ID_CONVERT = wxNewId(), 
      ID_WATCHER_TIMER = wxNewId()

Const ID_PLAYER_HIDE = wxNewId(), ID_OPTIONS = wxNewId(), 
      ID_DELETE_TITLE = wxNewId(), ID_NORMALIZE = wxNewId(), 
      ID_MEDIA_MARK_ALL = wxNewId(), ID_CHANGE_FILENAME = wxNewId(), ID_RELOAD_FILELIST = wxNewId(), 
      ID_OPEN_FILE = wxNewId(), ID_CHANGE_FILENAME_FREE = wxNewId(), ID_RENUM_LIST = wxNewId(), 
      ID_EDIT_WEBLIST = wxNewId(), ID_MULTISORT = wxNewId(), 
      ID_DATABASE_EXPORT = wxNewId(), ID_DATABASE_EXPORT_KODI = wxNewId(), ID_DATABASE_EXPORT_MIXED = wxNewId(), ID_DATABASE_EXPORT_MUSIC = wxNewId(), 
      ID_EXPORT_MUSIC = wxNewId(), 
      ID_ADD_FAVORITE = wxNewId(), ID_REM_FAVORITE = wxNewId(), ID_REM_FAVORITE1 = wxNewId(), ID_SHOW_FAVORITE = wxNewId(), 
      ID_VALIDATE_SEL = wxNewId(), ID_VALIDATION = wxNewId(), ID_EDIT_SEL = wxNewId(), ID_STATION_EDIT = wxNewId(), ID_LANGUAGE = wxNewId(), 
      ID_PLAY = wxNewId(), ID_LOAD = wxNewId(), ID_FAV_MENU = wxNewId()

'podcast ids
Const ID_MAX_PODS = wxNewId(), ID_DOWNLOAD_PODCAST = wxNewId(), ID_DOWNLOAD_ALL = wxNewId(), ID_DOWNLOAD_CHECKED = wxNewId(), 
      ID_SET_HEARD = wxNewId(), ID_SET_HEARD_SEL = wxNewId(), ID_SET_HEARD_ALL = wxNewId(), ID_REM_HEARD_SEL = wxNewId(), ID_REM_HEARD_ALL = wxNewId(),
      ID_POD_SELECT_ALL = wxNewId(), ID_RELOAD_PODCAST = wxNewId()

Dim checker As wxSingleInstanceChecker = wxSingleInstanceChecker("dsmPlayer", "")
wxImage_InitStandardHandlers()
wxHandleFatalExceptions(TRUE)

'get the executable directory and set the working directory
Dim playerPath As String = wxGetCwd()
Dim stPath As wxStandardPathsBase = wxStandardPaths_Get()
If !wxFileExists(playerPath &DELIMITER_CHAR &"dsmPlayer.exe") And !wxFileExists(playerPath &DELIMITER_CHAR &"dsmplayer.wxb") Then playerPath = stPath.GetDataDir()
wxSetWorkingDirectory(playerPath)

Dim ver = wxVersionInfo("dsmPlayer 1.0", 1, 0, 0, "", "2014-2026 by Dirk Noack")
Dim app As wxApp = wxTheApp
app.SetAppName("dsmPlayer")
app.SetVendorName("Dirk Noack")


'set delay for tooltips
wxToolTip_SetDelay(2000)

Dim playerIni As String = playerPath &DELIMITER_CHAR &"dsmplayer.ini"
Dim os = IIf(InStr(LCase(wxGetOsDescription()), "windows"), "win", "linux")

Dim pFilter = "*.aac|*.webm|*.flac|*.mp3|*.m4a|*.ogg|*.opus|*.wav|*.wv|*.mkv|*.mp4|*.mov|*.caf|*.avi|*.ts|*.mpc"

'used to handle phiola
Dim phiolaPath As String = playerPath &"\\ThirdParty\\phiola-2\\phiola.exe"
Dim phiolaPid As Integer = -1
Dim recPid As Integer = -1
Dim phiolaPrc As wxProcess
Dim defaultFont As wxFont
Dim recPrc As wxProcess = Nothing
Dim convPrc As wxProcess = Nothing
Dim infoPrc As wxProcess = Nothing
Dim valPrc As wxProcess = Nothing
Dim pTitle As String = ""
Dim oldpTitle As String = ""
Dim pCodec As String = ""
Dim errCnt As Integer = 0
Dim errMsg As String = ""
Dim isBroken As Integer = FALSE
Dim useIcons As Integer = FALSE
Dim useTransparency As Integer = TRUE
Dim showMusicTitle As Integer = FALSE
Dim showPodTitle As Integer = FALSE
Dim gainMode As Integer = 1
Dim timeout As Integer = 15

Dim ps As Number = 1
Dim oldps As Number = 1
Dim dockList As Integer = TRUE
Dim autoHeard As Integer = 0
Dim mediaPos As Integer = 0
Dim medialen As Integer = 0
Dim podPos As Integer = 0
Dim podLen As Integer = 0
Dim podUrl As String = ""
Dim playMode As Integer = ID_PLAY_WEBRADIO
Dim sort_ascending As Integer = TRUE
Dim oldCol As Integer = -1
Dim theme As Integer = 2
Dim tvPids As wxArrayInt = New wxArrayInt()
Dim tvPlayerPath As String = ""
Dim tvPlayerPara As String = ""
Dim loadLinePos As Integer = 0
Dim ppiDisplay = wxGetDisplayPPI()
Dim ppiH = ppiDisplay.GetHeight()
Dim Scale As Number = 96 / ppiH
Dim mFileWebRadio As Integer = -1
Dim mFileWebTV As Integer = -1
Dim musicFile As Integer = -1
Dim playDir As String = ""
Dim fileSep As String = "-"
Dim muted As Integer = FALSE
Dim isModify As Integer = FALSE
Dim isPlayed As Integer = FALSE
Dim isRefresh As Integer = FALSE
Dim isReading As Integer = FALSE
Dim posClicked As Integer = FALSE
Dim volClicked As Integer = FALSE
Dim volume As Integer = 80
Dim isRecord As Integer = FALSE
Dim isPaused As Integer = FALSE
Dim recordPath As String = playerPath &"\\Records"
Dim recordPathPod As String = playerPath &"\\Podcasts"
Dim recConv As Integer = FALSE
Dim recMode As Integer = 1
Dim recDel As Integer = 1
Dim recModes As Table = {1: "mp3", 2: "aac", 3: "m4a", 4: "ogg", 5: "opus", 6: "flac"}
Dim recName As String = ""

Dim oldX As Integer = 0
Dim oldY As Integer = 0

'Dim fullOnly As Integer = false
Dim singleFile As Integer = FALSE
Dim recordTime As Integer = 0
Dim editorTypes As String = ""
Dim editorPath As String = playerPath &DELIMITER_CHAR &"\\ThirdParty\\mp3DirectCut\\mp3DirectCut.exe"
Dim editorParam As String = ""
Dim searchWord As String = ""
Dim startPath As String = ""
Dim wgetPath As String = playerPath &DELIMITER_CHAR &"\\ThirdParty\\Wget64\\wget.exe"

'store app bitmaps in a table
Dim iList As Table = {}

'store image index from wxImagelist by image adress in web radio mode
Dim images As Table = {}

'store language codes for webradio stations
Dim langCodes As Table = {}

'set rectangles for effective redrawing of the music frame
Dim rects As Table = {}

Dim mediaTaskbarIcon As wxTaskBarIcon = New wxTaskBarIcon()
Dim validation As Integer = FALSE
Dim dragItemLC As wxDragImage = Nothing
Dim out As wxFFileOutputStream 
Dim zip As wxZipOutputStream

Dim playListFile As String = ""
Dim stationIconSize As Integer = 24
Dim mediaList As wxArrayString = New wxArrayString()
Dim allMediaFiles As wxArrayString = New wxArrayString()
Dim allMediaFilesInt As wxArrayInt = New wxArrayInt()
Dim copyInt As wxArrayInt = New wxArrayInt()
Dim genres As wxArrayString = New wxArrayString()

Dim musicFrame As wxFrame
Dim titleFrame As wxFrame
Dim lineFrame As wxFrame
Dim hMediaSizer As wxSizer
Dim musicFontColour As wxColour = wxWHITE
Dim musicHiColour As wxColour = wxWHITE
Dim musicBackColour As wxColour = wxLIGHT_GREY
Dim musicBackColour2 As wxColour = wxBLACK
Dim musicSelColour As wxColour = wxLIGHT_GREY
Dim lcWeb As wxListCtrl
Dim lcMedia As wxListCtrl
Dim lcPod As wxTreeListCtrl
Dim mProgressDlg As wxGenericProgressDialog

'timer for display time in file mode
Dim timerMedia As wxTimer

'timer for loading animation in web mode
Dim loadingTimer As wxTimer

Dim filesDb As wxDbEngine = wxDbEngine()
'used for web radio
Dim dbc As wxDbConnection
'used for podcasts
Dim dbp As wxDbConnection

'use filesystenwatcher for monitoring files or directorys for changes
Dim playerWatcher As wxFileSystemWatcher = New wxFileSystemWatcher()

'store types of watcher events
Dim eventType As wxArrayInt = wxArrayInt()
Dim eventFile As wxArrayString = wxArrayString()
Dim eventFileNew As wxArrayString = wxArrayString()

'create a timer for the watcher
Dim watcherTimer As wxTimer = New wxTimer(playerWatcher, ID_WATCHER_TIMER)
Connect(app, ID_WATCHER_TIMER, wxEVT_TIMER, "onWatcherTimer")

'add handler for archives
'used for station logos
wxFileSystem_AddHandler(New wxArchiveFSHandler())
wxFileSystem_AddHandler(New wxMemoryFSHandler())

Dim fd As wxFileDialog = New wxFileDialog(musicFrame)
Dim busyInfo As wxBusyInfo
Dim k1, k2 As Integer

Dim languageId As Integer = wxLocale_GetSystemLanguage()
Dim locale As wxLocale

'load the language before the menuitems are created
loadLanguage()

'load the language of the editor before including files and the program start
Sub loadLanguage()
  Try
    Dim cfg As wxFileConfig = wxFileConfig("", "", playerIni)
    cfg.SetPath("dsmPlayer")
    languageId = Val(cfg.Read("Language", languageId))
    Dim noLog As wxLog = wxLogNull()

    'setup locale for language from the language ID
    locale = New wxLocale()
    locale.AddCatalogLookupPathPrefix("Locale")

    If locale.IsAvailable(languageId) Then
      locale.InitById(languageId)
    Else
      locale.Init(wxLANGUAGE_ENGLISH)
    End If

    If languageId <> wxLANGUAGE_ENGLISH Then
      If locale.IsOk() Then
        Dim language As String = locale.GetCanonicalName()
        SetLocale(LC_ALL, language &".UTF-8")

        'look for the language file
        If !locale.AddCatalog("dsmplayer") Then
          Dim dl = wxGenericMessageDialog(Nothing, _("Your language cannot be offered at this time.") &"\n" &
          _("Use the default language of the application."), _("Note"), wxOK|wxCENTRE|wxICON_INFORMATION|wxDIALOG_NO_PARENT)
          dl.ShowModal()

          languageId = wxLANGUAGE_ENGLISH
          cfg.Write("Language", languageId)
        End If
      End If
    End If

  Catch
    dl = wxGenericMessageDialog(Nothing, _("Error loading language!"), _("Note"), wxOK|wxCENTRE|wxICON_INFORMATION|wxDIALOG_NO_PARENT)
    dl.ShowModal()

  Finally
    ~noLog
  End Try
End Sub


'create menu right mouse press
Dim musicTitleMenu As wxMenu = New wxMenu()
  musicTitleMenu.Append(ID_MEDIA_MARK_ALL, _("Select all"))
  musicTitleMenu.AppendSeparator()
  musicTitleMenu.Append(ID_CHANGE_FILENAME, _("Adjust filenames..."))
  musicTitleMenu.Append(ID_CHANGE_FILENAME_FREE, _("Freely adjust file names..."))
  musicTitleMenu.AppendSeparator()
  musicTitleMenu.Append(ID_DELETE_TITLE, _("Delete title"))
  musicTitleMenu.AppendSeparator()
  musicTitleMenu.Append(ID_SHOW_TAGS, _("Show tags"))
  musicTitleMenu.AppendSeparator()
  musicTitleMenu.Append(ID_OPEN_FILE, _("Edit file..."))

'create favoriten menu
Dim selFavMenu As wxMenu = New wxMenu()
  selFavMenu.AppendSeparator()
  selFavMenu.Append(ID_REM_FAVORITE1, _("Remove station from list"))

Dim favMenu As wxMenu = New wxMenu()
  favMenu.Append(ID_ADD_FAVORITE, _("Add station to favorites"))
  favMenu.Append(ID_REM_FAVORITE, _("Remove station from favorites"))
  favMenu.AppendSeparator()
  favMenu.AppendMenu(ID_SHOW_FAVORITE, _("Favorites list"), selFavMenu)

'create the main menu
Dim musicMenu As wxMenu = New wxMenu()
  musicMenu.Append(ID_PLAY_WEBRADIO, _("Web radio"), "", wxITEM_RADIO)
  musicMenu.Append(ID_PLAY_WEBTV, _("Web TV"), "", wxITEM_RADIO)
  musicMenu.Append(ID_PLAY_PODCAST, _("Podcast"), "", wxITEM_RADIO)
  musicMenu.Append(ID_PLAY_FILE, _("Local"), "", wxITEM_RADIO)
  musicMenu.AppendSeparator()
  musicMenu.Append(ID_OPTIONS, _("Settings") &" ...")
  musicMenu.AppendSeparator()
  musicMenu.AppendMenu(ID_SHOW_FAVORITE, _("Favorites"), selFavMenu)
  musicMenu.Append(ID_RELOAD_FILELIST, _("Reload web playlist"))
  musicMenu.Append(ID_MULTISORT, _("Sort web addresses..."))
  musicMenu.Append(ID_EDIT_WEBLIST, _("Edit web playlist"), "", wxITEM_CHECK)
  musicMenu.AppendSeparator()
  musicMenu.Append(ID_CREATE_PLAYLIST, _("Edit Playlists") &"...")
  musicMenu.Append(ID_CONVERT, _("Batch Convert/Rename") &"...")
  musicMenu.Append(ID_NORMALIZE, _("Batch Tag/Normalize") &"...")
  musicMenu.Append(ID_SHUFFLE, _("Title mix"))
  musicMenu.AppendSeparator()
  musicMenu.Append(ID_PLAYER_HIDE, _("Hide player"))
  musicMenu.Append(ID_MEDIA_TO_TRAY, _("To tray"))
  musicMenu.AppendSeparator()
  musicMenu.Append(ID_EXIT_PLAYER, _("Exit Player"), _("Closes the player"))

'create the edit menu
Dim editMenu As wxMenu = New wxMenu()
  editMenu.Append(wxID_INFO, _("Station Info"))
  editMenu.Append(ID_VALIDATE_SEL, _("Validate"))
  editMenu.AppendSeparator()
  editMenu.Append(wxID_CUT, _("Cut"))
  editMenu.Append(wxID_PASTE, _("Paste"))
  editMenu.AppendSeparator()
  editMenu.AppendMenu(ID_FAV_MENU, _("Favorites"), favMenu)

'create the taskbar menu
Dim musicTaskMenu As wxMenu = New wxMenu()
  musicTaskMenu.Append(ID_PLAY_MEDIA, _("Play"), _("Plays the selected title"))
  musicTaskMenu.Append(ID_PAUSE_MEDIA, _("Break"), _("Coffe break"))
  musicTaskMenu.Append(ID_STOP_MEDIA, _("Stop"), _("Stops playing"))
  musicTaskMenu.AppendSeparator()
  musicTaskMenu.Append(ID_PREV_MEDIA, _("Previous title"), _("Plays the previous track"))
  musicTaskMenu.Append(ID_NEXT_MEDIA, _("Next title"), _("Plays the next track"))
  musicTaskMenu.Append(ID_SHUFFLE, _("Mix"), _("Mix the titles"))
  musicTaskMenu.AppendSeparator()
  musicTaskMenu.Append(ID_MUTE_MEDIA, _("Mute"), _("Turns the sound on or off"), wxITEM_CHECK)
  musicTaskMenu.AppendSeparator()
  musicTaskMenu.Append(ID_PLAY_WEBRADIO, _("Play web radio"), _("Play radio from the web"), wxITEM_CHECK )
  musicTaskMenu.Append(ID_PLAY_WEBTV, _("Play TV from the web"), _("Play TV from the web"), wxITEM_CHECK )
  musicTaskMenu.Append(ID_PLAY_PODCAST, _("Podcast"), _("Play podcasts from the web"), wxITEM_CHECK)
  musicTaskMenu.Append(ID_PLAY_FILE, _("Play file"), _("Play files from disk"), wxITEM_CHECK )
  musicTaskMenu.AppendSeparator()
  musicTaskMenu.Append(ID_EXIT_PLAYER, _("Exit player"), _("Closes the player"))

'create the selection menu
Dim selMenu As wxMenu = New wxMenu()
  selMenu.Append(wxID_SELECTALL, _("Select all"))
  selMenu.Append(wxID_CLEAR, _("Deselect all"))

'create the podcast menu
Dim podMenu As wxMenu = New wxMenu()
  podMenu.Append(ID_RELOAD_PODCAST, _("Reload Podcast"))
  podMenu.AppendSeparator()
  podMenu.Append(ID_MAX_PODS, _("Visible episodes..."))
  podMenu.Append(ID_POD_SELECT_ALL, _("Select all episodes"))
  podMenu.AppendSeparator()
  podMenu.Append(ID_DOWNLOAD_CHECKED, _("Download checked episodes"))
  podMenu.Append(ID_DOWNLOAD_All, _("Download all episodes"))
  podMenu.AppendSeparator()
  podMenu.Append(ID_SET_HEARD_SEL, _("Set checked episodes as heard"))
  podMenu.Append(ID_SET_HEARD_ALL, _("Set all episodes as heard"))
  podMenu.AppendSeparator()
  podMenu.Append(ID_REM_HEARD_SEL, _("Set checked episodes as not heard"))
  podMenu.Append(ID_REM_HEARD_ALL, _("Set all episodes as not heard"))

'create the episode menu
Dim podItemMenu As wxMenu = New wxMenu()
  podItemMenu.Append(ID_DOWNLOAD_PODCAST, _("Download episode"))
  podItemMenu.AppendSeparator()
  podItemMenu.Append(ID_SET_HEARD, _("Heard"), "", wxITEM_CHECK)


'get the file format
'return the file extension
Function GetFileFormat(path As String)
  Dim FName As wxFileName = wxFileName(path)
  Return LCase(fName.GetExt())
End Function


Include "dsm_bitmaps.wxb"
Include "dsm_playlist.wxb"
Include "dsm_id3.wxb"
Include "dsm_convert.wxb"
Include "dsm_normalize.wxb"
Include "dsm_podcast.wxb"

'------------------------------------------------------------------------------------------------------
'functions
'------------------------------------------------------------------------------------------------------

'find a word in text between 'before' and 'after'
Function wordBetween(text As String, before As String, after As String)
  'find position of word in front
  Dim at As Integer = InStr(text, before)
  If at = 0 Then Return ""

  'get following portion
  at += Length(before)
  Dim result = Trim(text[at: ])

  'find delimiter on the right
  at = InStr(result, after)
  If at = 0 Then
    Return result
  Else
    Return result[: at - 1]
  End If
End Function


'find the bitmap type from the bitmap extension
'return the type for loading the bitmap
'wxBITMAP_TYPE_ANY has no effect here
Function GetBitmapType(FileName As String)
  Dim FName As wxFileName = wxFileName(FileName)
  Dim ext As String = fName.GetExt()

  Select Case LCase(ext)
  Case "jpg", "jpeg": Return wxBITMAP_TYPE_JPEG
  Case "bmp": Return wxBITMAP_TYPE_BMP
  Case "png": Return wxBITMAP_TYPE_PNG
  Case "pcx": Return wxBITMAP_TYPE_PCX
  Case "pnm": Return wxBITMAP_TYPE_PNM
  Case "tif": Return wxBITMAP_TYPE_TIF
  Case "xpm": Return wxBITMAP_TYPE_XPM
  Case "xbm": Return wxBITMAP_TYPE_XBM
  Case "ico": Return wxBITMAP_TYPE_ICO
  Case "icl": Return wxBITMAP_TYPE_ICO_RESOURCE
  Case "cur": Return wxBITMAP_TYPE_CUR
  Case "gif": Return wxBITMAP_TYPE_GIF
  Case Else: Return -1'wxBITMAP_TYPE_JPEG
  End Select
End Function


'replace different html entities in text when importing playlists
Function replaceHTMLEntities(text As String)
  Dim htmlEntities As List = ["&amp;", "&lt;", "&gt;", "&quot;", "&#039;", "&ndash;", "&apos;"]
  Dim replEntities As List = [" & ", "<", ">", "\"", "'", " - ", "'"]
  Dim s As wxString = wxString(text)

  For i = 1 To htmlEntities.Count()
    s.Replace(htmlEntities[i], replEntities[i])
  Next

  text = s.GetData()
  s.Clear()

  Return text
End Function


'check the genre while update a playlist
Function checkGenre(pList As String)
  'replace underscore with hyphen
  If InStr(pList, "_") Then pList = Replace(pList, "_", "-")

  Dim INDEX = genres.INDEX(pList, FALSE)
  'return the playlist in the right case
  If INDEX >= 0 Then Return genres.Item(INDEX)

  'combine different genres from import
  Dim rList As String = ""
  Select Case plist
  Case "hits-60s": rlist = "60s"
  Case "hits-70s": rlist = "70s"
  Case "hits-80s", "80s-disco", "80s-disco-italo": rList = "80s"
  Case "hits-90s", "90s-rock": rList = "90s"
  Case "acoustic-blues": rList = "Acoustic"
  Case "adult-album-alternative", "adult-contemporary", "adult-hits", "adult-rock": rList = "Adult"
  Case "africa", "african-music", "africa-2", "afro": rList = "African"
  Case "alternative-rock", "classic-alternative": rList = "Alternative"
  Case "ambience", "ambient-music": rList = "Ambient"
  Case "anime-music", "anime-songs": rList = "Anime"
  Case "arabic-2", "arabic-music": rList = "Arabic"
  Case "asian-music": rList = "Asian"
  Case "brazilian-music", "brazilian-popular": rList = "Brazil"
  Case "childrens-music", "childrens-topics": rList = "Children"
  Case "chill", "chilltop", "chill-out", "easy", "meditation", "relax", "relaxation", "relaxing", "relaxing-music", "zen": rList = "Chillout"
  Case "chillstep-mix": rList = "Chill-Step"
  Case "religious-music": rList = "Christian"
  Case "clasical", "classic", "classics": rList = "Classical"
  Case "alternative-country", "classic-country", "real-country": rList = "Country"
  Case "classic-hip-hop", "hip-hop": rList = "Hip-Hop"
  Case "acid-jazz", "bass-jazz", "classic-jazz", "cool-jazz", "current-jazz", "guitar-jazz", "jazz-ballads", "jazz-rock", 
       "mellow-jazz", "trumpet-jazz", "vibraphone-jazz", "nu-jazz", "saxophone-jazz", "smooth-jazz": rList = "Jazz"
  Case "blues-rock", "classic-rock": rList = "Rock"
  Case "classic-soul": rList = "Soul"
  Case "college-radio": rList = "College"
  Case "community-news": rList = "Community"
  Case "country-blues", "delta-blues": rList = "Blues"
  Case "country-music", "country-pop", "country-rock": rList = "Country"
  Case "cultural-music": rList = "Culture"
  Case "czech-music", "czech-republic": rList = "Czech"
  Case "dancehall", "dancehall-afrobeats": rList = "Dance"
  Case "dark-electro", "dark-wave": rList = "Dark"
  Case "deep-house": rList = "Deep"
  Case "disco-fox": rList = "DiscoFox"
  Case "dominican-republic": rList = "Dominica"
  Case "drum", "drum-and-bass", "drum-n-bass", "drum_and_bass": rList = "Drum-and-Bass"
  Case "easy-listening": rList = "Easy-Listening"
  Case "electric", "electro", "electronica", "eclectric", "electronic-music", "electropop", "electro-house", "electro-sound": rList = "Electronic"
  Case "educational", "educative": rList = "Education"
  Case "ethnic-music": rList = "Ethnic"
  Case "european-music", "euro-hits": rList = "Europe"
  Case "folk-music", "folk-rock", "folk-songs": rList = "Folk"
  Case "france-2", "french-hits", "french-music", "french-talk": rList = "France"
  Case "funky", "funky-house": rList = "Funk"
  Case "cafe-songs", "fusion-lounge", "lounge-music": rList = "Lounge"
  Case "germany", "german-music", "volksmusik": rList = "Deutsch"
  Case "greece", "greek-folk", "greek-music": rList = "Greek"
  Case "haiti-2": rList = "Haiti"
  Case "hard-rock": rList = "Hardrock"
  Case "hit", "top-charts": rList = "Hits"
  Case "indie-music", "indie-rock": rList = "Indie"
  Case "indian-music": : rList = "India"
  Case "reports": : rList = "Information"
  Case "instrumental-music": rList = "Instrumental"
  Case "islami", "islamic", "islamic-song", "islamic-talk": rList = "Islam"
  Case "italian-music", "italy", "italo": rList = "Italian"
  Case "latina", "latino", "latin-jazz", "latin-music", "latin-pop": rList = "Latin"
  Case "local-music", "local-dancehall", "local-news": rList = "Local"
  Case "love-song", "love-songs": rList = "Love"
  Case "malayalam-music": rList = "Malaysia"
  Case "metal-rock": rList = "Metal"
  Case "mexican": rList = "Mexico"
  Case "mix", "mix-2": rList = "Mixed"
  Case "netherlands-antilles", "mix-2": rList = "Netherlands"
  Case "national-news": rList = "News"
  Case "party-hits", "party-mix": rList = "Party"
  Case "poland": rList = "Polish"
  Case "pop-latino", "pop-rock", "slow-pop", "soft-pop": rList = "Pop"
  Case "portuguese-music", "pop-rock": rList = "Portugal"
  Case "quaran": rList = "Islam"
  Case "progressive-pop": rList = "Pop"
  Case "rb", "pop-rock": rList = "RNB"
  Case "light-rock", "melodic-rock", "new-rock", "rock-alternativo", "rock-and-roll", "rock-n-roll", "soft-rock", 
       "rock-classic", "rockaenroll", "rock-en-espanol", "roots-rock", "progressive-rock": rList = "Rock"
  Case "reggaeton", "pop-rock": rList = "Reggae"
  Case "romania", "romanian-music": rList = "Romanian"
  Case "romance", "romantica", "romantic", "romantic-song", "romantic-songs": rList = "Love"
  Case "rumbera": rList = "Rumba"
  Case "russia", "russian-music": rList = "Russian"
  Case "salsa-music", "russian-music": rList = "Salsa"
  Case "neo-soul": rList = "Soul"
  Case "hard-house", "house-classics", "soulful-house", "vocal-house", "progressive-house": rList = "House"
  Case "spanish", "spanish-music", "spanish-talk": rList = "Spain"
  Case "sports", "sports-news", "sports-talk": rList = "Sport"
  Case "tamil-2", "tamil-music", "tamil-songs": rList = "Tamil"
  Case "tech-house": rList = "Techno"
  Case "top-40", "top40", "topp-40": rList = "Top-40"
  Case "top-100": rList = "Top-100"
  Case "tropical-music": rList = "Tropical"
  Case "turkey", "turkish-music", "turkish-pop", "turkish-talk": rList = "Turk"
  Case "underground-music": rList = "Underground"
  Case "united-states", "alabama", "alaska": rList = "Usa"
  Case "new-wave": rList = "Wave"
  Case "world-music", "world-news", "world-talk": rList = "World"
  Case Else: rList = ""
  End Select

  Return rList
End Function


'set the path for wget
Function selectDownloadReader()
  If !FileExists(wgetPath) Then
    Dim about = wxAboutDialogInfo()
    about.SetName( _("Wget"))
    about.SetWebSite("https://eternallybored.org/misc/wget/", "https://eternallybored.org/misc/wget/")
    about.SetDescription(_("Wget was not found!") &"\n" &
      _("GNU Wget is a free software package for retrieving files via HTTP, HTTPS, FTP and FTPS") &",\n" &
      _("the most widely used Internet protocols.") &"\n\n" &
      _("Wget is used as the default downloader in the app.") &"\n" &
      _("You can download a precompiled version for Windows here:"))
    wxAboutBox(about)

    wgetPath = wxFileSelecTor("Path to Wget", "", "wget.exe", "", "wget.exe")

    Dim cfg As wxFileConfig = wxFileConfig("", "", playerIni)
    cfg.SetPath("/dsmPlayer")
    cfg.Write("Path_Wget", wgetPath)
  End If

  Return wgetPath
End Function


'select phiola path
Function selectPhiolaPath()
  If !wxFileExists(phiolaPath) Then
    phiolaPath = wxFileSelector("Path to Phiola", "", "phiola.exe", "", "phiola.exe")

    If !wxFileExists(phiolaPath) Then
      Dim dl = wxGenericMessageDialog(Nothing, _("Phiola Is required to display the title information and for recording!"), _("Note"), wxOK|wxCENTRE|wxICON_EXCLAMATION|wxDIALOG_NO_PARENT)
      dl.ShowModal()
      Return ""
    End If

    Return phiolaPath
  End If
End Function


'set the bitmap backgrund to transparent or not
Function SetBitmapBackground(bitmap As wxBitmap)
  Dim buf As wxBitmap = wxEmptyBitmap(stationIconSize, stationIconSize, 32)
  buf.UseAlpha()

  Dim memDC As wxMemoryDC = wxMemoryDCFromBitmap(buf)
  Dim gdc As wxGCDC = wxGCDCFromMemoryDC(memDC)
  gdc.SetBackground(wxTRANSPARENT_BRUSH)
  gdc.Clear()
  
  'draw a white rectangle
  gdc.SetBrush(wxWHITE_BRUSH)
  gdc.SetPen(wxTRANSPARENT_PEN)
  gdc.DrawRectangle(0, 0, stationIconSize, stationIconSize)
  gdc.DrawBitmap(bitmap, 0, 0, TRUE)

  gdc.SetPen(wxNullPen)
  gdc.SetBrush(wxNullBrush)
  memDC.SelectObject(wxNullBitmap)

  Return buf
End Function


'get the playlist type
Function getPlaylistType(path As String)
    Dim isStream As Integer = FALSE

    Dim freeNum As Integer = FOpen(path, "r")
    While !Eof(freeNum)
      If Left(FGets(freeNum), 4)= "http" Then
        isStream = TRUE
        Break
      End If
    Wend
    FClose(freeNum)
    
   Return IIf(isStream, "radio", "file")
End Function


'get the bitmap index for the items,
'if an item is moved up or down
Function GetBitmapIndex(station1 As Integer, station2 As Integer)
  Dim idx1, idx2 As Integer
  Dim Item As wxListItem

  Item = wxListItem()
  Item.SetMask(wxLIST_MASK_IMAGE)
  Item.SetId(station1)
  lcWeb.GetItem(Item)
  idx1 = Item.GetImage()
  Item.SetId(station2)
  lcWeb.GetItem(Item)
  idx2 = Item.GetImage()

  Return idx1, idx2
End Function


'search for the file num, select it and/or jump to it
Function SelectFile(num As Integer, SelectTheItem As Integer, jump As Integer)
  If num = -1 Then Return -1

  Dim sel As Integer

  Select Case playMode
  Case ID_PLAY_FILE
    Dim explorerMedia As wxGenericDirCtrl = DynamicCast("wxGenericDirCtrl", musicFrame.FindWindowByName("explorermedia"))
    If ((playlistFile <> "") And (playlistFile != explorerMedia.GetFilePath())) Or
       ((playlistFile = "") And (playDir <> explorerMedia.GetPath())) Then Return

    If playlistFile <> "" Then explorerMedia.SetPath(playlistFile)
    sel = lcMedia.FindItem(-1, "  " &musicFile)

    'deselect last played item
    If (sel >= 0) And SelectTheItem Then lcMedia.SetItemTextColour(sel, musicFontColour)
    sel = lcMedia.FindItem(-1, "  " &num)

    If (sel >= 0) Then
      If SelectTheItem Then lcMedia.SetItemTextColour(sel, musicHiColour)
      If jump Then lcMedia.EnsureVisible(sel)
      pTitle = IIf(playmode = ID_PLAY_FILE, wxFileNameFromPath(lcMedia.GetStringItem(sel, 1)), lcMedia.GetStringItem(sel, 2))

      Return sel
    End If

  Case ID_PLAY_PODCAST
    If podUrl <> "" Then
      'find the played item
      Dim Item As wxTreeListItem = findPodcastItem(podUrl, FALSE)
      If Item Then
        'select the item
        lcPod.Select(Item)
        'use wxDataViewCtrl to scroll the item into view
        Dim dv = lcPod.GetDataView()
        dv.EnsureVisible(dv.GetSelection())
      End If
    End If

  Case ID_PLAY_WEBRADIO, ID_PLAY_WEBTV
    sel = lcWeb.FindItem(0, "  " &IIf(playMode = ID_PLAY_WEBRADIO, mFileWebRadio, mFileWebTV))
    'deselect last played item
    If (sel >= 0) And SelectTheItem Then lcWeb.SetItemTextColour(sel, musicFontColour)
    sel = lcWeb.FindItem(-1, "  " &num)

    If (sel >= 0) Then
      If SelectTheItem Then lcWeb.SetItemTextColour(sel, musicHiColour)
      If jump Then lcWeb.EnsureVisible(sel)
      pTitle = IIf(playmode = ID_PLAY_FILE, wxFileNameFromPath(lcWeb.GetStringItem(sel, 1)), lcWeb.GetStringItem(sel, 2))

      Return sel
    End If
  End Select

  Return -1
End Function


'use selectFile for web and file mode
'add podcast mode
Function setFile(jump As Integer)
  Dim selection As Integer = -1

  Select Case playmode
  Case ID_PLAY_FILE
    If musicFile >= 0 Then
      selection = selectFile(musicFile, TRUE, jump)
    End If

  Case ID_PLAY_PODCAST
    Dim podItem As wxTreeListItem = findPodcastItem(podUrl, FALSE)

    If podItem Then
      'set this item to the first place in the podcastUrl arraystring
      lcPod.Select(poditem)
      setItemRect()
      setPodcAstInfo(podUrl, TRUE)
    End If

  Case Else
    Dim sel = IIf(playmode = ID_PLAY_WEBRADIO, mFileWebRadio, mFileWebTV)
    If sel >= 0 Then
       selection = selectFile(sel, TRUE, jump)
      If selection >= 0 Then pTitle = lcWeb.GetStringItem(selection, 2)
    End If
  End Select

  Return selection
End Function


'sort list by different options
'return true if ok, otherwise false
Function sortBy(name1 As String, name2 As String, name3 As String)
  If isModify Then
    Dim dl = wxGenericMessageDialog(Nothing, _("The playlist has been changed!") &"\n" &
    _("All changes are lost during sorting!") &"\n" &
    _("Save changes to database?"), _("Attention"), wxYES_NO|wxYES_DEFAULT|wxCENTRE|wxICON_WARNING|wxDIALOG_NO_PARENT)

    'wxYes = 5103 in wxGenericMessageDialog
    If dl.ShowModal() = 5103 Then saveStations(FALSE, TRUE)
  End If

  Try
    'deselect the current selected items
    Dim sel As Integer = lcWeb.GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED)
    While sel >= 0
      lcWeb.SetItemState(sel, 0, wxLIST_STATE_SELECTED|wxLIST_STATE_FOCUSED)
      sel = lcWeb.GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED)
    Wend

    If busyInfo Then ~busyInfo
    busyInfo = wxBusyInfo(_("Sort..."))
    isModify = FALSE

    sel = IIf((playMode = ID_PLAY_WEBRADIO), mFileWebRadio, mFileWebTV)
    If sel >= 0 Then lcWeb.SetItemTextColour(lcWeb.FindItem(0, "  " &sel), musicFontColour)
    
    Dim sorting As String

    Select Case sort_ascending
    Case TRUE: sorting = "ASC"
    Case Else: sorting = "DESC"
    End Select
    
    If name2 <> "" Then name2 = ", " &name2 &" COLLATE NOCASE " &sorting
    If name3 <> "" Then name3 = ", " &name3 &" COLLATE NOCASE " &sorting

    dbc = wxDbConnection("DBQ=IPTV.db;DefaultDir=.;Driver=SQLITE3;")
    If dbc.IsOpen() Then
      dbc.ExecSql("PRAGMA synchronous = OFF")
      dbc.ExecSql("PRAGMA journal_mode = MEMORY")
      dbc.ExecSql("PRAGMA cache_size = 1000000")
      dbc.ExecSql("PRAGMA locking_mode = EXCLUSIVE")
      dbc.ExecSql("PRAGMA temp_store = MEMORY")
      dbc.ExecSql("SET CHARACTER_SET 'utf8'")

      Dim results As wxResultSet
      If playMode = ID_PLAY_WEBRADIO Then
        results = dbc.GetResultSet("SELECT * FROM radio ORDER BY " &Name1 &" COLLATE NOCASE " &sorting &Name2 &Name3)
      Else
        results = dbc.GetResultSet("SELECT * FROM tv ORDER BY " &Name1 &" COLLATE NOCASE " &sorting &Name2 &Name3)
      End If

      musicFrame.Freeze()

      Dim iconPath As String
      Dim FileName As wxFileName = wxFileName("")
      Dim num As Integer
      Dim idx As Integer = IIf(playMode = ID_PLAY_WEBRADIO, IIf(useTransparency, 3, 2), IIf(useTransparency, 1, 0))


      For i = 0 To results.GetNumberRows() - 1
        num = results.GetValue(i, 0)
        iconPath = results.GetValue(i, 5)
        If iconPath <> "" Then
          FileName.AssignPath(iconPath)
          FileName.SetExt("png")
         lcWeb.SetStringItem(i, 0, "  " &num, images[FileName.GetFullName()])

        Else

         lcWeb.SetStringItem(i, 0, "  " &num, idx)
        End If

        lcWeb.SetStringItem(i, 1, results.GetValue(i, 1))
        lcWeb.SetStringItem(i, 2, results.GetValue(i, 2))
        lcWeb.SetStringItem(i, 3, results.GetValue(i, 3))
        lcWeb.SetStringItem(i, 4, results.GetValue(i, 4))
        lcWeb.SetStringItem(i, 5, results.GetValue(i, 5))
        If i%1000 = 0 Then wxYield()
      Next

      dbc.Close()
      musicFrame.Thaw()
      ~busyinfo

      'search and select the played station
      If sel >= 0 Then selectFile(sel, TRUE, FALSE)
      Return TRUE
    End If

    Return FALSE

  Catch
    Return FALSE
  End Try
End Function


'set the sort options for multisort items for the Web playlist
'it is different than normal column sorting because you can include or exclude TV stations
'and you can specify multiple conditions
Function setSortOptions(Save As Integer)
  Dim dl = wxDialog(musicFrame, -1, _("Sort playlist:"), wxDefaultPosition, wxSize(500, 300))
  Dim dSizeX = dl.GetClientSizeWidth()
  Dim dSizeY = dl.GetClientSizeHeight()
  sort_ascending = TRUE

  Dim sBox As wxStaticBox = wxStaticBox(dl, -1, _("Sort options"), wxPoint(10, 15), wxSize(dSizeX - 20, (dSizeY - 50)))
  Dim rb1 As wxRadioButton = wxRadioButton(sBox, -1, _("by country"), wxPoint(10, 30))
  Dim rb2 As wxRadioButton = wxRadioButton(sBox, -1, _("by name"), wxPoint(10, 55))
  Dim rb3 As wxRadioButton = wxRadioButton(sBox, -1, _("by genre"), wxPoint(10, 80))
  Dim rb4 As wxRadioButton = wxRadioButton(sBox, -1, _("by country and name"), wxPoint(10, 105))
  Dim rb5 As wxRadioButton = wxRadioButton(sBox, -1, _("by genre and name"), wxPoint(10, 130))
  Dim rb6 As wxRadioButton = wxRadioButton(sBox, -1, _("by country, genre and name"), wxPoint(10, 155))
  rb4.SetValue(TRUE)

  Dim buttonOK = wxButton(dl, wxID_OK, _("Ok"), wxPoint(0, dSizeY - 25), wxSize(dSizeX / 2, 25))
  Dim buttonCancel = wxButton(dl, wxID_CANCEL, _("Cancel"), wxPoint(dSizeX / 2, dSizeY - 25), wxSize(dSizeX / 2, 25))
  Dim Ok As Integer = FALSE

  If dl.ShowModal()= wxID_OK Then
    If rb1.GetValue() Then
      Ok = sortBy("country", "", "")

    Elseif rb2.GetValue() Then
      Ok = sortBy("name", "", "")

    Elseif rb3.GetValue() Then
      Ok = sortBy("genre", "", "")

    Elseif rb4.GetValue() Then
      Ok = sortBy("country", "name", "")

    Elseif rb5.GetValue() Then
      Ok = sortBy("genre", "name", "")

    Elseif rb6.GetValue() Then
      Ok = sortBy("country", "genre", "name")
    End If

    If Ok And Save Then saveStations(FALSE, TRUE)
    Return Ok
  End If

  dl.Destroy()

  Return FALSE
End Function


'save changed to database in web or podcast mode
'return true if ok, otherwise false
Function saveStations(query As Integer, renum As Integer)
  If !wxFileExists(playerPath &DELIMITER_CHAR &"IPTV.db") Then Return
  
  Dim cfg As wxFileConfig = wxFileConfig("", "", playerIni)
  cfg.SetPath("/Database")
  Dim backup As Integer = cfg.Read("DatabaseBackup", TRUE)

  'make a backup from the database
  If backup Then
    Dim bPath As String = playerPath &DELIMITER_CHAR &"IPTV.db"
    Dim bcount As Integer = cfg.Read("BackupNum", 5)

    'rename backup files
    If bcount > 1 Then
      For i = bcount - 1 To 1 Step - 1
        If FileExists(bPath &".bak" &i) Then
          Kill(bPath &".bak" &i + 1)
          Rename(bpath &".bak" &i, bPath &".bak" &i + 1)
        End If
      Next

      Kill(bPath &".bak1")
      wxCopyFile(bPath, bPath &".bak1")

    Else

      Kill(bPath &".bak")
      wxCopyFile(bPath, bPath &".bak")
    End If
  End If

  'renumbers the list as it is saved in the order shown.
  If renum Then renumList(0)

  If query Then
    Dim dl = wxGenericMessageDialog(Nothing, _("Attention") &"! " &"\n\n" &
    _("It will be saved in the current sorting!") &"\n" &
    _("This cannot be undone!"), _("Save playlist?"), wxYES_NO|wxYES_DEFAULT|wxCENTRE|wxICON_WARNING|wxDIALOG_NO_PARENT)

    'wxNO = 5104 in wxGenericMessageDialog
    If dl.ShowModal() = 5104 Then Return
  End If

  dbc = wxDbConnection("DBQ=IPTV.db;DefaultDir=.;Driver=SQLITE3;")
  If dbc.IsOpen() Then
    dbc.ExecSql("PRAGMA synchronous = OFF")
    dbc.ExecSql("PRAGMA journal_mode = MEMORY")
    dbc.ExecSql("PRAGMA cache_size = 1000000")
    dbc.ExecSql("PRAGMA locking_mode = EXCLUSIVE")
    dbc.ExecSql("PRAGMA temp_store = MEMORY")
    dbc.ExecSql("SET CHARACTER_SET 'utf8'")

    busyInfo = wxBusyInfo(_("Save playlist to database") &"\n" &_("Please don't interrupt..."))

    If playMode = ID_PLAY_WEBRADIO Then
      'clear database
      dbc.ExecSql("DELETE FROM radio")
      dbc.ExecSql("VACUUM")
      dbc.ExecSql("INSERT INTO radio(country, name, genre, adress, icon) VALUES (?, ?, ?, ?, ?)")
      dbc.ExecSql("Set name UTF8")
      'use BeginTransaction() for faster saving
      dbc.BeginTransaction()

      Dim s As String
      For i = 0 To lcWeb.GetItemCount() - 1
        'some stations has a quotation mark in the name
        'these must be replaced before saving
        s = lcWeb.GetStringItem(i, 2)
        If InStr(s, Chr(34)) Then s = Replace(s, Chr(34), "'")
        dbc.ExecSql("Insert INTO radio values(" &i + 1 &",'" &lcWeb.GetStringItem(i, 1) &"'," &Chr(34) &s &Chr(34) &",'" &lcWeb.GetStringItem(i, 3) &"','" &lcWeb.GetStringItem(i, 4) &"','" &lcWeb.GetStringItem(i, 5) &"');")
      Next

    Elseif playmode = ID_PLAY_PODCAST Then
      'clear database
      dbc.ExecSql("DELETE FROM podcast")
      dbc.ExecSql("VACUUM")
      dbc.ExecSql("INSERT INTO podcast(name, genre, adress, icon, active, counter, record) VALUES (?, ?, ?, ?, ?, ?, ?)")
      dbc.ExecSql("Set name UTF8")
      'use BeginTransaction() for faster saving
      dbc.BeginTransaction()

      Dim root = lcPod.GetRootItem()
      Dim child = lcPod.GetFirstChild(root)
      Dim url As String 
      While child.IsOk()
        s = lcPod.GetItemText(child, 0)
        url = lcPod.GetItemText(child, 4)

        'some stations has a quotation mark in the name
        'these must be replaced before saving
        If InStr(s, Chr(34)) Then s = Replace(s, Chr(34), "'")
        dbc.ExecSql("Insert INTO podcast values(" &Chr(34) &s &Chr(34) &",'" &lcPod.GetItemText(child, 2) &"','" &lcPod.GetItemText(child, 4) &"','" &lcPod.GetItemText(child, 5) &"','" &lcPod.GetCheckedState(child) &
        "','" &lcPod.GetItemText(child, 6) &"','" &lcPod.GetItemText(child, 7)  &"','" &lcPod.GetItemText(child, 8) &"');")

        Deallocate(child)
        child = lcPod.GetNextSibling(child)
      Wend
      Deallocate(root)

    Else

      dbc.ExecSql("DELETE FROM tv")
      dbc.ExecSql("VACUUM")
      dbc.ExecSql("INSERT INTO tv(country, name, genre, adress, icon) VALUES (?, ?, ?, ?, ?)")
      dbc.ExecSql("Set name UTF8")

      dbc.BeginTransaction()
      For i = 0 To lcWeb.GetItemCount() - 1
        s = lcWeb.GetStringItem(i, 2)
        If InStr(s, Chr(34)) Then s = Replace(s, Chr(34), "'")
        dbc.ExecSql("Insert INTO tv values(" &i + 1 &",'" &lcWeb.GetStringItem(i, 1) &"'," &Chr(34) &s &Chr(34) &",'" &lcWeb.GetStringItem(i, 3) &"','" &lcWeb.GetStringItem(i, 4) &"','" &lcWeb.GetStringItem(i, 5) &"');")
      Next
    End If

    'end the tranaction
    dbc.Commit()
    dbc.Close()

    ~busyinfo
    busyinfo = Nothing

    If query Then
      dl = wxGenericMessageDialog(Nothing, _("Playlist saved successfully."), _("Note"), wxOK|wxCENTER|wxICON_INFORMATION|wxDIALOG_NO_PARENT)
      dl.ShowModal()
    End If
    isModify = FALSE

    If !lcWeb.GetItemCount() Then Return FALSE
    setFile(FALSE)

    Return TRUE

  Else

    dl = wxGenericMessageDialog(Nothing, _("The playlist could not be saved"), _("Attention"), wxOK|wxCENTER|wxICON_EXCLAMATION|wxDIALOG_NO_PARENT)
    dl.ShowModal()
    Return FALSE
  End If
End Function


'return the filesize in a readable format
Function getReadableFileSize(fileSize)
  If fileSize > 0 Then
    Dim units As List = ["B", "KB", "MB", "GB", "TB", "PB"]
    For i = 0 To (fileSize > 1024)
      fileSize /= 1024
    Next

    Dim sizeString = Str(fileSize)
    Return Left(sizeString, Len(sizeString) - 4) &" " &units[i + 1]

  Else
  
    Return "--"
  End If
End Function


'return a formatted time from seconds
'needed for medialen or podlen
Function getTimeFromSec(fTime As Integer, isTitle As Integer)
  Try
    If fTime >= 0 Then
      Dim ts As wxTimeSpan = wxTimeSpan_Seconds(fTime)

      If isTitle Then
        Return ts.Format("%H:%M:%S")

      Else

        If ts.GetMinutes() > 59 Then
          Return ts.Format("%H:%M:%S")

        Else
          Return ts.Format("%M:%S")
        End If
      End If

    Else
      
      Return "--:--:--"
    End If

  Catch
      Return "--:--:--"
  end try
End Function


'return the time from a string
'either formatted or in seconds
Function getTimeFromString(tString As String, FormatTime As Integer, isTitle As Integer)
  If tString = "--:--" Then Return "--:--:--"

  Dim at As Integer = InStr(tString, ":")
  Dim cnt As Integer = Tally(tString, ":")

  If cnt Then
    Select Case cnt
    Case 1
      'format minutes:seconds
      'phiolas format for file info
      Dim ts As wxTimeSpan = wxTimeSpan(0, tString[: at - 1], tString[at + 1: ])
      
    Case 2
      'format hour:minutes:seconds
      'mostly podcast format
      Dim at1 As Integer = RInstr(tString, ":")
      ts = wxTimeSpan(tString[: at - 1], tString[at + 1: at1 - 1], tString[at1 + 1: ])
    End Select

    'format the time
    If FormatTime Then
      If (ts.GetHours()> 0) Or isTitle Then
        Return ts.Format("%H:%M:%S")
      Else
        Return ts.Format("%M:%S")
      End If
      
    Else

      'return the seconds
      Return ts.GetSeconds()
    End If

  Else

    Return IIf(isTitle, "--:--:--", 0)
  End If
End Function


'check for errors in a stream from phiola, if exitcode is greater than 0
'returns true if an error is present, otherwise false
Function checkError(text As String)
  Dim buffer As String = ""
  If phiolaPrc And phiolaPrc.IsInputOpened() Then
    Dim inStream As wxInputStream = phiolaPrc.GetInputStream()

    'read the input and error streams
    While phiolaPrc.IsInputAvailable()
      buffer &= instream.Read(1)
    Wend

    If InStr(buffer, "ERROR") Then 
      Dim errText = wxString_FromUTF8(buffer[InStr(LCase(buffer), "error")+ 6: ]) 
      buffer = Replace(buffer, text &":", "")
      Dim at = InStr(buffer, " *")
      If at Then errText = Trim(wxString_FromUTF8(buffer[InStr(at, buffer, ":") + 2: ])) 

      busyInfo = wxBusyInfo(errText)
      wxSleep(3)
      ~busyInfo
      busyInfo = Nothing

      Return TRUE
    End If
  End If

  Return FALSE
End Function


'get the language id from the language name
'new languages must be added here
Function LanguageCodeToId(languageCode As String)
  Select Case languageCode
  Case "de_DE", "German", Str(wxLANGUAGE_GERMAN) : Return wxLANGUAGE_GERMAN
  Case "en_GB", "English", Str(wxLANGUAGE_ENGLISH) : Return wxLANGUAGE_ENGLISH
  Case Else : Return wxLANGUAGE_ENGLISH
  End Select
End Function


Function testOpenWith()
'  Dim regKey As wxRegKey = wxRegKey("HKEY_CLASSES_ROOT\\SystemFileAssociations\\audio\\OpenWithList\\dsmPlayer")
  Dim regKey As wxRegKey = wxRegKey("HKEY_CLASSES_ROOT\\Applications\\dsmPlayer.exe")
  Dim keyExist As Integer = regkey.Exists()
  regkey.Close()

  Return keyExist
End Function

'------------------------------------------------------------------------------------------------------
'end functions
'------------------------------------------------------------------------------------------------------


'create the player
createDsmPlayer()


'load the web playlist from database
Sub loadPlaylistWeb()
  dbc = wxDbConnection("DBQ=IPTV.db;DefaultDir=.;Driver=SQLITE3;")
  If dbc.IsOpen() Then
    dbc.ExecSql("PRAGMA synchronous = OFF")
    dbc.ExecSql("PRAGMA journal_mode = MEMORY")
    dbc.ExecSql("PRAGMA cache_size = 1000000")
    dbc.ExecSql("PRAGMA locking_mode = EXCLUSIVE")
    dbc.ExecSql("PRAGMA temp_store = MEMORY")
    dbc.ExecSql("SET CHARACTER_SET 'utf8'")

    Dim hint As String
    Dim recSet As wxDbRecordset
    If busyInfo Then
      ~busyInfo
      busyInfo = Nothing
    End If

    Select Case playMode
    Case ID_PLAY_WEBRADIO
      hint = _("Loading radio stations...")
      recSet = wxDbRecordset(dbc, "select * from radio")

    Case Else
      hint = _("Loading TV stations...")
      recSet = wxDbRecordset(dbc, "select * from tv")
    End Select

    lcWeb.Freeze()
    lcWeb.DeleteAllItems()
    lcWeb.Thaw()

    Dim cnt As Integer = recSet.GetRowCount()
    If cnt > 3000 Then busyInfo = wxBusyInfo(hint)

    cnt = 0
    recSet.MoveFirst()
    While Not recSet.IsEOF()
      lcWeb.InsertStringItem(cnt, "  " &cnt + 1)
      lcWeb.SetStringItem(cnt, 1, recSet.FieldPos(2))
      lcWeb.SetStringItem(cnt, 2, recSet.FieldPos(3))
      lcWeb.SetStringItem(cnt, 3, recSet.FieldPos(4))
      lcWeb.SetStringItem(cnt, 4, recSet.FieldPos(5))
      lcWeb.SetStringItem(cnt, 5, recSet.FieldPos(6))
      recSet.MoveNext()

      If cnt % 200 = 0 Then wxSafeYield(musicFrame, TRUE)
      cnt += 1
    Wend

    recSet.Close()
    dbc.Close()
    If busyInfo Then ~busyInfo
    busyInfo = Nothing
  End If
  
  Dim Item As wxMenuItem
  Dim selName As String
  Dim isTV As Integer = (playMode = ID_PLAY_WEBTV)
  Dim sel = IIf((playMode = ID_PLAY_WEBRADIO), mFileWebRadio, mFileWebTV)
  If (playMode = ID_PLAY_WEBRADIO) And (sel >= 0) Then findFavSation()

  'load the station icons
  stationsIconsLoad()

  'select the lat file
  SelectFile(sel, TRUE, TRUE)
End Sub


Sub findFavSation()
  Dim sel As Integer = mFileWebRadio
  Dim Item As wxMenuItem
  Dim selName As String

  If sel >= 0 Then
    For i = 0 To selFavMenu.GetMenuItemCount() - 3
      Item = selFavMenu.FindItemByPosition(i)
      selName = Item.GetItemLabel()
      Item.Check(IIf(sel >= 0, selName = lcWeb.GetStringItem(sel - 1, 2), FALSE))
    Next
  End If
End Sub


'import a playlist
Sub importPlaylist(importList As String, importMode As Integer)
  If !FileExists(importList) Then Return

  Dim isTV As Integer = (playMode = ID_PLAY_WEBTV)
  Dim selection As Integer = lcWeb.FindItem(0, "  " &IIf(isTV, mFileWebTV, mFileWebRadio))
  If (selection >= 0) Then lcWeb.SetItemTextColour(selection, musicFontColour)

  Dim itemCount As Integer = lcWeb.GetItemCount()
  Dim cnt As Integer
  Dim FileName As wxFileName = wxFileName(importList)
  Dim listName As String = LCase(FileName.GetName())
  Dim fn As String
  Dim title As String
  Dim buffer As String
  Dim Item As String
  Dim country As String = ""
  Dim tCountry As String = ""
  Dim genre As String = ""
  Dim tGenre As String = ""
  Dim iconPath As String = ""
  Dim at As Integer
  Dim sorting As Integer = FALSE
  Dim updateOnly As Integer = FALSE
  Dim ignoreDouble As Integer = FALSE
  Dim char As String
  Dim Ascii As Integer
  Dim idx As Integer = IIf(playMode = ID_PLAY_WEBRADIO, 1, 0)

  Dim noLog As wxLog = wxLogNull()

  'import a single playlist from drive
  If importMode = 1 Then
    Dim sd = wxDialog(musicFrame, -1, _("Import playlist:"), wxDefaultPosition, wxSize(500, 370))
    Dim dSizeX = sd.GetClientSizeWidth()
    Dim dSizeY = sd.GetClientSizeHeight()
    Dim st As wxStaticText = wxStaticText(sd, -1, _("To transfer the data, leave the fields blank!"), wxPoint(10, 15))

    Dim sText = wxStaticText(sd, -1, _("Country code for all entries"), wxPoint(10, 55))
    Dim tcCountry = wxTextCtrl(sd, -1, country, wxPoint(10, 80), wxSize(450, 25))

    sText = wxStaticText(sd, -1, _("Genre:"), wxPoint(10, 120))
    Dim tcGenre = wxComboBox3(sd, -1, "" , wxPoint(10, 145), wxSize(450, 25), genres)
    Dim cb1 As wxCheckBox = wxCheckBox(sd, -1, _("Sort and save the playlist"), wxPoint(10, 185))
    Dim cb2 As wxCheckBox = wxCheckBox(sd, -1, _("Ignore duplicate station addresses in possibly other genres"), wxPoint(10, 205))
    cb1.SetValue(TRUE)
    cb2.SetValue(TRUE)

    Dim sBox As wxStaticBox = wxStaticBox(sd, -1, _("Import options:"), wxPoint(10, 235), wxSize(dSizeX - 20, 60))
    Dim rb1 As wxRadioButton = wxRadioButton(sBox, -1, _("Only update existing stations"), wxPoint(10, 20), wxDefaultSize, wxRB_GROUP)
    Dim rb2 As wxRadioButton = wxRadioButton(sBox, -1, _("Import new stations and update existing ones"), wxPoint(10, 40))
    rb1.SetValue(TRUE)

    Dim buttonOK = wxButton(sd, wxID_OK, _("Ok"), wxPoint(0, dSizeY - 25), wxSize(dSizeX / 2, 25))
    Dim buttonCancel = wxButton(sd, wxID_CANCEL, _("Cancel"), wxPoint(dSizeX / 2, dSizeY - 25), wxSize(dSizeX / 2, 25))

    If sd.ShowModal()= wxID_OK Then
      If busyInfo Then ~busyInfo
      busyInfo = wxBusyInfo(_("Import playlist") &" '" &FileName.GetFullName() &"'", musicFrame)

      updateOnly = rb1.GetValue() 
      ignoreDouble = cb2.GetValue()

      tGenre = tcGenre.GetValue()
      tCountry = tcCountry.GetValue()

      If cb1.GetValue() Then
        sorting = TRUE

      Else

        selection = lcWeb.GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED)
        If selection <> -1 Then
          cnt = selection + 1
        Else
          cnt = lcWeb.GetItemCount()
        End If
      End If
      ~sd

    Else

      sd.Destroy()
      Return
    End If

  Else

    'import playlists from web
    updateOnly =  Val(lcWeb.GetName()[: 1])
    ignoreDouble =  Val(lcWeb.GetName()[2: ])

    If isTV Then
      genre = ""
      country = ""

    Else
      'the filename of the imported file is the genre/playlist
      'summarize genres 
      genre = checkGenre(listName)
      If genre = "" Then genre = "Various"
      country = langCodes[listName]
    End If

    If country = Nothing Then country = ""
    sorting = TRUE
  End If

  Try
    'load the file into the buffer
    Dim NewLine As String
    Dim width As Integer
    Dim Name As String
    Dim foundNum As Integer = -1
    Dim adress As String
    Dim isPlaylistImport As Integer = FALSE
    Dim tempdir = wxFileName_GetTempDir() 

    Dim fStream As wxFileInputStream = wxFileInputStream(importList)
    Dim tStream As wxTextInputStream = wxTextInputStream(fStream, "\t", wxConvUTF8)

    If importMode = 1 Then titleFrame.Freeze()

    While Not fStream.Eof()
      If (cnt%50 = 0) And (mProgressDlg <> Nothing) Then
        Dim counter As Integer = mProgressDlg.GetRange() - mediaList.Count()
        Dim upd = mProgressDlg.Update(counter)

        If upd = FALSE Then
          If !InStr(importlist, ".m3u") Then
            zip.Close()
            ~zip
            out.Close()
            ~out
          End If

          ~noLog

          If importMode = 2 Then
            'delete temp file
            If InStr(importList, tempdir) Then Kill(importList)
          End If

          isBroken = TRUE
          mediaList.Clear()
          mProgressDlg.Destroy()
          mProgressDlg = Nothing
          Return
        End If
      End If

      NewLine = Nothing
      NewLine = tStream.ReadLine()
      If importMode = 1 Then genre = ""

      If (NewLine = "#EXTM3U") Then
         Continue

      'this is used for all in one file with different playlists
      'the filename begins with "---"
      Elseif UCase(NewLine[: 10])= "#PLAYLIST:" And listName[: 3] = "---" Then
        NewLine = Trim(NewLine[11: ])
        FileName.AssignPath(NewLine)
        fn = LCase(FileName.GetName())

        genre = checkGenre(fn)
        If genre = "" Then genre = "Various"
        country = langCodes[fn]
        If country = Nothing Then country = langCodes[LCase(genre)]
        If country = Nothing Then country = ""

      Elseif UCase(NewLine[: 8])= "#EXTINF:" Then
        NewLine = NewLine[9: ]
        iconPath = ""
        buffer = ""

        If isTV And (importMode = 2) Then
          country = ""
          genre = ""
        End If

        'the adress is in next line, read it
        adress = tStream.ReadLine()

        'no valid adress found or a station with this adress already exists
        'skip this station
        If (UCase(adress[: 4]) != "HTTP") Then Continue

        'get the station title
        at = RInstr(NewLine, ",")
        If at Then title = Trim(NewLine[at + 1: ])

        If importmode = 2 Then
          If isTV Then
            'handle index.m3u from tv playlist
            'tvg-id has the format title.country
            'split ist
            at = InStr(NewLine, "tvg-id=")
            If at Then
              buffer = wordBetween(NewLine[at: ], "\"","\"")
              If buffer <> "" Then
                If country = "" Then country = UCase(Right(buffer, 2))
              End If

            Else
              country = ""
              
            End If
          End If

        Else
        
          If country = "" Then country = tCountry
          If genre = "" Then genre = tGenre
        End If

        'load iptv playlist, radio or tv and the country
        at = InStr(NewLine, "group-title=")
        If at Then
          foundNum = -1
          buffer = wordBetween(NewLine[at: ], "\"","\"")

          'import from Kodi IPTV list
          'in Kodi radio and tv playlist is mixed
          'only accept the current playlist
          'otherwise go to the next entry
          If LCase(buffer[: 5])= "iptv-" Or LCase(buffer[: 6])= "radio-" Then
            
            If (isTV And LCase(buffer[: 6])= "radio-") Or ( !isTV And LCase(buffer[: 5])= "iptv-") Then Continue

            If tCountry <> "" Then
              country = tCountry
            Else
              country = Trim(buffer[RInstr(buffer, "-")+ 1: ])
            End If

            If tGenre <> "" Then
              genre = tGenre
            Else
              genre = "Various"
            End If

          'import other playlists
          Else

            If importMode = 1 Then
              If genre = "" Then genre = checkGenre(buffer)

              'is it a mixed playlist?
              If genre = "" Then
                at = RInstr(buffer, "-")
                If at Then
                  genre = buffer[: at - 1]
                  country = buffer[at + 1: ]
                End If
              End If

            Elseif importMode = 2 Then
              'remove the quality informations from imported stations
              'many stations has different quality informations, but the same web adress
              at = RInstr(title, "kbit/s")
              If at Then title = RTrim(title[: RInstr(title, "-") - 1])

              If isTV Then
                genre = checkGenre(buffer)
                If genre = "" Then genre = "Various"

                If country = "" Then
                  at = InStr(buffer, "(")
                  If at Then
                    country = wordbetween(buffer, "(", ")")
                  Else
                    country = langCodes[LCase(buffer)]
                  End If
                End If
              End If

              If country = Nothing Then country = ""
            End If
          End If
        End If

        'load the iconpath from iptv playlist
        at = InStr(NewLine, "tvg-logo=")
        If at Then iconPath = LCase(wordBetween(NewLine[at: ], "\"","\""))

        'some title have html entities in name, replace the most important ones
        If InStr(title, ";") Then title = replaceHTMLEntities(title)

        If genre = "" Then genre = "Various"

        'is the title already in list
        foundNum = allMediaFiles.INDEX(LCase(title))

        'the title is not found in current list
        If foundNum = -1 Then
          If updateOnly Then
            Continue

          Elseif title <> "" Then
            'ignore stations with an empty title
            'add the station at the end
            cnt = lcWeb.GetItemCount()
            lcWeb.InsertStringItem(cnt, "  " &Str(cnt + 1))
            lcWeb.SetStringItem(cnt, 1, Country)
            lcWeb.SetStringItem(cnt, 2, title)
            lcWeb.SetStringItem(cnt, 3, genre)
            lcWeb.SetStringItem(cnt, 4, adress)
            lcWeb.SetStringItem(cnt, 5, iconPath)
            If iconpath = "" Then lcWeb.SetItemImage(cnt, idx, idx)
            allMediaFiles.Add(LCase(title))
          End If

        Else

          If ignoreDouble Then
            'ignore double entrys for automatical update
            'update entrys
            If country <> "" Then lcWeb.SetStringItem(foundNum, 1, Country)
            If genre <> "" Then lcWeb.SetStringItem(foundNum, 3, genre)
            lcWeb.SetStringItem(foundNum, 4, adress)
            If iconpath <> "" Then lcWeb.SetStringItem(foundNum, 5, iconPath)

          Elseif (genre <> lcWeb.GetStringItem(foundNum, 3)) And (title <> "") Then
            'the genre is another then the original
            'add the title with another genre
            cnt = lcWeb.GetItemCount()
            lcWeb.InsertStringItem(cnt, "  " &Str(cnt + 1))
            lcWeb.SetStringItem(cnt, 1, Country)
            lcWeb.SetStringItem(cnt, 2, title)
            lcWeb.SetStringItem(cnt, 3, genre)
            lcWeb.SetStringItem(cnt, 4, adress)
            lcWeb.SetStringItem(cnt, 5, iconPath)
            If iconpath = "" Then lcWeb.SetItemImage(cnt, idx, idx)

          Elseif (country <> "") And (country <> lcWeb.GetStringItem(foundNum, 1)) Then
            'update the country, if another
           lcWeb.SetStringItem(foundNum, 1, Country)
            If iconpath <> "" Then lcWeb.SetStringItem(foundNum, 5, iconPath)

          Elseif iconpath <> "" Then
           lcWeb.SetStringItem(foundNum, 5, iconPath)

          End If
        End If

      Elseif NewLine[: 1]= "#" Then
        'ignore other directives, such as #EXTGRP:, #EXTART:, #EXTGENRE: etc.
        Continue
      End If

      If cnt % 300 = 0 Then wxYield()
    End While

    'autoarrenge number column width
    width = musicFrame.GetTextExtentX("  " &cnt)+ stationIconSize
    If Width > lcWeb.GetColumnWidth(0) Then lcWeb.SetColumnWidth(0, Width)

    ~noLog
    isModify = TRUE

  Catch
    Dim dl = wxGenericMessageDialog(Nothing, _("An error occurred while importing!"), _("Attention"), wxOK|wxCENTRE|wxICON_EXCLAMATION|wxDIALOG_NO_PARENT)
    dl.ShowModal()
    Return
  End Try

  If importMode = 1 Then
    If sorting And (itemCount < lcWeb.GetItemCount()) Then
      'save the playlist for sorting
      saveStations(FALSE, FALSE)

      Dim Ok = setSortOptions(TRUE)
      If !Ok Then renumList(0)
    End If

    titleFrame.Thaw()

  Elseif importMode = 2 Then
    'delete imported file, if it is in temp directory 
    If InStr(importList, tempdir) Then Kill(importList)
  End If

  'search and select the played file
  selectFile(IIf((playMode = ID_PLAY_WEBRADIO), mFileWebRadio, mFileWebTV), TRUE, TRUE)
  musicFrame.RefreshRect(rects["text"])

  If busyInfo Then ~busyInfo
  busyInfo = Nothing

  wxYield()
End Sub


'load a playlist in file mode
Sub loadPlayListMedia(file As String, firstStart As Integer, edit As Integer)
  If file = "" Then Return

  Dim FileName As wxFileName = wxFileName(file)
  Dim ext As String = lcase(FileName.GetExt())
  Dim editCtrl As wxListBox
  If edit Then editCtrl = DynamicCast("wxListBox", musicFrame.FindWindowByName("batchFileList"))
  Dim explorerMedia As wxGenericDirCtrl = DynamicCast("wxGenericDirCtrl", musicFrame.FindWindowByName("explorermedia"))

  If FileExists(file) Then
    Dim change As DateTime
    Dim cDate As wxDateTime = wxDateTime_wxDateTime()
    Dim titleLen As Integer
    Dim title As String
    Dim at As Integer
    Dim noLog As wxLog = wxLogNull()
    titleframe.Freeze()

    Try
      lcMedia.DeleteAllItems()

      'load the file into the buffer
      Dim NewLine As String
      Dim Width As Integer
      Dim path As String
      Dim foundNum As Integer = -1
      Dim cnt As Integer = 0
      Dim enc = wxLocale_GetSystemEncodingName() 

      'use wxTextInputStream to read lines
      'wxConvUTF8 don't show german umlauts
      'it cuts the text with and after the umlaut, if the system encoding is not UTF-8
      Dim fStream As wxFileInputStream = wxFileInputStream(file)
      Dim tStream As wxTextInputStream = wxTextInputStream(fStream, "\n", IIf(enc = "UTF-8", wxConvUTF8, wxConvFileName))
      Dim modTime As wxDateTime
      Dim isExtendedList As Integer = FALSE

      While Not fStream.Eof()
        NewLine = Nothing
        NewLine = LTrim(tStream.ReadLine())

        If ext = "m3u" Then
          'm3u playlist
          If (NewLine = "#EXTM3U") Then
            isExtendedList = TRUE
            Continue

          Elseif UCase(NewLine[: 8])= "#EXTINF:" Then
            If !isExtendedList Then
              Dim dl = wxGenericMessageDialog(Nothing, _("The playlist does not have the correct format"), _("Attention"), wxOK|wxCENTRE|wxICON_INFORMATION|wxDIALOG_NO_PARENT)
              dl.ShowModal()
              Break
            End If

            NewLine = NewLine[9: ]

            'load path to the station icon
            at = RInstr(NewLine, ",")
            If at Then title = Trim(NewLine[at + 1: ])

            'this can used to autoarrenge the column width
  '          width = musicFrame.GetTextExtentX(title)
  '          If width > lcMedia.GetColumnWidth(1) Then lcMedia.SetColumnWidth(1, width)
            If (playlistFile = explorerMedia.GetFilePath()) And (allmediafiles.Count()> 0) And !edit Then
              FileName.AssignPath(allMediaFiles.Item(cnt))
              lcMedia.InsertStringItem(cnt, "  " &allMediaFilesInt.Item(cnt))
              lcMedia.SetItemData(cnt, 0)
              lcMedia.SetStringItem(cnt, 1, FileName.GetFullName())

              If FileName.FileExists() Then
                modTime = FileName.GetModificationTime()
                lcMedia.SetStringItem(cnt, 3, modtime.FormatDate() &"  " & modtime.FormatTime())
                lcMedia.SetStringItem(cnt, 4, getReadableFileSize(wxFileSize(FileName.GetFullPath())))

              Else

                lcMedia.SetStringItem(cnt, 2, "--:--:--")
                lcMedia.SetStringItem(cnt, 3, "--")
                lcMedia.SetStringItem(cnt, 4, "--")
              End If
              lcMedia.SetStringItem(cnt, 5, FileName.GetFullPath())

            Else

              'read title length, if available
              titleLen = NewLine[: at - 1]

              'read next line, path to the title
              NewLine = tStream.ReadLine()

              'filename without a path, add the current path from the dirctrl
              If !wxFileExists(NewLine) And !edit Then NewLine = wxPathOnly(explorerMedia.GetPath()) &DELIMITER_CHAR &NewLine

              If edit Then
                editCtrl.Append(NewLine)
                Continue
              End If

              'set counter
              lcMedia.InsertStringItem(cnt, "  " &cnt + 1)
              lcMedia.SetItemData(cnt, 0)


              'insert additional informations, if the file exists
              If wxFileExists(NewLine) Then
                'insert filename
                lcMedia.SetStringItem(cnt, 1, title)

                'set title length, if available
                If titleLen > -1 Then
                  lcMedia.SetStringItem(cnt, 2, getTimeFromSec(titleLen, FALSE))
                Else
                  getFileInfo(NewLine, cnt)
                End If

                'insert file modification time
                change = TimeValue(wxFileModificationTime(NewLine))
                cDate = wxDateTimeFromTimeT(change)
                lcMedia.SetStringItem(cnt, 3, cDate.Format("%d.%m.%y") &"  " &cDate.Format("%H:%M:%S"))

                'insert filesize
                lcMedia.SetStringItem(cnt, 4, getReadableFileSize(wxFileSize(NewLine)))

                'insert full file path
                lcMedia.SetStringItem(cnt, 5, NewLine)

              Else

                lcMedia.SetStringItem(cnt, 1, "?? " &title)
                lcMedia.SetStringItem(cnt, 2, "--:--")
                lcMedia.SetStringItem(cnt, 3, "--")
                lcMedia.SetStringItem(cnt, 4, "--")
                lcMedia.SetStringItem(cnt, 5,  "?? " &title)
              End If
            End If

            cnt += 1

          Elseif NewLine[: 1]= "#" Then
            'ignore other directives, such as #EXTGRP:, #EXTART:, #EXTGENRE: etc.
            Continue

          Elseif NewLine <> "" Then
            If !isExtendedList Then
              If edit Then
                editCtrl.Append(NewLine)

              Else

                insertItems(cnt, NewLine, "")
                cnt += 1
              End If
            End If
          End If

        Else

          'cue playlist
          If NewLine[: 4]= "FILE" Then
            FileName.AssignPath(wordbetween(NewLine, "\"","\""))
            If FileName.IsRelative() Then FileName.MakeAbsolute(wxPathOnly(file))
            
            lcMedia.InsertStringItem(cnt, "  " &cnt + 1)
            lcMedia.SetItemData(cnt, 0)

          Elseif NewLine[: 5]= "TITLE" And lcMedia.GetItemCount() Then
            title = wordbetween(NewLine, "\"","\"")
            path = FileName.GetFullPath()

            If wxFileExists(path) Then
              'insert filename
              lcMedia.SetStringItem(cnt, 1, title)

              'set title length, if available
              getFileInfo(path, cnt)

              'insert file modification time
              change = TimeValue(wxFileModificationTime(path))
              cDate = wxDateTimeFromTimeT(change)
              lcMedia.SetStringItem(cnt, 3, cDate.Format("%d.%m.%y") &"  " &cDate.Format("%H:%M:%S"))

              'insert filesize
              lcMedia.SetStringItem(cnt, 4, getReadableFileSize(wxFileSize(path)))

              'insert full file path
              lcMedia.SetStringItem(cnt, 5, path)

            Else

              lcMedia.SetStringItem(cnt, 1, "?? " &title)
              lcMedia.SetStringItem(cnt, 2, "--:--")
              lcMedia.SetStringItem(cnt, 3, "--")
              lcMedia.SetStringItem(cnt, 4, "--")
              lcMedia.SetStringItem(cnt, 5,  "?? " &path)
            End If

            cnt += 1
          End If
        End If

        If cnt%50 Then wxYield()
      End While

      ~noLog

    Catch
      titleFrame.Thaw()
      dl = wxGenericMessageDialog(Nothing, _("An error occurred while loading the playlist!"), _("Attention"), wxOK|wxCENTRE|wxICON_EXCLAMATION|wxDIALOG_NO_PARENT)
      dl.ShowModal()
      Return
    End Try

    titleframe.Thaw()
    setFile(TRUE)

    If showMusicTitle Then musicFrame.RefreshRect(wxRect(0, 24, musicFrame.GetSizeWidth(), 30))
  End If
End Sub


'download files during database update
Sub FilesDownload(path As String)
  Dim FileName As wxFileName = wxFileName(path)
  Dim tempDir = wxFileName_GetTempDir()

  If mProgressDlg <> Nothing Then
    Dim counter As Integer = mProgressDlg.GetRange() - mediaList.Count()
    Dim upd As Integer 
    
    If FileName.GetFullName() = "contents" Then
      upd = mProgressDlg.Update(counter, counter + 1 &"/" &mProgressDlg.GetRange() &"  " &"Loading file content...")

    Elseif Left(FileName.GetName(), 3)= "---" Then
      upd = mProgressDlg.Update(counter, counter + 1 &"/" &mProgressDlg.GetRange() &"  " &"Import music playlist from Github")
      
    Elseif Left(FileName.GetExt(), 3)<> "m3u" Then
      upd = mProgressDlg.Update(counter, counter + 1 &"/" &mProgressDlg.GetRange() &"  " &"Import station logos")

    Else
      upd = mProgressDlg.Update(counter, counter + 1 &"/" &mProgressDlg.GetRange() &"  " &"Import IPTV playlists from Github")
    End If

    If upd = FALSE Then
      If !InStr(path, ".m3u") Then
        zip.Close()
        ~zip
        out.Close()
        ~out
      End If

      isBroken = TRUE
      mediaList.Clear()
      mProgressDlg.Destroy()
      mProgressDlg = Nothing
      Return
    End If
  End If

  Dim prc = New wxProcessWithFlags(wxPROCESS_REDIRECT)
  Connect(prc, wxEVT_END_PROCESS, "onEndDownloadProcess")
  Dim pid As Integer = wxExecute(Chr(34) &wgetPath &Chr(34) &" --local-encoding=UTF-8 --timeout=20 --tries=5 --remote-encoding=UTF-8 --no-verbose -P " &tempDir &" " &path, wxEXEC_ASYNC, prc)
  If !pid Then ~prc
End Sub


'the download has been completed
Sub onEndDownloadProcess(event As wxProcessEvent)
  wxYield()
  Dim dFile As String = mediaList.Item(0)
  Dim tempDir = wxFileName_GetTempDir()
  Dim fn As String
  Dim FileName As wxFileName = wxFileName(dFile)
  Dim ext As String = FileName.GetExt()
  Dim noLog = wxLogNull()
  Dim img As wxImage

  If FileName.HasExt() Then
    If Left(ext, 3) = "m3u" Then

      'download a playlist is finished
      'import the playlist
      fn = tempDir &DELIMITER_CHAR &wxFileNameFromPath(dFile)
      If wxFileExists(fn) Then importPlaylist(fn, 2)

    Else

      fn = tempDir &DELIMITER_CHAR &wxFileNameFromPath(dFile)
      If wxFileExists(fn) Then
        If Right(LCase(fn), 7)= "svg.png" Then wxRenameFile(fn, fn[: RInstr(fn, ".") - 1])

        If (Right(LCase(fn), 3)= "svg") Then
          Dim bundle = wxBitmapBundle_FromSVGFile(fn, wxSize(stationIconSize, stationIconSize))
          img = wxImageFromBitmap(bundle.GetBitmap(wxSize(stationIconSize, stationIconSize)))

        Else

          Dim Type As Integer = GetBitmapType(fn)
          img = wxImageFromFile(fn, Type)
        End If


        If img And img.IsOk() Then
          'get width of the image after file loading
          Dim width As Integer = img.GetWidth()
          Dim height As Integer = img.GetHeight()

          'set the aspect ratio
          Dim p As Number = IIf(Width > height, stationIconSize / width, stationIconSize / height)
          width = width * p
          height = height * p
          
          'rescale the image proportionally to the iconsize in the aspect ratio
          Deallocate(img)
          img = img.Rescale(width, height, wxIMAGE_QUALITY_HIGH)

          'resize the image to the iconsize to be added to the imagelist by adding a border to it and center the image
          Deallocate(img)
          img = img.Resize(wxSize(stationIconSize, stationIconSize), wxPoint((stationIconSize - width) / 2, (stationIconSize - height) / 2), -1, -1, -1)

          Dim oStream As wxOutputStream = wxMemoryOutputStream()
          img.SaveStreamFile(oStream, wxBITMAP_TYPE_PNG)
          Dim inStream As wxMemoryInputStream = wxMemoryInputStreamFromOutput(oStream)

          FileName.AssignPath(fn)
          FileName.SetExt("png")
          zip.PutNextEntry(FileName.GetFullName())
          zip.WriteFromStream(inStream)

          ~inStream
          oStream.Close()
          ~oStream
          ~img
          Kill(fn)

        Else
          mProgressDlg.SetName(Val(mProgressDlg.GetName())+ 1)
        End If

      Else

        mProgressDlg.SetName(Val(mProgressDlg.GetName())+ 1)
      End If
    End If

  Else

    Dim buffer As String
    Dim file As wxFileName = wxFileName("")
    Dim link As String
    Dim freenum = FreeFile()
    fn = tempDir &DELIMITER_CHAR &wxFileNameFromPath(dFile)

    If wxFileExists(fn) Then
      Open (fn) For Input As #freeNum

      While Not Eof(freeNum)
        Line Input #freeNum, buffer
        buffer = Trim(buffer)

        If (Left(buffer, 14)= (Chr(34) &"download_url" &Chr(34))) Then
          buffer = buffer[15: ]
          link = wordbetween(buffer, Chr(34), Chr(34))
          file.AssignPath(link)
          If file.GetExt()= "m3u" And Left(file.GetName(), 3) != "---" Then mediaList.Add(link)
        End If
      End While

      Close #freeNum
      mProgressDlg.SetRange(mediaList.Count())
    End If
  End If
  ~nolog

  mediaList.RemoveAt(0)

  If mediaList.Count() Then
    FilesDownload(mediaList.Item(0))

  Else

    If mProgressDlg Then
      'read range and error counter from the progrss dialog
      If Left(ext, 3) != "m3u" Then
        Dim counter As Integer = mProgressDlg.GetRange()
        Dim errors As Integer = mProgressDlg.GetName()
      End If

      'delete progrss dialog
      mProgressDlg.Destroy()
      mProgressDlg = Nothing

      'show message from imported icons
      If Left(ext, 3) != "m3u" Then
        Dim x, y As Integer
        x, y = wxDisplaySize()
        Dim dl = wxGenericMessageDialog(Nothing, _("Total icons:") &Space(5) &counter &"\n" &
        _("Download error:") &Space(5) &errors &"\n" &
        _("Logos saved:") &Space(5) &(counter - errors), 
        _("Summary:"), wxOK|wxCENTER|wxDIALOG_NO_PARENT)

        dl.SetSize(wxSize(400, 190))
        dl.SetPosition(wxPoint(x / 2 - 200, y / 2 - 90))
        dl.ShowModal()
      End If
    End If

    'this is the contents file from the github repo
    'do nothing with it
    If !FileName.HasExt() Then
      Kill(fn)
      Return
    End If

    If (Left(ext, 3) != "m3u") And (ext <> "")  Then
      zip.Close()
      ~zip
      out.Close()
      ~out

      If wxFileExists(wxFileName_GetTempDir() &DELIMITER_CHAR &"tempdb.zip") Then
        Dim Ok = wxCopyFile(wxFileName_GetTempDir() &DELIMITER_CHAR &"tempdb.zip", playerPath &DELIMITER_CHAR &"stationLogos.zip")
        If Ok Then Kill(tempDir &DELIMITER_CHAR &"tempdb.zip")
      End If

      'both the original archive and the new one must be closed
      'before Commit -- let the destructors do it (there's no Close
      'method in wxFFileInputStream, anyway)

      'tempfile.Commit()

      'load the icons into the program
      stationsIconsLoad()

    Else

      If titleframe.IsFrozen() Then titleFrame.Thaw()
      allMediaFiles.Clear()
      langCodes = {}

      If !isBroken Then
        Dim updateOnly =  Val(lcWeb.GetName()[: 1])
        If !updateOnly Then
          Ok = saveStations(FALSE, FALSE)
          If Ok Then setSortOptions(TRUE)

        Else

          saveStations(TRUE, TRUE)
        End If

        stationsIconsLoad()
      End If

      isBroken = FALSE
    End If

    'handle false favotite item number, after import
    Dim Item As wxMenuItem
    Dim id As Integer

    dbc = wxDbConnection("DBQ=IPTV.db;DefaultDir=.;Driver=SQLITE3;")
    If dbc.IsOpen() Then
      dbc.ExecSql("PRAGMA synchronous = OFF")
      dbc.ExecSql("PRAGMA journal_mode = MEMORY")
      dbc.ExecSql("PRAGMA cache_size = 1000000")
      dbc.ExecSql("PRAGMA locking_mode = EXCLUSIVE")
      dbc.ExecSql("PRAGMA temp_store = MEMORY")
      dbc.ExecSql("SET CHARACTER_SET 'utf8'")

      For i = 0 To selFavMenu.GetMenuItemCount() - 1
        Item = selFavMenu.FindItemByPosition(i)
        id = dbc.ExecSql("SELECT id FROM radio where name=" &"'" &Item.GetItemLabel() &"' COLLATE NOCASE")
        If id Then
          If Item.IsChecked() Then mFileWebRadio = id
          selectFile(id, TRUE, TRUE)
          Item.SetHelp(id)
        End If
      Next
      dbc.Close()
    End If
  End If
End Sub


'load station icons
Sub stationsIconsLoad()
  If !useIcons Then Return

  If busyInfo Then
    ~busyInfo
    busyInfo = Nothing
  End If


  If lcWeb.GetItemCount()> 3000 Then busyInfo = wxBusyInfo(_("Set station logos..."))

  images = {}
  Dim ilWeb As wxImageList = lcWeb.GetImageList(1)
  ilWeb.RemoveAll()
  ilWeb.Add(iList["tv"])
  ilWeb.Add(iList["tv_T"])
  ilWeb.Add(iList["radio"])
  ilWeb.Add(iList["radio_T"])

  Dim idx As Integer = IIf(playMode = ID_PLAY_WEBRADIO, IIf(useTransparency, 3, 2), IIf(useTransparency, 1, 0))

  If !wxFileExists(playerPath &DELIMITER_CHAR &"stationLogos.zip") Then
    For i = 0 To lcWeb.GetItemCount() - 1
      'add the image to the listctrl
     lcWeb.SetItemImage(i, idx, idx)
    Next

    If busyInfo Then
      ~busyInfo
      busyInfo = Nothing
    End If

    Return
  End If

  Dim FileName As wxFileName = wxFileName("")
  Dim file As String
  Dim bmp As wxBitmap
  Dim buf As wxBitmap
  Dim fs As wxFileSystem = wxFileSystem()
  Dim fsFile As wxFSFile
  Dim stream As wxInputStream
  Dim img As wxImage
  Dim noLog As wxLog = wxLogNull()
  Dim cnt As Integer

  For i = 0 To lcWeb.GetItemCount() - 1
    file = lcWeb.GetStringItem(i, 5)

    If file <> "" Then
      FileName.AssignPath(file)
      FileName.SetExt("png")
      file = FileName.GetFullName()

      fsfile = fs.OpenFile(playerPath &DELIMITER_CHAR &"stationLogos.zip#zip:" &file)
      If fsFile Then
        stream = fsFile.GetStream()

        If stream.IsOk() Then
          img = wxImageFromStream(stream, wxBITMAP_TYPE_PNG)

          If img And img.IsOk() Then
            bmp = wxBitmapFromImage(img)

            If useTransparency Then
              buf = wxBitmapCopy(bmp)
            Else
              buf = SetBitmapBackground(bmp)
            End If

            'adding the first bitmap to the imagelist get an error, but the bitmap is ok ("daserste.png")
            'but the image is already added
            'replace the the added bitmap with the real bitmap and it works !?
            If !ilWeb.Add(buf) Then
              If buf.IsOk() Then
                ilWeb.Replace(ilWeb.GetImageCount() - 1, buf)
              End If
            End If
            cnt = ilWeb.GetImageCount() - 1
            lcWeb.SetItemImage(i, cnt, cnt)

            'hold the image index from the iconpath
            images[file]= cnt

            ~buf
            ~img
            img = Nothing
            ~bmp

          Else

           lcWeb.SetItemImage(i, idx, idx)
          End If

        Else

         lcWeb.SetItemImage(i, idx, idx)
        End If
        ~fsfile

      Else

       lcWeb.SetItemImage(i, idx, idx)
      End If

    Else

     lcWeb.SetItemImage(i, idx, idx)
    End If

    If i % 300 = 0 Then wxSafeYield(musicFrame, TRUE)
  Next

  ~fs
  ~noLog

  If busyInfo Then
    ~busyInfo
    busyInfo = Nothing
  End If
End Sub


'simple m3u format, only paths are added
Sub insertItems(counter As Integer, file As String, title As String)
  Dim explorerMedia As wxGenericDirCtrl = DynamicCast("wxGenericDirCtrl", musicFrame.FindWindowByName("explorermedia"))

  'create a new line in the listctrl, if the line not exists
  If lcMedia.GetItemCount()= counter Then
    lcMedia.InsertStringItem(counter, "  " &counter + 1)
    lcMedia.SetItemData(counter, 0)
  End If

  'set the title, if not already set
  If title <> "" Then lcMedia.SetStringItem(counter, 1, title)
  Dim FileName As wxFileName = wxFileName(file)
  If !FileName.IsAbsolute() Then File = wxPathOnly(explorerMedia.GetPath()) &DELIMITER_CHAR &file

  'insert additional informations, if the file exists
  If wxFileExists(file) Then
    'insert filename
    lcMedia.SetStringItem(counter, 1, file)

    'read the play time
    getFileInfo(file, counter)

    Dim change = TimeValue(wxFileModificationTime(file))
    Dim cDate As wxDateTime = wxDateTimeFromTimeT(change)
    'insert file modification time
    lcMedia.SetStringItem(counter, 3, cDate.Format("%d.%m.%y") &"  " &cDate.Format("%H:%M:%S"))
    'insert filesize
    lcMedia.SetStringItem(counter, 4, getReadableFileSize(wxFileSize(file)))
    lcMedia.SetStringItem(counter, 5,  file)

  Else

    lcMedia.SetStringItem(counter, 1,  "?? " &file)
    lcMedia.SetStringItem(counter, 2, "--:--")
    lcMedia.SetStringItem(counter, 3, "--")
    lcMedia.SetStringItem(counter, 4, "--")
    lcMedia.SetStringItem(counter, 5,  "?? " &file)
  End If
End Sub


'paint the player and controls
Sub onPaintMusicPlayer(event As wxPaintEvent)
  If isRefresh Then Return
  isRefresh = TRUE
  Dim explorerMedia As wxGenericDirCtrl = DynamicCast("wxGenericDirCtrl", musicFrame.FindWindowByName("explorermedia"))

  'create the paint dc
  Dim dc As wxBufferedDC = wxBufferedPaintDCWithTemp(musicFrame)

  'get the update rect
  Dim rect As wxRect = musicFrame.GetUpdateClientRect()

  'get real coords
  Dim x As Integer = dc.DeviceToLogicalXRel(rect.GetX())
  Dim y As Integer = dc.DeviceToLogicalYRel(rect.GetY())

  'paint player bitmap to screen to reset the view
  Dim memDC As wxMemoryDC = wxMemoryDC()
  memDC.SelectObject(iList["frame"])
  dc.Blit(x, y, rect.GetWidth(), rect.GetHeight(), memDC, x, y, wxCOPY, FALSE)

  'get the mouse point relative to the player frame
  Dim point As wxPoint = musicFrame.ScreenToClientPoint(wxGetMousePosition()) 
  Dim px As Integer = point.GetX()
  Dim py As Integer = point.GetY()

  Dim sel As Integer = -1
  Dim isWeb As Integer = 0
  Select Case playMode
  Case ID_PLAY_WEBRADIO: sel = mFileWebRadio: isWeb = 1
  Case ID_PLAY_WEBTV: sel = mFileWebTV: isWeb = 1
  End Select
  If sel >= 0 Then sel = lcWeb.FindItem(0, "  " &sel)

  'draw the text for radio station in webradio mode
  'draw the title in file mode
  'draw the text in validation mode
  If rect.Intersects(rects["text"]) Or rect.Intersects(rects["time"]) Then
    Dim fs = (9.5 * Scale * ps)
    'set the text font and colour
    Dim font As wxFont = wxFont(fs, wxDEFAULT, wxNORMAL, IIf((playMode = ID_PLAY_FILE) Or (playmode = ID_PLAY_PODCAST), wxBOLD, wxNORMAL))
    dc.SetFont(font)
    Dim text As String = ""

    If (((playMode = ID_PLAY_FILE) Or (playMode = ID_PLAY_PODCAST)) And rect.Intersects(rects["time"])) Then
      dc.SetTextForeground(IIf(theme = 1, wxWHITE, wxBLACK))
      'draw time value in file mode
      text = getTimeFromSec(IIf(playMode = ID_PLAY_FILE, mediaPos, podPos), TRUE) & " / " & getTimeFromSec(IIf(playMode = ID_PLAY_FILE, mediaLen, podLen), TRUE)
      Dim xT As Integer = ((rects["mute"].GetLeft() - (rects["mSlider"].GetRight())) - dc.GetTextExtentWidth(text))/ 2
      dc.DrawText(text, rects["mSlider"].GetRight()+ xT, rects["time"].GetY())
    End If

    'refresh the text
    If (((playMode = ID_PLAY_WEBRADIO) Or (playMode = ID_PLAY_WEBTV)) And rect.Intersects(rects["text"])) Then
      'draw the title to the player window
      text = pTitle
      dc.SetTextForeground(IIf(theme = 1, wxWHITE, wxBLACK))

      If validation And (playMode = ID_PLAY_WEBRADIO) Then
        'validation is in progress
        If allMediaFilesInt.Count() Then
          text = _("Test address") &" " &(allMediaFilesInt.Item(0)+ 1) &"  (" &(errCnt - allMediaFilesInt.Count()+ 1) &" / " &errCnt &")"
        End If
      End If

    Elseif playMode = ID_PLAY_FILE Then 
      'set title text in file mode
      text = IIf((musicFile <> -1) And  showMusicTitle, pTitle, "")
      dc.SetTextForeground(IIf(theme = 3, wxBLACK, wxWHITE))

    Elseif playMode = ID_PLAY_PODCAST Then
      'set title text in podcast mode
      text = IIf(showPodTitle, pTitle, "")
      dc.SetTextForeground(IIf(theme = 3, wxBLACK, wxWHITE))
    End If

    'set the position from the given text
    Dim sMode As Integer = IIf((playMode = ID_PLAY_FILE) Or (playMode = ID_PLAY_PODCAST), TRUE, FALSE)
    Dim posY As Integer = (musicFrame.GetSizeHeight() + IIf(sMode, 23 * ps, 0) - dc.GetTextExtentHeight(text))/ 2
    Dim tWidth As Integer = dc.GetTextExtentWidth(text)

    'draw the text
    Dim posX As Integer = rects["text"].GetX()

    'reduce the font size to display the entire title
    While tWidth >= rects["text"].GetWidth()
      If font.GetPointSize()> (7.5 * Scale * ps) Then
        font.SetPointSize(font.GetPointSize() -.5)
        dc.SetFont(font)
      Else
        'shorten long text, if the font is to small
        text = Left(text, Len(text) - 1)
      End If

      tWidth = dc.GetTextExtentWidth(text)
      posY = (musicFrame.GetSizeHeight() + IIf(playmode = ID_PLAY_FILE, (24 * ps), 0) - dc.GetTextExtentHeight(text))/ 2
    Wend

    'get the text start position
    posX = posX + (rects["text"].GetWidth() - tWidth)/ 2

    'draw the channel name
    If text <> "" Then dc.DrawText(text, posX, posY)

    dc.SetFont(wxNullFont)
  End If

  'draw explorer window arrows
  If rect.Intersects(rects["expl"]) Then
    If !titleFrame.IsShown() Then
      If rects["expl"].Contains(px, py) Then
        memDC.SelectObject(iList["explDownHover"])
      Else
        memDC.SelectObject(iList["explDown"])
      End If

    Else

      If rects["expl"].Contains(px, py) Then
        memDC.SelectObject(iList["explUpHover"])
      Else
        memDC.SelectObject(iList["explUp"])
      End If
    End If
    dc.Blit(rects["expl"].GetX(), rects["expl"].GetY(), rects["expl"].GetWidth(), rects["expl"].GetHeight(), memDC, 0, 0, wxCOPY, TRUE)
  End If

  'draw to tray arrow
  If rect.Intersects(rects["tray"]) Then
    If rects["tray"].Contains(px, py) Then
      memDC.SelectObject(iList["trayHover"])
    Else
      memDC.SelectObject(iList["tray"])
    End If
    dc.Blit(rects["tray"].GetX(), rects["tray"].GetY(), rects["tray"].GetWidth(), rects["tray"].GetHeight(), memDC, 0, 0, wxCOPY, TRUE)
  End If

  'draw hide arrow
  If rect.Intersects(rects["hide"]) Then
    If rects["hide"].Contains(px, py) Then
      memDC.SelectObject(iList["hideHover"])
    Else
      memDC.SelectObject(iList["hide"])
    End If
    dc.Blit(rects["hide"].GetX(), rects["hide"].GetY(), rects["hide"].GetWidth(), rects["hide"].GetHeight(), memDC, 0, 0, wxCOPY, TRUE)
  End If

  'draw volume slider
  If rect.Intersects(rects["vSlider"]) Then
    memDC.SelectObject(iList["vSlider"])
    dc.Blit(rects["vSlider"].GetX(), rects["vSlider"].GetY(), rects["vSlider"].GetWidth(), rects["vSlider"].GetHeight(), memDC, 0, 0, wxCOPY, TRUE)

    memDC.SelectObject(iList["pos"])
    dc.Blit(rects["vPos"].GetX(), rects["vPos"].GetY(), rects["vPos"].GetWidth(), rects["vPos"].GetHeight(), memDC, 0, 0, wxCOPY, TRUE)
  End If

  'draw position slider
  If ((playMode = ID_PLAY_FILE) Or (playMode = ID_PLAY_PODCAST)) And rect.Intersects(wxRect(rects["mSlider"].GetX(), 0, rects["mSlider"].GetWidth(), 24 * ps / Scale)) Then
    memDC.SelectObject(iList["mSlider"])
    dc.Blit(rects["mSlider"].GetX(), rects["mSlider"].GetY(), rects["mSlider"].GetWidth(), rects["mSlider"].GetHeight(), memDC, 0, 0, wxCOPY, TRUE)
    memDC.SelectObject(iList["pos"])
    dc.Blit(rects["mPos"].GetX(), rects["mPos"].GetY(), rects["mPos"].GetWidth(), rects["mPos"].GetHeight(), memDC, 0, 0, wxCOPY, TRUE)
  End If

  'draw play button
  If rect.Intersects(rects["play"]) Then
    If (rects["play"].Contains(px, py) Or isPlayed) And !isPaused Then
      memDC.SelectObject(iList["playHover"])
    Else
      memDC.SelectObject(iList["play"])
    End If
    dc.Blit(rects["play"].GetX(), rects["play"].GetY(), rects["play"].GetWidth(), rects["play"].GetHeight(), memDC, 0, 0, wxCOPY, TRUE)
  End If

  'draw pause button
  If rect.Intersects(rects["pause"]) Then
    If ( !isplayed And !isPaused) Or !((playMode = ID_PLAY_FILE) Or (playMode = ID_PLAY_PODCAST)) Then
      memDC.SelectObject(iList["pauseDisabled"])
    Elseif rects["pause"].Contains(px, py) Or isPaused Then
      memDC.SelectObject(iList["pauseHover"])
    Else
      memDC.SelectObject(iList["pause"])
    End If
    dc.Blit(rects["pause"].GetX(), rects["pause"].GetY(), rects["pause"].GetWidth(), rects["pause"].GetHeight(), memDC, 0, 0, wxCOPY, TRUE)
  End If

  'draw stop button
  If rect.Intersects(rects["stop"]) Then
    If !isplayed And !ispaused Then
      memDC.SelectObject(iList["stopDisabled"])
    Elseif rects["stop"].Contains(px, py) Then
      memDC.SelectObject(iList["stopHover"])
    Else
      memDC.SelectObject(iList["stop"])
    End If
    dc.Blit(rects["stop"].GetX(), rects["stop"].GetY(), rects["stop"].GetWidth(), rects["stop"].GetHeight(), memDC, 0, 0, wxCOPY, TRUE)
  End If

  'draw previus button
  If rect.Intersects(rects["prev"]) Then
    Dim Ok As Integer = FALSE
    If (playMode = ID_PLAY_PODCAST) And IsPlayed Then
      Dim Item As wxTreeListItem = findPodcastItem(podUrl, TRUE)
      If Item And Item.IsOk() Then Ok = TRUE
    End If

    If ((playMode = ID_PLAY_FILE) And (allMediaFilesInt.Count()>= musicFile) And (allMediaFilesInt.INDEX(musicFile)= 0)) Or
       (isWeb And (sel <= 0)) Or
       ((playMode = ID_PLAY_PODCAST) And !Ok) Or
       ( !isPlayed And !ispaused) Then
      memDC.SelectObject(iList["prevDisabled"])

    Elseif rects["prev"].Contains(px, py) Then
      memDC.SelectObject(iList["prevHover"])

    Else
      memDC.SelectObject(iList["prev"])
    End If
    dc.Blit(rects["prev"].GetX(), rects["prev"].GetY(), rects["prev"].GetWidth(), rects["prev"].GetHeight(), memDC, 0, 0, wxCOPY, TRUE)
  End If

  'draw next button
  If rect.Intersects(rects["next"]) Then
    Ok = FALSE
    If (playMode = ID_PLAY_PODCAST) And IsPlayed Then
      Item = findPodcastItem(podUrl, FALSE)
      Dim a = lcpod.GetItemParent(lcpod.GetItemParent(lcpod.GetNextItem(Item)))
      Ok = a.IsOk()
    End If

    If ((playMode = ID_PLAY_FILE) And (allMediaFilesInt.Count()>= musicFile) And (allMediaFilesInt.INDEX(musicFile)= allMediaFilesInt.Count() - 1)) Or
       (isWeb And ((sel = -1) Or (sel = (lcWeb.GetItemCount() - 1)))) Or
       ((playMode = ID_PLAY_PODCAST) And !Ok) Or
       ( !isPlayed And !ispaused) Then
      memDC.SelectObject(iList["nextDisabled"])

    Elseif rects["next"].Contains(px, py) Then
      memDC.SelectObject(iList["nextHover"])

    Else
      memDC.SelectObject(iList["next"])
    End If
    dc.Blit(rects["next"].GetX(), rects["next"].GetY(), rects["next"].GetWidth(), rects["next"].GetHeight(), memDC, 0, 0, wxCOPY, TRUE)
  End If


  'draw record button
  If rect.Intersects(rects["rec"]) And (playMode = ID_PLAY_WEBRADIO) Then
    If (rects["rec"].Contains(px, py) Or isRecord) And isPlayed Then
      memDC.SelectObject(iList["recHover"])
    Else
      memDC.SelectObject(iList["rec"])
    End If
    dc.Blit(rects["rec"].GetX(), rects["rec"].GetY(), rects["rec"].GetWidth(), rects["rec"].GetHeight(), memDC, 0, 0, wxCOPY, TRUE)
  End If

  'draw play button
  If rect.Intersects(rects["mute"]) Then
    If rects["mute"].Contains(px, py) Then
      memDC.SelectObject(IIf(muted, iList["mute"], iList["volHover"]))
    Else
      memDC.SelectObject(IIf(muted, iList["mute"], iList["vol"]))
    End If
    dc.Blit(rects["mute"].GetX(), rects["mute"].GetY(), rects["mute"].GetWidth(), rects["mute"].GetHeight(), memDC, 0, 0, wxCOPY, TRUE)
  End If

  memDC.SelectObject(wxNullBitmap)
  ~memDC
  ~dc
  isRefresh = FALSE
End Sub


Sub onSetTheme(event As wxCommandEvent)
  theme = event.GetSelection()
  setTheme()
End Sub


'set the selected theme
Sub setTheme()
  'prevent false theme number from prvious versions
  If (theme < 0) Or (theme > 6) Then theme = 2
  Dim memDC As wxMemoryDC = wxMemoryDCFromBitmap(iList["frame"])

  Select Case theme
  Case 0: 'black
    musicBackColour = wxBLACK
    musicBackColour2 = wxColour(235, 235, 235)
    Dim gradientColour As wxColour = wxBLACK
    musicFontColour = wxWHITE
    musicHiColour = wxGREEN
    musicSelColour = wxRED
    Dim sepColour As wxColour = wxColour(197, 188, 243)
    memDC.GradientFillLinear(wxRect(0, 0, memDC.GetSizeX(), memDC.GetSizeY()), wxBLACK, gradientColour, wxSOUTH)

  Case 1: 'black & white
    musicBackColour = wxBLACK
    musicBackColour2  = wxBLACK
    gradientColour = wxBLACK
    musicFontColour = wxWHITE
    musicHiColour = wxGREEN
    musicSelColour = wxRED
    sepColour = wxColour(197, 188, 243)
    memDC.GradientFillLinear(wxRect(0, 0, memDC.GetSizeX(), memDC.GetSizeY()), wxBLACK, gradientColour, wxSOUTH)

  Case 2: 'grey
    musicBackColour = wxColour(70, 70, 70)
    musicBackColour2 = wxColour(235, 235, 235)
    gradientColour = wxColour(130, 130, 130)
    musicFontColour = wxWHITE
    musicHiColour = wxGREEN
    musicSelColour = wxRED
    sepColour = wxColour(197, 188, 243)
    memDC.GradientFillLinear(wxRect(0, 0, memDC.GetSizeX(), memDC.GetSizeY()), wxBLACK, gradientColour, wxSOUTH)

  Case 3: 'green
    musicBackColour = wxColour(0, 158, 0)
    musicBackColour2 = wxColour(235, 235, 235)
    gradientColour = wxGREEN
    musicFontColour = wxBLACK
    musicHiColour = wxWHITE'wxColor(183, 0, 0)
    musicSelColour = wxRED
    sepColour = wxColour(197, 188, 243)
    memDC.GradientFillLinear(wxRect(0, 0, memDC.GetSizeX(), memDC.GetSizeY()), wxBLACK, gradientColour, wxSOUTH)

  Case 4: 'blue
    musicBackColour = wxBLUE
    musicBackColour2 = wxColour(235, 235, 235)
    gradientColour = wxBLUE
    musicFontColour = wxWHITE
    musicHiColour = wxBLACK'wxColour(255, 60, 255)
    musicSelColour = wxRED
    sepColour = wxColour(197, 188, 243)
    memDC.GradientFillLinear(wxRect(0, 0, memDC.GetSizeX(), memDC.GetSizeY()), wxBLACK, gradientColour, wxSOUTH)

  Case 5: 'red
    musicBackColour = wxRED
    musicBackColour2 = wxColour(235, 235, 235)
    gradientColour = wxRED
    musicFontColour = wxWHITE
    musicHiColour = wxBLACK
    musicSelColour = wxLIGHT_GREY
    sepColour = wxColour(197, 188, 243)
    memDC.GradientFillLinear(wxRect(0, 0, memDC.GetSizeX(), memDC.GetSizeY()), wxBLACK, gradientColour, wxSOUTH)

  Case 6: 'brown
    musicBackColour = wxColour(121, 61, 0)
    musicBackColour2 = wxColour(235, 235, 235)
    gradientColour = wxColour(121, 61, 0)
    musicFontColour = wxWHITE
    musicHiColour = wxColour(213, 106, 0)
    musicSelColour = wxLIGHT_GREY
    sepColour = wxColour(197, 188, 243)
    memDC.GradientFillLinear(wxRect(0, 0, memDC.GetSizeX(), memDC.GetSizeY()), wxBLACK, gradientColour, wxSOUTH)
  End Select

  createPlayerButtons()

  Dim x As Integer = musicFrame.GetSizeWidth()
  Dim sTitle As Integer = IIf(((showMusicTitle And (playMode = ID_PLAY_FILE)) Or (showPodTitle And (playMode = ID_PLAY_PODCAST))), TRUE, FALSE)
  Dim y As Integer = IIf(sTitle, 45 * ps, 24 * ps)

  If theme <> 1 Then
    Dim gc = wxGraphicsContext_CreateFromMemoryDC(memDC)
    gc.SetAntialiasMode(wxANTIALIAS_DEFAULT)
    gc.SetInterpolationQuality(wxINTERPOLATION_BEST)

    Dim brush As wxBrush = wxBrush(musicBackColour2, wxSOLID)
    gc.SetBrush(brush)
    gc.DrawRoundedRectangle(25 * ps, 2 * ps, 530 * ps, IIf(sTitle, y - (26 * ps), y - (5 * ps)), 10 * ps)
    Dim pen As wxPen = wxPenFromColor(sepColour, 1, wxSOLID)
    gc.SetPen(pen)
    gc.StrokeLine(95 * ps, 6 * ps, 95 * ps, IIf(sTitle, y - (28 * ps), y - (5 * ps)))

    gc.SetPen(wxNullPen)
    gc.SetBrush(wxNullBrush)
  End If
  memDC.SelectObject(wxNullBitmap)

  musicFrame.Update()
  musicFrame.Refresh()

  Dim explorerMedia As wxGenericDirCtrl = DynamicCast("wxGenericDirCtrl", musicFrame.FindWindowByName("explorermedia"))
  Dim tr = explorerMedia.GetTreeCtrl()
  tr.SetBackgroundColour(musicBackColour)
  tr.SetForegroundColour(IIf(theme = 3, wxBLACK, wxWHITE))
  tr.Refresh()
  Deallocate(tr)

  lcMedia.SetBackgroundColour(musicBackColour)
  lcMedia.SetTextColour(musicFontColour)
  lcMedia.Refresh()

  lcWeb.SetBackgroundColour(musicBackColour)
  lcWeb.SetTextColour(musicFontColour)
  lcWeb.Refresh()

  lcPod.SetBackgroundColour(musicBackColour)
  lcPod.SetForegroundColour(musicFontColour)
  lcPod.Refresh()

  Dim html As wxHtmlWindow = DynamicCast("wxHtmlWindow", musicFrame.FindWindowByName("htmlwin"))
  html.SetPage("<body bgcolor=" &"RGB(" &musicBackcolour.Red() &"," &musicBackcolour.Green() &"," &musicBackcolour.Blue() &")> " &
  "<font color=" &"RGB(" &musicFontcolour.Red() &"," &musicFontcolour.Green() &"," &musicFontcolour.Blue() &")>" &
  "</body>")
  html.Refresh()

  titleFrame.SetBackgroundColour(wxSystemSettings_GetColour(wxSYS_COLOUR_WINDOW))
  titleFrame.Refresh()

  'refresh search, if a seachword is typed
  'otherwise the new theme will not be applied correctly.
  If playmode <> ID_PLAY_PODCAST Then searchItem()

  wxYield()

  'select the current file
  setFile(FALSE)
End Sub


Sub onHTMLlink(event As wxHtmlLinkEvent)
  Dim info As wxHtmlLinkInfo = event.GetLinkInfo()
  wxLaunchDefaultApplication(info.GetHref())
End Sub


'draw the loading animation for web radio
Sub setLoadingAni()
  Dim gc = wxGraphicsContext_CreateFromWindow(musicFrame)

  gc.SetPen(wxTRANSPARENT_PEN)
  Dim brush = gc.CreateLinearGradientBrush(loadlinePos, 0, 20 + loadlinePos, 10, wxColour(100, 100, 100), wxWHITE)
  gc.SetBrush2(brush)
  Dim x = IIf(playMode = ID_PLAY_PODCAST, rects["next"].GetRight() + (5 * ps), rects["rec"].GetRight() + (5 * ps))
  Dim w = IIf(playMode = ID_PLAY_PODCAST, rects["mSlider"].GetWidth(), rects["text"].GetWidth())
  gc.DrawRoundedRectangle(x, 5 * ps, w, 13 * ps, (6.5 * ps))

  loadLinePos += 3

  gc.SetPen(wxNullPen)
  gc.SetBrush(wxNullBrush)
  ~gc
End Sub


'create a new database, if not exist
Sub createDB()
  If !FileExists(playerPath &DELIMITER_CHAR &"IPTV.db") Then
    Dim file = FOpen(playerPath &DELIMITER_CHAR &"IPTV.db", "w" )
    FClose(file)
  End If

  Dim db As wxDbEngine = wxDbEngine()
  If db.Open("DBQ=IPTV.db;DefaultDir=.;Driver=SQLITE3;") Then
    If !db.TableExists("radio") Then
      db.ExecSql("create table radio(id integer PRIMARY KEY," &
      "country text Not Null," &
      "name text Not Null," &
      "genre text Not Null," &
      "adress text Not Null," &
      "icon text Not Null);")
    End If

    If !db.TableExists("podcast") Then
      db.ExecSql("Create Table podcast(name text Not Null," &
      "genre text Not Null," &
      "adress text Not Null," &
      "icon text Not Null," &
      "active integer Not Null," &
      "counter integer Not Null," &
      "record integer Not Null," &
      "cert integer Not Null);")
    End If

    If !db.TableExists("tv") Then
      db.ExecSql("create table tv(id integer PRIMARY KEY," &
      "country text Not Null," &
      "name text Not Null," &
      "genre text Not Null," &
      "adress text Not Null," &
      "icon text Not Null);")
    End If

    db.Close()

  Else
  
    Dim dlg = wxGenericMessageDialog(Nothing, _("Cannot open the database"), _("Attention"), wxOK|wxCENTRE|wxICON_EXCLAMATION|wxDIALOG_NO_PARENT)
    dlg.ShowModal()
  End If
End Sub


'create the player and load config
Sub createDsmPlayer()
  Dim cfg As wxFileConfig = wxFileConfig("", "", playerIni)
  cfg.SetPath("/dsmPlayer")

  Dim single = Val(cfg.Read("SingleInstance", FALSE))
  startPath = Command(3)

  'close program, if the player is already running
  'this must be done, otherwise remote control does not work
  If checker.IsAnotherRunning() And single Then
    wxMessageBox(_("dsmPlayer is already running!"), _("Attention"), wxICON_INFORMATION)
    End
  End If

  'create an empty database for the player, if these not exist
  createDB()

  'create an empty database for poscasts, if these not exist
  'needed for episodes
  createPodcastDB()

  'add the genres to the genres list
  addGenres()

  Dim FileName As wxFileName = wxFileName("")

  'load player config
  Dim buffer As Variant
  theme = Val(cfg.Read("Theme", theme))
  Dim posX As Integer = cfg.Read("PlayerPosX", 600)
  Dim posY As Integer = cfg.Read("PlayerPosY", 0)
  Dim playlistPosX As Integer = cfg.Read("PlaylistPosX", 600)
  Dim playlistPosy As Integer = cfg.Read("PlaylistPosY", 24)

  Dim autoplay As Integer = 0
  autoplay = Val(cfg.Read("Autoplay", autoplay))
  volume = Val(cfg.Read("Volume", volume))
  dockList = cfg.Read("DockList", dockList)
  muted = cfg.Read("Mute", FALSE)
  wgetPath = cfg.Read("Path_Wget", wgetPath)
  timeout = cfg.Read("Timeout", timeout)
  ps = cfg.Read("PlayerSize", ps)
  oldPs = ps
  Dim upperLine = Val(cfg.Read("UseUpperPos", FALSE))
  If upperLine Then useUpperLine(TRUE)

  cfg.SetPath("/TV")
  tvPlayerPath = cfg.Read("TVPlayerPath", "")
  'get the last played number of the tv station
  mFileWebTV = Val(cfg.Read("TVStation", mFileWebTV))
  tvPlayerPara = cfg.Read("TVPlayerPara", TVPlayerPara)
  If tvPlayerPara = "" Then
    FileName.AssignPath(tvPlayerPath)
    If InStr(LCase(FileName.GetName()), "mpc-hc") Then
      tvPlayerPara = "/viewpreset 1 /nofocus"'/volume N

    Elseif InStr(LCase(FileName.GetName()), "mpc-be") Then
      tvPlayerPara = "/fullscreen"

    Elseif Left(FileName.GetName(), 3)= "vlc" Then
      tvPlayerPara = "--one-instance"
    End If
  End If

  cfg.SetPath("/File")
  showMusicTitle = cfg.Read("ShowTitle", showMusicTitle)
  gainMode = cfg.Read("GainMode", gainMode)
  editorTypes = cfg.Read("EditorTypes", "mp3;aac;")
  editorPath = cfg.Read("EditorPath", playerPath &"\\ThirdParty\\mp3DirectCut\\mp3DirectCut.exe")
  editorParam = cfg.Read("EditorParam", "%f /localini /overwrite")
  'set playlist for files, if it is selected in last session
  playListFile = cfg.Read("PlaylistFile", "")
  'get the last played number and position of the music file
  musicFile = cfg.Read("File", -1)
  mediaPos = cfg.Read("Position", 0)
  Dim filePath As String = cfg.Read("Directory", "")

  cfg.SetPath("/Web")
  useTransparency = cfg.Read("TransparentIcons", TRUE)
  useIcons = cfg.Read("UseIcons", FALSE)
  buffer = cfg.Read("Editable", TRUE): musicMenu.Check(ID_EDIT_WEBLIST, buffer)
  'get the last played number of the radio station
  mFileWebRadio = Val(cfg.Read("RadioStation", -1))

  recordPath = cfg.Read("RecordsPath", recordPath)
'  fullOnly = cfg.Read("RecordFull", fullOnly)
  singleFile = cfg.Read("SingleFile", singleFile)
  recordTime = cfg.Read("RecordTime", recordTime)
  recConv = cfg.Read("RecConvert", recConv)
  recMode = cfg.Read("RecMode", recMode)
  recDel =  cfg.Read("DeleteSource", recDel)

  cfg.SetPath("/Podcast")
  showPodTitle = cfg.Read("ShowPodTitle", showPodTitle)
  autoHeard = cfg.Read("AutoHeard", autoHeard)
  checkCertAll = cfg.Read("CheckCert", checkCertAll)
  'get the last played url and position of the podcast
  podUrl = cfg.Read("Podcast", "")
  podPos = cfg.Read("Position", 0)

  'set playmode
  cfg.SetPath("/dsmPlayer")
  If startPath = "" Then
    buffer = cfg.Read("PlayMode", "radio")

  Elseif startPath[: 4]= "http" Then
    buffer = "radio"

  Elseif Right(startPath, 3)= "m3u" Then
    buffer = getPlaylistType(startPath)

  Elseif startPath[: 4]= "m3u8" Then
    buffer = "tv"

  Else
    buffer = "file"
  End If

  Select Case buffer
  Case "radio"
    playmode = ID_PLAY_WEBRADIO
    musicMenu.Check(ID_PLAY_WEBRADIO, TRUE)

  Case "tv"
    playmode = ID_PLAY_WEBTV
    musicMenu.Check(ID_PLAY_WEBTV, TRUE)

  Case "podcast"
    playMode = ID_PLAY_PODCAST
    musicMenu.Check(ID_PLAY_PODCAST, TRUE)

  Case Else
    playmode = ID_PLAY_FILE
    musicMenu.Check(ID_PLAY_FILE, TRUE)
  End Select


  'create the frame
  Dim sTitle As Integer = IIf(((showMusicTitle And (playMode = ID_PLAY_FILE)) Or (showPodTitle And (playMode = ID_PLAY_PODCAST))), TRUE, FALSE)
  musicFrame = New wxFrame(Nothing, -1, "dsmPlayer", wxPoint(posX, posY), wxSize(580 * ps, IIf(sTitle, 45 * ps, 24 * ps)), wxSTAY_ON_TOP|wxFRAME_NO_TASKBAR|wxFRAME_SHAPED|wxNO_BORDER|wxWANTS_CHARS)
  musicFrame.Show(FALSE)
  musicFrame.DragAcceptFiles(TRUE)
  musicFrame.SetBackgroundStyle(wxBG_STYLE_CUSTOM) '8= wxBG_STYLE_PAINT? )
  app.SetTopWindow(musicFrame)

  defaultFont = musicFrame.GetFont()
  Connect(app, -1, wxEVT_DISPLAY_CHANGED, "onDisplayCanged")

  Dim x As Integer = musicFrame.GetSizeWidth()
  Dim y As Integer = musicFrame.GetSizeHeight()

  titleFrame = New wxFrame(musicFrame, -1, "dsmPlayer - Playlist", wxPoint(playlistPosX, playlistPosX), wxSize(x, 500), wxRESIZE_BORDER|wxFRAME_NO_TASKBAR)'|wxSTAY_ON_TOP)
  titleFrame.Show(FALSE)

  'timer for display time
  timerMedia = New wxTimer(musicFrame, ID_PLAY)
  loadingTimer = New wxTimer(musicFrame, ID_LOAD)
  Connect(musicFrame, ID_PLAY, wxEVT_TIMER, "OnMediaTimer")
  Connect(musicFrame, ID_LOAD, wxEVT_TIMER, "onLoadingTimer")


  'register a hotkeys for system wide actions
  musicFrame.RegisterHotKey(0, wxMOD_CONTROL, 80)        'control + p = play/stop
  musicFrame.RegisterHotKey(1, wxMOD_NONE, WXK_PAUSE)    'control + pause = mute
  musicFrame.RegisterHotKey(2, wxMOD_CONTROL, WXK_RIGHT) 'control + right key = fast foreward 5 seconds
  musicFrame.RegisterHotKey(3, wxMOD_CONTROL, WXK_LEFT)  'control + left key = rewind 5 seconds
  musicFrame.RegisterHotKey(4, wxMOD_CONTROL, 82)        'control + r = record/stop record
  musicFrame.RegisterHotKey(5, wxMOD_NONE, WXK_F10)      'key F10 = show/hide player
  musicFrame.RegisterHotKey(6, wxMOD_SHIFT, WXK_F5)      'Shift + F5 = show/hide playlist
  musicFrame.RegisterHotKey(7, wxMOD_SHIFT, WXK_F11)     'Shift + F11 = bring the playlist to the front if it is not hidden
  musicFrame.RegisterHotKey(8, wxMOD_CONTROL, WXK_UP)    'control + up key = prevoius title (back)
  musicFrame.RegisterHotKey(9, wxMOD_CONTROL, WXK_DOWN)  'control + down key = next title

  musicTaskMenu.Check(ID_MUTE_MEDIA, muted)

  Dim searchCtrl As wxSearchCtrl = New wxSearchCtrl(titleFrame, -1, "", wxDefaultPosition, wxSize(250, -1), wxTE_PROCESS_ENTER)
  searchCtrl.SetName("searchctrl")
  searchCtrl.ShowSearchButton(TRUE)
  searchCtrl.ShowCancelButton(TRUE)
  searchCtrl.Enable(playmode!= ID_PLAY_PODCAST)
  Connect(searchCtrl, -1, wxEVT_SEARCHCTRL_SEARCH_BTN, "onSearchItem")
  Connect(searchCtrl, -1, wxEVT_TEXT_ENTER, "onSearchItem")
  Connect(searchCtrl, -1, wxEVT_TEXT, "onSearchItem")

  Dim btn As wxBitmapButton = New wxBitmapButton(titleFrame, -1, wxArtProvider_GetBitmap(wxART_GO_DOWN))
  btn.SetToolTip(_("Select search results"))
  btn.SetName("select")
  btn.Enable(playmode!= ID_PLAY_PODCAST)
  Connect(btn, -1, wxEVT_COMMAND_BUTTON_CLICKED, "onSelectResults")

  Dim btn1 As wxBitmapButton = New wxBitmapButton(titleFrame, -1, wxArtProvider_GetBitmap(wxART_FULL_SCREEN))
  btn1.SetName("fullscreen")
  btn1.SetToolTip(_("Maximize Playlist"))
  Connect(btn1, -1, wxEVT_COMMAND_BUTTON_CLICKED, "onListMaximize")

  Dim btn2 As wxBitmapButton = New wxBitmapButton(titleFrame, -1, wxArtProvider_GetBitmap(wxART_CLOSE))
  btn2.SetName("closetf")
  btn2.SetToolTip(_("Close Playlist"))
  Connect(btn2, -1, wxEVT_COMMAND_BUTTON_CLICKED, "onHideTitleFrame")

  Dim hCapSizer As wxBoxSizer = New wxBoxSizer(wxHORIZONTAL)
  hCapSizer.AddSpacer(5)
  hCapSizer.AddWindow(searchCtrl, 0, 0|wxALIGN_CENTER_VERTICAL)
  hCapSizer.AddWindow(btn)
  hCapSizer.AddStretchSpacer(1)
  hCapSizer.AddWindow(btn1)
  hCapSizer.AddSpacer(5)
  hCapSizer.AddWindow(btn2)
  hCapSizer.AddSpacer(5)

  Dim splitterMedia = wxSplitterWindow(titleFrame, -1, wxPoint(0, 0), wxSize(titleFrame.GetClientSizeWidth(), titleFrame.GetClientSizeHeight()))
  splitterMedia.SetName("splitter")
  Connect(splitterMedia, -1, wxEVT_COMMAND_SPLITTER_SASH_POS_CHANGED, "onSashposChanged")

  Dim vSizer As wxBoxSizer = New wxBoxSizer(wxVERTICAL)
  Dim explorerMedia = New wxGenericDirCtrl(splitterMedia)
  explorerMedia.SetWindowStyle(wxDIRCTRL_SHOW_FILTERS)
  explorerMedia.SetFilter("*.m3u;*.cue")
  explorerMedia.SetName("explorermedia")
  explorerMedia.SetPath(filePath)
  vSizer.AddWindow(explorerMedia, 1, 0)

  lcWeb = wxListCtrl(splitterMedia, -1, wxDefaultPosition, wxDefaultSize, wxLC_REPORT)'2 = wxLC_VIRTUAL, not sopported in wxb
  lcWeb.SetName("listweb")
  lcWeb.InsertColumnInfo(0, _("No."))
  lcWeb.InsertColumnInfo(1, _("Country"))
  lcWeb.InsertColumnInfo(2, _("Station name"))
  lcWeb.InsertColumnInfo(3, _("List"))
  lcWeb.InsertColumnInfo(4, _("Url"))
  lcWeb.InsertColumnInfo(5, _("Icon"))

  If useIcons Then
    Dim ilWeb = New wxImageList(stationIconSize, stationIconSize, TRUE)
    lcWeb.SetImageList(ilWeb, 1)
  End If
  vSizer.AddWindow(lcWeb, 1, wxEXPAND)

  lcMedia = wxListCtrl(splitterMedia, ID_LISTCTRL_MEDIA, wxDefaultPosition, wxDefaultSize, wxLC_REPORT)
  lcMedia.SetName("listmedia")
  lcMedia.InsertColumnInfo(0, _("No."))
  lcMedia.InsertColumnInfo(1, _("Title"))
  lcMedia.InsertColumnInfo(2, _("Length"), wxLIST_FORMAT_RIGHT)
  lcMedia.InsertColumnInfo(3, _("Date"), wxLIST_FORMAT_RIGHT)
  lcMedia.InsertColumnInfo(4, _("Size"), wxLIST_FORMAT_RIGHT)
  lcMedia.InsertColumnInfo(5, _("File"))
  vSizer.AddWindow(lcMedia, 1, wxEXPAND)

  lcPod = wxTreeListCtrl(splitterMedia, ID_LISTCTRL_PODCAST, wxDefaultPosition, wxDefaultSize, wxTL_SINGLE|wxTL_CHECKBOX)
  lcPod.SetName("listpodcast")
  lcPod.SetBackgroundStyle(wxBG_STYLE_CUSTOM)
  Dim dv = lcPod.GetDataView()
  Connect(dv, -1, wxEVT_ERASE_BACKGROUND, "onErasePodBack")

  'wxCOL_RESIZABLE   = 1
  'wxCOL_SORTABLE    = 2
  'wxCOL_REORDERABLE = 4
  'wxCOL_HIDDEN      = 8
  'wxCOL_WIDTH_DEFAULT  = -1
  'wxCOL_WIDTH_AUTOSIZE = -2
  lcPod.AppendColumn(_("Podcast"), -1, wxALIGN_LEFT, 1|2|4)
  lcPod.AppendColumn(_("Length"), -1, wxALIGN_RIGHT, 1|2|4)
  lcPod.AppendColumn(_("Genre"), -1, wxALIGN_RIGHT, 1|2|4)
  lcPod.AppendColumn(_("Date"), -1, wxALIGN_RIGHT, 1|2|4)
  lcPod.AppendColumn(_("Url"), 0, wxALIGN_LEFT, 8)
  lcPod.AppendColumn(_("Icon"), 0, wxALIGN_LEFT, 8)
  lcPod.AppendColumn(_("Counter"), 0, wxALIGN_LEFT, 8)
  lcPod.AppendColumn(_("Rec"), 0, wxALIGN_LEFT, 8)
  lcPod.AppendColumn(_("Cert"), 0, wxALIGN_LEFT, 8)
  'append a dummy column, because the last column is always shown
  lcPod.AppendColumn("", 0)

  Dim htmlWin = wxHtmlWindow(splitterMedia, -1, wxPoint(0, 0))
  htmlWin.SetName("htmlwin")
  Connect(htmlWin, -1, wxEVT_COMMAND_HTML_LINK_CLICKED, "onHTMLlink")

  vSizer.AddWindow(lcPod, 1, wxEXPAND)
  splitterMedia.SetAutoLayout(TRUE)
  splitterMedia.SetSizer(vSizer)

  hMediaSizer = New wxBoxSizer(wxHORIZONTAL)

  Dim control = New wxButton(titleFrame, wxID_OK, _("Save"), wxDefaultPosition, wxSize(-1, 25))
  control.SetBitmap(wxArtProvider_GetBitmap(wxART_FILE_SAVE, wxART_OTHER, wxSize(16, 16)), wxLEFT)
  Connect(control, -1, wxEVT_COMMAND_BUTTON_CLICKED, "onStationsSave")
  hMediaSizer.AddWindow(control, 1, 0)

  control = New wxButton(titleFrame, -1, _("New"), wxDefaultPosition, wxSize(-1, 25))
  control.SetBitmap(wxArtProvider_GetBitmap(wxART_NEW, wxART_OTHER, wxSize(16, 16)), wxLEFT)
  Connect(control, -1, wxEVT_COMMAND_BUTTON_CLICKED, "onStationAdd")
  hMediaSizer.AddWindow(control, 1, 0)

  control = New wxButton(titleFrame, ID_STATION_EDIT, _("Edit"), wxDefaultPosition, wxSize(-1, 25))
  control.SetBitmap(wxArtProvider_GetBitmap(wxART_REPORT_VIEW, wxART_OTHER, wxSize(16, 16)), wxLEFT)
  control.SetName("editweb")
  Connect(control, ID_STATION_EDIT, wxEVT_COMMAND_BUTTON_CLICKED, "onStationEdit")
  hMediaSizer.AddWindow(control, 1, 0)

  control = New wxButton(titleFrame, -1, _("Delete"), wxDefaultPosition, wxSize(-1, 25))
  control.SetBitmap(wxArtProvider_GetBitmap(wxART_DELETE, wxART_OTHER, wxSize(16, 16)), wxLEFT)
  control.SetName("deleteweb")
  Connect(control, -1, wxEVT_COMMAND_BUTTON_CLICKED, "onStationDelete")
  hMediaSizer.AddWindow(control, 1, 0)

  control = New wxButton(titleFrame, wxID_UP, _("Up"), wxDefaultPosition, wxSize(-1, 25))
  control.SetBitmap(wxArtProvider_GetBitmap(wxART_GO_UP, wxART_OTHER, wxSize(16, 16)), wxLEFT)
  control.SetName("up")
  control.Enable(playmode!= ID_PLAY_PODCAST)
  Connect(control, -1, wxEVT_COMMAND_BUTTON_CLICKED, "onStationUP")
  hMediaSizer.AddWindow(control, 1, 0)

  control = New wxButton(titleFrame, wxID_DOWN, _("Down"), wxDefaultPosition, wxSize(-1, 25))
  control.SetBitmap(wxArtProvider_GetBitmap(wxART_GO_DOWN, wxART_OTHER, wxSize(16, 16)), wxLEFT)
  control.SetName("down")
  control.Enable(playmode!= ID_PLAY_PODCAST)
  Connect(control, -1, wxEVT_COMMAND_BUTTON_CLICKED, "onStationDown")
  hMediaSizer.AddWindow(control, 1, 0)

  Dim titleSizer = New wxBoxSizer(wxVERTICAL)
  titleSizer.AddSpacer(5)
  titleSizer.AddSizer(hCapSizer, 0, wxEXPAND|wxALL)
  titleSizer.AddSpacer(5)
  titleSizer.AddWindow(splitterMedia, 1, wxEXPAND|wxALL)
  titleSizer.AddSizer(hMediaSizer, 0, wxEXPAND|wxALL)

  titleFrame.SetAutoLayout(TRUE)
  titleFrame.SetSizerAndFit(titleSizer)


  'create the frame and control bitmaps
  setFrameSize(FALSE, TRUE)
  musicFrame.SetIcon(iList["taskbarIcon"])
  titleFrame.SetIcon(iList["taskbarIcon"])

  'enable or disable menuitems
  enableMenuItems()

  'check or uncheck menus
  musicMenu.Check(ID_PLAY_WEBTV, playMode = ID_PLAY_WEBTV)
  musicMenu.Check(ID_PLAY_WEBRADIO, playMode = ID_PLAY_WEBRADIO)
  musicMenu.Check(ID_PLAY_FILE, playMode = ID_PLAY_FILE)
  musicMenu.Check(ID_PLAY_PODCAST, playMode = ID_PLAY_PODCAST)

 
  Connect(titleFrame, -1, wxEVT_LEFT_DCLICK, "onListMaximize")

  Connect(musicFrame, -1, wxEVT_PAINT, "onPaintMusicPlayer")

  'connections from include files
  Connect(musicFrame, ID_SHOW_TAGS, wxEVT_COMMAND_MENU_SELECTED, "onShowTags")
  Connect(musicFrame, ID_CREATE_PLAYLIST, wxEVT_COMMAND_MENU_SELECTED, "onCreatePlaylist")
  Connect(musicFrame, ID_CONVERT, wxEVT_COMMAND_MENU_SELECTED, "onConvert")
  Connect(musicFrame, ID_NORMALIZE, wxEVT_COMMAND_MENU_SELECTED, "onNormalize")

  'connect the menus directly for listctrl selection 
  Connect(favMenu, ID_ADD_FAVORITE, wxEVT_COMMAND_MENU_SELECTED, "onFavoriteAdd")
  Connect(favMenu, ID_REM_FAVORITE, wxEVT_COMMAND_MENU_SELECTED, "onFavoriteRemove")

  Connect(selFavMenu, ID_REM_FAVORITE1, wxEVT_COMMAND_MENU_SELECTED, "onFavoriteRemove1")

  Connect(selMenu, wxID_SELECTALL, wxEVT_COMMAND_MENU_SELECTED, "onValSelect")
  Connect(selMenu, wxID_CLEAR, wxEVT_COMMAND_MENU_SELECTED, "onValSelect")

  Connect(podMenu, ID_POD_SELECT_ALL, wxEVT_COMMAND_MENU_SELECTED, "onPodcastSelectall")
  Connect(podMenu, ID_MAX_PODS, wxEVT_COMMAND_MENU_SELECTED, "onPodSetMax")
  Connect(podMenu, ID_RELOAD_PODCAST, wxEVT_COMMAND_MENU_SELECTED, "onPodcastReload")
  Connect(podMenu, ID_SET_HEARD_SEL, wxEVT_COMMAND_MENU_SELECTED, "onPodHeardChecked")
  Connect(podMenu, ID_SET_HEARD_ALL, wxEVT_COMMAND_MENU_SELECTED, "onPodHeardAll")
  Connect(podMenu, ID_REM_HEARD_SEL, wxEVT_COMMAND_MENU_SELECTED, "onPodHeardChecked")
  Connect(podMenu, ID_REM_HEARD_ALL, wxEVT_COMMAND_MENU_SELECTED, "onPodHeardAll")
  Connect(podMenu, ID_DOWNLOAD_CHECKED, wxEVT_COMMAND_MENU_SELECTED, "onPodcastDownloadChecked")
  Connect(podMenu, ID_DOWNLOAD_ALL, wxEVT_COMMAND_MENU_SELECTED, "onPodcastDownloadAll")

  Connect(podItemMenu, ID_DOWNLOAD_PODCAST, wxEVT_COMMAND_MENU_SELECTED, "onPodcastDownload")
  Connect(podItemMenu, ID_SET_HEARD, wxEVT_COMMAND_MENU_SELECTED, "onPodcastHeard")

  Connect(musicTaskMenu, ID_PLAY_MEDIA, wxEVT_COMMAND_MENU_SELECTED, "OnMediaPlay")
  Connect(musicTaskMenu, ID_PAUSE_MEDIA, wxEVT_COMMAND_MENU_SELECTED, "OnMediaPause")
  Connect(musicTaskMenu, ID_STOP_MEDIA, wxEVT_COMMAND_MENU_SELECTED, "OnMediaStop")
  Connect(musicTaskMenu, ID_NEXT_MEDIA, wxEVT_COMMAND_MENU_SELECTED, "onNextFile")
  Connect(musicTaskMenu, ID_PREV_MEDIA, wxEVT_COMMAND_MENU_SELECTED, "onPrevFile")
  Connect(musicTaskMenu, ID_MUTE_MEDIA, wxEVT_COMMAND_MENU_SELECTED, "onMediaMute")
  Connect(musicTaskMenu, ID_PLAY_WEBRADIO, wxEVT_COMMAND_MENU_SELECTED , "onSetPlayMode")
  Connect(musicTaskMenu, ID_PLAY_WEBTV, wxEVT_COMMAND_MENU_SELECTED , "onSetPlayMode")
  Connect(musicTaskMenu, ID_PLAY_FILE, wxEVT_COMMAND_MENU_SELECTED , "onSetPlayMode")
  Connect(musicTaskMenu, ID_PLAY_PODCAST, wxEVT_COMMAND_MENU_SELECTED , "onSetPlayMode")
  Connect(musicTaskMenu, ID_EXIT_PLAYER, wxEVT_COMMAND_MENU_SELECTED, "onExit_Player")

  Connect(lcPod, -1, wxEVT_TREELIST_ITEM_ACTIVATED, "onPodcastItemActivated")
  Connect(lcPod, -1, wxEVT_TREELIST_ITEM_CHECKED, "onPodcastItemChecked")
  Connect(lcPod, -1, wxEVT_TREELIST_SELECTION_CHANGED, "onPodcastSelectionChanged")
  Connect(lcPod, -1, wxEVT_TREELIST_ITEM_CONTEXT_MENU, "onPodMenu")
  Connect(lcPod, -1, wxEVT_TREELIST_COLUMN_SORTED, "onPodSort")

  'set the theme
  setTheme()

  'set the size of the titleframe and the column widths
  setColumnWidths()

  'show/hide edit controls for web list
  showEditWebList()

  'set the playdir and store the files in directory
  setMediaPath()

  musicFrame.Show(1)
  musicFrame.Update()
  musicFrame.Refresh()
  wxYield()

  Select Case playMode
  Case ID_PLAY_FILE
    cfg.SetPath("/File")
    Dim sashPos As Integer = cfg.Read("SashPos", 200)
    splitterMedia.SplitVertically(explorerMedia, lcMedia, 200)
    lcWeb.Show(0)
    lcPod.Show(0)
    htmlWin.Show(0)
    splitterMedia.SetSashPosition(sashPos)

    'set playlist for files
    If startPath = "" Then
      If playlistFile <> "" Then
        explorerMedia.SetPath(playlistFile)
        loadPlayListMedia(playListFile, TRUE, FALSE)
        
      Else

        selectDir(TRUE, TRUE)
        storeMediaFiles()
      End If

    Else
  
      mediapos = 0
      explorermedia.SetPath(startPath)
      selectDir(TRUE, FALSE)
      storeMediaFiles()

      For i = 0 To lcMedia.GetItemCount() - 1
        If lcMedia.GetStringItem(i, 5)= startPath Then
          musicFile = lcMedia.GetStringItem(i, 0)
          setFile(TRUE)
          Break
        End If
      Next
    End If

    'prevent incorrect numbers in file playlist
    If (lcMedia.GetItemCount()< musicFile) Then
      musicFile = -1

    Elseif musicFile >= 0 Then
      getFileInfo(lcmedia.GetStringItem(Val(lcMedia.FindItem(-1, "  " &musicFile)), 5), -1)
    End If

  Case ID_PLAY_PODCAST
    cfg.SetPath("/Podcast")
    explorerMedia.Show(0)
    lcMedia.Show(0)
    lcWeb.Show(0)
    htmlWin.Show(1)
    sashPos = cfg.Read("SashPos", 550)
    splitterMedia.SplitVertically(lcPod, htmlWin, sashpos)

    'load the podcast playlist
    loadPlaylistPodcast()

    If podUrl <> "" Then
      Dim podItem As wxTreeListItem = findPodcastItem(podUrl, FALSE)
      If !podItem Or (podItem And !podItem.IsOk()) Then
        podPos = 0
        podLen = 0
        podUrl = ""

      Else

        pTitle = lcPod.GetItemText(podItem, 0)
        podLen = getTimeFromString(lcPod.GetItemText(podItem, 1), FALSE, FALSE)
        Dim spos = (podPos / podLen * 200 * ps)

        'set the position slider pos
        rects["mPos"].SetX(rects["mSlider"].GetX() - (5 * ps) + sPos)
      End If

    Else

      podlen = 0
      podPos = 0
      podUrl = ""
    End If

  Case Else
    splitterMedia.Initialize(lcWeb)
    explorerMedia.Show(0)
    lcMedia.Show(0)
    lcPod.Show(0)
    htmlWin.Show(0)

    If startPath <> "" Then
      musicMenu.Check(ID_EDIT_WEBLIST, FALSE)
      showEditWeblist()
      lcWeb.SetName(0, 0)
      importPlaylist(startPath, 2)
    Else
      loadPlaylistWeb()
    End If
    titleFrame.SetName(playmode)

    'prevent incorrect numbers in radio playlist
    If (lcWeb.GetItemCount()< mFileWebRadio) And (playMode = ID_PLAY_WEBRADIO) Then mFileWebRadio = -1

    'prevent incorrect numbers in TV playlist
    If (lcWeb.GetItemCount()< mFileWebTV) And (playMode = ID_PLAY_WEBTV) Then mFileWebTV = -1
  End Select

  Connect(explorerMedia, -1, wxEVT_COMMAND_TREE_SEL_CHANGED, "onSelectionDirChanged")

  'set the favorite menu
  cfg.SetPath("/Favorites")
  Dim Item As wxMenuItem
  Dim id As Integer
  Dim text As String
  Dim Name As String
  Dim genre As String
  Dim at As Integer
  i = 1

  'get the selected station
  Dim selection As Integer = lcWeb.FindItem(0, "  " &mFileWebRadio)

  While cfg.HasEntry("Favorite" &i)
    text = cfg.Read("Favorite" &i, "")
    at = RInstr(text, ",")
    Name = text[: at - 1 ]
    genre = text[at + 1: ]
    id = wxNewId()
    Item = selFavMenu.Insert(selFavMenu.GetMenuItemCount() - 2, id, Name, genre, wxITEM_CHECK)
    Connect(musicFrame, id, wxEVT_COMMAND_MENU_SELECTED, "onFavoriteClick")
    Connect(selFavMenu, id, wxEVT_COMMAND_MENU_SELECTED, "onFavoriteClick")
    If (selection >= 0) And lcWeb.GetItemCount() And ((lcWeb.GetItemCount()+ 1)>= selection) Then Item.Check(lcWeb.GetStringItem(selection, 2)= Name)

    i += 1
  Wend

  If startPath <> "" Then muted = FALSE

  If (startPath <> "") Or autoplay Then
    If playMode <> ID_PLAY_PODCAST Then
      playMedia(-1)
    Else
      If podItem Then podcastPlay(podItem)
    End If
  End If
End Sub


Sub onSashposChanged(event As wxSplitterEvent)
  Dim cfg As wxFileConfig = wxFileConfig("", "", playerIni)
  Dim sashPos = event.GetSashPosition()

  Select Case playmode
  Case ID_PLAY_FILE
    cfg.SetPath("/File")
    cfg.Write("sashPos", sashPos)

  Case ID_PLAY_PODCAST
    cfg.SetPath("/Podcast")
    cfg.Write("sashPos", sashPos)
  End Select
End Sub


'use the filesystemwatcher to monitor changes to the files in the selected directory.
Sub onPlayerWatcher(event As wxFileSystemWatcherEvent) Handles playerWatcher.fswatcher(-1)
  Dim newFile As wxFileName = event.GetNewPath()
  Dim file As wxFileName = event.GetPath()
  Dim ext As String = LCase(file.GetExt())

  Select Case ext
    Case "aac", "webm", "flac", "mp3", "m4a", "ogg", "opus", "wav", "wv", "mkv", "mp4", "mov", "caf", "avi", "ts", "mpc"
  Case Else
    'the file is not supported, ignore it
    Return
  End Select

  'skip files with special chars
  If file.GetFullPath()<> "" Then
    'add event type and paths to the arraystring
    eventType.Add(event.GetChangeType())
    eventFile.Add(file.GetFullPath())
    eventFileNew.Add(newFile.GetFullPath())
  End If

  'start the watcher timer
  If !watchertimer.IsRunning() Then watcherTimer.Start(1000)
End Sub


Sub onWatcherTimer(event As wxTimerEvent)
  Dim curType As Integer
  Dim curFile As String
  Dim newFile As String
  Dim FileName As wxFileName = wxFileName("")
  Dim cFlag As Integer = FALSE
  Dim file As String = ""

  'save a file will generate a delete, create and rename event
  'mostly event sequences: 1-2-4 or 2-1-4 (without changing event)
  'remove the events in this sequence
  If (eventType.Count()>= 3) And 
    (((eventType.Item(0) = 1) And (eventType.Item(1)= 2) And (eventType.Item(2)= 4)) Or
    ((eventType.Item(0) = 2) And (eventType.Item(1)= 1) And (eventType.Item(2)= 4))) Then

    file = IIf(eventType.Item(0)= 1, eventFile.Item(1), eventFile.Item(0))
    For i = 0 To lcMedia.GetItemCount() - 1
      'find the right position to insert the filename
      'use strcomp for compare because it ignores case sensitivity
      If StrComp(lcMedia.GetStringItem(i, 5), file, textcompare)> 0  Then
        getFileInfo(file, i - 1)
        Exit For
      End If
    Next

    For i = 1 To 3
      eventType.RemoveAt(0)
      eventFile.RemoveAt(0)
      eventFileNew.RemoveAt(0)
    Next
  End If

  'curType=1 a file is created
  'curType=2 a file is deleted
  'curType=4 a file is renamed
  'curType=8 a file is changed
  Try
    While !eventType.IsEmpty()
      curType = eventType.Item(0)
      curFile = eventFile.Item(0)
      newFile = eventFileNew.Item(0)
      FileName.AssignPath(newFile)

      Select Case curType
      Case 1 'a file is new in the folder (create)
        For i = 0 To lcMedia.GetItemCount() - 1
          'find the right position to insert the filename
          'use strcomp for compare because it ignores case sensitivity
          If StrComp(lcMedia.GetStringItem(i, 5), newFile, textcompare)> 0  Then Exit For
        Next

        If wxFileExists(newFile) Then
          lcMedia.InsertStringItem(i, "  " &i + 1)
          lcMedia.SetItemData(i, 0)
          lcMedia.SetStringItem(i, 1, wxFileNameFromPath(newFile))
          Dim modTime = FileName.GetModificationTime()
          lcMedia.SetStringItem(i, 3, modtime.FormatISODate() &"  " & modtime.FormatISOTime())
          lcMedia.SetStringItem(i, 4, getReadableFileSize(wxFileSize(newFile)))
          lcMedia.SetStringItem(i, 5, newFile)
          getFileInfo(newFile, i)
          cFlag = TRUE
        End If

      Case 2 'a file is deleted
        For i = 0 To lcMedia.GetItemCount() - 1
          If lcMedia.GetStringItem(i, 5)= newFile Then
            Dim sel As Integer = lcMedia.FindItem(0, "  " &musicFile)
            If (lcMedia.FindItem(0, "  " &Val(lcMedia.GetStringItem(i, 0)))< sel) And (musicFile <> -1) Then musicFile -= 1

            If (sel >= 0) And (lcMedia.GetStringItem(sel, 5)= newFile) Then
              If isPlayed Then stopMedia()
              musicFile = -1
              mediaLen = 0
              mediaPos = 0
              pTitle = ""
              musicFrame.Refresh()
            End If

            lcMedia.DeleteItem(i)
            Exit For
          End If
        Next
        cFlag = TRUE

      Case 4 'a file is renamed
        For i = 0 To lcMedia.GetItemCount() - 1
          If lcMedia.GetStringItem(i, 5)= curFile Then
            lcMedia.SetStringItem(i, 1, wxFileNameFromPath(newFile))
            lcMedia.SetStringItem(i, 5, newFile)
            Exit For
          End If
        Next
      End Select

      eventType.RemoveAt(0)
      eventFile.RemoveAt(0)
      eventFileNew.RemoveAt(0)
    Wend

    watcherTimer.Stop()
    If cFlag Then renumList(0)
    storeMediaFiles()

  Catch
  End Try
End Sub


'prevent resize of hiden columns
Sub onColBeginDrag(event As wxListEvent) Handles lcMedia.listcolbegindrag, lcWeb.listcolbegindrag
  Dim col = event.GetColumn()
  Dim maxCol As Integer = IIf(playMode = ID_PLAY_FILE, 4, 3)

  If col > maxCol Then event.Veto()
End Sub


'save the column widths
Sub onSaveColumnWidths(event As wxListEvent) Handles lcMedia.listcolenddrag, lcWeb.listcolenddrag
  Dim cfg As wxFileConfig = wxFileConfig("", "", playerIni)
  Dim col = event.GetColumn()
  Dim buffer As String = ""
  Dim cnt As Integer

  Select Case playMode
  Case ID_PLAY_FILE
    If col > 3 Then lcMedia.SetColumnWidth(col, 0)
    cnt = 5'lcMedia.GetColumnCount()
    For i = 0 To cnt - 1
      buffer &= lcMedia.GetColumnWidth(i) &IIf(i < (cnt - 1), ",", "")
    Next
    cfg.SetPath("/File")
    cfg.Write("columnWidth", buffer)

  Case Else

    If col > 3 Then lcWeb.SetColumnWidth(col, 0)
    cnt = 4'lcWeb.GetColumnCount()
    For i = 0 To cnt - 1
      buffer &= lcWeb.GetColumnWidth(i) &IIf(i < (cnt - 1), ",", "")
    Next
    cfg.SetPath("/Web")
    cfg.Write("columnWidth", buffer)
  End Select
End Sub


'set the size, position and the column widths of the playlist
Sub setColumnWidths()
  Dim buffer As Variant
  Dim widths As wxArrayString
  Dim cnt As Integer
  Dim s As String
  Dim pos As String = musicFrame.GetPositionX() &"," &musicFrame.GetPositionY()+ musicFrame.GetSizeHeight()

  Dim cfg As wxFileConfig = wxFileConfig("", "", playerIni)

  Select Case playmode
  Case ID_PLAY_FILE
    Dim explorerMedia As wxGenericDirCtrl = DynamicCast("wxGenericDirCtrl", musicFrame.FindWindowByName("explorermedia"))

    cfg.SetPath("/File")
    s = cfg.Read("Size", Str((750 + explorerMedia.GetSizeWidth())) &",-1")
    pos = cfg.Read("Pos", pos)

    buffer = cfg.Read("columnWidth", "")
    widths = wxStringTokenize(buffer, ",")

    cnt = widths.Count()
    If !cnt Then
      widths.Add(40)
      widths.Add(280)
      widths.Add(70)
      widths.Add(120)
      widths.Add(70)
      widths.Add(0)
    End If

    For i = 0 To 4
      lcMedia.SetColumnWidth(i, widths.Item(i))
    Next
    lcMedia.SetColumnWidth(5, 0)

  Case ID_PLAY_PODCAST
    cfg.SetPath("/Podcast")
    s = cfg.Read("Size", "850,550")
    pos = cfg.Read("Pos", pos)

    buffer = cfg.Read("columnWidth", "")
    widths = wxStringTokenize(buffer, ",")

    cnt = widths.Count()
    If !cnt Then
      widths.Add(300)
      widths.Add(60)
      widths.Add(80)
      widths.Add(120)
    End If

    For i = 0 To 3
     lcPod.SetColumnWidth(i, widths.Item(i))
    Next

  Case Else

    cfg.SetPath("/Web")
    s = cfg.Read("Size", "-1,-1")
    pos = cfg.Read("Pos", pos)

    buffer = cfg.Read("columnWidth", "")
    widths = wxStringTokenize(buffer, ",")

    cnt = widths.Count()
    If !cnt Then
      widths.Add(45 + stationIconSize)
      widths.Add(45)
      widths.Add(titleFrame.GetClientSizeWidth() - 185 - stationIconSize)
      widths.Add(75)
    End If

    For i = 0 To 3
     lcWeb.SetColumnWidth(i, widths.Item(i))
    Next
    lcWeb.SetColumnWidth(4, 0)
    lcWeb.SetColumnWidth(5, 0)
  End Select
  widths.Clear()


  cfg.SetPath("/dsmPlayer")
  Dim IsMaximized As Integer = cfg.Read("Maximized", FALSE)

  If IsMaximized Then
    titleframe.Maximize()

  Else

    Dim arr As wxArrayString = wxStringTokenize(s, ",")
    If arr.Count()= 2 Then titleFrame.SetSizeXY(arr.Item(0), arr.Item(1))
    arr.Clear()

    arr = wxStringTokenize(pos, ",")
    titleFrame.MoveXY(arr.Item(0), arr.Item(1))
    arr.Clear()
  End If
End Sub


Sub onSelectPathClick(event As wxCommandEvent)
  Dim path As String = wxFileSelecTor(_("Path to the program"))

  If path <> "" Then
    Dim win = wxFindWindowByName("path")
    If win Then
      Dim txt = DynamicCast("wxTextCtrl", win)
      txt.SetValue(path)
    End If
  End If
End Sub


Sub onSetEditorPath(event As wxCommandEvent)
  Dim dl = wxDialog(musicFrame, -1, _("Path to the editor program"), wxDefaultPosition, wxSize(660, 320))
  dl.CenterOnParent()
  Dim w As Integer = dl.GetSizeWidth()

  Dim st1 = wxStaticText(dl, -1, _("Set the path to the selected editor program:"), wxPoint(10, 10))
  Dim rect = st1.GetRect()
  Dim txt1 = wxFilePickerCtrl(dl, -1, ediTorPath, _("Set the path to the selected editor program:"), ".", wxPoint(10, rect.GetBottom()+ 5), wxSize(w - 20, -1))
  txt1.SetName("path")

  rect = txt1.GetRect()
  Dim st2 = wxStaticText(dl, -1, _("Set the parameters: (%f = file to be transferred):"), wxPoint(10, rect.GetBottom()+ 15))
  rect = st2.GetRect()
  Dim txt2 = wxTextCtrl(dl, -1, editorParam, wxPoint(10, rect.GetBottom()+ 5), wxSize(w - 20, -1))

  rect = txt2.GetRect()
  Dim st3 = wxStaticText(dl, -1, _("Supported file types:"), wxPoint(10, rect.GetBottom()+ 15))
  rect = st3.GetRect()
  Dim txt3 = wxTextCtrl(dl, -1, editorTypes[: Len(editorTypes) - 1], wxPoint(10, rect.GetBottom()+ 5), wxSize(w - 20, -1))

  rect = txt3.GetRect()
  Dim Ok = wxButton(dl, wxID_OK, _("Ok"), wxPoint(0, rect.GetBottom()+ 10), wxSize(w / 2, 25))
  Dim cl = wxButton(dl, wxID_CANCEL, _("Cancel"), wxPoint(w / 2, rect.GetBottom()+ 10), wxSize(w / 2, 25))
  rect = Ok.GetRect()
  dl.SetClientSizeWH(660, rect.GetBottom())

  If dl.ShowModal()= wxID_OK Then
    Dim path As String = txt1.GetPath()
    If !wxFileExists(path) Then
      Dim dlg = wxGenericMessageDialog(Nothing, _("The file does not exist on the disk"), _("Attention"), wxOK|wxCENTRE|wxICON_EXCLAMATION|wxDIALOG_NO_PARENT)
      dlg.ShowModal()
      ~dlg

    Else

      editorPath = path
      editorParam = txt2.GetValue()
      editorTypes = txt3.GetValue()
      Dim win As wxWindow = musicFrame.FindWindowByName("editor")
      If win Then
        Dim pbtn As wxButton = DynamicCast("wxButton", win)
        pbtn.SetLabel(editorPath)
      End If
      editorTypes &= ";"
    End If
  End If
  dl.Destroy()
End Sub


'handle system wide hotkeys
Sub onHotkey(event As wxKeyEvent) Handles musicFrame.hotkey(-1)
  'get the keycode
  Dim keyCode = event.GetKeyCode()

  If event.ControlDown() Then
    Select Case keyCode
    Case 80:                                   'control + p, play or stop
      If isPlayed Then
        stopMedia()
      Else
        PlayMedia(-1) 
      End If

    Case WXK_LEFT: wind(FALSE)                 'control + left, rewind 5 seconds
    Case WXK_RIGHT: wind(TRUE)                 'control + right, fast forward 5 seconds
    Case WXK_UP: nextFile(FALSE)               'control + up, prevoius file
    Case WXK_DOWN: NextFile(TRUE)              'control + down, next file

    Case 82                                    'control + r, record station
      If IsPlayed Then
        recordStation()
        musicFrame.RefreshRect(rects["rec"])
      End If
    End Select

  Elseif event.ShiftDown() Then
    Select Case keyCode
    Case WXK_F5: ShowMedia()                   'shift + F5, show playlist
    Case WXK_F11: playlistToFront()            'shift + F11, playlist to front
    End Select

  Else
  
    Select Case keyCode
    Case WXK_PAUSE: muteMedia()                'pause key, mute the media
    Case WXK_F10: ShowMusicFrame()             'F10 key, show or hide player
    End Select
  End If
End Sub


'catch keyboard input
Sub OnKeyDown(event As wxKeyEvent) Handles musicFrame.charhook(-1)
  Dim keyCode = event.GetKeyCode()

  Select Case keyCode
  Case WXK_F1
    'ensure the current played item is visible
    'get the item
    Dim sel As Integer
    Select Case playmode
    Case ID_PLAY_WEBRADIO: sel = mFileWebRadio
    Case ID_PLAY_PODCAST: sel = 0
    Case ID_PLAY_WEBTV: sel = mFileWebTV
    Case Else
      Dim explorerMedia As wxGenericDirCtrl = DynamicCast("wxGenericDirCtrl", musicFrame.FindWindowByName("explorermedia"))
      If (playDir <> explorerMedia.GetPath()) Then explorerMedia.SetPath(playdir)
      sel = musicFile
    End Select

    'goto the item
    selectFile(sel, FALSE, TRUE)


  'deselect all items with escape
  Case WXK_ESCAPE
    DeselectItems()

    If searchWord <> "" Then
      searchWord = ""
      searchItem()
    End If
  End Select

  'edit not in file mode
  If (playMode != ID_PLAY_FILE) Then
    Select Case keyCode
    Case WXK_F4: stationEdit()        'edit the station
    Case WXK_F7: stationAdd()         'add a new station
    Case WXK_DELETE: stationDelete()  'delete a station
    End Select

  Else
    Select Case keyCode
    Case WXK_F2: ChangeFilenameFree() 'freely rename a file
    Case WXK_DELETE: DeleteTitle()    'delete a file
    end select
  End If

  event.Skip()
End Sub


Sub onSearchItem(event As wxCommandEvent)' Handles searchctrl.searchctrlsearchbtn, searchCtrl.text, searchctrl.textenter
  searchWord = event.GetString()
  searchItem()
End Sub


'search an item from the search ctrl
Sub searchItem()
  deselectItems()

  Dim win = titleFrame.FindWindowByName("results")
  Dim sc As wxWindow = wxFindWindowByName("select")

  If searchWord = "" Then
    If win Then: ~win: win = Nothing: End if
    Return
  End If

  If win Then
    Dim st As wxStaticText = DynamicCast("wxStaticText", win)
  Else
    Dim th As Integer = musicFrame.GetTextExtentY(_("Results:"))
    st = wxStaticText(titleFrame, -1, _("Results:") &" " &0, wxPoint(sc.GetPositionX()+ sc.GetSizeWidth()+ 5, (25 * ps) - th))
    st.SetName("results")
  End If

  Dim cnt As Integer = 0

  Select Case playmode
  Case ID_PLAY_FILE
    'seach in the listctrl by name in file mode
    Dim isFirst As Integer = -1

    For i = 0 To lcMedia.GetItemCount() - 1
      If LCase(Left(lcMedia.GetStringItem(i, 1), Len(searchWord)))= LCase(searchword) Then
        If isFirst = -1 Then isFirst = i
        cnt += 1
        lcMedia.SetItemBackgroundColour(i, musicSelColour)
        lcMedia.SetItemData(i, 1)
     End If
    Next

    lcMedia.EnsureVisible(isFirst)

  Case Else

    'searching in the database is faster
    Dim sel As String
    dbc = wxDbConnection("DBQ=IPTV.db;DefaultDir=.;Driver=SQLITE3;")
    If dbc.IsOpen() Then
      dbc.ExecSql("PRAGMA synchronous = OFF")
      dbc.ExecSql("PRAGMA journal_mode = MEMORY")
      dbc.ExecSql("PRAGMA cache_size = 1000000")
      dbc.ExecSql("PRAGMA locking_mode = EXCLUSIVE")
      dbc.ExecSql("PRAGMA temp_store = MEMORY")
      dbc.ExecSql("SET CHARACTER_SET 'utf8'")

      Dim results As wxResultSet

      If playMode = ID_PLAY_WEBRADIO Then
        results = dbc.GetResultSet("SELECT * FROM radio where name like '" &searchWord &"%' COLLATE NOCASE")
        sel = mFileWebRadio

      Else

        results = dbc.GetResultSet("SELECT * FROM tv where name like '" &searchWord &"%' COLLATE NOCASE")
        sel = mFileWebTV
      End If
    End If

    cnt = results.GetNumberRows()
    Dim num As Integer

    For i = 0 To results.GetNumberRows() - 1
      num = results.GetValue(i, 0) - 1
      lcWeb.SetItemBackgroundColour(num, musicSelColour)
      lcWeb.SetItemData(num, 1)
      If i = 0 Then lcWeb.EnsureVisible(num)
    Next

    dbc.Close()
  End Select

  st.SetLabel(_("Results:") &" " &cnt)
End Sub


'the select button is clicked after search
Sub onSelectResults(event As wxCommandEvent)
  Select Case playmode
  Case ID_PLAY_FILE
    For i = 0 To lcMedia.GetItemCount() - 1
      If lcMedia.GetItemData(i)= TRUE Then lcMedia.SetItemState(i, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED)
    Next

  Case Else

    For i = 0 To lcWeb.GetItemCount() - 1
      If lcWeb.GetItemData(i)= TRUE Then lcWeb.SetItemState(i, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED)
    Next
 End Select
End Sub



Sub onStationAdd(event As wxCommandEvent)
  stationAdd()
End Sub

Sub stationAdd()
  If !titleFrame.IsShown() Then Return
  createStationFrame(-1, FALSE)
End Sub


Sub onStationEdit(event As wxCommandEvent)
  stationEdit()
End Sub


'edit a station
Sub stationEdit()
  If !titleFrame.IsShown() Then Return

  If playmode = ID_PLAY_PODCAST Then
    If lcPod.GetSelection()= 0 Then
      Dim dl = wxGenericMessageDialog(Nothing, _("No entry selected!"), _("Note"), wxOK|wxCENTER|wxICON_INFORMATION|wxDIALOG_NO_PARENT)
      dl.ShowModal()

    Else
    
      createStationFrame(lcPod.GetSelection(), FALSE)
    End If

  Else

    If lcWeb.GetSelectedItemCount()> 1 Then
      dl = wxGenericMessageDialog(Nothing, _("You can only edit one entry at a time"), _("Note"), wxOK|wxCENTER|wxICON_INFORMATION|wxDIALOG_NO_PARENT)
      dl.ShowModal()

    Elseif lcWeb.GetSelectedItemCount()= 0 Then
      dl = wxGenericMessageDialog(Nothing, _("No entry selected!"), _("Note"), wxOK|wxCENTER|wxICON_INFORMATION|wxDIALOG_NO_PARENT)
      dl.ShowModal()

    Else
    
      createStationFrame(lcWeb.GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED), FALSE)
    End If
  End If
End Sub


Sub onStationDelete(event As wxCommandEvent)
  stationDelete()
End Sub


'delete a station
Sub stationDelete()
  If !titleFrame.IsShown() Then Return

  If playmode = ID_PLAY_PODCAST Then
    Dim selection = lcPod.GetSelection()
    If selection.IsOk() Then
      Dim url As String = lcpod.GetItemText(selection, 4)
      'if an episode of the podcast you want to delete is currently playing, stop playback
      If isPlayed Then
        'find the item
        Dim Item As wxTreeListItem = findpodcastitem(podUrl, FALSE)
        If Item.IsOk() Then
          'get the parent url
          Dim pUrl As String = lcpod.GetItemText(lcpod.GetItemParent(Item), 4)
          'the parent url is the podcast to delete
          If pUrl = url Then
            isPlayed = FALSE
            killphiola()
          End If
        End If
      End If
    End If

  Else

    selection = lcWeb.GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED)
  End If

  If ((playmode = ID_PLAY_PODCAST) And selection.IsOk()) Or ((playmode = ID_PLAY_WEBRADIO) And (selection >= 0)) Then 
    Dim dl = wxGenericMessageDialog(Nothing, _("Do you really want to delete the selected station(s)?"), _("Attention"), wxYES_NO|wxNO_DEFAULT|wxCENTRE|wxICON_EXCLAMATION|wxDIALOG_NO_PARENT)

    'wxYes = 5103 in wxGenericMessageDialog
    If dl.ShowModal() = 5103 Then 
      If playmode = ID_PLAY_PODCAST Then
        'delete the podcast item and update the database
        setPodcastInfo(url, FALSE)
        lcPod.DeleteItem(selection)
        podFeeds[url]= Nothing

        dbp = wxDbConnection("DBQ=podcasts.db;DefaultDir=.;Driver=SQLITE3;")
        If dbp.IsOpen() Then
          dbp.ExecSql("DELETE FROM podcasts where mainurl=" &Chr(34) &url &Chr(34) &" COLLATE NOCASE")
          dbp.Close()
        End If

      Else

        Dim sel As Integer = IIf((playMode = ID_PLAY_WEBRADIO), mFileWebRadio, mFileWebTV)
        If sel >= 0 Then sel = lcWeb.FindItem(0, "  " &sel)
        Dim selName = lcWeb.GetStringItem(sel, 1)

        lcWeb.Freeze()
        While selection >= 0
          if lcWeb.GetStringItem(selection, 1)=selName then
            If playMode = ID_PLAY_WEBRADIO Then
              mFileWebRadio = -1
            Else
              mFileWebTV = -1
            End If
          End If

          lcWeb.DeleteItem(selection)
          selection = lcWeb.GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED)
        Wend
        lcWeb.Thaw()

        isModify = TRUE
        saveStations(TRUE, TRUE)

      End If
      musicFrame.RefreshRect(wxRect(rects["play"].GetX(), 5 * ps, rects["mute"].GetX() - rects["play"].GetX(), 15 * ps))
    End If

  Else
  
    dl = wxGenericMessageDialog(Nothing, _("No entry selected!"), _("Note"), wxOK|wxCENTER|wxICON_INFORMATION|wxDIALOG_NO_PARENT)
    dl.ShowModal()
  End If
End Sub


Sub onStationUP(event As wxCommandEvent)
  stationUp()
End Sub

'move station up
Sub stationUp()
  If playMode = ID_PLAY_PODCAST Then return

  Dim selection As Integer = lcWeb.GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED)
  If selection = -1 Then
    Dim dl = wxGenericMessageDialog(Nothing, _("No entry selected!"), _("Note"), wxOK|wxCENTER|wxICON_INFORMATION|wxDIALOG_NO_PARENT)
    dl.ShowModal()
    Return
  End If

  Dim idx1 As Integer
  Dim idx2 As Integer

  Dim sel As Integer = IIf((playMode = ID_PLAY_WEBRADIO), mFileWebRadio, mFileWebTV)
  If sel >= 0 Then sel = lcWeb.FindItem(0, "  " &sel)

  lcWeb.Freeze()

  While selection >= 0
    idx1, idx2 = GetBitmapIndex(selection, selection - 1)

    'copy the selected item
   lcWeb.InsertStringItem(selection - 1, "  " &Str(selection))
   lcWeb.SetItemData(selection - 1, 0)

   lcWeb.SetStringItem(selection - 1, 1, lcWeb.GetStringItem(selection + 1, 1))
   lcWeb.SetStringItem(selection - 1, 2, lcWeb.GetStringItem(selection + 1, 2))
   lcWeb.SetStringItem(selection - 1, 3, lcWeb.GetStringItem(selection + 1, 3))
   lcWeb.SetStringItem(selection - 1, 4, lcWeb.GetStringItem(selection + 1, 4))
   lcWeb.SetStringItem(selection - 1, 5, lcWeb.GetStringItem(selection + 1, 5))
   lcWeb.SetItemImage(selection - 1, idx1, idx1)

   lcWeb.DeleteItem(selection + 1)
   lcWeb.SetStringItem(selection, 0, "  " &Str(selection + 1), idx2)
   lcWeb.SetItemState(selection - 1, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED)
    
    If sel = selection Then
      If playMode = ID_PLAY_WEBRADIO Then: mFileWebRadio -= 1: Else: mFileWebTV -= 1: End If
      lcWeb.SetItemTextColour(sel - 1, musicHiColour)
    End If

    selection = lcWeb.GetNextItem(selection, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED)
  Wend

  lcWeb.Thaw()
  isModify = TRUE
End Sub


Sub onStationDown(event As wxCommandEvent)
  stationDown()
End Sub


'move station down
Sub stationDown()
  If playMode = ID_PLAY_PODCAST Then Return

  Dim selection As Integer = lcWeb.GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED)
  If selection = -1 Then
    Dim dl = wxGenericMessageDialog(Nothing, _("No entry selected!"), _("Note"), wxOK|wxCENTER|wxICON_INFORMATION|wxDIALOG_NO_PARENT)
    dl.ShowModal()
    Return
  End If

  Dim idx1 As Integer
  Dim idx2 As Integer
  Dim Item As Integer

  'add selected items to arrayint for backward action
  Dim nums As wxArrayInt = wxArrayInt()
  While selection >= 0
    nums.Add(selection)
    selection = lcWeb.GetNextItem(selection, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED)
  Wend

  Dim sel As Integer = IIf((playMode = ID_PLAY_WEBRADIO), mFileWebRadio, mFileWebTV)
  If sel >= 0 Then sel = lcWeb.FindItem(0, "  " &sel)

  lcWeb.Freeze()

  While nums.Count() > 0
    'get the last selected item
    Item = nums.Last()

    If Item < lcWeb.GetItemCount() - 1 Then 
      idx1, idx2 = GetBitmapIndex(Item, Item + 1)

      'copy the selected item
     lcWeb.InsertStringItem(Item + 2, "  " &Str(Item + 2))
     lcWeb.SetItemData(Item + 2, 0)
     lcWeb.SetStringItem(Item + 2, 1, lcWeb.GetStringItem(Item, 1))
     lcWeb.SetStringItem(Item + 2, 2, lcWeb.GetStringItem(Item, 2))
     lcWeb.SetStringItem(Item + 2, 3, lcWeb.GetStringItem(Item, 3))
     lcWeb.SetStringItem(Item + 2, 4, lcWeb.GetStringItem(Item, 4))
     lcWeb.SetStringItem(Item + 2, 5, lcWeb.GetStringItem(Item, 5))
     lcWeb.SetItemImage(Item + 2, idx1, idx1)

     lcWeb.DeleteItem(Item)
     lcWeb.SetStringItem(Item, 0, "  " &Str(Item + 1), idx2)
     lcWeb.SetItemState(Item + 1, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED)

      If sel = Item Then
        If playMode = ID_PLAY_WEBRADIO Then: mFileWebRadio += 1: Else: mFileWebTV += 1: End If
        lcWeb.SetItemTextColour(sel + 1, musicHiColour)
      End If
    End If

    nums.Remove(Item)
    Item = nums.Last()
  Wend

  nums.Clear()
  lcWeb.Thaw()
  isModify = TRUE
End Sub


'create a frame for create or edit a station
Sub createStationFrame(selection As Variant, test As Integer)
  Dim playList As String

  Dim message, Name As String
  Select Case playMode
  Case ID_PLAY_PODCAST
    message = _("Edit Podcast")
    Name = _("Name of the Feed:")

    If selection <> -1 Then
      Dim sName As String = lcPod.GetItemText(selection, 0)
      Dim country As String = ""
      Dim playListRTV As String = lcPod.GetItemText(selection, 2)
      Dim url As String = lcPod.GetItemText(selection, 4)
      Dim iconpath As String =  lcPod.GetItemText(selection, 5)

    Else
      sName = ""
      url = ""
      country = ""
      playListRTV = "Various"
      iconpath = ""

    End If

  Case Else

    If selection = -1 Then
      sName = ""
      url = ""
      country = ""
      playListRTV = "Various"
      iconpath = ""

    Else

      country = lcWeb.GetStringItem(selection, 1)
      sName = lcWeb.GetStringItem(selection, 2)
      playlistRTV = lcWeb.GetStringItem(selection, 3)
      url = lcWeb.GetStringItem(selection, 4)
      iconPath = lcWeb.GetStringItem(selection, 5)
    End If

    message = IIf(test, _("Station Info"), _("Edit station:"))
    Name = _("Name of the station:")
  End Select

  Dim sd = wxDialog(musicFrame, -1, message, wxDefaultPosition, wxSize(650, -1))
  sd.Show(FALSE)
  Dim font As wxFont = sd.GetFont()
  font.SetPointSize(font.GetPointSize()* ps)
  sd.SetFont(font)

  Dim dSizeX = sd.GetClientSizeWidth()
  Dim dSizeY = sd.GetClientSizeHeight()

  Dim sText = wxStaticText(sd, -1, Name, wxPoint(10, 15))
  Dim rect = sText.GetRect()
  Dim tcName = wxTextCtrl(sd, -1, sName, wxPoint(10, rect.GetBottom()+ 2), wxSize(dSizeX - 20, -1))
  If test Or (playMode = ID_PLAY_PODCAST) Then tcName.Enable(FALSE)

  rect = tcName.GetRect()
  sText = wxStaticText(sd, -1, IIf(playmode = ID_PLAY_PODCAST, _("Description"), _("Country:")), wxPoint(10, rect.GetBottom()+ 10))
  rect = sText.GetRect()
  Dim tcCountry = wxTextCtrl(sd, -1, country, wxPoint(10, rect.GetBottom()+ 2), wxSize(dSizeX - 20, -1))
  If test Or (playMode = ID_PLAY_PODCAST) Then tcCountry.Enable(FALSE)

  rect = tcCountry.GetRect()
  sText = wxStaticText(sd, -1, _("Playlist:"), wxPoint(10,  rect.GetBottom()+ 10))
  rect = sText.GetRect()
  Dim tcPlaylist = wxComboBox3(sd, -1, playlistRTV , wxPoint(10, rect.GetBottom()+ 2), wxSize(dSizeX - 20, -1), genres)
  If test Or (playMode = ID_PLAY_PODCAST) Then tcPlaylist.Enable(FALSE)
  
  rect = tcPlaylist.GetRect()
  sText = wxStaticText(sd, -1, _("Url:"), wxPoint(10, rect.GetBottom()+ 10))
  rect = sText.GetRect()
  Dim tcUrl = wxTextCtrl(sd, -1, url, wxPoint(10, rect.GetBottom()+ 2), wxSize(dSizeX - 20, -1))
  If test Then tcUrl.Enable(FALSE)

  rect = tcUrl.GetRect()
  sText = wxStaticText(sd, -1, _("Icon:"), wxPoint(10,  rect.GetBottom()+ 10))
  rect = sText.GetRect()
  Dim tcIcon = wxTextCtrl(sd, -1, iconPath, wxPoint(10, rect.GetBottom()+ 2), wxSize(dSizeX - 20, -1))
  If test Or (playMode = ID_PLAY_PODCAST) Then tcIcon.Enable(FALSE)
  rect = tcIcon.GetRect()

  'execute phiola to get the file informations
  Dim prc = New wxProcess(musicFrame)
  prc.Redirect()
  Connect(prc, wxEVT_END_PROCESS, "onEndInfoProcess")
  
  'get a stream info
  If test Then
    Dim sBox As wxStaticBox = wxStaticBox(sd, -1, _("Stream Info:"), wxPoint(10 , rect.GetBottom()+ 15), wxSize(dSizeX - 20, Round(60 * ps)))
    Dim infoText = wxStaticText(sBox, -1, _("Reading Station Info...") , wxPoint(10, 35))
    infoText.CenterOnParent()
    sd.Show(TRUE)

    Dim pid = wxExecute(Chr(34) &phiolaPath &Chr(34) &" info "   &Chr(34) &url &Chr(34) &" -connect_timeout " &timeout &" -recv_timeout " &timeout, wxEXEC_ASYNC, prc)

    wxSafeYield(musicFrame)
    If pid Then
      'get the stream
      Dim inStream = prc.GetInputStream()
      Dim buffer As String = ""
      Dim text As String = ""
      Dim cnt As Integer = 1

      'read the stream
      If inStream And inStream.IsOk() Then
        'use textinputstream to read the lines
        Dim tStream As wxTextInputStream = wxTextInputStream(inStream, "\t", wxConvUTF8)

        While !inStream.Eof()
          text = tStream.ReadLine()
          If InStr(text, "INFO") Or (text = "") Or text[: 2]= "0:" Then Continue
          buffer &= text &"\n"
        Wend

        'split the lines from the buffer to an arraystring
        Dim info = wxStringTokenize(buffer, "\n")
        For i = info.Count() - 1 To 0 Step -1
          buffer = info.Item(i)

          'get station info
          If buffer[: 1] = "#" Then
            Dim at = RInstr(buffer, Chr(34))
            buffer = Trim(buffer[at + 1: InStr(at - 1, buffer, "(") - 1] &buffer[RInstr(buffer, ")")+ 1: ])

            'audio formats:
            'WAV format                type
            '32-bit floating-point   = float32
            '32-bit PCM              = int32
            '16-bit PCM              = int16
            '8-bit PCM               = uint8

            'tokenize the line
            Dim info1 As wxArrayString = wxStringTokenize(buffer, " ")
            sText = wxStaticText(sBox, -1, _("Bitrate:")  &"\t" &info1.Item(2), wxPoint(10, 25), wxSize(150, -1), wxALIGN_LEFT)
            sText = wxStaticText(sBox, -1, _("Format:") &"\t" &info1.Item(4), wxPoint(200, 25), wxSize(150, -1), wxALIGN_LEFT)
            sText = wxStaticText(sBox, -1, _("Samplerate:") &" " &info1.Item(5), wxPoint(400, 25), wxSize(170, -1), wxALIGN_LEFT)
            rect = sText.GetRect()
            Dim y As Integer = sText.GetPositionY()
            sText = wxStaticText(sBox, -1, _("MPEG:") &"\t" &info1.Item(3), wxPoint(10, rect.GetBottom()+ 1), wxSize(150, -1), wxALIGN_LEFT)
            sText = wxStaticText(sBox, -1, _("Mode:") &"\t" &info1.Item(6), wxPoint(200, rect.GetBottom()+ 1), wxSize(150, -1), wxALIGN_LEFT)
            info1.Clear()
            Break

          Elseif InStr(buffer, "ERROR") Then
            text = wxString_FromUTF8(buffer[InStr(buffer, "ERROR")+ 6: ]) 
            at = InStr(buffer, "http-client:")
            If at Then text = wxString_FromUTF8(buffer[InStr(at, buffer, ":") + 2: ])

            at = InStr(buffer, " *")
            If at Then text = wxString_FromUTF8(buffer[InStr(at, buffer, ":") + 2: ]) 
            sText = wxStaticText(sBox, -1, text , wxPoint(10, 35))
            sText.SetForegroundColor(wxRED)
            sText.CenterOnParent()
          End If
        Next

        info.Clear()
        rect = sBox.GetRect()
      End If

    Else

      ~prc
    End If
    ~infotext
  End If

  Dim buttonOK = wxButton(sd, wxID_OK, _("Ok"), wxPoint(0, rect.GetBottom()+ 10), wxSize(dSizeX / 2, 25))
  Dim buttonCancel = wxButton(sd, wxID_CANCEL, _("Cancel"), wxPoint(dSizeX / 2, rect.GetBottom()+ 10), wxSize(dSizeX / 2, 25))
  rect = buttonOK.GetRect()
  sd.SetClientSizeXY(dSizeX, rect.GetBottom())
  sd.Refresh()

  If sd.ShowModal()= wxID_OK Then
    sName = tcName.GetValue()
    url = tcUrl.GetValue()
    playListRTV = tcPlaylist.GetValue()
    country = tcCountry.GetValue()

    If playMode = ID_PLAY_PODCAST Then
      If selection = -1 Then
        Dim root = lcPod.GetRootItem()
        Dim Item = lcpod.AppendItem(root, sName)
        lcpod.SetItemColText(Item, 2, playListRTV)
        lcpod.SetItemColText(Item, 4, url)
        lcpod.SetItemColText(Item, 5, tcIcon.GetValue())
        lcPod.SetItemColText(Item, 6, 10)    'max counter
        lcPod.SetItemColText(Item, 7, FALSE) 'rec
        lcPod.SetItemColText(Item, 8, TRUE)  'check certification
        lcPod.CheckItem(Item, TRUE)
        lcPod.Select(Item)

        podFeeds[url]= Item

        readUrl(url)
        setPodcastInfo(url, TRUE)

      Else

        lcPod.SetItemColText(selection, 2, tcPlaylist.GetValue())
        lcPod.SetItemColText(selection, 4, tcUrl.GetValue())
        lcPod.SetItemColText(selection, 5, tcIcon.GetValue())

      End If

    Else

      If selection = -1 Then
        Dim ilWeb As wxImageList = lcWeb.GetImageList(1)
        If ilWeb Then ilWeb.Add(IIf((LCase(playListRTV)= "tv"), IIf(useTransparency, iList["tv_T"], iList["tv"]), IIf(useTransparency, iList["radio_T"], iList["radio"])))

        selection = lcWeb.GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED)+ 1
        lcWeb.InsertStringItem(selection, "  " &selection + 1)
        lcWeb.SetItemData(selection, 0)
        lcWeb.SetStringItem(selection, 1, tcCountry.GetValue())
        lcWeb.SetStringItem(selection, 2, tcName.GetValue())
        lcWeb.SetStringItem(selection, 3, tcPlaylist.GetValue())
        lcWeb.SetStringItem(selection, 4, tcUrl.GetValue())
        lcWeb.SetStringItem(selection, 5, tcIcon.GetValue())
        If ilWeb Then lcWeb.SetItemImage(selection, ilWeb.GetImageCount() - 1, ilWeb.GetImageCount() - 1)
        
        renumList(selection + 1)

      Else

        lcWeb.SetStringItem(selection, 1, tcCountry.GetValue())
        lcWeb.SetStringItem(selection, 2, tcName.GetValue())
        lcWeb.SetStringItem(selection, 3, tcPlaylist.GetValue())
        lcWeb.SetStringItem(selection, 4, tcUrl.GetValue())
        lcWeb.SetStringItem(selection, 5, tcIcon.GetValue())

      End If
    End If

    isModify = TRUE
  End If

  sd.Destroy()
End Sub


'sort list by column click in web mode
Sub onSortList(event As wxListEvent) Handles lcWeb.listcolclick
  'sorting is for web database only
  If playMode = ID_PLAY_FILE Then Return

  'sort the list ca take a while
  'this is how long the wxListctrl holds the mouse cursor and the user can accidentally move the column
  lcWeb.ReleaseMouse()

  Dim colText As String
  Dim colText1 As String = ""
  Dim col = event.GetColumn()
  If oldCol <> col Then sort_ascending = TRUE

  Select Case col
  Case 0: colText = "id"
  Case 1: colText = "country": colText1 = "name"
  Case 2: colText = "name"
  Case 3: colText = "genre": colText1 = "name"
  Case 4: colText = "adress"
  Case 5: colText = "icon"
  End Select

  Dim Ok As Integer = sortBy(colText, colText1, "")

  If Ok Then
    oldCol = col
    sort_ascending = !sort_ascending
  End If
End Sub


'sort list by different columns
Sub onMultiSort(event As wxCommandEvent) Handles musicframe.menuselected(ID_MULTISORT)
  setSortOptions(FALSE)
End Sub


'sorting files by column click
'this is not very effective und slow
'I can not take the way like in wxBasic
'so I use a virtual database for sorting
Sub onSortFiles(event As wxListEvent) Handles lcMedia.listcolclick
  Dim sel = lcMedia.FindItem(-1, "  " &musicFile)
  'deselect last played item
  If (sel >= 0) Then lcMedia.SetItemTextColour(sel, musicFontColour)

  'if you click on a column, the mouse is automatically captured
  'sort the list can take a while
  'this is how long the wxListctrl holds the mouse cursor and the user can accidentally move the column
  'so we must release the mouse here
  lcMedia.ReleaseMouse()

  sort_ascending = !sort_ascending  

  Dim col As Integer = event.GetColumn()
  If oldCol <> col Then sort_ascending = FALSE

  'create a virtual database
  createVirtualDb()

  If filesDb.IsOpen() Then
    Select Case sort_ascending
    Case TRUE: Dim sorting = "ASC"
    Case Else: sorting = "DESC"
    End Select

    Dim buffer As String = filesDb.ExecSql("SELECT name FROM PRAGMA_TABLE_INFO('files');")
    Dim cols As wxArrayString = wxStringTokenize(buffer, "\n")
    Dim colname = cols.Item(col)
    cols.Clear()

    If col <> 4 Then
      Dim results As wxResultSet = filesDB.GetResultSet("SELECT * FROM files ORDER BY " &colName &" COLLATE NOCASE " &sorting)
    Else
      results = filesDB.GetResultSet("SELECT * FROM files ORDER BY " &"CAST(" &colName &" as integer) " &sorting)
    End If

    musicFrame.Freeze()
    For i = 0 To results.GetNumberRows() - 1
      lcMedia.SetStringItem(i, 0, "  " &results.GetValue(i, 0))
      lcMedia.SetStringItem(i, 1, results.GetValue(i, 1))
      lcMedia.SetStringItem(i, 2, results.GetValue(i, 2))
      lcMedia.SetStringItem(i, 3, results.GetValue(i, 3))
      lcMedia.SetStringItem(i, 4, results.GetValue(i, 4))
      lcMedia.SetStringItem(i, 5, results.GetValue(i, 5))
      If i%50 = 0 Then wxYield()
    Next
    musicFrame.Thaw()

    filesDb.Close()
  End If

  oldCol = event.GetColumn()
  musicFrame.Refresh()

  storeMediaFiles()
  selectfile(musicFile, TRUE, TRUE)
End Sub


Sub onStationsLoad(event As wxCommandEvent)
  lcWeb.DeleteAllItems()
  loadPlaylistWeb()

  Dim sel = IIf((playMode = ID_PLAY_WEBRADIO), mFileWebRadio, mFileWebTV)
  If sel >= 0 Then
    sel = lcWeb.FindItem(0, "  " &sel)
    lcWeb.SetItemTextColour(sel, musicHiColour)
    lcWeb.EnsureVisible(sel)
  End If
End Sub


Sub onStationsSave(event As wxCommandEvent)
  saveStations(TRUE, TRUE)
End Sub



Sub exportStations(expMode As Integer, path As String)
  Dim FileName As wxFileName = wxFileName(path)
  busyInfo = wxBusyInfo(_("Export playlist to") &" '" &FileName.GetFullName() &"'")

  Dim IsRadio As String = IIf((playMode = ID_PLAY_WEBRADIO), TRUE, FALSE)
  Dim Type As String 
  Dim radio As String
  Dim buffer = "#EXTM3U" &"\n"

  Select Case expMode
  Case ID_EXPORT_MUSIC
    'export from shown list
    'm3u music playlist without icons
    For i = 0 To lcWeb.GetItemCount() - 1
      buffer &= "#EXTINF:-1, " &lcWeb.GetStringItem(i, 2) &"\n"
      buffer &= lcWeb.GetStringItem(i, 4) &"\n"
    Next

  Case Else

    dbc = wxDbConnection("DBQ=IPTV.db;DefaultDir=.;Driver=SQLITE3;")
    If dbc.IsOpen() Then
      dbc.ExecSql("PRAGMA synchronous = OFF")
      dbc.ExecSql("PRAGMA journal_mode = MEMORY")
      dbc.ExecSql("PRAGMA cache_size = 1000000")
      dbc.ExecSql("PRAGMA locking_mode = EXCLUSIVE")
      dbc.ExecSql("PRAGMA temp_store = MEMORY")
      dbc.ExecSql("SET CHARACTER_SET 'utf8'")

      If expMode != ID_DATABASE_EXPORT_MUSIC Then
        For i = 1 To 2
          Dim recSet As wxDbRecordset
          If i = 1 Then
            recSet = wxDbRecordset(dbc, "select * from tv")
          Else
            recSet = wxDbRecordset(dbc, "select * from radio")
          End If

          recSet.MoveFirst()

          While Not recSet.IsEOF()
            If expMode = ID_DATABASE_EXPORT_KODI Then
              'pure Kodi plalist without genres
              Type = Chr(34) &IIf(i = 1, "IPTV-", "Radio-") &recSet.FieldPos(2) &Chr(34) &" "
      
            Elseif expMode = ID_DATABASE_EXPORT_MIXED Then
              'mixed IPTV playlist with genres
              Type = Chr(34) &IIf( i = 1, "IPTV-", recSet.FieldPos(4) &"-") &recSet.FieldPos(2) &Chr(34) &" "
            End If
      
            radio = IIf(i = 1, "", "radio=" &Chr(34) &"TRUE" &Chr(34) &" ")
            buffer &= "#EXTINF:-1 " &"tvg-name=" &Chr(34) &recSet.FieldPos(3) &Chr(34) &" group-title=" &Type &radio &"tvg-logo=" &Chr(34) &recSet.FieldPos(6) &Chr(34) &"," &recSet.FieldPos(3) &"\n"
            buffer &=  recSet.FieldPos(5) &"\n"

            recSet.MoveNext()
          Wend

          recSet.Close()
        Next

      Else

        recSet = wxDbRecordset(dbc, "select * from radio")
        recSet.MoveFirst()

        While Not recSet.IsEOF()
          buffer &= "#EXTINF:-1, " &recSet.FieldPos(3) &"\n"
          buffer &=  recSet.FieldPos(5) &"\n"
          recSet.MoveNext()
        Wend

        recSet.Close()
      End If

      dbc.Close()
    End If
  End Select

  'write the file
  Dim outStream = wxFileOutputStream(path)
  If outStream.IsOk() Then
    Dim textStream = wxTextOutputStream(outStream, wxEOL_NATIVE, wxConvUTF8)
    textStream.WriteString(buffer)
  End If

  ~busyInfo
  busyInfo = Nothing
End Sub


Sub onEnterButton(event)
  Dim Button = musicFrame.FindWindowById(event.GetID())
  musicFrame.RefreshRect(wxRect(Button.GetPositionX(), Button.GetPositionY(), 16, 16))
End Sub


'left mouse is clicked/down on the clockFrame
Sub OnMusicFrameLeftDown(event) Handles musicFrame.leftdown(-1)
  musicFrame.CaptureMouse()
  isRefresh = FALSE

  Dim sel As Integer = IIf((playMode = ID_PLAY_WEBRADIO), mFileWebRadio, mFileWebTV)
  If sel >= 0 Then sel = lcWeb.FindItem(0, "  " &sel)

  Dim point = musicFrame.ScreenToClientPoint(wxGetMousePosition()) 
  k1 = point.GetX() 
  k2 = point.GetY() 

  If ((playmode = ID_PLAY_FILE) Or (playMode = ID_PLAY_PODCAST)) And rects["mPos"].Contains(k1, k2) Then
    posClicked = TRUE
    wxToolTip_SetDelay(0)

  Elseif rects["vPos"].Contains(k1, k2) Then
    wxToolTip_SetDelay(0)
    volClicked = TRUE
    muted = FALSE
    musicFrame.RefreshRect(wxRect(rects["mute"].GetX() - (3 * ps), rects["mute"].GetY(), rects["mute"].GetWidth()+ (3 * ps), rects["mute"].GetHeight()))

  Elseif ((playmode = ID_PLAY_FILE)  Or (playMode = ID_PLAY_PODCAST)) And rects["mSlider"].Contains(k1, k2) Then
    Dim mx As Integer = rects["mSlider"].GetX()
    Dim mw As Integer = rects["mSlider"].GetWidth()
    If k1 <= (mx - 5) Then k1 = mx - 5
    If k1 >= (mx + mw - 5) Then k1 = mx + mw - (5)
    
    If playmode = ID_PLAY_FILE Then
      mediaPos = (k1 - mx) * mediaLen / mw
      If mediaPos < 0 Then mediaPos = 0
      If mediaPos < mediaLen Then rects["mPos"].SetX(k1 - (5 * ps))

    Else

      podPos = (k1 - mx) * podLen / mw
      If podPos < 0 Then podPos = 0
      If podPos < podLen Then rects["mPos"].SetX(k1 - (5 * ps))
    End If
    
    killphiola()

  Elseif rects["vSlider"].Contains(k1, k2) Then
    mx = rects["vSlider"].GetX()
    mw = rects["vSlider"].GetWidth()

    If k1 <= (mx - 5) Then k1 = mx - (5 * ps)
    If k1 >= (mx + mw - 5) Then k1 = mx + mw - (55 * ps)
    rects["vPos"].SetX(k1)

    volume = (k1 - mx)* 2
    musicFrame.SetToolTip(_("Volume:") &" " &volume)
    musicFrame.RefreshRect(wxRect(rects["vSlider"].GetX() - (3 * ps), rects["vSlider"].GetY(), rects["vSlider"].GetWidth()+ (12 * ps), rects["vSlider"].GetHeight()))
    If phiolaPrc Then phiolaPrc.Open(Chr(34) &phiolaPath &Chr(34) &" remote volume " &volume &" -id " &wxGetProcessId())
'    Dim prc = New wxProcess(musicFrame, -1)
'    Connect(prc, -1, wxEVT_END_PROCESS, "onEndInfoProcess")
'    prc.Redirect()
'    Dim pid = wxExecute(Chr(34) &phiolaPath &Chr(34) &" remote volume " &volume &" -id " &wxGetProcessId(), wxEXEC_ASYNC, prc)
'    If !pid Then ~prc

  Elseif rects["expl"].Contains(k1, k2) Then
    showMedia()

  Elseif rects["play"].Contains(k1, k2) Then
    If isPlayed Or isConvert Then Return

    If playMode = ID_PLAY_PODCAST Then
      podcastPlay(lcPod.GetSelection())
    Else
      playMedia(-1)
    End If

  Elseif rects["pause"].Contains(k1, k2) Then
    If (playMode = ID_PLAY_FILE) Or (playMode = ID_PLAY_PODCAST) Then pauseMedia()

  Elseif rects["stop"].Contains(k1, k2) Then
    musicFrame.RefreshRect(rects["stop"])
    stopMedia()

  Elseif rects["prev"].Contains(k1, k2) And isPlayed Then
    nextFile(FALSE)

  Elseif rects["next"].Contains(k1, k2) And isPlayed Then
    nextFile(TRUE)

  Elseif (playMode = ID_PLAY_WEBRADIO) And rects["rec"].Contains(k1, k2) Then
    If IsPlayed Then recordStation()

  Elseif rects["tray"].Contains(k1, k2) Then
    minimizeToTray()

  Elseif rects["hide"].Contains(k1, k2) Then
    ShowMusicFrame()

  Elseif rects["mute"].Contains(k1, k2) Then
    muteMedia()
  End If

  event.Skip()
End Sub


Sub onMusicFrameMotion(event) Handles musicFrame.motion(-1)
  Dim point = musicFrame.ScreenToClientPoint(wxGetMousePosition()) 
  Dim x = point.GetX() 
  Dim y = point.GetY()

  If event.LeftIsDown() Then
    If posClicked Then
      If ((playmode = ID_PLAY_FILE) Or (playMode = ID_PLAY_PODCAST)) Then
        Dim mx As Integer = rects["mSlider"].GetX()
        Dim mw As Integer = rects["mSlider"].GetWidth()
        If x <= (mx) Then x = mx
        If x >= (mx + mw) Then x = mx + mw

        Dim pos As Integer = podPos
        If playmode = ID_PLAY_FILE Then
          pos = mediapos
          pos = (x - mx) * mediaLen / mw
        Else
          pos = podpos
          pos = (x - mx) * podLen / mw
        End If
        If pos < 0 Then pos = 0

        'set new selection rect position
        rects["mPos"].SetX(x - (5 * ps))

        'refresh painted slider
        musicFrame.RefreshRect(wxRect(rects["mSlider"].GetX() - (5 * ps), rects["mPos"].GetY(), rects["mSlider"].GetWidth()+ (10 * ps), rects["mPos"].GetHeight()))
        If playMode = ID_PLAY_FILE Then: mediapos = pos: Else: podPos = pos: End If
      End If

    Elseif volClicked Then
      mx = rects["vSlider"].GetX()
      mw = rects["vSlider"].GetWidth()
      If x <= mx Then x = mx
      If x >= (mx + mw) Then x = mx + mw

      musicFrame.RefreshRect(wxRect(rects["mute"].GetX() - (5 * ps), rects["mute"].GetY(), rects["vSlider"].GetRight() - rects["mute"].GetX() + (15 * ps), rects["mute"].GetHeight()))

      rects["vPos"].SetX(x - (5 * ps))
      volume = Round((x - mx)/ ps) * 2
      muted = IIf(volume, FALSE, TRUE)
      musicFrame.SetToolTip(_("Volume:") &" " &volume)

      If phiolaPrc Then phiolaPrc.Open(Chr(34) &phiolaPath &Chr(34) &" remote volume " &volume &" -id " &wxGetProcessId())
'      Dim prc = New wxProcess(musicFrame, -1)
'      Connect(prc, -1, wxEVT_END_PROCESS, "onEndInfoProcess")
'      prc.Redirect()
'      Dim pid = wxExecute(Chr(34) &phiolaPath &Chr(34) &" remote volume " &volume &" -id " &wxGetProcessId(), wxEXEC_ASYNC, prc)
'      If !pid Then ~prc

    Elseif !rects["vSlider"].Contains(k1, k2) And !(rects["mSlider"].Contains(k1, k2) And Playmode = ID_PLAY_FILE) And !rects["play"].Contains(k1, k2) And !rects["pause"].Contains(k1, k2) And 
           !rects["stop"].Contains(k1, k2) And !rects["prev"].Contains(k1, k2) And !rects["next"].Contains(k1, k2) And !rects["expl"].Contains(k1, k2) And !rects["mute"].Contains(k1, k2) Then

      Dim winx = musicFrame.GetPositionX()
      Dim winy = musicFrame.GetPositionY()
      Dim winxtest = winx + x - k1
      Dim winytest = winy + y - k2 

      If winxtest < 0 Then winXTest = 0
      If winytest < 0 Then winYTest = 0 

      winx = winxtest 
      winy = winytest 
      musicFrame.MoveXY(winx, winy)

      If dockList And !titleFrame.IsMaximized() Then
        titleFrame.MoveXY(titleFrame.GetPositionX(), winy + musicFrame.GetSizeHeight())
      End If
    End If

  Else

    'refresh painted buttons ans set tooltip
    If (rects["expl"].Contains(x, y) And !rects["expl"].Contains(oldX, oldY)) Or ( !rects["expl"].Contains(x, y) And rects["expl"].Contains(oldX, oldY)) Then: musicFrame.RefreshRect(rects["expl"]): musicFrame.SetToolTip(_("Show Playlist")):  End If
    If (rects["play"].Contains(x, y) And !rects["play"].Contains(oldX, oldY)) Or ( !rects["play"].Contains(x, y) And rects["play"].Contains(oldX, oldY)) Then: musicFrame.RefreshRect(rects["play"]): musicFrame.SetToolTip(_("Play")): End If
    If (rects["pause"].Contains(x, y) And !rects["pause"].Contains(oldX, oldY)) Or ( !rects["pause"].Contains(x, y) And rects["pause"].Contains(oldX, oldY)) Then: musicFrame.RefreshRect(rects["pause"]): musicFrame.SetToolTip(_("Pause")): End If
    If (rects["stop"].Contains(x, y) And !rects["stop"].Contains(oldX, oldY)) Or ( !rects["stop"].Contains(x, y) And rects["stop"].Contains(oldX, oldY)) Then: musicFrame.RefreshRect(rects["stop"]): musicFrame.SetToolTip(_("Stop")): End If
    If (rects["prev"].Contains(x, y) And !rects["prev"].Contains(oldX, oldY)) Or ( !rects["prev"].Contains(x, y) And rects["prev"].Contains(oldX, oldY)) Then: musicFrame.RefreshRect(rects["prev"]): musicFrame.SetToolTip(_("Previous Station/File")): End If
    If (rects["next"].Contains(x, y) And !rects["next"].Contains(oldX, oldY)) Or ( !rects["next"].Contains(x, y) And rects["next"].Contains(oldX, oldY)) Then: musicFrame.RefreshRect(rects["next"]): musicFrame.SetToolTip(_("Next Station/File")): End If
    If ((rects["rec"].Contains(x, y) And !rects["rec"].Contains(oldX, oldY)) Or ( !rects["rec"].Contains(x, y) And rects["rec"].Contains(oldX, oldY))) And !((playmode = ID_PLAY_FILE) Or (playmode = ID_PLAY_PODCAST)) Then: musicFrame.RefreshRect(rects["rec"]): musicFrame.SetToolTip(_("Record Station")): End If
    If ((rects["text"].Contains(x, y) And !rects["text"].Contains(oldX, oldY)) Or ( !rects["text"].Contains(x, y) And rects["text"].Contains(oldX, oldY))) And (playmode != ID_PLAY_FILE) Then musicFrame.RefreshRect(rects["text"])
    If ((rects["mSlider"].Contains(x, y) And !rects["mSlider"].Contains(oldX, oldY)) Or ( !rects["mSlider"].Contains(x, y) And rects["mSlider"].Contains(oldX, oldY))) And (playmode = ID_PLAY_FILE) Then:  musicFrame.SetToolTip("Set Position"): End If
    If (rects["mute"].Contains(x, y) And !rects["mute"].Contains(oldX, oldY)) Or ( !rects["mute"].Contains(x, y) And rects["mute"].Contains(oldX, oldY)) Then: musicFrame.RefreshRect(rects["mute"]): musicFrame.SetToolTip(_("Mute") &" " & IIf(muted, _("on"), _("off"))): End If
    If (rects["vSlider"].Contains(x, y) And !rects["vSlider"].Contains(oldX, oldY)) Or ( !rects["vSlider"].Contains(x, y) And rects["vSlider"].Contains(oldX, oldY)) Then: musicFrame.SetToolTip(_("Volume:") &" " &volume): End If
    If (rects["tray"].Contains(x, y) And !rects["tray"].Contains(oldX, oldY)) Or ( !rects["tray"].Contains(x, y) And rects["tray"].Contains(oldX, oldY)) Then: musicFrame.RefreshRect(rects["tray"]): musicFrame.SetToolTip(_("Player to Tray")): End If
    If (rects["hide"].Contains(x, y) And !rects["hide"].Contains(oldX, oldY)) Or ( !rects["hide"].Contains(x, y) And rects["hide"].Contains(oldX, oldY)) Then: musicFrame.RefreshRect(rects["hide"]): musicFrame.SetToolTip(_("Hide Player")): End If
    If rects["text"].Contains(x, y) Then: musicFrame.SetToolTip(""): End If
  End If

  oldX = x
  oldY = y
End Sub 


'left mouse is up on the clockFrame
Sub OnMusicFrameLeftUp(event) Handles musicFrame.LeftUp(-1)
  musicFrame.ReleaseMouse()
  wxToolTip_SetDelay(2000)

'we can set the volume here
'  If volClicked And phiolaPrc Then phiolaPrc.Open(Chr(34) &phiolaPath &Chr(34) &" remote volume " &volume &" -id " &wxGetProcessId())

  Dim point = musicFrame.ScreenToClientPoint(wxGetMousePosition()) 
  Dim x = point.GetX() 
  Dim y = point.GetY()

  'refresh painted buttons
  If rects["expl"].Contains(x, y) Then musicFrame.RefreshRect(rects["expl"])
  If rects["play"].Contains(x, y) Then musicFrame.RefreshRect(rects["pause"])
  If rects["stop"].Contains(x, y) Then musicFrame.RefreshRect(rects["stop"])
  If rects["prev"].Contains(x, y) Then musicFrame.RefreshRect(rects["prev"])
  If rects["next"].Contains(x, y) Then musicFrame.RefreshRect(rects["next"])
  If rects["rec"].Contains(x, y) And (playmode = ID_PLAY_WEBRADIO) Then musicFrame.RefreshRect(rects["rec"])
  If rects["tray"].Contains(x, y) Then musicFrame.RefreshRect(rects["tray"])
  If rects["hide"].Contains(x, y) Then musicFrame.RefreshRect(rects["hide"])
  If rects["mute"].Contains(x, y) Then musicFrame.RefreshRect(rects["mute"])
  If rects["mSlider"].Contains(x, y) And ((playmode = ID_PLAY_FILE) Or (playMode = ID_PLAY_PODCAST)) Then musicFrame.RefreshRect(wxRect(rects["mSlider"].GetX() - 5, rects["mSlider"].GetY(), rects["mSlider"].GetWidth() + 10, rects["mSlider"].GetHeight()))
 
  'pihola set position
  If posClicked And ((playmode = ID_PLAY_FILE) Or (playMode = ID_PLAY_PODCAST)) Then
    'currently stop phiola and restart it with seek
    killphiola()

'remote seek is currently not implemented
'    prc = New wxProcess(musicFrame, -1)
'    Connect(prc, -1, wxEVT_END_PROCESS, "onEndInfoProcess")
'    prc.Redirect()
'    dim pid=wxExecute(Chr(34) &phiolaPath &Chr(34) &" remote seek " &mediapos, wxEXEC_ASYNC, prc)
'    if !pid then ~prc
  End If

  volClicked = FALSE
  posClicked = FALSE
  event.Skip()
End Sub 


'mouse wheel on the clockFrame chenges volume
Sub OnMusicFrameWheel(event) Handles musicFrame.mousewheel(-1)
  volume += IIf(event.GetWheelRotation()> 0, 5, -5)
  If volume > 100 Then
    volume = 100
  Elseif volume < 0 Then
    volume = 0
  End If

  muted = IIf(volume, FALSE, TRUE)

  Dim mx = rects["vSlider"].GetX()
  Dim mw = rects["vSlider"].GetWidth()
  rects["vPos"].SetX(mx + (mw / 100 * volume) - (5 * ps))

  musicFrame.SetToolTip(_("Volume:") &" " &volume)
  musicFrame.RefreshRect(wxRect(rects["mute"].GetX() - (5 * ps), rects["mute"].GetY(), rects["vSlider"].GetRight() - rects["mute"].GetX() + (15 * ps), rects["mute"].GetHeight()))

  Dim prc = New wxProcess(musicFrame, -1)
  Connect(prc, -1, wxEVT_END_PROCESS, "onEndInfoProcess")
  prc.Redirect()
  Dim pid = wxExecute(Chr(34) &phiolaPath &Chr(34) &" remote volume " &volume &" -id " &wxGetProcessId(), wxEXEC_ASYNC, prc)
  If !pid Then ~prc
End Sub


'show the media explorer
Sub showMedia()
  titleFrame.Show( !titleFrame.IsShown())
  If titleFrame.IsShown() Then
    titleFrame.Raise()
    titleframe.Layout()
  End If
  musicFrame.RefreshRect(rects["expl"])
End Sub


Sub playlistToFront()
  If titleFrame.IsShown() Then titleFrame.Raise()
End Sub


Sub onEndSession(event As wxCloseEvent) Handles musicFrame.endsession(-1), musicFrame.queryendsession(-1)
  exit_Player(FALSE)
End Sub


Sub onExit_Player(event As wxCommandEvent) Handles musicframe.menuselected(ID_EXIT_PLAYER)
  exit_Player(FALSE)
End Sub


Sub exit_Player(restart As Integer)
  'delete temporary image file from podcasts, if exist
  If wxFileExists(wxFileName_GetTempDir() &DELIMITER_CHAR &"image.png") Then Kill(wxFileName_GetTempDir() &DELIMITER_CHAR &"image.png")

  'break loading operations
  isBroken = TRUE

  'close databeses if open
  If dbc And dbc.IsOpen() Then dbc.Close()
  If dbp And dbp.IsOpen() Then dbp.Close()

  If isModify Then
    Dim dl = wxGenericMessageDialog(Nothing, _("The playlist has been changed!") &"\n" &_("Save changes To database?"), _("Attention"), wxYES_NO|wxCENTRE|wxICON_EXCLAMATION|wxDIALOG_NO_PARENT)
    'wxYES = 5103 in wxGenericMessageDialog
    If dl.ShowModal() = 5103 Then saveStations(FALSE, TRUE)
  End If

  Try
    Dim splitterMedia As wxSplitterWindow = DynamicCast("wxSplitterWindow", musicFrame.FindWindowByName("splitter"))

    'write other options to player config
    Dim cfg As wxFileConfig = wxFileConfig("", "", playerIni)
    cfg.SetPath("/dsmPlayer")
    'write player position

    cfg.Write("PlayerPosX", musicFrame.GetPositionX())
    cfg.Write("PlayerPosY", musicFrame.GetPositionY())
    cfg.Write("Maximized", titleFrame.IsMaximized())
    cfg.Write("Volume", volume)
    cfg.Write("Mute", muted)

    Dim buffer As Variant
    Select Case playmode
    Case ID_PLAY_WEBRADIO: buffer = "radio" 
    Case ID_PLAY_WEBTV: buffer = "tv"
    Case ID_PLAY_PODCAST: buffer = "podcast"
    Case Else: buffer = "file"
    End Select
    cfg.Write("PlayMode", buffer)

    cfg.SetPath("/File")
    cfg.Write("Directory", playDir)
    If (playMode = ID_PLAY_FILE) And !titleFrame.IsMaximized() Then cfg.Write("Size", titleFrame.GetSizeWidth() &"," &titleFrame.GetSizeHeight())

    If startPath = "" Then
      cfg.Write("File", musicFile)
      cfg.Write("Position", mediaPos)
      cfg.Write("PlaylistFile", playlistFile)
    End If

    cfg.SetPath("/Web")
    cfg.Write("RadioStation", mFileWebRadio)
    cfg.Write("Editable", musicMenu.IsChecked(ID_EDIT_WEBLIST))
    If (playMode = ID_PLAY_WEBRADIO) And !titleFrame.IsMaximized() Then cfg.Write("Size", titleFrame.GetSizeWidth() &"," &titleFrame.GetSizeHeight())

    cfg.SetPath("/TV")
    cfg.Write("TVStation", mFileWebTV)
    If (playmode = ID_PLAY_WEBTV) And !titleFrame.IsMaximized() Then cfg.Write("Size", titleFrame.GetSizeWidth() &"," &titleFrame.GetSizeHeight())

    'we can't catch changing column widths in wxTreeListCtrl
    cfg.SetPath("/Podcast")
    If (playMode = ID_PLAY_PODCAST) And !titleFrame.IsMaximized() Then cfg.Write("Size", titleFrame.GetSizeWidth() &"," &titleFrame.GetSizeHeight())

    buffer = ""
    For i = 0 To 3
      buffer &= lcPod.GetColumnWidth(i) &IIf(i < 3, ",", "")
    Next
    cfg.Write("columnWidth", buffer)
    cfg.Write("Podcast", podUrl)
    cfg.Write("Position", podPos)

    cfg.DeleteGroup("/Favorites")
    Dim Item As wxMenuItem
    cfg.SetPath("/Favorites")
      For i = 0 To selFavMenu.GetMenuItemCount() - 3
        Item = selFavMenu.FindItemByPosition(i)
        cfg.Write("Favorite" &i + 1, Item.GetItemLabelText() &"," &Item.GetHelp())
      Next

  Catch
    dl = wxGenericMessageDialog(Nothing, _("Error saving configuration!"), _("Attention"), wxICON_WARNING|wxDIALOG_NO_PARENT)
    dl.ShowModal()
  End Try

  muted = TRUE

  'clear and delete all rects, bitmaps, arrays etc. for mhm
  'delete timer
  timerMedia.Stop()
  ~timerMedia
  If loadingtimer.IsRunning() Then loadingTimer.Stop()
  ~loadingTimer

  If recPrc Then wxProcess_Kill(recPid, wxSIGKILL)
  killTV()
  killPhiola()

  ~musicFrame
  app.Exit()

  If restart Then wxExecute(playerPath &DELIMITER_CHAR &"dsmplayer.exe")
End Sub


Sub onHideTitleFrame(event As wxCommandEvent)
  showMedia()
End Sub


Sub onCloseTitleFrame(event As wxCloseEvent) Handles titleframe.closewindow
  showMedia()
  event.Veto()
End Sub


Sub killTV()
  While tvPids.Count()> 0
    wxProcess_Kill(tvPids.Item(0), wxSIGKILL, wxKILL_CHILDREN)
    tvPids.RemoveAt(0)
  Wend

  isplayed = FALSE
End Sub


'play the file
Sub playMedia(num As Integer)
  Dim explorerMedia As wxGenericDirCtrl = DynamicCast("wxGenericDirCtrl", musicFrame.FindWindowByName("explorermedia"))
  Dim selection As Integer
  Dim sel As Integer = -1
  Dim path As String
  Dim noLog As wxLog = wxLogNull()
  Dim prc As wxProcess

  Try
    'select the playmode
    If playmode = ID_PLAY_FILE Then
      'set the default colour to the old played file
      selection = lcMedia.FindItem(0, "  " &musicFile)
      If selection >= 0 Then lcMedia.SetItemTextColour(selection, musicFontColour)

      'store all files in the directory
      'so you can browse or edit in other directorys
      If (((playlistFile <> "") And (playlistFile != explorerMedia.GetFilePath())) Or
       ((playlistFile = "") And (playDir <> explOrerMedia.GetPath()))) Or !allMediaFiles.Count() Then setMediaPath()

      'a specific file number was passed
      If num > -1 Then
        musicFile = num
        sel = allMediaFilesInt.INDEX(num)

      Else

        'find a selection to play
        sel = lcMedia.GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED)

        'a seelction was found, get the musicfile
        If (sel <> -1) Then musicFile = allMediaFilesInt.Item(sel)

        'no file to play
        If (musicFile = -1) Then Return

        'get the file from the musicfile, if no selection found
        sel = allMediaFilesInt.INDEX(musicFile)
      End If

      'get the file path
      path = allMediaFiles.Item(sel)

      'set the highlighted colour
      If (playDir = explorerMedia.GetPath()) Or (playlistfile = explorerMedia.GetPath()) Then lcMedia.SetItemTextColour(sel, musicHiColour)

      'set the title shown in player
      pTitle = wxFileNameFromPath(path)

      'the path does not exist in a m3u playlist
      If Left(path, 2) = "??" Then
        Dim dl As wxGenericMessageDialog = wxGenericMessageDialog(Nothing, _("The file does not exist!"), _("Attention"), wxOK|wxCENTRE|wxICON_EXCLAMATION|wxDIALOG_NO_PARENT)
        dl.ShowModal()
       Return
      End If

  'we connot play a new file with the same phiola process at position 0
  'phiola always start at the first seeked positon
  '"remote start -seek 0" is not working here
  'maybe we can use it in the feature

  '    'a file is already played
  '    If phiolaPrc Then
  '      'the next/previous file is clicked
  '      'must set mediapos to zero here
  '      mediaPos = 0
  '
  '      'remote start with parameters is not yet supported by phiola
  '      phiolaPrc.Open(Chr(34) &phiolaPath &Chr(34) &" remote start " &Chr(34) &path &Chr(34) &" -id " &wxGetProcessId())
  '
  '    Else

        'the shown directory is the played directory
        If (playDir = explorerMedia.GetPath()) Then
          'read the media length
          Dim buffer = lcMedia.GetStringItem(lcMedia.FindItem(0, "  " &musicFile), 2)

          'a length is shown in list 
          If (buffer <> "") And (buffer <> "--:--") Then
            mediaLen = getTimeFromString(buffer, FALSE, FALSE)

          Else
            'read the file infos from the file
            getFileInfo(path, -1)
          End If

        Else

          getFileInfo(path, -1)
        End If

        Dim opt As String = ""
        If gainMode = 1 Then
          opt = " -norm \"\""
        Elseif gainMode = 2 Then
          opt = " -rgnorm"
        End If

        If mediapos Then
          phiola("", path, "-seek " &mediapos  &" -vol " &IIf(muted, 0, volume) &" -remote_id " &wxGetProcessId() &opt)
          'phiola("-D -L phi.log", path, "-seek " &mediapos &" -vol " &IIf(muted, 0, volume) &" -remote" &gainMode)

        Else

          phiola("", path, "-vol " &IIf(muted, 0, volume) &" -remote_id " &wxGetProcessId() &" " &opt)
        End If
  '    End If

    Else

      'web radio or tv
      'set old selection colour to normal
      sel = IIf((playMode = ID_PLAY_WEBTV), mFileWebTV, mFileWebRadio)
      selection = lcWeb.FindItem(0, "  " &sel)
      If (selection >= 0) Then lcWeb.SetItemTextColour(selection, musicFontColour)

      If num = -1 Then
        Dim s = lcWeb.GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED)
        If s <> -1 Then 
          num = lcWeb.GetItemText(s)
        Elseif sel <> -1 Then
          num = sel
        End If
      End If

      If num = -1 Then Return

      mediapos = 1
      sel = lcWeb.FindItem(0, "  " &num)

      If sel >= 0 Then
        lcWeb.SetItemTextColour(sel, musicHiColour)
        pTitle = lcWeb.GetStringItem(sel, 2)
      Else
        Return
      End If

      Dim Item As wxMenuItem
      Dim selName As String
      For i = 0 To selFavMenu.GetMenuItemCount() - 3
        Item = selFavMenu.FindItemByPosition(i)
        selName = Item.GetItemLabel()
        Item.Check(IIf(sel >= 0, selName = lcWeb.GetStringItem(sel, 2), FALSE))
        Deallocate(Item)
      Next

      path = lcWeb.GetStringItem(sel, 4)
      If playMode = ID_PLAY_WEBTV Then
        'load webTV
        mFileWebTV = num

        If !wxFileExists(tvPlayerPath) Then setTVPlayerPath()
        If !wxFileExists(tvPlayerPath) Then Return
        
        prc = New wxProcess(musicFrame)
        Connect(prc, -1, wxEVT_END_PROCESS, "onEndTV")
        Dim param = Replace(tvPlayerPara, "%f", "\"" &path &"\"")

        Dim pid = wxExecuteProcess(Chr(34) &tvPlayerPath &Chr(34) &" " &param, FALSE, prc)
        If pid Then
          isPlayed = TRUE
          tvPids.Add(pid)
        Else
          ~prc
        End If

        wxSafeYield(musicFrame)
        musicFrame.Raise()

      Else

        loadLinePos = 0
        pCodec = ""
        mFileWebRadio = num

  '      pTitle = lcWeb.GetStringItem(sel, 2)
        oldpTitle = ""

        'start loading animation
        If !loadingTimer.IsRunning() Then loadingTimer.Start(30)

        If phiolaPrc Then
          If !phiolaPrc.Open(Chr(34) &phiolaPath &Chr(34) &" remote start " &path &" -id " &wxGetProcessId()) Then
            loadingTimer.Stop()
            readStream()
          End If

        Else

          phiola("", path, "-vol " &IIf(muted, 0, volume) &" -connect_timeout " &timeout &" -recv_timeout " &timeout &" -remote_id " &wxGetProcessId())
        End If
      End If
    End If

  Catch
  End Try

  musicFrame.Refresh()
  musicTaskMenu.Enable(ID_PLAY_MEDIA, FALSE)
  musicTaskMenu.Enable(ID_PAUSE_MEDIA, IIf(playmode != ID_PLAY_FILE, FALSE, TRUE))
  musicTaskMenu.Enable(ID_STOP_MEDIA, TRUE)
  musicTaskMenu.Enable(ID_NEXT_MEDIA, TRUE)
  musicTaskMenu.Enable(ID_PREV_MEDIA, TRUE)
  musicTaskMenu.Enable(ID_MUTE_MEDIA, TRUE)

  ~noLog
  If busyInfo Then ~busyInfo
  busyInfo = Nothing
End Sub


'set the play directory in file mode and store all files
Sub setMediaPath()
  Dim explorerMedia As wxGenericDirCtrl = DynamicCast("wxGenericDirCtrl", musicFrame.FindWindowByName("explorermedia"))
  'set the play directory
  playDir = IIf(playlistFile = "", explorerMedia.GetPath(), wxPathOnly(explorerMedia.GetPath()))
  'is it a playlist file?
  playlistFile = IIf(explorerMedia.GetFilePath()<> "", explorerMedia.GetFilePath(), "")

  storeMediaFiles()
End Sub


'stop tv
Sub onEndTV(event As wxProcessEvent)
  Dim exitCode = event.GetExitCode()
  tvPids.Remove(event.GetPid())
  If !tvPids.Count() Then isPlayed = FALSE

  musicFrame.RefreshRect(wxRect(rects["play"].GetX(), rects["play"].GetTop(), rects["mute"].GetX() - rects["play"].GetX(), rects["play"].GetHeight()))
End Sub


'press the play button
Sub OnMediaPlay(event As wxCommandEvent)
  playMedia(-1)
End Sub


'get informations from a file or podcast
Sub getFileInfo(path As Variant, addList As Integer)
  If ((playMode = ID_PLAY_FILE) And !wxFileExists(path)) Or ((playMode = ID_PLAY_PODCAST) And (path = "")) Then Return
  Dim buffer As String = ""
  Dim at As Integer
  Dim inStream As wxInputStream

  'phiola info command return zero as duration on aac files
  'so we must use another routine to get the duration
  If Right(LCase(path), 3)= "aac" Then
    'play the file briefly to get some information about it
    Dim prc = New wxProcess(musicFrame)
    prc.Redirect()
    Connect(prc, wxEVT_END_PROCESS, "onEndInfoProcess")
    
    'get a stream info
    Dim pid = wxExecute(Chr(34) &phiolaPath &Chr(34) &Chr(34) &path &Chr(34) &" -vol 0", wxEXEC_ASYNC, prc)
    If pid Then
      'get the stream
      inStream = prc.GetInputStream()

      'read the stream
      If inStream And inStream.IsOk() Then
        'use textinputstream to read the lines
        Dim tStream As wxTextInputStream = wxTextInputStream(inStream, "\t", wxConvUTF8)

        While !inStream.Eof()
          buffer = tStream.ReadLine()

          If buffer[: 1]= "#" Then
            'stop playing and get the file information
            wxProcess_Kill(pid, wxSIGKILL)

            at = RInstr(buffer, "(") - 2
            buffer = buffer[: at]
            buffer = buffer[RInstr(buffer, " ")+ 1: RInstr(buffer, ".") - 1]
          End If
        Wend

        ~tStream
      End If
    End If

  Else

    prc = New wxProcess(musicFrame, -1)
    prc.Redirect()
    Connect(prc, -1, wxEVT_END_PROCESS, "onEndInfoProcess")
    pid = wxExecute(Chr(34) &phiolaPath &Chr(34) &" info "  &Chr(34) &path &Chr(34), wxEXEC_ASYNC, prc)

    If pid Then
      'get the stream
      inStream = prc.GetInputStream()

      'read the stream
      If inStream And inStream.IsOk() Then
        While !inStream.Eof()
          buffer &= instream.Read(1)
        Wend

        buffer = Trim(buffer)
      End If
    End If
  End If


  If buffer <> "" Then
    medialen = 0
    If InStr(buffer, "ERROR") Then Return

    If addList > -1 Then
      Dim theTime As String = getTimeFromString(buffer[ RInstr(buffer, " ")+ 1: ], TRUE, FALSE)
      lcMedia.SetStringItem(addList, 2, theTime)

    Else

      at = RInstr(buffer, "\n")+ 1
      If at Then buffer = buffer[at: ]

      at = RInstr(buffer, " ")+ 1
      If at Then buffer = buffer[ at: ]

      mediaLen = getTimeFromString(buffer, FALSE, FALSE)
      If mediaPos > medialen Then mediaPos = 0

      If medialen Then
        rects["mPos"].SetX(rects["mSlider"].GetX() - (5 * ps) + (mediaPos / mediaLen * 200 * ps))
      Else
        rects["mPos"].SetX(rects["mSlider"].GetX() - (5 * ps))
      End If

      musicFrame.RefreshRect(wxRect(rects["mSlider"].GetX() - (5 * ps), rects["mSlider"].GetY(), rects["mute"].GetX() - rects["mSlider"].GetX(), rects["mSlider"].GetHeight()))
    End If
  End If

  wxYield()
End Sub


'store all media file in arraystring and arrayint
Sub storeMediaFiles()
  If validation Then Return
  allMediaFiles.Clear()
  allMediaFilesInt.Clear()

  For i = 0 To lcMedia.GetItemCount() - 1
    allMediaFilesInt.Add(lcMedia.GetStringItem(i, 0))
    allMediaFiles.Add(lcMedia.GetStringItem(i, 5))
  Next
End Sub


'press the pause button
Sub OnMediaPause(event As wxCommandEvent)
  pauseMedia()
End Sub


Sub pauseMedia()
  isPaused = !isPaused
  musicFrame.RefreshRect(wxRect(rects["play"].GetX(), rects["play"].GetTop(), rects["mute"].GetX() - rects["play"].GetX(), rects["play"].GetHeight()))

  musicTaskMenu.Enable(ID_PLAY_MEDIA, isPaused)
  musicTaskMenu.Enable(ID_PAUSE_MEDIA, !isPaused)
  musicTaskMenu.Enable(ID_STOP_MEDIA, isPaused)
  musicTaskMenu.Enable(ID_NEXT_MEDIA, isPaused)
  musicTaskMenu.Enable(ID_PREV_MEDIA, isPaused)
  musicTaskMenu.Enable(ID_MUTE_MEDIA, isPaused)

  If !isPaused Then
    If playMode = ID_PLAY_FILE Then
      playMedia(musicFile)

    Else
      podcastPlay(findPodcastItem(podUrl, FALSE))
    End If

  Else

    killPhiola()
  End If

'remote pause is not implemented yet
'  If phiolaPrc Then
'    Dim prc = New wxProcess(musicFrame, -1)
'    Connect(prc, -1, wxEVT_END_PROCESS, "onEndInfoProcess")
'    prc.Redirect()
'    pid= wxExecute(Chr(34) &phiolaPath &Chr(34) &" remote pause" , wxEXEC_ASYNC, prc)
'    If !pid Then ~prc
'  End If
End Sub


'press the stop button
Sub OnMediaStop(event As wxCommandEvent)
  stopMedia()
End Sub


Sub stopMedia()
  isPaused = FALSE
  isPlayed = FALSE

  If playMode = ID_PLAY_WEBTV Then
    killTV()

  Elseif playMode = ID_PLAY_WEBRADIO Then
    killPhiola()

  Else

    mediapos = 0
    If loadingtimer.IsRunning() Then loadingTimer.Stop()
    killPhiola()
    rects["mPos"].SetX(rects["mSlider"].GetX() - (5 * ps))
    musicFrame.RefreshRect(rects["mSlider"])
  End If

  musicTaskMenu.Enable(ID_PLAY_MEDIA, TRUE)
  musicTaskMenu.Enable(ID_STOP_MEDIA, FALSE)
  musicTaskMenu.Enable(ID_PAUSE_MEDIA, FALSE)
  musicTaskMenu.Enable(ID_NEXT_MEDIA, FALSE)
  musicTaskMenu.Enable(ID_PREV_MEDIA, FALSE)
  musicTaskMenu.Enable(ID_MUTE_MEDIA, FALSE)

  musicFrame.RefreshRect(wxRect(rects["play"].GetX(), rects["play"].GetTop(), rects["mute"].GetX() - rects["play"].GetX(), rects["play"].GetHeight()))
End Sub


Sub wind(nx As Integer)
  If isPlayed And !isPaused Then
    Dim opt As String = IIf(nx = 0, "back", "forward")

    If playMode = ID_PLAY_FILE Then
      Dim prc = New wxProcess(musicFrame, -1)
      Connect(prc, -1, wxEVT_END_PROCESS, "onEndInfoProcess")
      prc.Redirect()
      Dim pid = wxExecute(Chr(34) &phiolaPath &Chr(34) &" remote seek " &opt &" -id " &wxGetProcessId(), wxEXEC_ASYNC, prc)
      If !pid Then ~prc
    End If
  End If
End Sub


'press next file button
Sub onNextFile(event As wxCommandEvent)
  nextFile(TRUE)
End Sub


'press previous file button
Sub onPrevFile(event As wxCommandEvent)
  nextFile(FALSE)
End Sub


'play next file or radio stream
Sub nextFile(nx As Integer)
  Select Case playMode
  Case ID_PLAY_FILE
    nextMusicFileLocal(nx)

  Case ID_PLAY_PODCAST
    nextMusicFilePod(nx)

  Case Else
    nextMusicFileWeb(nx)
  End Select
End Sub


'load next radio or tv station
Sub nextMusicFileWeb(nx As Integer)
  Dim sel = IIf((playMode = ID_PLAY_WEBRADIO), mFileWebRadio, mFileWebTV)
  Dim selection As Integer = -1

  If sel >= 0 Then selection = lcWeb.FindItem(-1, "  " &sel)
  If (sel = -1) Or ((nx = TRUE) And(selection = lcWeb.GetItemCount() - 1)) Or((nx = FALSE) And (selection = 0)) Then Return

  lcWeb.SetItemTextColour(selection, musicFontColour)
  selection = IIf(nx, selection + 1, selection - 1)
  lcWeb.EnsureVisible(selection)
  playMedia(lcWeb.GetItemText(selection))
End Sub


'load next radio or tv station
Sub nextMusicFilePod(nx As Integer)
  Try
    Dim Item As wxTreeListItem = findPodcastItem(podUrl, IIf(nx, FALSE, TRUE))

    If Item And Item.IsOk() Then
      If nx Then Item = lcPod.GetNextItem(Item)

      Dim a = lcpod.GetItemParent(lcpod.GetItemParent(Item))
      'if a is not ok, it is a child of the root item,
      'so it's a podcast adress and not an episode
      If !a.IsOk() Then Return

      podPos = 0
      podUrl = lcPod.GetItemText(Item, 4)
      lcPod.Select(Item)

      If phiolaPrc Then
        killphiola()

      Elseif isPlayed Then
        podcastPlay(lcpod.GetSelection())
      End If

      musicFrame.RefreshRect(wxRect(rects["next"].GetRight(), rects["next"].GetY(), rects["mute"].GetX() - rects["next"].GetRight(), rects["next"].GetHeight()))
      setPodcAstInfo(podUrl, TRUE)
    End If

  Catch
  End Try
End Sub


'load next local file
Sub nextMusicFileLocal(nx As Integer)
  Dim idx As Integer = allmediafilesInt.INDEX(musicFile)
  If (idx = -1) Or ((nx = TRUE) And (allmediafilesInt.Count()<= (idx + 1))) Or ((nx = FALSE) and (idx <= 0)) Then Return

  'remote start -seek' is not implemented yet
  'so we must kill phiola and start it again
  timerMedia.Stop()
  mediapos = 0
  rects["mPos"].SetX(rects["mSlider"].GetX() - (5 * ps))

  Dim explorerMedia As wxGenericDirCtrl = DynamicCast("wxGenericDirCtrl", musicFrame.FindWindowByName("explorermedia"))
  If playDir = IIf(playListFile = "", explorerMedia.GetPath(), wxPathOnly(explorerMedia.GetPath())) Then
    lcMedia.SetItemTextColour(idx, musicFontColour)
    lcMedia.EnsureVisible(IIf(nx = TRUE, idx + 1, idx - 1))
  End If

  musicFile = allmediafilesInt.Item(IIf(nx = TRUE, idx + 1, idx - 1))

  If phiolaPrc Then

    'kill phiola so that the next track can be played when the next button is pressed
    killphiola()

  Else

    'track has finished playing
    'play the next track
    playMedia(musicFile)
  End If
End Sub


'record a web radio station
Sub recordStation()
  If !wxFileExists(phiolaPath) Then phiolaPath = selectPhiolaPath()
  If !wxFileExists(phiolaPath) Then
    Return 

  Else

    If !wxDirExists(recordPath) Then wxFileName_Mkdir(recordPath, 4095, wxPATH_MKDIR_FULL)
    isRecord = !isRecord

    If isRecord Then
      Dim sel As Integer = mFileWebRadio

      If sel >= 0 Then sel = lcWeb.FindItem(0, "  " &sel)
        Dim cmd As String = ""
        'start phiola with debug log
'        Dim cmd As String = "-D -L phi.log"
        Dim opt As String = "-vol 0 -tee " &"\"" &recordPath &DELIMITER_CHAR &"@artist - @title." &pCodec &"\"" &" remote_id " &wxGetProcessId() + 10

        If singleFile Then
          cmd = "convert"
          opt = "-copy -o " &recordPath &DELIMITER_CHAR &"@nowdate-@nowtime." &pCodec'  &" remote_id " &wxGetProcessId() + 10
        End If

        If recordTime > 0 Then opt = "-until " &recordTime &":0 " &opt &" rermote_id " &wxGetProcessId() + 10

       'start record process
        recPrc = New wxProcess(musicFrame, -1)
        Connect(recPrc, -1, wxEVT_END_PROCESS, "onEndInfoProcess")
        recPrc.Redirect()
        recPid = wxExecute(Chr(34) &phiolaPath &Chr(34) &" " &cmd &" "  &"\"" &lcWeb.GetStringItem(sel, 4) &"\"" &" " &opt, wxEXEC_ASYNC, recPrc)

        If !recPid Then
          ~recPrc
          isRecord = FALSE
          musicframe.RefreshRect(rects["rec"])
        End If

    Else

      wxProcess_Kill(recPid, wxSIGKILL)
      recPrc = Nothing

      'convert recorded files, if checked in settings
      If recConv And (convPrc = Nothing) Then
        'hold the title to convert for the process end event
        recName = recordPath &DELIMITER_CHAR &oldpTitle &"."

        'convert the file
        convertFile()
      End If
    End If
  End If
End Sub


'mute button is pressed
Sub onMediaMute(event As wxCommandEvent)
  muteMedia()
End Sub


'mute
Sub muteMedia()
  muted = !muted
  musicTaskMenu.Check(ID_MUTE_MEDIA, muted)
  musicFrame.RefreshRect(rects["mute"])

  If isPlayed Then
   'pihola volume control
    Dim prc = New wxProcess(musicFrame, -1)
    Connect(prc, -1, wxEVT_END_PROCESS, "onEndInfoProcess")
    prc.Redirect()
    Dim pid = wxExecute(Chr(34) &phiolaPath &Chr(34) &" remote volume " &IIf(muted, 0, volume) &" -id " &wxGetProcessId(), wxEXEC_ASYNC, prc)
    If !pid Then ~prc
  End If
End Sub


'show a menu for selected title
Sub onTitleMenu(event As wxCommandEvent) Handles lcMedia.listitemrightclick
  Dim point = lcMedia.ScreenToClientPoint(wxGetMousePosition())
  lcMedia.PopupMenuPoint(musicTitleMenu, point)
  event.Skip()
End Sub


'show a menu for the selected title
Sub onEditMenu(event As wxCommandEvent)
  If !musicMenu.IsChecked(ID_EDIT_WEBLIST) Then Return
  enableFavMenuItems()
  If (playMode = ID_PLAY_WEBRADIO) And mFileWebRadio >= 0 Then findFavSation()
  editMenu.Enable(wxID_PASTE, copyInt.Count())

  Dim point = lcWeb.ScreenToClientPoint(wxGetMousePosition())
  lcWeb.PopupMenuPoint(editMenu, point)
  event.Skip()
End Sub


'show a menu for the selected title
Sub onFavMenu(event As wxCommandEvent)
  enableFavMenuItems()
  If mFileWebRadio >= 0 Then findFavSation()

  Dim point = lcWeb.ScreenToClientPoint(wxGetMousePosition())
  lcWeb.PopupMenuPoint(favMenu, point)
End Sub


'enable/disable favorites menu
Sub enableFavMenuItems()
  Dim selection = lcWeb.GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED)
  Dim selName As String = ""
  If selection >= 0 Then selName = lcWeb.GetStringItem(selection, 2)

  If selFavMenu.FindItem(selName)= wxNOT_FOUND Then
    selFavMenu.Enable(ID_REM_FAVORITE1, FALSE)
    favMenu.Enable(ID_ADD_FAVORITE, TRUE)
    favMenu.Enable(ID_REM_FAVORITE, FALSE)

  Else

    selFavMenu.Enable(ID_REM_FAVORITE1, TRUE)
    favMenu.Enable(ID_ADD_FAVORITE, FALSE)
    favMenu.Enable(ID_REM_FAVORITE, TRUE)
  End If
End Sub


Sub onDragBegin(event As wxListEvent)
  'use an unconventional way with wxDragImage
  Dim point = lcWeb.ScreenToClientPoint(wxGetMousePosition())
  oldY = lcWeb.HitTest(point, point)'wxLIST_HITTEST_ONITEM)
  'the dragimage is shown at the upper left corner at the begin, but the cursor at the correct position
  'store the position relative to the corner
  k1 = point.GetX()
  k2 = point.GetY()
  adressCut()

  'so use wxDragString with an empty string to hide the dragImage
  dragItemLC = wxDragString(lcWeb.GetStringItem(event.GetIndex(), 2))', wxCursorFromId(wxCURSOR_HAND))
  'we can also use the item number as icon
'  dragItemLC = wxDragListItem(listCtrlWeb, event.GetIndex())

  dragItemLC.BeginDrag(point, lcWeb, FALSE)
  dragItemLC.Show()

  'this should work but...
  'we can not set a droptarget, so the icon will show a false icon
  'and DoDragDrop return wxDragNone always
  'can't override the icon, so it is not usable for me
  'the pos is correct, so in theory we can use it
'  Dim obj = wxTextDataObject(event.GetIndex())
'  Dim cur As wxCursor = wxCursorFromStock(wxCURSOR_HAND)
'  Dim dSource = New wxDropSourceWithData(obj,lcWeb, cur, cur, cur)
''  dSource.SetCursor(wxDragNone, cur)
' lcWeb.SetDropTarget(wxDropTarget....)
'
'  '0 = wxDrag_CopyOnly
'  '1 = wxDrag_AllowMove
'  '3 = wxDrag_DefaultMove
''  Print dSource.DoDragDrop(1)
'  Dim result = dSource.DoDragDrop(2)
''  If result = wxDragMove Then
'    point =lcWeb.ScreenToClientPoint(wxGetMousePosition())
'    Dim pos =lcWeb.HitTest(point, point)
'   'pos is correct
''   lcWeb.DeleteItem(event.GetItem())
''  Else
''    Print result &" - " &wxDragCopy, wxDragError, wxDragLink, wxDragMove, wxDragNone
''  End If

'  ~dSource
'  dragItemLC.Hide()
'  dragItemLC.EndDrag()
'  ~dragItemLC
End Sub


Sub onDragMotion(event As wxMouseEvent)
  If dragItemLC = Nothing Then Return

  Dim point As wxPoint = lcWeb.ScreenToClientPoint(wxGetMousePosition())
  Dim point1 = wxPoint(point.GetX()+ k1, point.GetY()+ k2)

  'HitTest has a bug and require 2 objects instead an integer
  Dim Item As Integer = lcWeb.HitTest(point, point)'wxLIST_HITTEST_ONITEM)
  dragItemLC.Move(point1)

  If oldY <> Item Then
    'set font on mouse position to unterlined
    Dim font As wxFont = lcWeb.GetItemFont(Item)
    font.MakeUnderlined()
    lcWeb.SetItemFont(Item, font)
    font.SetUnderlined(FALSE)
    lcWeb.SetItemFont(oldY, font)

    oldY = Item
  End If
End Sub


Sub onDragEnd(event As wxMouseEvent)
  If dragItemLC = Nothing Then Return

  dragItemLC.Hide()
  dragItemLC.EndDrag()
  ~dragItemLC
  dragItemLC = Nothing

  Dim point As wxPoint = lcWeb.ScreenToClientPoint(wxGetMousePosition())
  Dim Item As Integer = lcWeb.HitTest(point, point)

  'set item font to normal
  Dim font As wxFont = lcWeb.GetItemFont(Item)
  font.SetUnderlined(FALSE)
  lcWeb.SetItemFont(Item, font)

  'insert the item datas
  If copyInt.Item(0) != Item Then adressPaste(Item + 1)
  isModify = TRUE
End Sub


'deselect all items in file or web mode
Sub deselectItems()
  Dim lc As wxListCtrl = IIf(playMode = ID_PLAY_FILE, lcMedia, lcWeb)

  'deselect selection separately
  'its faster then set each item
  Dim selection As Integer = lc.GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED)
  While selection >= 0
    lc.SetItemState(selection, 0, wxLIST_STATE_SELECTED)
    selection = lc.GetNextItem(selection, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED)
  Wend

  'deselect search results
  For i = 0 To lc.GetItemCount() - 1
    If lc.GetItemData(i) Then
      lc.SetItemBackgroundColour(i, musicBackColour)
      lc.SetItemData(i, 0)
    End If
  Next
End Sub


'select all items in file or web mode
Sub onSelectAllMedia(event As wxCommandEvent) Handles musicframe.menuselected(ID_MEDIA_MARK_ALL)
  selectAllMedia()
End Sub


Sub selectAllMedia()
  If playMode = ID_PLAY_FILE Then
    For i = 0 To lcMedia.GetItemCount() - 1
      lcMedia.SetItemState(i, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED)
    Next

  Else

    For i = 0 To lcWeb.GetItemCount() - 1
     lcWeb.SetItemState(i, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED)
    Next
  End If
End Sub


Sub onPlaylistWebReload(event As wxCommandEvent) Handles musicframe.menuselected(ID_RELOAD_FILELIST)
  'reload the playlist
  loadPlaylistWeb()
End Sub


'batch change filenames in file mode
Sub onChangeFilename(event As wxCommandEvent) Handles musicframe.menuselected(ID_CHANGE_FILENAME)
  If lcMedia.GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED)= -1 Then
    Dim dl = wxGenericMessageDialog(Nothing, _("No file selected!"), _("Attention"), wxOK|wxCENTER|wxICON_INFORMATION|wxDIALOG_NO_PARENT)
    dl.ShowModal()
    Return
  End If

  'create a dialog with self calculated with, height and child positions
  Dim dlg = wxDialog(musicFrame, -1, _("Edit file names"), wxDefaultPosition, wxSize(-1, -1), wxCAPTION, "filedlg")
  Dim seps As List = ["-", ",", "&", "#", "_"]
  Dim rb[6]

  Dim sb1 As wxStaticBox = wxStaticBox(dlg, -1, _("Separator between the information"), wxPoint(10, 10), wxSize(-1, 80))
  rb[1] = wxRadioButton(sb1, wxID_HIGHEST + 4101, Space(3) &Chr(34) &" - " &Chr(34) &Space(2) &_("(Minus)"), wxPoint(10, 25))
  Dim rect = rb[1].GetRect()
  rb[2] = wxRadioButton(sb1, wxID_HIGHEST + 4102, Space(3) &Chr(34) &" , " &Chr(34) &Space(2) &_("(Comma)"), wxPoint(-1, 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, rect.GetBottom()+ 2))
  rb[5] = wxRadioButton(sb1, wxID_HIGHEST + 4105, Space(3) &Chr(34) &" _ " &Chr(34) &Space(2) &_("(Underscore) "), wxPoint(-1, rect.GetBottom()+ 2))
  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
  rect = rb[4].GetRect()
  'calculate the sbox height
  Dim sbH As Integer = rect.GetBottom()+ 5

  Dim cb1 As wxCheckBox = wxCheckBox(dlg, -1, _("Remove text in brackets"), wxPoint(10, 110)): cb1.SetName("cb1")
  rect = cb1.GetRect()
  Dim cb2 As wxCheckBox = wxCheckBox(dlg, -1, _("Remove everything right after separator"), wxPoint(10, rect.GetBottom()+ 2)): cb2.SetName("cb2")
  rect = cb2.GetRect()
  Dim cb3 As wxCheckBox = wxCheckBox(dlg, -1, _("Remove everything to the left of the separator"), wxPoint(10, rect.GetBottom()+ 2)): cb3.SetName("cb3")
  rect = cb3.GetRect()
  Dim cb4 As wxCheckBox = wxCheckBox(dlg, -1, _("Remove everything between the right and left separators"), wxPoint(10, rect.GetBottom()+ 2)): cb4.SetName("cb4")
  rect = cb4.GetRect()
  Dim cb5 As wxCheckBox = wxCheckBox(dlg, -1, _("reduce multiple spaces to one"), wxPoint(10, rect.GetBottom()+ 2)): cb5.SetName("cb5")
  rect = cb5.GetRect()
  Dim cb6 As wxCheckBox = wxCheckBox(dlg, -1, _("Remove spaces completely"), wxPoint(10, rect.GetBottom()+ 2)): cb6.SetName("cb6")
  rect = cb6.GetRect()
  Dim cb7 As wxCheckBox = wxCheckBox(dlg, -1, _("Replace separators with spaces"), wxPoint(10, rect.GetBottom()+ 2)): cb7.SetName("cb7")
  rect = cb7.GetRect()
  Dim cb8 As wxCheckBox = wxCheckBox(dlg, -1, _("Remove quotation marks, replace first quotation mark with separator"), wxPoint(10, rect.GetBottom()+ 2)): cb8.SetName("cb8")
  rect = cb8.GetRect()
  Dim st As wxStaticText = wxStaticText(dlg, -1, _("Please note, all similar characters will also be removed (ASCII: 34, 132, 147, 148, 152)"), wxPoint(rect.GetLeft()+ 20, rect.GetBottom()+ 2))
  st.SetForegroundColor(wxRED)

  rect = st.GetRect()
  'calculate the dialog width with the longest text
  Dim w As Integer = rect.GetRight()+ 30
  sb1.SetClientSizeWH(w - 20, sbH)
  Dim Ok As wxButton = wxButton(dlg, wxID_OK, _("Ok"), wxPoint(0, rect.GetBottom()+ 10), wxSize(w / 3, 30))
  Dim Apply = wxButton(dlg, wxID_APPLY, _("Test run"), wxPoint(w / 3, rect.GetBottom()+ 10), wxSize(w / 3, 30))
  Connect(Apply, -1, wxEVT_COMMAND_BUTTON_CLICKED, "onTestRename")
  Dim Cancel As wxButton = wxButton(dlg, wxID_CANCEL, _("Cancel"), wxPoint(w / 3 * 2, rect.GetBottom()+ 10), wxSize(w / 3, 30))
  rect = Cancel.GetRect()
  dlg.SetClientSizeWH(w, rect.GetBottom())
  rb[2].SetPosition(wxPoint(w / 3, rb[2].GetPositionY()))
  rb[3].SetPosition(wxPoint((w / 3)* 2, rb[3].GetPositionY()))
  rb[5].SetPosition(wxPoint((w / 3), rb[5].GetPositionY()))

  If dlg.ShowModal()= wxID_OK Then
    renameFiles(cb1.GetValue(), cb2.GetValue(), cb3.GetValue(), cb4.GetValue(), cb5.GetValue(), cb6.GetValue(), cb7.GetValue(), cb8.GetValue(), FALSE)
  End If

  dlg.Destroy()
End Sub


'change filename free for one file
Sub onChangeFilenameFree(event As wxCommandEvent) Handles musicframe.menuselected(ID_CHANGE_FILENAME_FREE)
  ChangeFilenameFree()
End Sub


Sub ChangeFilenameFree()
  Dim cnt As Integer = lcMedia.GetSelectedItemCount()

  If cnt > 1 Then
    Dim dl = wxGenericMessageDialog(Nothing, _("Free customization only works with one file"), _("Freely adjust file names"), wxOK|wxCENTRE|wxICON_INFORMATION|wxDIALOG_NO_PARENT)
    dl.ShowModal()
    Return

  Else

    Dim selection = lcMedia.GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED)
    Dim NewName = wxGetTextFromUser(_("New Filename:"), _("Enter new file name"), lcMedia.GetStringItem(selection, 1))

    If newName <> "" Then
      If wxFileExists(wxPathOnly(musicFile) &DELIMITER_CHAR &newName) And (newName <> wxFileNameFromPath(musicFile)) Then
        dl = wxGenericMessageDialog(Nothing, _("The file already exists!") &"\n" &_("Overwrite?"), wxYES_NO|wxCENTRE|wxICON_EXCLAMATION|wxDIALOG_NO_PARENT)
        'wxNO = 5104 in wxGenericMessageDialog
        If dl.ShowModal() = 5104 Then Return
      End If

      Dim explorerMedia As wxGenericDirCtrl = DynamicCast("wxGenericDirCtrl", musicFrame.FindWindowByName("explorermedia"))
      Dim file = explorerMedia.GetPath() &DELIMITER_CHAR &lcMedia.GetStringItem(selection, 1)
      Dim Ok = wxRenameFile(file, wxPathOnly(file) &DELIMITER_CHAR &newName)

      If Ok Then
        lcMedia.SetStringItem(selection, 1, newName)
        lcMedia.SetStringItem(selection, 5, wxPathOnly(file) &DELIMITER_CHAR &newName)
        storeMediaFiles()
      End If
    End If
  End If
End Sub


'set the separator between album, artist, title or other informations
Sub onFileSepSelected(event As wxCommandEvent)
  Select Case event.GetID()
  Case wxID_HIGHEST + 4101: filesep = "-"
  Case wxID_HIGHEST + 4102: filesep = ","
  Case wxID_HIGHEST + 4103: filesep = "&&"
  Case wxID_HIGHEST + 4104: filesep = "#"
  Case wxID_HIGHEST + 4105: filesep = "_"
  End Select
End Sub


'test the rename action, show results before rename file
Sub onTestRename(event As wxCommandEvent)
  Dim cb[8]
  cb[1] = DynamicCast("wxCheckbox", wxFindWindowByName("cb1"))
  cb[2] = DynamicCast("wxCheckbox", wxFindWindowByName("cb2"))
  cb[3] = DynamicCast("wxCheckbox", wxFindWindowByName("cb3"))
  cb[4] = DynamicCast("wxCheckbox", wxFindWindowByName("cb4"))
  cb[5] = DynamicCast("wxCheckbox", wxFindWindowByName("cb5"))
  cb[6] = DynamicCast("wxCheckbox", wxFindWindowByName("cb6"))
  cb[7] = DynamicCast("wxCheckbox", wxFindWindowByName("cb7"))
  cb[8] = DynamicCast("wxCheckbox", wxFindWindowByName("cb8"))

  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")

  renameFiles(cb[1].GetValue(), cb[2].GetValue(), cb[3].GetValue(), cb[4].GetValue(), cb[5].GetValue(), cb[6].GetValue(), cb[7].GetValue(), cb[8].GetValue(), TRUE)

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


'rename the files
Sub renameFiles(cb1 As Integer, cb2 As Integer, cb3 As Integer, cb4 As Integer, cb5 As Integer, cb6 As Integer, cb7 As Integer, cb8 As Integer, IsPreview As Integer)
  Try
    Dim tString As wxString = wxString()
    Dim FileName As wxFileName = wxFileName("")
    Dim at, at1 As Integer
    Dim char, title As String

    If IsPreview Then
      Dim win = wxFindWindowByName("previewCtrl")
      Dim pdlg = DynamicCast("wxTextCtrl", win)
    End If

    Dim explorerMedia As wxGenericDirCtrl = DynamicCast("wxGenericDirCtrl", musicFrame.FindWindowByName("explorermedia"))
    Dim selection = lcMedia.GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED)

    While selection >= 0
      title = explorerMedia.GetPath() &DELIMITER_CHAR &lcMedia.GetStringItem(selection, 1)
      FileName.AssignPath(title)
      tstring.SetValue(wxString_FromUTF8(FileName.GetName()))

      'replace chars in braces
      If cb1 Then
        Dim char1, char2 As String
        For i = 1 To 3
          Select Case i
          Case 1: char1 = "(": char2 = ")"
          Case 2: char1 = "[": char2 = "]"
          Case 3: char1 = "{": char2 = "}"
          End Select

          at = tstring.Find("(")
          Dim b = tstring.Find(")")
          While at > 0
            at1 = tstring.Find(")")
            If at1 > 0 Then
              tstring.Replace(tstring.SubString(at, at1), "")
            Else
              Break
            End If

            at = tstring.Find("(")
          Wend
        Next
      End If

      'replace text betreen separators
      If cb4 Then
        at = InStr(tstring.GetData(), fileSep)
        at1 = RInstr(tstring.GetData(), fileSep)
        If (at > 0) And (at <> at1) Then tString.SetValue(tstring.SubString(0, at - 1) &" " &tString.SubString(at1 + 1, tString.Length()))
      End If

      'replace text right from the separator
      If cb2 Then
        at = RInstr(tstring.GetData(), fileSep)
        If at > 0 Then tstring.SetValue(tstring.SubString(0, at - 2))
      End If

      'replace text left from the separator
      If cb3 Then
        at = InStr(tstring.GetData(), fileSep)
        If at > 0 Then tString.SetValue(LTrim(tString.SubString(at, tString.Length())))
      End If

      'replace separator with space
      If cb7 Then
        tstring.Replace(fileSep, " ")
      End If

      If cb8 Then
        Dim cnt As Integer = 1

        For i = 1 To 5
          Select Case i
          Case 1: char = Chr(32)
          Case 2: char = Chr(132)
          Case 3: char = Chr(147)
          Case 4: char = Chr(148)
          Case 5: char = Chr(152)
          End Select

          at = InStr(tstring.GetData(), char)
          While at > 0
            tstring.Replace(char, IIf(cnt = 1, fileSep, ""), FALSE)
            cnt += 1
            at = InStr(tstring.GetData(), char)
          Wend
        Next
      End If

      'remove spaces
      If cb6 Then
        tstring.Replace(" ", "")
      End If

      'reduce more spaces to one
      If cb5 Then
        While InStr(tstring.GetData(), "  ")> 0
          tstring.Replace("  ", " ")
        Wend
      End If

      tstring.Trim()
      tstring.Trim(FALSE)
      FileName.SetName(tstring.GetData())

      If !IsPreview Then
        If title <> FileName.GetFullPath() Then
          wxRenameFile(title, FileName.GetFullPath())
          lcMedia.SetStringItem(selection, 1, FileName.GetFullName())
          lcMedia.SetStringItem(selection, 5, FileName.GetPath() &DELIMITER_CHAR &FileName.GetFullName())
        End If
        lcMedia.SetItemState(selection, 0, wxLIST_STATE_SELECTED)

      Else

        pdlg.AppendText(FileName.GetFullName() &"\n")
      End If
      
      selection = lcMedia.GetNextItem(selection, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED)
    Wend

    tString.Clear()
    FileName.Clear()

  Catch
  End Try
End Sub


'delete file is selected
Sub onTitleDelete(event As wxCommandEvent) Handles musicframe.menuselected(ID_DELETE_TITLE)
  deleteTitle()
End Sub


'delete the file 
Sub deleteTitle()
  Dim explorerMedia As wxGenericDirCtrl = DynamicCast("wxGenericDirCtrl", musicFrame.FindWindowByName("explorermedia"))
  

  Dim dl = wxGenericMessageDialog(Nothing, _("Permanently delete the selected title(s)?") &"\n" &_("Are you sure ?"), _("Delete file"), wxYES_NO | wxICON_QUESTION|wxDIALOG_NO_PARENT)
  'wxNO = 5104 in wxGenericMessageDialog
  If dl.ShowModal() = 5103 Then
    Try
      Dim nolog = wxLogNull()
      lcMedia.Freeze()
      Dim selection = lcMedia.GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED)
      If selection = -1 Then Return

      Dim realSel As Integer = lcMedia.FindItem(0, "  " &musicFile)
      Dim isMusicfile As Integer = FALSE
      While selection >= 0
        If realSel = selection Then isMusicFile = TRUE

        If (realSel >= selection) And (musicFile <> -1) Then
          musicFile -= 1
        End If

        Dim title = explorerMedia.GetPath() &DELIMITER_CHAR &lcMedia.GetStringItem(selection, 1)

        'delete the file
        Dim Ok = wxRemoveFile(title)
        If !Ok Then
          lcMedia.SetItemState(selection, 0, wxLIST_STATE_SELECTED)
          Dim dl1 As wxGenericMessageDialog = wxGenericMessageDialog(Nothing, _("The file could not be deleted!"), title, wxOK|wxICON_INFORMATION|wxDIALOG_NO_PARENT)
          dl1.ShowModal()

        Else
          lcMedia.DeleteItem(selection)

          'begin is 0, because shuffle can resort the files and numbers
          For i = 0 To lcMedia.GetItemCount() - 1
            If Val(lcMedia.GetStringItem(i, 0))> (selection + 1) Then lcMedia.SetStringItem(i, 0, "  " &i + 1)
          Next
        End If
        
        selection = lcMedia.GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED)
      Wend
      lcMedia.Thaw()
      ~noLog

      storeMediaFiles()

      If isMusicFile Then
        If IsPlayed Then
          nextFile(TRUE)
        Else
          musicFile = -1
        End If
      End If

    Catch
    End Try
  End If
  ~dl
End Sub


'open a file in the selected edit program
Sub onTitleEdit(event As wxCommandEvent) Handles musicframe.menuselected(ID_OPEN_FILE)
  Dim selections As Integer = lcMedia.GetSelectedItemCount()
  Dim sel = lcMedia.GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED)

  If !wxFileExists(editorPath) Then
    Dim dl = wxGenericMessageDialog(Nothing, _("No path specified for the editor program!"), _("Attention"), wxOK|wxCENTRE|wxICON_EXCLAMATION|wxDIALOG_NO_PARENT)
    dl.ShowModal()
    Return

  Elseif selections > 1 Then
    dl = wxGenericMessageDialog(Nothing, _("Only one file can be opened for editing."), _("Attention"), wxOK|wxCENTRE|wxICON_EXCLAMATION|wxDIALOG_NO_PARENT)
    dl.ShowModal()
    Return

  Elseif sel = -1 Then
    Return
  End If

  dl = wxGenericMessageDialog(Nothing, _("Open selected file for editing?"),  _("Open file"), wxYES_NO | wxICON_QUESTION|wxDIALOG_NO_PARENT)
  'wxYES = 5103 in wxGenericMessageDialog
  If dl.ShowModal() = 5103 Then

    'use the label to hold the selected action
    'we can also use wxClientData to do this, but this way is easier
    Dim explorerMedia As wxGenericDirCtrl = DynamicCast("wxGenericDirCtrl", musicFrame.FindWindowByName("explorermedia"))
    Dim filepath As String
    Dim FileName As wxFileName

    If playlistfile <> "" Then
      filePath = lcMedia.GetStringItem(sel, 1)
      FileName.AssignPath(filePath)
      If !FileName.IsAbsolute() Then filePath = explorerMedia.GetPath() &DELIMITER_CHAR &lcMedia.GetStringItem(sel, 1)
    Else
      filepath = lcMedia.GetStringItem(sel, 5)
    End If

    wxExecute(Chr(34) &editorPath &Chr(34) &" " &filePath)
  End If
  ~dl
End Sub


'load informations about a stream adress
Sub onAdressInfo(event As wxCommandEvent) Handles musicframe.menuselected(wxID_INFO)
  Dim selection As Integer = lcWeb.GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED)
  If selection >= 0 Then createStationFrame(selection, TRUE)
End Sub


Sub onAdressCut(event As wxCommandEvent) Handles musicframe.menuselected(wxID_CUT)
  adressCut()
End Sub


Sub adressCut()
  copyInt.Clear()
  Dim selection As Integer = lcWeb.GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED)

  While selection >= 0
    copyInt.Add(selection)
    selection = lcWeb.GetNextItem(selection, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED)
  Wend
End Sub


Sub onAdressPaste(event As wxCommandEvent) Handles musicframe.menuselected(wxID_PASTE)
  Dim selection As Integer = lcWeb.GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED)
  adressPaste(selection + 1)

  'deselect insert item
  lcWeb.SetItemState(selection, 0, wxLIST_STATE_SELECTED)
End Sub


Sub adressPaste(itemNum As Integer)
  Dim stations As Table = {}
  Dim cnt As Integer
  Dim Item As Integer
  Dim idx1, idx2 As Integer

  'store datas from selected items
  For i = copyInt.Count() - 1 To 0 Step -1
    cnt = copyInt.Item(i)
    stations[i, 0]= lcWeb.GetStringItem(cnt, 0) 
    stations[i, 1]= lcWeb.GetStringItem(cnt, 1) 
    stations[i, 2]= lcWeb.GetStringItem(cnt, 2) 
    stations[i, 3]= lcWeb.GetStringItem(cnt, 3) 
    stations[i, 4]= lcWeb.GetStringItem(cnt, 4) 
    stations[i, 5]= lcWeb.GetStringItem(cnt, 5)
    stations[i, 6]= GetBitmapIndex(copyInt.Item(i), 0)
  Next

  For i = 0 To stations.Count() - 1
    'substract an item, because the number becomes smaller after the entry is deleted
    If copyInt.Item(i)< itemNum Then itemNum -= 1

    'remove the dragged item from old position in list
    lcWeb.DeleteItem(lcWeb.FindItem(0, stations[i, 0]))

    lcWeb.InsertImageStringItem(itemNum, stations[i, 0], stations[i, 6])
    lcWeb.SetStringItem(itemNum, 1, stations[i, 1])
    lcWeb.SetStringItem(itemNum, 2, stations[i, 2])
    lcWeb.SetStringItem(itemNum, 3, stations[i, 3])
    lcWeb.SetStringItem(itemNum, 4, stations[i, 4])
    lcWeb.SetStringItem(itemNum, 5, stations[i, 5])

    'select the dragged item
    lcWeb.SetItemState(itemNum, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED)
    itemNum += 1
  Next

  renumList(0)
  stations = {}
  copyInt.Clear()
  isModify = TRUE
End Sub


'renumber file or web playlists
Sub renumList(Start As Integer)
  Dim sel, selection As Integer = -1
  Dim Name, adress As String = ""
  If busyInfo Then ~busyInfo

  Select Case playMode
  Case ID_PLAY_FILE
    If !lcMedia.GetItemCount() Then
      Return

    Elseif lcMedia.GetItemCount()> 3000 Then
      busyInfo = wxBusyInfo(_("Renumber..."))
    End If

    sel = musicFile
    'start renum
    For i = Start To lcMedia.GetItemCount() - 1
      lcMedia.SetStringItem(i, 0, "  " &i + 1)
      lcMedia.SetItemTextColour(i, musicFontColour)

      If i%300 = 0 Then wxYield()
    Next

    selectFile(musicFile, TRUE, FALSE)

  Case Else

    If !lcWeb.GetItemCount() Then
      Return

    Elseif lcWeb.GetItemCount()> 3000 Then
      busyInfo = wxBusyInfo(_("Renumber..."))
    End If

    'hold name and web adress from the station
    sel = IIf((playMode = ID_PLAY_WEBRADIO), mFileWebRadio, mFileWebTV)
    selection = lcWeb.FindItem(0, "  " &sel)

    If selection >= 0 Then
      Name = lcWeb.GetStringItem(selection, 2)
      adress = lcWeb.GetStringItem(selection, 4)
    End If

    'start renum
    For i = Start To lcWeb.GetItemCount() - 1
      lcWeb.SetStringItem(i, 0, "  " &i + 1)
      lcWeb.SetItemTextColour(i, musicFontColour)

      If Name <> "" Then
        'get the new item number of the current played item
        If lcWeb.GetStringItem(i, 2)= Name And lcWeb.GetStringItem(i, 4)= adress Then
          'set the new item number 
          If playMode = ID_PLAY_WEBRADIO Then
            If sel Then mFileWebRadio = i + 1
             selectFile(mFileWebRadio, TRUE, FALSE)

          Elseif playMode = ID_PLAY_WEBTV Then
            If sel Then mFileWebTV = i + 1
            selectFile(mFileWebTV, TRUE, FALSE)
          End If
        End If
      End If

      If i%300 = 0 Then wxYield()
    Next

    'set new item number to the favorites
    Dim Item As wxMenuItem
    Dim isFound As Integer
    For i = 0 To selFavMenu.GetMenuItemCount() - 3
      Item = selFavMenu.FindItemByPosition(i)
      isFound = FALSE

      For j = 0 To lcWeb.GetItemCount() - 1
        If lcWeb.GetStringItem(j, 2)= Item.GetItemLabelText() Then
          Item.SetHelp(LTrim(lcWeb.GetStringItem(j, 0)))
          isFound = TRUE
          Break
        End If
      Next

      If !isFound Then Item.SetHelp(-1)
    Next
  End Select

  If busyInfo Then ~busyinfo
  busyinfo = Nothing
End Sub


'add a favorite to the favirite menu
Sub onFavoriteAdd(event As wxCommandEvent) Handles musicframe.menuselected(ID_ADD_FAVORITE)
  Dim selection = lcWeb.GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED)

  If selection >= 0 Then
    Dim selName As String = lcWeb.GetStringItem(selection, 2)
    'wxMenuitem handle '&&' as "&" char
    If selFavMenu.FindItem(selName)= wxNOT_FOUND Then
      Dim id As Integer = wxNewId()
      Dim Item = selFavMenu.Insert(selFavMenu.GetMenuItemCount() - 2, id, Replace(selName, "&", "&&"), LTrim(lcWeb.GetStringItem(selection, 0)), wxITEM_CHECK)
      Connect(musicframe, id, wxEVT_COMMAND_MENU_SELECTED, "onFavoriteClick")
      Connect(selFavMenu, id, wxEVT_COMMAND_MENU_SELECTED, "onFavoriteClick")

      Dim sel = IIf((playMode = ID_PLAY_WEBRADIO), mFileWebRadio, mFileWebTV)
      If sel >= 0 Then
        sel = lcWeb.FindItem(0, "  " &sel)
        Item.Check(lcWeb.GetStringItem(sel, 2)= selName)
      End If
    End If
  End If
End Sub


'remove a favorite from the favorite menu
Sub onFavoriteRemove(event As wxCommandEvent) Handles musicframe.menuselected(ID_REM_FAVORITE)
  Dim selection = lcWeb.GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED)

  If selection >= 0 Then
    Dim selName As String = lcWeb.GetStringItem(selection, 2)

    Dim id As Integer = selFavMenu.FindItem(selName)
    If id <> wxNOT_FOUND Then selFavMenu.DeleteById(id)
  End If
End Sub


'remove a favotite from by the favorite menu
Sub onFavoriteRemove1(event As wxCommandEvent) Handles musicframe.menuselected(ID_REM_FAVORITE1)
  Dim Item As wxMenuItem

  For i = 0 To selFavMenu.GetMenuItemCount() - 3
    Item = selFavMenu.FindItemByPosition(i)
    If Item.IsChecked() Then
      selFavMenu.DeleteItem(Item)
      Break
    End If
  Next
End Sub


'select a favorite from the menu
Sub onFavoriteClick(event As wxCommandEvent)
  Dim id = event.GetID()
  Dim itemId As Integer
  Dim Item As wxMenuItem
  Dim itemLabel As String
  Dim sel As Integer
  Dim isFound As Integer = 1

  For i = 0 To selFavMenu.GetMenuItemCount() - 3
    Item = selFavMenu.FindItemByPosition(i)
    itemId = Item.GetID()
    Item.Check(ItemId = id)

    If Item.GetID()= id Then
      If InStr(itemLabel, "&&")> 0 Then itemLabel = Replace(itemLabel, "&&", "&")
      sel = lcWeb.FindItem(-1, "  " &Item.GetHelp())

      'if the favorite has a false item number, set it to zero
      'so the routine search for the correct line
      If sel = -1 Then sel = 0

      'handle false favotite item number, for example after import a playlist
      If (sel > lcWeb.GetItemCount()) Or (lcWeb.GetStringItem(sel, 2) != Item.GetItemLabel()) Then
        isFound = -1

        For j = 0 To lcWeb.GetItemCount() - 1
          If lcWeb.GetStringItem(j, 2) = Item.GetItemLabel() Then
            isFound = 1
            sel = LTrim(lcWeb.GetStringItem(j, 0))
            Item.SetHelp(sel)
            Break
          End If
        Next

      Else

        sel = Item.GetHelp()
      End If

      If isFound <> -1 Then
        selectFile(sel, TRUE, TRUE)

      Else
        Dim dl = wxGenericMessageDialog(Nothing, _("The station was not found") &"\n" &
        _("Should the station be removed from favorites?"), 
        _("Attention"), wxCENTRE|wxYES_NO|wxYES_DEFAULT|wxICON_EXCLAMATION|wxDIALOG_NO_PARENT)

        'wxYES = 5103 in wxGenericMessageDialog
        If dl.ShowModal()= 5103 Then
          selFavMenu.DeleteItem(Item)
        Else
          Item.Check(FALSE)
        End If

        Return
      End If

      playMedia(sel)
      Break
    End If
  Next
End Sub


'load url from listctrl
Sub onSelectionUrlChanged(event As wxCommandEvent) Handles lcWeb.listitemactivated
  Dim sel As Integer = IIf((playMode = ID_PLAY_WEBRADIO), mFileWebRadio, mFileWebTV)
  'find the last selected item by index
  If sel >= 0 Then
    sel = lcWeb.FindItem(0, "  " &sel)

    'set the item colour to standard
   lcWeb.SetItemTextColour(sel, musicFontColour)
  End If

  'get the index from the new selected item
  Dim selItem As Integer = event.GetIndex()
  sel = lcWeb.GetStringItem(selItem, 0)

  playMedia(sel)
End Sub


'the file selection is changed
Sub onSelectionItemChanged(event As wxCommandEvent) Handles lcMedia.listitemfocused
  Dim Item As Integer = event.GetIndex()
  
  'enable/disable open file in editor program based on the file extension
  Dim file As String = lcMedia.GetStringItem(Item, 1)
  Dim ext As String = getFileFormat(file)
  musicTitleMenu.Enable(ID_OPEN_FILE, InStr(editorTypes, ext &";") > 0)
End Sub


'load file from listctrl
Sub onSelectionFileChanged(event As wxCommandEvent) Handles lcMedia.listitemactivated
  startPath = ""
  mediaPos = 0

  If timerMedia.IsRunning() Then timerMedia.Stop()
  Dim file As Integer = lcMedia.FindItem(0, "  " &musicFile)
  lcMedia.SetItemTextColour(file, musicFontColour)

  musicFile = lcMedia.GetStringItem(event.GetIndex(), 0)
  rects["mPos"].SetX(rects["mSlider"].GetX() - (5 * ps))
  musicFrame.RefreshRect(rects["mSlider"])
 
  'remote start -seek is not implemented yet
  'so we must kill phiola and start it again
  If phiolaPrc Then
    killphiola()

  Else

    playMedia(-1)
  End If
End Sub


'the directory is changed in file mode
Sub onSelectionDirChanged(event As wxTreeEvent)
  SelectDir(FALSE, TRUE)
End Sub

Sub selectDir(firstStart As Integer, selFile As Integer)
  Dim explorerMedia As wxGenericDirCtrl = DynamicCast("wxGenericDirCtrl", musicFrame.FindWindowByName("explorermedia"))
  Dim FilePath As String = explorerMedia.GetPath()
  Dim FileName As wxFileName = wxFileName(filePath)

  If firstStart And (filePath = "") Then explorerMedia.SetPath(wxGetCwd())
  lcMedia.DeleteAllItems()

  Dim m3uFile As String = explorerMedia.GetFilePath()
  FilePath = explorerMedia.GetPath()

  'directory names with special characters cannot be handled by the program
  If (filepath = "") And (m3ufile = "") Then 
    Dim dl = wxGenericMessageDialog(Nothing, _("The directory name contains unsupported characters.") &"\n" &_("The contents cannot be displayed!"), _("Note"), wxOK|wxCENTRE|wxICON_INFORMATION|wxDIALOG_NO_PARENT)
    dl.ShowModal()
    Return
  End If

  Dim nolog = wxLogNull()
  'playlist file
  If wxFileExists(m3uFile) Then
    Dim Type = getPlaylistType(m3uFile)

    If Type = "file" Then
      lcMedia.DeleteAllItems()
      loadPlayListMedia(m3uFile, firstStart, FALSE)

      If playListFile = m3uFile Then
        Dim sel = lcMedia.FindItem(0, "  " &musicFile)
        If sel >= 0 Then
          lcMedia.SetItemTextColour(sel, musicHiColour)
          lcMedia.EnsureVisible(sel)
        End If
      End If

    Else

      If !firstStart Then
        dl = wxGenericMessageDialog(musicFrame, _("The playlist appears to be an internet playlist.") &"\n" &_("Do you want to switch to the Internet player?"), _("Notice"), wxYES_NO|wxYES_DEFAULT|wxICON_QUESTION|wxCENTRE|wxDIALOG_NO_PARENT)
        'wxNO = 5104 in wxGenericMessageDialog
        If dl.ShowModal() = 5104 Then Return

        stopMedia()
        musicMenu.Check(ID_PLAY_WEBRADIO, TRUE)
        pTitle = ""
        mfileWebRadio = -1
        setPlayMode(ID_PLAY_WEBRADIO, FALSE)
        musicMenu.Check(ID_EDIT_WEBLIST, FALSE)
        showEditWeblist()
        lcWeb.SetName(0, 0)
        lcWeb.DeleteAllItems()
        lcWeb.Refresh()
        lcWeb.Update()

        importPlaylist(m3uFile, 2)
        isModify = FALSE
      End If
    End If

  Else

    playerWatcher.RemoveAll()
    If wxDirExists(filePath) Then playerWatcher.AddTree(FileName.DirName(filePath), 1|2|4) 'create, delete, rename, 8=modify

    Dim modTime As wxDateTime
    lcMedia.DeleteAllItems()

    If (playDir = filePath) And (playlistFile = "") And lcMedia.GetItemCount() Then
      For i = 0 To allMediaFiles.Count() - 1
        FileName.AssignPath(allMediaFiles.Item(i))
        lcMedia.InsertStringItem(i, "  " &allMediaFilesInt.Item(i))
        lcMedia.SetItemData(i, 0)
        lcMedia.SetStringItem(i, 1, FileName.GetFullName())
        modTime = FileName.GetModificationTime()
        lcMedia.SetStringItem(i, 3, modtime.FormatISODate() &"  " & modtime.FormatISOTime())
        lcMedia.SetStringItem(i, 4, getReadableFileSize(wxFileSize(FileName.GetFullPath())))
        lcMedia.SetStringItem(i, 5, FileName.GetFullPath())
      Next
      If selFile Then selectFile(musicFile, TRUE, TRUE)

    Else

      Try
        Dim ext As String
        Dim cnt As Integer = 0

        Dim files As wxArrayString = wxArrayString()
        'get all files from the directory
        'we can also use wxDir.GetFirst and GetNext(), but it stops at UTF8 characters
        wxDir_GetAllFiles(filePath, files, "*.*", wxDIR_FILES)

        'sort out files
        For i = 0 To files.Count() - 1
          FileName.AssignPath(files.Item(i))
          ext = LCase(FileName.GetExt())
          FileName.SetPath(filePath)

          Select Case ext
          Case "aac", "webm", "flac", "mp3", "m4a", "ogg", "opus", "wav", "wv", "mkv", "mp4", "mov", "caf", "avi", "ts", "mpc"
            lcMedia.InsertStringItem(cnt, "  " &cnt + 1)
            lcMedia.SetItemData(cnt, 0)
            lcMedia.SetStringItem(cnt, 1, FileName.GetFullName())
            modTime = FileName.GetModificationTime()
            lcMedia.SetStringItem(cnt, 3, modtime.FormatISODate() &"  " & modtime.FormatISOTime())
            lcMedia.SetStringItem(cnt, 4, getReadableFileSize(wxFileSize(FileName.GetFullPath())))
            lcMedia.SetStringItem(cnt, 5, FileName.GetFullPath())

            If cnt%10 Then wxSafeYield(lcMedia)
            cnt += 1
          End Select
        Next
        files.Clear()

        'select the file without start it
        If (playDir = filePath) And (playlistFile = "") And (musicFile > -1) Then
          If selFile Then setFile(TRUE)

        Elseif musicFile = -1 Then
          playDir = filePath
        End If

      Catch
        dl = wxGenericMessageDialog(Nothing, _("Error reading directory") &" '" &filePath &"' !", _("Attention"), wxOK|wxCENTRE|wxICON_ERROR|wxDIALOG_NO_PARENT)
        dl.ShowModal()

      Finally
        lcMedia.Refresh()
      End Try
    End If

    Connect(musicFrame, -1, wxEVT_IDLE, "onIdle")
  End If

  ~noLog
End Sub


'read the media durations, if the system is idle
Sub OnIdle(event As wxIdleEvent)
  Disconnect(musicFrame, -1, wxEVT_IDLE)
  readMediaTimes()
End Sub


'read the title duration for all titles
Sub readMediaTimes()
  If !lcMedia.GetItemCount() Then Return

  If isReading Then
    isBroken = TRUE
    isReading = FALSE
  End If

  Dim explorerMedia As wxGenericDirCtrl = DynamicCast("wxGenericDirCtrl", musicFrame.FindWindowByName("explorermedia"))

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

  Dim pid = wxExecute(Chr(34) &phiolaPath &Chr(34) &" info " &
  Chr(34) &explorerMedia.GetPath() &DELIMITER_CHAR &"*.mp3" &Chr(34) &" " &
  Chr(34) &explorerMedia.GetPath() &DELIMITER_CHAR &"*.aac" &Chr(34) &" " &
  Chr(34) &explorerMedia.GetPath() &DELIMITER_CHAR &"*.ogg" &Chr(34) &" " &
  Chr(34) &explorerMedia.GetPath() &DELIMITER_CHAR &"*.flac" &Chr(34) &" " &
  Chr(34) &explorerMedia.GetPath() &DELIMITER_CHAR &"*.m4a" &Chr(34) &" " &
  Chr(34) &explorerMedia.GetPath() &DELIMITER_CHAR &"*.opus" &Chr(34) &" " &
  Chr(34) &explorerMedia.GetPath() &DELIMITER_CHAR &"*.wv" &Chr(34) &" " &
  Chr(34) &explorerMedia.GetPath() &DELIMITER_CHAR &"*.mpc" &Chr(34) &" " &
  Chr(34) &explorerMedia.GetPath() &DELIMITER_CHAR &"*.ape" &Chr(34) &" " &
  Chr(34) &explorerMedia.GetPath() &DELIMITER_CHAR &"*.wav" &Chr(34), wxEXEC_ASYNC, prc)

  If pid Then
    'get the stream
    Dim inStream = prc.GetInputStream()
    Dim errStream = prc.GetErrorStream()
    Dim cnt As Integer = 0

    'read the stream
    If inStream And inStream.IsOk() Then
      Dim buffer As String = ""
      Dim char As String = ""
   
      'sometimes a file information or warning contains a hidden unichar
      'if this is passed to the string, the loop will crash
      While !inStream.Eof()
        char = inStream.Read(1)
        If Asc(char)<> -1 Then buffer&= char
      Wend

      If isBroken Then
        isBroken = FALSE
        Return
      End If

      'create a virtual database to find the results in database
      'the results are sorted differently than in listctrl
      'so we have to find the real item
      createVirtualDB()

      Dim titleLen As String
      Dim num As Integer
      Dim path As String
      Dim at As Integer

      Dim lines As wxArrayString = wxStringTokenize(buffer, "\n")
      For i = 0 To lines.Count() - 1
        If isBroken Then Break

        buffer = lines.Item(i)

        If InStr(buffer, "INFO") Or InStr(buffer, "WARN") Or buffer[: 1]= "[" Or buffer = "" Then Continue

        'search for the path
        at = RInstr(buffer, "\"")
        at = RInstr(at - 1, buffer, "\"")
        titleLen = buffer[at: ]
        path = wxString_FromUTF8(wordbetween(titleLen, "\"","\""))

        If path = "" Then
          Continue

        Else

          'search for the path in the database to get the real list number as equivalent to the listctrl
          num = filesDB.ExecSql("SELECT id FROM files where path=" &Chr(34) &path &Chr(34) &" COLLATE NOCASE")
        End If

        'reduce the line, get the string after the last quotation mark until the end
        at = RInstr(titleLen, "\"")
        buffer = LTrim(titleLen[at + 1: ])

        'get the length string
        at = InStr(buffer, ":")
        titleLen = Trim(buffer[RInstr(at, buffer, " "): InStr(at, buffer, " ") - 1])
        lcMedia.SetStringItem(num - 1, 2, getTimeFromString(titleLen, TRUE, FALSE))

        cnt += 1
        If cnt%10 = 0 Then wxYield()
      Next

      filesDB.Close()
      lines.Clear()
    End If

  Else
    ~prc
  End If

  If isBroken Then
    isBroken = FALSE
    Return
  End If

  'phiola cannot handle duplicate file extensions in wildcards such as mp3.mp3
  'for example "phiola info *.mp3" will ignore "file.mp3.mp3"
  'therefore the files in the list above are ignored
  'the file length is also not read for aac files
  'check empty places and read the file as a single file
  Dim files As wxArrayInt = wxArrayInt()

  'check fot empty file durations
  For i = 0 To lcMedia.GetItemCount() - 1
    If isBroken Then Break
    buffer = lcMedia.GetStringItem(i, 2)
    If (buffer = "") Or (buffer = "00:00") Then files.Add(i)
  Next

  Dim lLen As Integer
  For i = 0 To files.GetCount() - 1
    If isBroken Then Break
    num = files.Item(i)
    buffer = lcMedia.GetStringItem(num, 2)

    'empty places from ignored files and
    'aac or other files, which did not return any duration
    If (buffer = "") Or (buffer = "00:00") Then getFileInfo(lcMedia.GetStringItem(num, 5), num)

    wxYield()
  Next

  files.Clear()
  ~files
  isReading = FALSE
  isBroken = FALSE
End Sub


'create a virtual database from the files listctrl
Sub createVirtualDB()
  If filesDb.Open("DBQ=:memory:;Driver=SQLITE3;") Then
    filesDb.ExecSql("create table files(id integer PRIMARY KEY," &
    "title text Not Null," &
    "len text Not Null," &
    "date text Not Null," &
    "size integer Not Null," &
    "path text Not Null);")

    filesDb.ExecSql("PRAGMA synchronous = OFF")
    filesDb.ExecSql("PRAGMA journal_mode = MEMORY")
    filesDb.ExecSql("PRAGMA journal_size_limit = 6144000")
    filesDb.ExecSql("PRAGMA cache_size = 1000000")
    filesDb.ExecSql("PRAGMA locking_mode = EXCLUSIVE")
    filesDb.ExecSql("PRAGMA temp_store = MEMORY")
    filesDb.ExecSql("SET CHARACTER_SET 'UTF8'")
    filesDb.ExecSql("Set title UTF8")

    filesDb.BeginTransaction()

    Dim s As String
    For i = 0 To lcMedia.GetItemCount() - 1
      'some title has a quotation mark in the name
      'these must be replaced before saving
      s = lcMedia.GetStringItem(i, 1)
      If InStr(s, Chr(34)) Then s = Replace(s, Chr(34), "'")

      filesDb.ExecSql("Insert INTO files values(" &LTrim(lcMedia.GetStringItem(i, 0)) &"," &Chr(34) &s &Chr(34) &"," &Chr(34) &lcMedia.GetStringItem(i, 2) &Chr(34) &",'" &lcMedia.GetStringItem(i, 3) &"','" &lcMedia.GetStringItem(i, 4) &"',"  &Chr(34) &lcMedia.GetStringItem(i, 5) &Chr(34) &");")
    Next

    'end the tranaction
    filesDb.Commit()
  End If
End Sub


'validate web adresses
Sub onValidateWebAdress(event As wxCommandEvent) Handles musicframe.menuselected(ID_VALIDATE_SEL)
  selectPhiolaPath()
  If ! wxFileExists(phiolaPath) Then Return

  Dim valDialog = musicFrame.FindWindowByName("valdlg")
  If (valDialog <> Nothing) Then Return

  If isModify Then
    Dim dl = wxGenericMessageDialog(Nothing, _("The playlist has been changed!") &"\n" &_("Save changes To database?") &
    "\n" &_("An up-to-date database is required for validation."), _("Attention"), wxYES_NO|wxCENTRE|wxICON_EXCLAMATION|wxDIALOG_NO_PARENT)
    'wxYES = 5103 in wxGenericMessageDialog
    If dl.ShowModal() = 5103 Then
      saveStations(FALSE, TRUE)
    Else
      Return
    End If
  End If

  dl = wxGenericMessageDialog(musicFrame, _("The playlist addresses are now being checked!") &"\n" &_("This can take a very long time.") &" " &_("Start anyway?"), _("Note"), wxYES_NO|wxYES_DEFAULT|wxICON_QUESTION|wxCENTRE|wxDIALOG_NO_PARENT)
  'wxNO = 5104 in wxGenericMessageDialog
  If dl.ShowModal() = 5104 Then Return

  validation = TRUE
  allMediaFilesInt.Clear()
  Dim selCount As Integer = lcWeb.GetSelectedItemCount()

  If (playMode <> ID_PLAY_WEBRADIO) Or ((playMode = ID_PLAY_WEBRADIO) And !selCount) Then
    dbc = wxDbConnection("DBQ=IPTV.db;DefaultDir=.;Driver=SQLITE3;")
    If dbc.IsOpen() Then
      dbc.ExecSql("PRAGMA synchronous = OFF")
      dbc.ExecSql("PRAGMA journal_mode = MEMORY")
      dbc.ExecSql("PRAGMA cache_size = 1000000")
      dbc.ExecSql("PRAGMA locking_mode = EXCLUSIVE")
      dbc.ExecSql("PRAGMA temp_store = MEMORY")
      dbc.ExecSql("SET CHARACTER_SET 'utf8'")

      Dim hint As String
      Dim recSet As wxDbRecordset = wxDbRecordset(dbc, "select * from radio")
      For i = 1 To recSet.GetRowCount()
        allMediaFilesInt.Add(i)
      Next

      recSet.Close()
      dbc.Close()
    End If

  Else

    Dim selection As Integer = lcWeb.GetNextItem(-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED)

    While selection <> -1
      allMediaFilesint.Add(selection + 1)
      selection = lcWeb.GetNextItem(selection, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED)
    Wend
  End If

  valDialog = wxDialog(musicFrame, ID_VALIDATION, _("Failed connections: 0"), wxDefaultPosition, wxSize(800, 400), wxDEFAULT_DIALOG_STYLE|wxMINIMIZE_BOX)
  valDialog.SetName("valdlg")
  valDialog.SetMinSize(wxSize(400, 50))

  Dim dSizeX = valDialog.GetClientSizeWidth()
  Dim dSizeY = valDialog.GetClientSizeHeight()
  Dim clb As wxCheckListBox = wxCheckListBox(valDialog, -1, wxPoint(0, 0), wxSize(dSizeX, dSizeY - 25), 0, [], wxLB_DEFAULT|wxLB_HSCROLL)
  clb.SetName("valbox")
  Connect(clb, wxEVT_RIGHT_UP, "onValidateRightMenu")

  Dim buttonStop = wxButton(valDialog, wxID_STOP, _("Stop test"), wxPoint(0, dSizeY - 25), wxSize(dSizeX / 6, 25))
  buttonStop.SetToolTip(_("Stop Validation"))
  Connect(buttonStop, -1, wxEVT_COMMAND_BUTTON_CLICKED, "onValidateStop")

  Dim buttonDelete = wxButton(valDialog, wxID_OK, _("Delete"), wxPoint(dSizeX / 6, dSizeY - 25), wxSize(dSizeX / 6, 25))
  buttonDelete.SetToolTip(_("Delete selected stations from database"))
  buttonDelete.SetName("deletebutton")
  Connect(buttonDelete, -1, wxEVT_COMMAND_BUTTON_CLICKED, "onValidateDelete")

  Dim buttonRetest = wxButton(valDialog, -1, _("Test again"), wxPoint(2 * (dSizeX / 6), dSizeY - 25), wxSize(dSizeX / 6, 25))
  buttonRetest.SetToolTip(_("Test selected stations again"))
  buttonRetest.SetName("retestbutton")
  Connect(buttonRetest, -1, wxEVT_COMMAND_BUTTON_CLICKED, "onValidateNew")

  Dim buttonView = wxButton(valDialog, ID_EDIT_SEL, _("Look at"), wxPoint(3 * (dSizeX / 6), dSizeY - 25), wxSize(dSizeX / 6, 25))
  buttonView.SetToolTip(_("Display station informations"))
  buttonView.SetName("viewbutton")
  Connect(buttonView, -1, wxEVT_COMMAND_BUTTON_CLICKED, "onValidateShow")

  Dim buttonSave = wxButton(valDialog, wxID_SAVE, _("Save list"), wxPoint(4 * (dSizeX / 6), dSizeY - 25), wxSize(dSizeX / 6, 25))
  butTonSave.SetToolTip(_("Save station list to file"))
  buttonSave.SetName("savebutton")
  Connect(buttonSave, -1, wxEVT_COMMAND_BUTTON_CLICKED, "onValidateSave")

  Dim buttonCancel = wxButton(valDialog, wxID_CANCEL, _("Quit"), wxPoint(5 * (dSizeX / 6), dSizeY - 25), wxSize(dSizeX / 6, 25))
  buttonCancel.SetToolTip(_("Cancel validation and close dialog"))
  Connect(buttonCancel, -1, wxEVT_COMMAND_BUTTON_CLICKED, "onValidateExit")
  Connect(valDialog, -1, wxEVT_CLOSE_WINDOW , "onValidateExit")

  buttonDelete.Enable(FALSE)
  buttonRetest.Enable(FALSE)
  buttonView.Enable(FALSE)
  buttonSave.Enable(FALSE)
  Dim noLog As wxLog = wxLogNull()

  If (playMode = ID_PLAY_WEBRADIO) Then musicFrame.RefreshRect(rects["text"])
  'store validation counter
  errCnt = allMediaFilesInt.Count()
  valDialog.Show(TRUE)
  wxSafeYield(musicFrame)

  'phiola is fast on loading, so we use a short time
  phiolaValidate(allMediaFilesInt.Item(0))
End Sub


'right menu in the validate results
Sub onValidateRightMenu(event As wxMouseEvent)
  Dim clb As wxCheckListBox = DynamicCast("wxCheckListBox", musicFrame.FindWindowByName("valbox"))
  Dim point = clb.ScreenToClientPoint(wxGetMousePosition())
  clb.PopupMenuPoint(selMenu, point)
  event.Skip()
End Sub


'select all in the results is selected
Sub onValSelect(event As wxCommandEvent)
  Dim clb As wxCheckListBox = DynamicCast("wxCheckListBox", musicFrame.FindWindowByName("valbox"))
  For i = 0 To clb.GetCount() - 1
    clb.Check(i, event.GetID()= wxID_SELECTALL)
  Next
End Sub


'validate adresses with phiola
Sub phiolaValidate(id As Integer)
  Dim text = _("Test address") &" " &(allMediaFilesInt.Item(0)) &"  (" &(errCnt - allMediaFilesInt.Count()+ 1) &" / " &errCnt &")"
  Dim valDialog As wxDialog = DynamicCast("wxDialog", musicFrame.FindWindowByName("valdlg"))
  Dim clb As wxCheckListBox = DynamicCast("wxCheckListBox", musicFrame.FindWindowByName("valbox"))
  valDialog.SetTitle(text &"  -  " &_("Failed connections:") &" " &clb.GetCount()) 
  If (playMode = ID_PLAY_WEBRADIO) Then musicFrame.RefreshRect(rects["text"])

  dbc = wxDbConnection("DBQ=IPTV.db;DefaultDir=.;Driver=SQLITE3;")
  If dbc.IsOpen() Then
    dbc.ExecSql("PRAGMA synchronous = OFF")
    dbc.ExecSql("PRAGMA journal_mode = MEMORY")
    dbc.ExecSql("PRAGMA cache_size = 1000000")
    dbc.ExecSql("PRAGMA locking_mode = EXCLUSIVE")
    dbc.ExecSql("PRAGMA temp_store = MEMORY")
    dbc.ExecSql("SET CHARACTER_SET 'utf8'")
    Dim adress As String = dbc.ExecSql("SELECT adress FROM radio where id=" &id)

    'validation start
    'execute phiola to get the file informations
    valPrc = New wxProcess(musicFrame)
    valPrc.Redirect()
    Connect(valPrc, wxEVT_END_PROCESS, "onValidateProcessEnd")

    Dim pid = wxExecute(Chr(34) &phiolaPath &Chr(34) &" info " &"\"" &adress &"\"" &" -connect_timeout " &timeout &" -recv_timeout " &timeout, wxEXEC_ASYNC, valPrc)
    If !pid Then
      ~valPrc
      valPrc = Nothing
      dbc.Close()
    End If
  End If
End Sub


'get next file to validate
Sub onValidateProcessEnd(event As wxProcessEvent)
  If !valPrc Then Return

  Dim clb As wxCheckListBox = DynamicCast("wxCheckListBox", musicFrame.FindWindowByName("valbox"))
  Dim inStream = valPrc.GetInputStream()

  'read the stream
  If inStream And inStream.IsOk() Then
    Dim buffer As String = ""
    Dim text As String

    'use textinputstream to read the lines
    Dim tStream As wxTextInputStream = wxTextInputStream(inStream, "\t", wxConvUTF8)

    While !inStream.Eof()
      text = tStream.ReadLine()
      If InStr(text, "INFO") Or (text = "") Or text[: 2]= "0:" Then Continue
      buffer &= text &"\n"
    Wend

    Dim cnt As Integer = allMediaFilesInt.Item(0)
    Dim title As String = dbc.ExecSql("SELECT name FROM radio where id=" &cnt)
    Dim sel As Integer = -1

    For i = 0 To clb.GetCount()
      If InStr(clb.GetString(i), cnt &" - " &title) Then
        sel = i
        Break
      End If
    Next

    'split the lines from the buffer to an arraystring
    Dim info = wxStringTokenize(buffer, "\n")
    Dim Item As String
    Dim at As Integer
    text = ""

    For i = 0 To info.Count() - 1
      buffer = info.Item(i)

      'get station info
      If buffer[: 1] = "#" Then
        If (sel >= 0) Then clb.Delete(sel)

      Elseif InStr(buffer, "ERROR") Or InStr(buffer, "WARN") Then
        at = RInstr(buffer, ":")
        text = " (" &Trim(buffer[at + 1: ])  &")"
        If Tally(text, ")")> 1 Then text = " (" &Trim(text[InStr(text, ")") + 1: ])

        If sel = -1 Then
          sel = clb.Append(cnt &" - " &title &text)
          clb.Check(sel, TRUE)
          clb.ScrollLines(1)

        Elseif !InStr(clb.GetString(sel), text) Then
          buffer = clb.GetString(sel)
          buffer = buffer[: Len(buffer) - 1] &" - " &text[3: ]
          clb.SetString(sel, buffer)
        End If
      End If
    Next

    info.Clear()
  End If


'  'let the host time to refresh
'  wxMilliSleep(100)

  allMediaFilesInt.RemoveAt(0)
  ~valPrc
  valPrc = Nothing

  If allMediaFilesInt.Count() Then
    phiolaValidate(allMediaFilesInt.Item(0))

  Else

    Dim valDialog As wxDialog = DynamicCast("wxDialog", musicFrame.FindWindowByName("valdlg"))
    valDialog.SetTitle(_("Failed connections:") &" " &clb.GetCount() &" " &_("of") &" " &errCnt) 
    musicFrame.RefreshRect(rects["text"])

    stopValidate()
  End If

  If (playMode = ID_PLAY_WEBRADIO) Then musicFrame.RefreshRect(rects["text"])
End Sub


'delete checked items
Sub onValidateDelete(event As wxCommandEvent)
  Dim dl = wxGenericMessageDialog(Nothing, _("The selected files are now removed from the playlist.") &"\n" &_("Are you sure?"), _("Attention"), wxYES_NO|wxYES_DEFAULT|wxICON_QUESTION|wxCENTRE|wxDIALOG_NO_PARENT)
  'wxYes = 5103 in wxGenericMessageDialog
  If dl.ShowModal() = 5103 Then
    Dim clb As wxCheckListBox = DynamicCast("wxCheckListBox", musicFrame.FindWindowByName("valbox"))
    Dim at As Integer
    Dim text As String
    Dim num As Integer
    Dim sel As Integer
    deselectItems()

    For i = clb.GetCount() - 1 To 0 Step -1
      If clb.IsChecked(i) Then
        text = clb.GetString(i)
        at = InStr(text, " -")
        num = Val(text[: at - 1]) - 1
        If num = mFileWebRadio Then mFileWebRadio = -1
        lcWeb.DeleteItem(num)
        clb.Delete(i)
      End If
    Next
    renumList(0)
  End If
  ~dl

  dl = wxGenericMessageDialog(Nothing, _("Write changes to the database?"), _("Attention"), wxYES_NO|wxYES_DEFAULT|wxICON_QUESTION|wxCENTRE|wxDIALOG_NO_PARENT)
  'wxYes = 5103 in wxGenericMessageDialog
  If dl.ShowModal() = 5103 Then saveStations(FALSE, TRUE)

  validateExit()
End Sub


'exit validate process
Sub onValidateExit(event)
  validateExit()
End Sub


Sub validateExit()
  stopValidate()
  Dim clb As wxCheckListBox = DynamicCast("wxCheckListBox", musicFrame.FindWindowByName("valbox"))
  clb.Clear()
  clb.Destroy()
  Dim valDialog As wxDialog = DynamicCast("wxDialog", musicFrame.FindWindowByName("valdlg"))
  valDialog.Destroy()
  valDialog = Nothing
End Sub


'show information about a station in the validate dialog
Sub onValidateShow(event As wxCommandEvent)
  Dim clb As wxCheckListBox = DynamicCast("wxCheckListBox", musicFrame.FindWindowByName("valbox"))
  Dim at As Integer
  Dim text As String
  Dim num As Integer
  Dim sel As Integer = clb.GetSelection()
  
  If sel >= 0 Then
    text = clb.GetString(sel)
    at = InStr(text, " -")
    num = Val(text[: at - 1]) - 1

    createStationFrame(num, TRUE)
  End If
End Sub


'validate checked items again
Sub onValidateNew(event As wxCommandEvent)
  Dim clb As wxCheckListBox = DynamicCast("wxCheckListBox", musicFrame.FindWindowByName("valbox"))
  If !clb.GetCount() Then Return

  Dim at As Integer
  Dim text As String
  Dim num As Integer

  For i = 0 To clb.GetCount() - 1
    If clb.IsChecked(i) Then
      text = clb.GetString(i)
      at = InStr(text, " -")
      num = Val(text[: at - 1])
      allMediaFilesInt.Add(num)
    End If
  Next

  validation = TRUE
  Dim valDialog As wxDialog = DynamicCast("wxDialog", musicFrame.FindWindowByName("valdlg"))
  errCnt = allMediaFilesInt.Count()

  phiolaValidate(allMediaFilesint.Item(0))
  musicFrame.RefreshRect(rects["text"])
End Sub


'save validation results to a textfile
Sub onValidateSave(event As wxCommandEvent)
  fd.SetDirectory("")
  fd.SetMessage(_("Choose the file name"))
  fd.SetFileName("fails")
  fd.SetWildcard("*.txt")
  fd.SetWindowStyle(wxFD_SAVE)

  If fd.ShowModal() = wxID_OK Then
    Dim path As String = fd.GetPath()
    Dim clb As wxCheckListBox = DynamicCast("wxCheckListBox", musicFrame.FindWindowByName("valbox"))

    If wxFileExists(path) Then
      Dim dl = wxGenericMessageDialog(Nothing, _("The file already Exists!") &"\n" &_("Overwrite?"), _("Attention"), wxYES_NO|wxYES_DEFAULT|wxICON_EXCLAMATION|wxCENTRE|wxDIALOG_NO_PARENT)
      'wxNO = 5104 in wxGenericMessageDialog
      If dl.ShowModal() = 5104 Then Return

    Elseif wxFileName_IsDirWritable(path) Then
      dl = wxGenericMessageDialog(Nothing, _("The directory is write-protected.") , _("Attention"), wxOK|wxICON_EXCLAMATION|wxCENTRE|wxDIALOG_NO_PARENT)
      'wxNO = 5104 in wxGenericMessageDialog
      dl.ShowModal()
      Return
    End If
      
    Try
      Dim file = FOpen(path, "w" )
      FPuts(file, _("Incorrect connections from") &" " &Date() &" " &Time() &"\n")

      For i = 0 To clb.GetCount() - 1
        FPuts(file, clb.GetString(i) &"\n")
      Next

      dl = wxGenericMessageDialog(Nothing, _("File saved successfully!"), _("Note"), wxOK|wxICON_INFORMATION|wxCENTRE |wxDIALOG_NO_PARENT)

    Catch
      dl = wxGenericMessageDialog(Nothing, _("Error writing file!"), _("Attention"), wxOK|wxICON_EXCLAMATION|wxCENTRE|wxDIALOG_NO_PARENT)

    Finally
      dl.ShowModal()
      FClose(file)
    End Try
  End If
End Sub


'stop validate process
Sub onValidateStop(event As wxCommandEvent)
  stopValidate()
End Sub


Sub stopValidate()
  Dim valDialog As wxDialog = DynamicCast("wxDialog", musicFrame.FindWindowByName("valdlg"))
  Dim Button = valDialog.FindWindowByName("deletebutton")
  Button.Enable(TRUE)
  Button = valDialog.FindWindowByName("retestbutton")
  Button.Enable(TRUE)
  Button = valDialog.FindWindowByName("viewbutton")
  Button.Enable(TRUE)
  Button = valDialog.FindWindowByName("savebutton")
  Button.Enable(TRUE)

  If valPrc Then 
    wxProcess_Kill(valPrc.GetPid(), wxSIGKILL)
    valPrc = Nothing
  End If

  allMediaFilesint.Clear()
  validation = FALSE
  If dbc And dbc.IsOpen() Then dbc.Close()

  musicFrame.RefreshRect(rects["text"])
  valDialog.Raise()
  wxYield()
End Sub


' -----------------------------------------------------------------------
'display loading animation in web mode
Sub onLoadingTimer(event As wxTimerEvent)
  If phiolaPrc And phiolaPrc.IsInputAvailable() Then
    loadingTimer.Stop()
    musicFrame.Refresh()
    If !timerMedia.IsRunning() Then timerMedia.Start(1000)

  Elseif phiolaPrc = Nothing Then
    loadingTimer.Stop()
    musicFrame.Refresh()

  Else

    setLoadingAni()
  End If
End Sub


' update the position in slider in file play
' update title name in webradio
Sub OnMediaTimer(event As wxTimerEvent)
  'prevent incorrect display in position slider if the duration is displayed incorrectly
  Select Case playmode
  Case ID_PLAY_FILE
    If mediapos > mediaLen Then mediapos = medialen

  Case ID_PLAY_PODCAST
    If podPos > podLen Then podPos = podLen
'    If !podlen Then podLen = getTimeFromString(lcPod.GetItemText(findPodcastItem(podUrl), 1), FALSE, FALSE)

  Case Else
    'use the seconds to switch between the station and the title in web mode
    mediapos += 1
  End Select

  'read the title and codec from the stream in webradio or title length in file mode
  readStream()

  'read the stream from recoding
  'check for errors
  If recPrc And recPrc.IsInputOpened() Then
    Dim recInStream As wxInputStream = recPrc.GetInputStream()
    Dim recErrStream As wxInputStream = recPrc.GetErrorStream()
    Dim buffer As String = ""

    'read the input and error streams
    While recPrc.IsInputAvailable()
      buffer &= recInstream.Read(1)
    Wend

    While phiolaPrc.IsErrorAvailable()
      recErrStream.Read(1)
    Wend

    If InStr(LCase(buffer), "error") Then
      If !InStr(LCase(buffer), "@artist - @title") Then
        'use wxRichToolTip if no jump target is available
        Dim rt = wxRichToolTip(_("Attention"), _("The title is skipped because it already exists."))
        rt.SetBackgroundColour(wxColour(255, 128, 128))
        rt.SetStandardIcon()
        rt.SetTipKind(wxTipKind_Auto)
        rt.SetTimeout(4000)
        rt.ShowFor(musicFrame, wxRect(rects["rec"].GetX(), rects["rec"].GetBottom(), 10, 10))
      End If
    End If
  End If
End Sub


'read the radio stream
Sub readStream()
  If phiolaPrc And phiolaPrc.IsInputOpened() Then
    Dim phiolaInStream As wxInputStream = phiolaPrc.GetInputStream()
    Dim phiolaErrStream As wxInputStream = phiolaPrc.GetErrorStream()

    'read the input and error streams
    Dim buffer As String = ""
    While phiolaPrc.IsInputAvailable()
      buffer &= phiolaInstream.Read(1)
    Wend

    While phiolaPrc.IsErrorAvailable()
      phiolaErrStream.Read(1)
    Wend

    If InStr(buffer, "ERROR") Then
      pTitle = IIf(playmode = ID_PLAY_FILE, _("Error playing file"), _("Error playing stream"))
      musicFrame.RefreshRect(rects["text"])
      Return

    'play files or podcasts
    Elseif (playMode = ID_PLAY_FILE) Or (playMode = ID_PLAY_PODCAST) Then
      If posClicked Then Return

      Dim pos = IIf(playMode = ID_PLAY_FILE, mediaPos, podPos)
      Dim llen = IIf(playMode = ID_PLAY_FILE, mediaLen, podLen)

      'read the position from the stream
      'it is better than from mediapos counter in timer event 
      Dim at = RInstr(buffer, "]")
      If at Then
        pos = getTimeFromString(Trim(buffer[at + 1: InStr(at + 2, buffer, "/") - 1 ]), FALSE, FALSE)
        'sometimes the listed episode time in podcast mode is incorrect
        'this is corrected here
        llen = getTimeFromString(buffer[RInstr(buffer, " ") + 1: ], FALSE, FALSE)
      End If

      Dim spos As Integer = 0

      If (playMode = ID_PLAY_FILE) Then
        If !mediaLen Then medialen = llen
        If medialen Then spos = (pos / mediaLen * 200)
        If pos > mediaLen Then spos = medialen * 200

      Else

        If (podLen <> llen) And (llen <> 0) Then
          podLen = llen
          Dim Item = findPodcastItem(podUrl, FALSE)
          lcPod.SetItemColText(Item, 1, getTimeFromSec(podLen, TRUE))
        End If

        If podlen Then spos = (pos / podLen * 200)
        If pos > podLen Then sPos = podLen * 200
      End If

      'set the slider position
      rects["mPos"].SetX(rects["mSlider"].GetX() - (5 * ps) + (sPos * ps))
      If playMode = ID_PLAY_FILE Then: mediapos = pos: Else: podPos = pos: End If

      'repaint slider and time
      musicFrame.RefreshRect(wxRect(rects["mSlider"].GetX() - (5 * ps), rects["mute"].GetY(), rects["mute"].GetX() - rects["mSlider"].GetX()+ (10 * ps), rects["mute"].GetHeight()))

    'play webradio 
    Elseif (playmode = ID_PLAY_WEBRADIO) Then
      Dim station As String = ""

      If mFileWebRadio >= 0 Then station = lcWeb.GetStringItem(lcWeb.FindItem(0, "  " &mFileWebRadio), 2)
      If pTitle = "" Then pTitle = station

      'ignore info line
      at = InStr(buffer, "INFO ")
      If at > 0 Then buffer = buffer[InStr(at, buffer, "\n"): ]

      at = RInstr(buffer, "#")
      If at Then
        'get the stream codec
        If pCodec = "" Then
          If RInstr(buffer[RInstr(buffer, ")")+ 1: ], "AAC")> 0 Then
            pCodec = "aac"
          Elsif RInstr(buffer[RInstr(buffer, ")")+ 1: ], "MP3")> 0 Then
            pCodec = "mp3"
          Elseif RInstr(buffer[RInstr(buffer, ")")+ 1: ], "Vorbis")> 0 Then
            pCodec = "ogg"
          Elseif RInstr(buffer[RInstr(buffer, ")")+ 1: ], "Opus")> 0 Then
            pCodec = "opus"
          End If
        End If

        'find the title
        Dim title As String = Trim(wordbetween(buffer[at: ], "\"","\""))

        'ignore empty titles or jingles
        If !((title = "") Or (Left(title, 1)= "-")) Then
          pTitle = wxString_FromUTF8(title)
          mediaPos = 1

          If oldpTitle <> pTitle Then
            'hold the title to convert for the process end event
            recName = recordPath &DELIMITER_CHAR &oldpTitle &"."
            oldpTitle = pTitle
            musicFrame.RefreshRect(rects["text"])

            'convert recorded files, if checked in settings
            If isRecord And recConv And (convPrc = Nothing) Then convertFile()
          End If
        End If
      End If

      'no title information is send, so dsmPlayer will use the station information as title
      'set the station as title
      If InStr(pTitle, "kbps") Then
        pTitle = station
        oldPTitle = station
      End If

      'switch every 10 seconds between station name and title
      If mediaPos % 10 = 0 Then
        If (pTitle = station) Then
          if oldPtitle<>"" then pTitle = oldpTitle
        Else
          pTitle = station
        End If
        musicFrame.RefreshRect(rects["text"])
      End If
    End If
  End If
End Sub


Sub convertFile()
  'get the target format
  Dim ext As String = recModes[recMode]

  'nothing to do, if the target format is the same as the recording format
  If wxFileExists(recName &pCodec) And (ext <> pCodec) Then
    convPrc = New wxProcess(musicFrame)
    convPrc.Redirect()
    Connect(convPrc, wxEVT_END_PROCESS, "onEndConvProcess")

    'set the paths
    Dim pathOpt As String = Chr(34) &recName &pCodec &Chr(34) &" -o " &Chr(34) &recName &ext &Chr(34)
    If (pCodec = "aac") And (ext = "m4a") Then
      'convert from aac to m4a has the same AAC codec
      'this means the data can be copied
      Dim cmd = Chr(34) &phiolaPath &Chr(34) &" convert -copy " &pathOpt

    Else
      'convert the data
      cmd = Chr(34) &phiolaPath &Chr(34) &" convert "  &pathOpt
    End If

    Dim pid = wxExecute(cmd, wxEXEC_ASYNC, convPrc)
    If !pid Then
      ~convPrc

    Else

      'read the stream
      Dim inStream As wxInputStream = convPrc.GetInputStream()
      Dim errStream As wxInputStream = convPrc.GetErrorStream()

      If inStream And inStream.IsOk() Then
        Dim cnt As Integer = 0
        While !inStream.Eof()
          cnt += 1
          instream.Read(1)
          If cnt % 1000 = 0 Then app.Yield()
        Wend

        While !errStream.Eof()
          errstream.Read(1)
        Wend
      End If
    End If
  End If
End Sub


Sub onEndConvProcess(event As wxProcessEvent)
  convPrc = Nothing
  If recDel And wxFileExists(recName &recModes[recMode]) Then Kill(recName &pCodec)
End Sub


'show the main menu
Sub onPlayerPopupMenu(event As wxMouseEvent) Handles musicFrame.RightUp(-1)
  If (playMode = ID_PLAY_WEBRADIO) And mFileWebRadio >= 0 Then findFavSation()
  Dim pos = musicFrame.ScreenToClientPoint(wxGetMousePosition())
  musicFrame.PopupMenuPoint(musicMenu, pos)
End Sub


'import a radio playlist
Sub onImportPlaylistRadio(event As wxCommandEvent)
  If playMode != ID_PLAY_WEBRADIO Then
    Dim dl = wxGenericMessageDialog(Nothing, _("This option imports a web radio playlist.") &"\n" &_("Please switch the play mode to web radio."), _("Attention"), wxOK|wxCENTRE|wxICON_EXCLAMATION|wxDIALOG_NO_PARENT)
    dl.ShowModal()
    Return
  End If

  fd.SetDirectory(playerPath)
  fd.SetMessage(_("Select the radio playlist to import"))
  fd.SetWildcard("*.m3u")
  fd.SetWindowStyle(wxFD_OPEN)

  If fd.ShowModal() = wxID_OK Then
    Dim impPlaylist = fd.GetPath()

    If wxFileExists(impPlaylist) Then
      allMediaFiles.Clear()
      allMediaFilesInt.Clear()

      'hold the station names for compare
      For i = 0 To lcWeb.GetItemCount() - 1
        allMediaFiles.Add(LCase(lcWeb.GetStringItem(i, 2)))
      Next

      importPlaylist(impPlaylist, 1)
    End If
  End If
End Sub


'set a new playmode
Sub onSetPlayMode(event As wxCommandEvent) Handles musicframe.menuselected(ID_PLAY_WEBRADIO), musicframe.menuselected(ID_PLAY_WEBTV), musicframe.menuselected(ID_PLAY_PODCAST), 
    musicframe.menuselected(ID_PLAY_FILE)

  Dim noLog As wxLog = wxLogNull()
  pTitle = ""

  If validation Then
    Dim dl = wxGenericMessageDialog(Nothing, _("When changing Play mode, the test Is interrupted.") &"\n" &_("Proceed anyway?"), _("Attention"), wxYES_NO|wxCENTER|wxICON_EXCLAMATION|wxDIALOG_NO_PARENT)
   'wxNO = 5104 in wxGenericMessageDialog
    If dl.ShowModal() = 5104 Then Return

    validateExit()
  End If

  'stop phiola
  If isPlayed Then killphiola()

  'stop playing tv
  killTV()

  'set new playmode
  SetPlayMode(event.GetID(), TRUE)
  ~noLog
End Sub


'set the playmode
Sub setPlayMode(pm As Integer, loadDatabase As Integer)
  Dim splitterMedia As wxSplitterWindow = DynamicCast("wxSplitterWindow", musicFrame.FindWindowByName("splitter"))
  Dim explorerMedia As wxGenericDirCtrl = DynamicCast("wxGenericDirCtrl", musicFrame.FindWindowByName("explorermedia"))
  Dim htmlWin As wxHtmlWindow = DynamicCast("wxHtmlWindow", musicFrame.FindWindowByName("htmlwin"))
  Dim titleSizer As wxSizer = titleFrame.GetSizer()
'  Disconnect(titleFrame, -1, wxEVT_SIZE)

  Dim cfg As wxFileConfig = wxFileConfig("", "", playerIni)
  Dim buffer As String = ""

  'write the playlist position, size and the column widths from the old playmode to the config
  If playMode = ID_PLAY_FILE Then
    cfg.SetPath("/File")
    For i = 0 To 4
      buffer &= lcMedia.GetColumnWidth(i) &IIf(i < 4, ",", "")
    Next

  Elsif playmode = ID_PLAY_PODCAST Then
    cfg.SetPath("/Podcast")
    For i = 0 To 3
      buffer &= lcPod.GetColumnWidth(i) &IIf(i < 3, ",", "")
    Next
  Else

    cfg.SetPath("/Web")
    For i = 0 To 3
      buffer &= lcWeb.GetColumnWidth(i) &IIf(i < 3, ",", "")
    Next
  End If

  If !titleFrame.IsMaximized() Then
    cfg.Write("Size", titleFrame.GetSizeWidth() &"," &titleFrame.GetSizeHeight())
    cfg.Write("Pos", titleFrame.GetPositionX() &"," &titleFrame.GetPositionY())
  End If
  cfg.Write("columnWidth", buffer)

  'hide not needed controls and show controls from the new playmode
  playMode = pm
  titleFrame.Freeze()

  'enable or disable menuitems
  enableMenuItems()
  setColumnWidths()

  Dim up As wxWindow = wxFindWindowByName("up")
  Dim down As wxWindow = wxFindWindowByName("down")
  Dim sc As wxWindow = wxFindWindowByName("searchctrl")
  Dim selB As wxWindow = wxFindWindowByName("select")

  Select Case playMode
  Case ID_PLAY_FILE
    If splitterMedia.IsSplit() Then
      splitterMedia.Unsplit(htmlWin)
      splitterMedia.ReplaceWindow(lcPod, explorerMedia)
    Else
      splitterMedia.ReplaceWindow(lcWeb, explorerMedia)
    End If

    splitterMedia.SplitVertically(explorerMedia, lcMedia, 200)
    cfg.SetPath("/File")
    Dim sashPos = cfg.Read("SashPos", 250)
    If musicMenu.IsChecked(ID_EDIT_WEBLIST) Then titleSizer.HideSizer(hMediaSizer)
    splitterMedia.SetSashPosition(IIf ( !sashPos, 250, sashPos))

    explorerMedia.Show(TRUE)
    lcMedia.Show(TRUE)
    lcWeb.Show(FALSE)
    lcPod.Show(FALSE)
    htmlWin.Show(FALSE)
    sc.Enable(TRUE)
    selb.Enable(TRUE)
    wxYield()

    'show or hide the music title
    showTitle(showMusicTitle)

    titleSizer.Layout()
    titleFrame.Thaw()

    selectDir(TRUE, TRUE)

    'play files
    Dim path As String = lcMedia.GetStringItem(musicFile, 5)
    pTitle = wxFileNameFromPath(path)
    rects["text"] = New wxRect(1 * ps, 19 * ps, musicFrame.GetSizeWidth(), musicFrame.GetSizeHeight() - (19 * ps))
    getFileInfo(lcmedia.GetStringItem(Val(lcMedia.FindItem(-1, "  " &musicFile)), 5), -1)


  Case ID_PLAY_PODCAST
    rects["text"] = New wxRect(1 * ps, 19 * ps, musicFrame.GetSizeWidth(), musicFrame.GetSizeHeight() - (19 * ps))

    cfg.SetPath("/Podcast")
    sashPos = cfg.Read("SashPos", titleframe.GetSizeWidth() - 280)

    If splitterMedia.IsSplit() Then
      splitterMedia.Unsplit(lcMedia)
      splitterMedia.ReplaceWindow(explorerMedia, lcPod)
    Else
      splitterMedia.ReplaceWindow(lcWeb, lcPod)
    End If

    splitterMedia.SplitVertically(lcPod, htmlWin, sashPos)
    splittermedia.Update()
    htmlWin.Show(TRUE)
    lcPod.Show(TRUE)
    lcWeb.Show(FALSE)
    explorerMedia.Show(FALSE)
    lcMedia.Show(FALSE)

    If musicMenu.IsChecked(ID_EDIT_WEBLIST) Then titleSizer.ShowSizer(hMediaSizer)

    up.Enable(FALSE)
    down.Enable(FALSE)
    sc.Enable(FALSE)
    selb.Enable(FALSE)

    showTitle(showPodTitle)
    showEditWebList()

    titleFrame.Layout()
    titleSizer.Layout()
    titleFrame.Thaw()
    wxSafeYield(titleframe)

    'the list is empty, load podcast list and infos
    Dim Item = lcPod.GetFirstItem()
    If !Item.IsOk() And loadDatabase Then loadPlaylistPodcast()

    If podUrl <> "" Then
      Dim podcAst As wxTreeListItem = findPodcastItem(podUrl, FALSE)
      If podcast Then
        pTitle = lcPod.GetItemText(podcast, 0)
        podLen = getTimeFromString(lcPod.GetItemText(podcast, 1), FALSE, FALSE)
        'set the position slider pos
        Dim spos = (podPos / podLen * (200 * ps))
        rects["mPos"].SetX(rects["mSlider"].GetX() - (5 * ps) + sPos)
      End If
    End If

  Case Else

    up.Enable(TRUE)
    down.Enable(TRUE)
    sc.Enable(TRUE)
    selb.Enable(TRUE)
    editMenu.Enable(ID_FAV_MENU, playmode = ID_PLAY_WEBRADIO)
    editMenu.Enable(ID_VALIDATE_SEL, playmode = ID_PLAY_WEBRADIO)
    editMenu.Enable(wxID_INFO, playmode = ID_PLAY_WEBRADIO)

    rects["text"] = New wxRect(rects["rec"].GetRight()+ (5 * ps), 1 * ps, rects["mute"].GetX() - rects["rec"].GetRight() - (10 * ps), 20 * ps)
    If splitterMedia.IsSplit() Then
      showTitle(FALSE)
      splitterMedia.Unsplit()
    End If

    splitterMedia.ReplaceWindow(splitterMedia.GetWindow1(), lcWeb)
    splittermedia.Update()

    lcWeb.Show(TRUE)
    htmlWin.Show(FALSE)
    lcPod.Show(FALSE)
    explorerMedia.Show(FALSE)
    lcMedia.Show(FALSE)
    If musicMenu.IsChecked(ID_EDIT_WEBLIST) Then titleSizer.ShowSizer(hMediaSizer)
    showEditWebList()

    titleSizer.Layout()
    titleFrame.Thaw()

    If Str(playMode) != titleFrame.GetName() Then loadPlaylistWeb()
    titleFrame.SetName(playmode)
  End Select

  If isBroken Then Return
'  Connect(titleFrame, -1, wxEVT_SIZE, "onListSize")

  'select the file or station without start it
  setFile(TRUE)
  musicFrame.Refresh()
End Sub


'enable/disable the menu items
Sub enableMenuItems()
  'web items
  musicMenu.Enable(ID_RELOAD_FILELIST, (playMode = ID_PLAY_WEBRADIO) Or (playMode = ID_PLAY_WEBTV))
  musicMenu.Enable(ID_MULTISORT, (playMode = ID_PLAY_WEBRADIO) Or (playMode = ID_PLAY_WEBTV))
  musicMenu.Enable(ID_EDIT_WEBLIST, playMode != ID_PLAY_FILE)
  musicMenu.Enable(ID_SHOW_FAVORITE, playMode = ID_PLAY_WEBRADIO)

  'file items
  musicMenu.Enable(ID_SHUFFLE, playMode = ID_PLAY_FILE)
  musicMenu.Enable(ID_SHUFFLE, playMode = ID_PLAY_FILE)
  musicMenu.Enable(ID_PAUSE_MEDIA, playMode = ID_PLAY_FILE)
  musicMenu.Enable(ID_CREATE_PLAYLIST, playMode = ID_PLAY_FILE)
  musicMenu.Enable(ID_CONVERT, playMode = ID_PLAY_FILE)
  musicMenu.Enable(ID_NORMALIZE, playMode = ID_PLAY_FILE)

  'task menu
  musicTaskMenu.Enable(ID_PAUSE_MEDIA, playMode = ID_PLAY_FILE)
  musicTaskMenu.Enable(ID_SHUFFLE, playMode = ID_PLAY_FILE)
  musicTaskMenu.Check(ID_PLAY_WEBRADIO, playMode = ID_PLAY_WEBRADIO)
  musicTaskMenu.Check(ID_PLAY_WEBTV, playMode = ID_PLAY_WEBTV)
  musicTaskMenu.Check(ID_PLAY_FILE, playMode = ID_PLAY_FILE)
  musicTaskMenu.Check(ID_PLAY_PODCAST, playMode = ID_PLAY_PODCAST)
End Sub


'shuffle title in listctrl
Sub onShuffle(event As wxCommandEvent) Handles musicframe.menuselected(ID_SHUFFLE)
  Dim stations = {}
  Dim cnt = lcMedia.GetItemCount()

  For i = 0 To lcMedia.GetItemCount() - 1
    stations[i, 0]= lcMedia.GetStringItem(i, 0)
    stations[i, 1]= lcMedia.GetStringItem(i, 1)
    stations[i, 2]= lcMedia.GetStringItem(i, 2)
    stations[i, 3]= lcMedia.GetStringItem(i, 3)
    stations[i, 4]= lcMedia.GetStringItem(i, 4)
    stations[i, 5]= lcMedia.GetStringItem(i, 5)
  Next

  'store numbers of titles in a table 
  Dim a = {}
  For i = 1 To cnt
    a[i]= i
  Next

  Dim b As Integer
  Dim c As wxArrayInt = wxArrayInt()

  'shuffle numbers and ignore double generated numbers 
  While a.Count() > 0
    'create a random number between 1 and the listctrl count
    b = Rnd(cnt)
    'test if the number is already present in the arrayint
    If c.INDEX(b)= -1 Then
      'add this number to an arrayint
      c.Add(b)
      'remove the number from the table
      a.Remove(b)
    End If
  Wend

  'clear listctrl and add the random titles
  lcMedia.DeleteAllItems()
  For i = 0 To c.Count() - 1
    lcMedia.InsertStringItem(i, stations[c.Item(i) - 1, 0])
    lcMedia.SetItemData(i, 0)
    lcMedia.SetStringItem(i, 1, stations[c.Item(i) - 1, 1])
    lcMedia.SetStringItem(i, 2, stations[c.Item(i) - 1, 2])
    lcMedia.SetStringItem(i, 3, stations[c.Item(i) - 1, 3])
    lcMedia.SetStringItem(i, 4, stations[c.Item(i) - 1, 4])
    lcMedia.SetStringItem(i, 5, stations[c.Item(i) - 1, 5])
  Next

  If musicFile >= 0 Then
    'find the current played music title
    Dim sel = lcMedia.FindItem(0, "  " &musicFile)
    
    lcMedia.SetItemTextColour(sel, musicHiColour)
    lcMedia.EnsureVisible(sel)
  End If

  storeMediaFiles()
End Sub


'show/hide the edit button bar
Sub onShowEditWebList(event As wxCommandEvent) Handles musicframe.menuselected(ID_EDIT_WEBLIST)
  showEditWebList()
End Sub


Sub showEditWebList()
  Disconnect(lcWeb, -1, wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK)
  Dim titleSizer As wxSizer = titleFrame.GetSizer()

  If musicMenu.IsChecked(ID_EDIT_WEBLIST) And (playMode != ID_PLAY_FILE) Then
    titleSizer.ShowSizer(hMediaSizer)
    Connect(lcWeb, -1, wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK, "onEditMenu")
    Connect(lcWeb, -1, wxEVT_COMMAND_LIST_BEGIN_DRAG, "onDragBegin")
    Connect(lcWeb, -1, wxEVT_MOTION, "onDragMotion")
    Connect(lcWeb, -1, wxEVT_LEFT_UP, "onDragEnd")

  Elseif titleSizer.IsSizerShown(hMediaSizer) Then
    titleSizer.HideSizer(hMediaSizer)
    Connect(lcWeb, -1, wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK, "onFavMenu")
    Disconnect(lcWeb, -1, wxEVT_COMMAND_LIST_BEGIN_DRAG)
    Disconnect(lcWeb, -1, wxEVT_MOTION)
    Disconnect(lcWeb, -1, wxEVT_LEFT_UP)
  End If

  titleFrame.SendSizeEvent()
End Sub


'export a playlist
Sub onExportPlaylist(event As wxCommandEvent)
  Dim id As Integer = event.GetID()
  If (id = ID_EXPORT_MUSIC) And (playMode != ID_PLAY_WEBRADIO) then
    Dim dl = wxGenericMessageDialog(Nothing, _("This option saves the currently visible web music playlist without a database.") &"\n" &_("This means the current play mode must be web radio."), _("Attention"), wxOK|wxCENTRE|wxICON_EXCLAMATION|wxDIALOG_NO_PARENT)
    dl.ShowModal()
    Return
  End If

  fd.SetDirectory("")
  fd.SetFileName("playlist.m3u")
  fd.SetMessage(_("Choose the file name"))
  fd.SetWildcard("*.m3u")
  fd.SetWindowStyle(wxFD_SAVE)

  If fd.ShowModal() = wxID_OK Then
    Dim path As String = fd.GetPath()

    If wxFileExists(path) Then
      dl = wxGenericMessageDialog(Nothing, _("The file already Exists!") &"\n" &_("Overwrite?"), _("Attention"), wxYES_NO|wxYES_DEFAULT|wxICON_EXCLAMATION|wxCENTRE|wxDIALOG_NO_PARENT)
      'wxNo = 5104 in wxGenericMessageDialog
      If dl.ShowModal() = 5104 Then Return
    End If

    exportStations(event.GetID(), path)
  End If
End Sub


Sub UseUpperLine(UseLine As Integer)
  If UseLine Then
    'calculate line width for all monitors
    Dim cnt As Integer = wxDisplay_GetCount()
    Dim disp, rect
    Dim x = 0

    For i = 1 To cnt
      disp = wxDisplay(i - 1)
      rect = disp.GetGeometry()
      x += rect.GetWidth()
    Next

    lineFrame = New wxFrame(musicFrame, wxID_ANY, "", wxPoint(0, 0), wxSize(x, 1), wxNO_BORDER|wxSTAY_ON_TOP|wxFRAME_NO_TASKBAR)
    lineFrame.Show(TRUE)
    Connect(lineFrame, -1, wxEVT_LEFT_DOWN, "onShowMusicFrame")

  Else

    ~lineFrame
    lineFrame = Nothing
  End If
End Sub


'show the title in file or podcast mode
Sub ShowTitle(showFlag As Integer)
  Dim mode As Integer = IIf((playMode = ID_PLAY_FILE) Or (playMode = ID_PLAY_PODCAST), TRUE, FALSE)
  Dim x As Integer = musicFrame.GetSizeWidth()
  Dim y As Integer = IIf(showFlag And mode, 45 * ps, 24 * ps)

  ~iList["frame"]
  iList["frame"] = New wxEmptyBitmap(x, y)
  setTheme()

  musicFrame.SetSizeXY(x, y)

  Dim memDC As wxMemoryDC = wxMemoryDCFromBitmap(wxEmptyBitmap(x, y))
  Dim gc = wxGraphicsContext_CreateFromMemoryDC(memDC)
  Dim path As wxGraphicsPath = gc.CreatePath()

  path.AddRoundedRectangle(0, 0, x, y, 6 * ps)
  musicFrame.SetShapeGraphicsPath(path)
  musicFrame.Refresh()
  memDC.SelectObject(wxNullBitmap)
  ~memDC

  If dockList Then titleFrame.MoveXY(titleFrame.GetPositionX(), musicFrame.GetPositionY() + musicFrame.GetSizeHeight())
End Sub


'show or remove icons
Sub iconsShow()
  If useIcons Then
    useIcons = TRUE
    Dim ilWeb = New wxImageList(stationIconSize, stationIconSize, TRUE)
    lcWeb.SetImageList(ilWeb, 1)
    stationsIconsLoad()

  Else

    useIcons = FALSE
    lcWeb.SetImageList(wxImageListEmpty(), 1)
    ilWeb = lcWeb.GetImageList(1)
    ilWeb.RemoveAll()
    ilWeb = Nothing
  End If
End Sub


'update the playlist
Sub onPlaylistsUpdate(event As wxCommandEvent)
  If !((playMode = ID_PLAY_WEBRADIO) Or (playMode = ID_PLAY_WEBTV)) Then
    Dim dl = wxGenericMessageDialog(Nothing, _("This option update web playlists.") &"\n" &_("Please switch the play mode to web radio or web TV."), _("Attention"), wxOK|wxCENTRE|wxICON_EXCLAMATION|wxDIALOG_NO_PARENT)
    dl.ShowModal()
    Return
  End If

  Dim readerPath As String = selectDownloadReader()
  Dim isTV As Integer = (playMode = ID_PLAY_WEBTV)

  If !wxFileExists(readerPath) Then
    dl = wxGenericMessageDialog(Nothing, _("No download program specified"), _("Attention"), wxOK|wxCENTRE|wxICON_EXCLAMATION|wxDIALOG_NO_PARENT)
    dl.Raise()
    dl.ShowModal()
    Return
  End If

  'we can update the playlist comletely with all new stations or we only update the stations that are already in the list
  'this can be advantageous if you have deleted many unnecessary stations from the list
  dl = wxDialog(Nothing, -1, _("Webupdate:"), wxDefaultPosition, wxSize(-1, -1), wxSTAY_ON_TOP|wxDEFAULT_DIALOG_STYLE|wxDIALOG_NO_PARENT)
  dl.Center()

  Dim sBox As wxStaticBox = wxStaticBox(dl, -1, _("Update options:"), wxPoint(10, 5), wxSize(-1, -1))
  Dim rb1 As wxRadioButton = wxRadioButton(sBox, -1, _("Only update existing stations"), wxPoint(10, 30), wxDefaultSize, wxRB_GROUP)
  Dim rect = rb1.GetRect()
  Dim rb2 As wxRadioButton = wxRadioButton(sBox, -1, _("Import new stations and update existing ones"), wxPoint(10, rect.GetBottom()+ 2))
  rect = rb2.GetRect()
  Dim cb1 As wxCheckBox = wxCheckBox(sbox, -1, _("Ignore duplicate station addresses in possibly other genres"), wxPoint(10, rect.GetBottom()+ 10))

  rect = cb1.GetRect()
  Dim w As Integer = rect.GetRight()+ 30
  Dim rb3 As wxRadioButton = wxRadioButton(sBox, -1, _("Only stations from the Kodi IPTV playlist"), wxPoint(10, rect.GetBottom()+ 10), wxDefaultSize, wxRB_GROUP)
  rect = rb3.GetRect()
  Dim rb4 As wxRadioButton = wxRadioButton(sBox, -1, _("Only stations from IPTV playlists (with station logos)"), wxPoint(10, rect.GetBottom()+ 2))
  rect = rb4.GetRect()
  Dim rb5 As wxRadioButton = wxRadioButton(sBox, -1, _("Only stations from music playlists (without station logos)"), wxPoint(10, rect.GetBottom()+ 2))
  rect = rb5.GetRect()
  Dim rb6 As wxRadioButton = wxRadioButton(sBox, -1, _("All of that"), wxPoint(10, rect.GetBottom()+ 2))
  rect = rb6.GetRect()
  sBox.SetClientSizeWH(w - 20, rect.GetBottom()+ 10)

  rb1.SetValue(TRUE)
  rb3.SetValue(TRUE)
  cb1.SetValue(TRUE)

  'the checkboxes are not interesting for tv playlist
  If isTV Then rb5.Enable(FALSE)

  rect = sbox.GetRect()
  Dim buttonOK = wxButton(dl, wxID_OK, _("Ok"), wxPoint(0, rect.GetBottom()), wxSize(w / 2, 25))
  Dim buttonCancel = wxButton(dl, wxID_CANCEL, _("Cancel"), wxPoint(w / 2, rect.GetBottom()), wxSize(w / 2, 25))
  rect = buttonOK.GetRect()
  dl.SetClientSizeWH(w, rect.GetBottom())

  If dl.ShowModal()= wxID_OK Then
    'hold the station names to compare existing stations
    allMediaFiles.Clear()
    allMediaFilesInt.Clear()
    isBroken = FALSE

    For i = 0 To lcWeb.GetItemCount() - 1
      allMediaFiles.Add(LCase(lcWeb.GetStringItem(i, 2)))
    Next

    'set the language codes from the filenames
    langCodes = {"afghanistan": "AF", "albania": "AL", "algeria": "DZ", "andorra": "AD", "argentina": "AR", "armenia": "AM", 
    "azerbaijan": "AZ", "australia": "AU", "austria": "AT", 
    "belarus": "BY", "belgium": "BE", "bosnia-and-herzegovina": "BA", "bosnia and herzegovina": "BA", "bolivia": "BO", 
    "brazil": "BR", "bulgaria": "BG", "canada": "CA", "chad": "TD", "chile": "CL", 
    "china": "CN", "colombia": "CO", "costa rica": "CR", "croatia": "HR", "cyprus": "CY", "czech": "CZ", "czech republic": "CZ", 
    "denmark": "DK", "deutsch": "DE", "germany": "DE", "dominica": "DM", "dominican republic": "DO", "ecuador": "EC", 
    "egypt": "EG", "el-salvador": "SV", "estonia": "EE", "faroe islands": "FO", "finland": "FI", "france": "FR", 
    "georgia": "GE", "ghana": "GH", 
    "greek": "GR", "greece": "GR", "greenland": "GL", "guatemala": "GT", "haiti": "HT", 
    "honduras": "HN", "hong kong": "HK", "hungary": "HU", "iceland": "IS", "india": "IN", "iran": "IR", "iraq": "IQ", 
    "indonesia": "ID", "irland": "IE", "ireland": "IE", "israel": "IL", "italian": "IT", "italy": "IT", "vod italy": "IT", 
    "jamaica": "JM", "japan": "JP", "kazakhstan": "KZ", "kenya": "KE", 
    "korea": "KE/KR", "kosovo": "RS-KM", "kyrgyzstan": "KG", "latvia": "LV", "lebanon": "LB", "lithuania": "LT", "luxembourg": "LU", 
    "macau": "MO", "macedonia": "", 
    "malaysia": "MY", "mali": "ML", "malta": "MT", "mexico": "MX", "moldova": "MD", "monaco": "MC", "montenegro": "ME", 
    "morocco": "MA", "nepal": "NP", "netherlands": "NL", "north korea": "KP", "south korea": "KR", 
    "nicaragua": "NI", "nigeria": "NG", "north macedonia": "MK", "norway": "NO", "pakistan": "PK", "palestine": "PS", 
    "panama": "PA", "paraguay": "PY", "peru": "PE", "philippines": "PH", 
    "polish": "PL", "poland": "PL", "portugal": "PT", "puerto-rico": "PR", "qatar": "QA", "romanian": "RO", "romania": "RO", 
    "russian": "RU", "russia": "RU", "san marino": "SM", "saudi arabia": "SA", "serbia": "RS", "slovakia": "SK", 
    "slovenia": "SI", "somalia": "SO", "south-africa": "ZA", "spain": "ES", "es": "ES", "spain vod": "ES", "sri-lanka": "LK", "sweden": "SE", 
    "switzerland": "CH", "syria": "SY", "taiwan": "TW", "tamil": "", "thailand": "TH", "trinidad": "TT", 
    "tunisia": "TN", "turk": "TR", "turkey": "TR", "uganda": "UG", "ukraine": "UA", "united-arab-emirates": "AE", "united arab emirates": "AE", 
    "united-kingdom": "UK", "uk": "UK", "uruguay": "UY", "usa": "US", "usa vod": "US", "venezuela": "VE"}

    'use 'SetName' for holding the update options
    'it's not intended for that, but it's the easiest way to hold the data
    lcWeb.SetName(rb1.GetValue() &cb1.GetValue())

    If isTV Then
      If rb3.GetValue() Or rb6.GetValue() Then
        mediaList.Add("https://jnk22.github.io/kodinerds-iptv/iptv/clean/clean.m3u")
      End If

      If rb4.GetValue() Or rb6.GetValue() Then
        mediaList.Add("https://raw.githubusercontent.com/Free-TV/IPTV/master/playlist.m3u8")
        mediaList.Add("https://iptv-org.github.io/iptv/index.m3u")
      End If

    Else

      If rb3.GetValue() Or rb6.GetValue() Then
        'download the kodi IPTV playlist
        mediaList.Add("https://jnk22.github.io/kodinerds-iptv/iptv/clean/clean.m3u")
      End If

      If rb5.GetValue() Or rb6.GetValue() Then
        'download pure music playlists without icons
        mediaList.Add("https://github.com/junguler/m3u-radio-music-playlists/raw/main/all-online_radio/---everything-full.m3u")
      End If

      If rb4.GetValue() Or rb6.GetValue() Then
        'download the main directory content of the github repo
        'this contents handle IPTV different playlists with icons
        'the all in one file has lost many stations, so load each genre individually
        mediaList.Add("https://api.github.com/repos/junguler/m3u-radio-music-playlists/contents")
      End If
    End If

    Dim noLog As wxLog = wxLogNull()
    If mediaList.Count() Then
      Dim x, y
      x, y = wxDisplaySize()
      mProgressDlg = New wxGenericProgressDialog(_("Update playlist") &":", "", mediaList.Count(), musicFrame, wxPD_AUTO_HIDE|wxPD_APP_MODAL|wxPD_CAN_ABORT)
      mProgressDlg.SetSize(wxSize(400, 190))
      mProgressDlg.SetPosition(wxPoint(x / 2 - 200, y / 2 - 90))
      mProgressDlg.SetName(0)
      mProgressDlg.Fit()

      Dim selection As Integer = lcWeb.FindItem(0, "  " &IIf(isTV, mFileWebTV, mFileWebRadio))
      If (selection >= 0) Then lcWeb.SetItemTextColour(selection, musicFontColour)

      FilesDownload(mediaList.Item(0))
    End If

    ~noLog
  End If

  dl.Destroy()
End Sub


'download icons
Sub onIconsDownload(event As wxCommandEvent)
  Dim readerPath As String = selectDownloadReader()
  If !wxFileExists(readerPath) Then
    Dim dl = wxGenericMessageDialog(Nothing, _("No download program specified"), _("Attention"), wxOK|wxCENTRE|wxICON_EXCLAMATION|wxDIALOG_NO_PARENT)
    dl.ShowModal()
    Return

  Elseif !wxFileExists(playerPath &DELIMITER_CHAR &"IPTV.db") Then
    dl = wxGenericMessageDialog(Nothing, _("No playlist found!"), _("Attention"), wxOK|wxCENTRE|wxICON_EXCLAMATION|wxDIALOG_NO_PARENT)
    dl.ShowModal()
    Return
  End If

  Dim NewLine As String
  Dim iconPath As String
  Dim at As Integer
  Dim FileName As wxFileName = wxFileName("")

  If !wxFileExists(playerPath &DELIMITER_CHAR &"stationLogos.zip") Then
    out = wxFFileOutputStream(playerPath &DELIMITER_CHAR &"stationLogos.zip")
    zip = wxZipOutputStream(out, -1, wxConvUTF8)

    dbc = wxDbConnection("DBQ=IPTV.db;DefaultDir=.;Driver=SQLITE3;")
    If dbc.IsOpen() Then
      dbc.ExecSql("PRAGMA synchronous = OFF")
      dbc.ExecSql("PRAGMA journal_mode = MEMORY")
      dbc.ExecSql("PRAGMA cache_size = 1000000")
      dbc.ExecSql("PRAGMA locking_mode = EXCLUSIVE")
      dbc.ExecSql("PRAGMA temp_store = MEMORY")
      dbc.ExecSql("SET CHARACTER_SET 'utf8'")

      Dim recSet As wxDbRecordset
      Dim cnt As Integer = 0

      For i = 1 To 2
        If i = 1 Then
          recSet = wxDbRecordset(dbc, "select * from radio")
        Else
          recSet = wxDbRecordset(dbc, "select * from tv")
        End If

        recSet.MoveFirst()
        While Not recSet.IsEOF()
          iconPath = recSet.FieldPos(6)
          If (iconPath <> "") Then
            FileName.AssignPath(iconPath)

            'some icon paths from imported lists are incorrect and has no extension
            If FileName.HasExt() Then
              If (mediaList.INDEX(iconPath)= -1) Then mediaList.Add(iconPath) 
            End If
          End If
          recSet.MoveNext()

          If cnt % 1000 = 0 Then wxSafeYield(musicFrame, TRUE)
          cnt += 1
        Wend
        recset.Close()
      Next
    End If

  Else

    'search for icons in zip
    Dim fs As wxFileSystem = wxFileSystem()
    Dim fsFile As wxFSFile

    For i = 0 To lcWeb.GetItemCount() - 1
      iconPath = lcWeb.GetStringItem(i, 5)

      If (iconPath <> "") Then
        FileName.AssignPath(iconPath)

        If !FileName.HasExt() Then
         lcWeb.SetStringItem(i, 5, "")
          Continue
        End If

        fsfile = fs.OpenFile(playerPath &DELIMITER_CHAR &"stationLogos.zip" &"#zip:" &FileName.GetName() &"." &"png")
        If !fsFile Then
          mediaList.Add(iconPath) 

        Else
          ~fsFile
        End If
      End If
    Next

    If mediaList.Count() Then
      If wxFileExists(wxFileName_GetTempDir() &DELIMITER_CHAR &"tempdb.zip") Then Kill(wxFileName_GetTempDir() &DELIMITER_CHAR &"tempdb.zip")

      'create as temporary zip file
      'wxTempFileOutputStream would be better, but it is not implemented yet
      'we'll need these destroyed before Commit in wxTempFileOutputStream
      out = New wxFFileOutputStream(wxFileName_GetTempDir() &DELIMITER_CHAR &"tempdb.zip")
      zip = New wxZipOutputStream(out, 8, wxConvUTF8)
      Dim zipFile As wxFFileInputStream = wxFFileInputStream(playerPath &DELIMITER_CHAR &"stationLogos.zip")
      Dim zin As wxZipInputStream = wxZipInputStream(zipFile, wxConvUTF8)
      Dim entry As wxZipEntry

      'copy archive entrys to temp archive
      entry = zin.GetNextEntry()
      While entry
        zip.CopyEntry(entry, zin)

        Deallocate(entry)
        entry = zin.GetNextEntry()
      Wend

      'comments are stored at the end
      zip.CopyArchiveMetaData(zin)
      ~zin
      ~zipFile
    End If

    ~fs
  End If


  If mediaList.Count() Then
    Dim x, y As Integer
    x, y = wxDisplaySize()
    mProgressDlg = New wxGenericProgressDialog(_("Download station logos") &":", "", mediaList.Count(), Nothing, wxPD_AUTO_HIDE|wxPD_APP_MODAL|wxPD_CAN_ABORT|wxMINIMIZE_BOX)
    mProgressDlg.SetSize(wxSize(400, 190))
    mProgressDlg.SetPosition(wxPoint(x / 2 - 200, y / 2 - 90))
    mProgressDlg.SetName(0)

    FilesDownload(mediaList.Item(0))
  End If
End Sub


'left mouse button is pressed in playlist
Sub onListDown(event As wxMouseEvent) Handles titleFrame.leftdown
  Dim point  As wxPoint = titleFrame.ScreenToClientPoint(wxGetMousePosition()) 
  k1 = point.GetX() 
  k2 = point.GetY() 

  titleFrame.CaptureMouse()
  event.Skip()
End Sub


'move the playlist
Sub onListMove(event As wxMouseEvent) Handles titleframe.motion
  If titleFrame.IsMaximized() Then Return

  Dim point As wxPoint = titleFrame.ScreenToClientPoint(wxGetMousePosition()) 
  Dim x = point.GetX() 
  Dim y = point.GetY()

  If event.LeftIsDown() Then
      Dim winx = titleFrame.GetPositionX()
      Dim winy = titleFrame.GetPositionY()
      Dim winxtest = winx + x - k1
      Dim winytest = winy + y - k2 

      If winxtest < 0 Then winXTest = 0
      If winytest < 0 Then winYTest = 0 

      winx = winxtest 
      winy = winytest 

      titleFrame.MoveXY(winx, IIf(dockList, musicFrame.GetPositionY() + musicFrame.GetSizeHeight(), winy)) 
  End If
End Sub


'left mouse button is up
'write the playlist position
Sub onListUp(event As wxMouseEvent) Handles titleframe.LeftUp
  titleFrame.ReleaseMouse()
  Dim cfg As wxFileConfig = wxFileConfig("", "", playerIni)

  If playMode = ID_PLAY_FILE Then
    cfg.SetPath("/File")

  Elseif playmode = ID_PLAY_PODCAST Then
    cfg.SetPath("/Podcast")

  Else
    cfg.SetPath("/Web")
  End If

  cfg.Write("Pos", titleFrame.GetPositionX() &"," &titleFrame.GetPositionY())
  event.Skip()
End Sub


'maximize the playlist by left doubleclick
Sub onListMaximize(event)' Handles titleframe.LeftDClick
  titleFrame.Maximize( !titleFrame.IsMaximized())
  musicFrame.Raise()

  Dim cfg As wxFileConfig = wxFileConfig("", "", playerIni)
  cfg.SetPath("/dsmPlayer")
  cfg.Write("Maximized", titleframe.IsMaximized())

  event.Skip()
End Sub


'when the title frame is docked, the size of the title frame should not be above the player
Sub onListSize(event As wxSizeEvent) Handles titleframe.Size
  If dockList And !titleFrame.IsMaximized() Then
    Dim winx = titleFrame.GetPositionX()
    Dim winy = titleFrame.GetPositionY()
    If winy <> (musicFrame.GetPositionY() + musicFrame.GetSizeHeight()) Then titleFrame.MoveXY(winx, musicFrame.GetPositionY() + musicFrame.GetSizeHeight())
  End If

  event.Skip()
End Sub


'hide button is pressed or hide player menuitem is selected
Sub onHidePlayer(event As wxCommandEvent) Handles musicframe.menuselected(ID_PLAYER_HIDE)
  showMusicFrame()
End Sub


'show the player window by left click on the top of the screen
Sub onShowMusicFrame(event As wxMouseEvent)
  showMusicFrame()
  event.Skip()
End Sub


Sub showMusicFrame()
  'effects are not force the paint event
  'so we can't use it here
  'maybe we can use it in future versions of wxwidgets or wxbasic
  If !musicFrame.IsShown() Then
    musicFrame.ShowWithEffect(wxSHOW_EFFECT_NONE, 500)
    musicFrame.Refresh()
    musicFrame.Raise()

  Else

    musicFrame.HideWithEffect(wxSHOW_EFFECT_NONE, 500)
    titleFrame.HideWithEffect(wxSHOW_EFFECT_NONE, 500)
  End If
End Sub


'set the TV player path is selected
Sub onSetTVPlayerPath(event As wxCommandEvent)
  setTVPlayerPath()
End Sub


'set the TV player path and parameters
Sub setTVPlayerPath()
  Dim dl = wxDialog(musicFrame, -1, _("Choose a TV player"), wxDefaultPosition, wxSize(660, 250))
  dl.CenterOnParent()
  Dim w As Integer = dl.GetSizeWidth()

  Dim st1 = wxStaticText(dl, -1, _("Set the path to the selected player:"), wxPoint(10, 10))
  Dim rect = st1.GetRect()
  Dim txt1 = wxFilePickerCtrl(dl, -1, tvPlayerPath, _("Set the path to the selected editor program:"), "*.*", wxPoint(10, rect.GetBottom()+ 5), wxSize(w - 20, -1), wxFLP_CHANGE_DIR|wxFLP_FILE_MUST_EXIST|wxFLP_OPEN|wxFLP_USE_TEXTCTRL)
  txt1.SetName("path")
  Connect(txt1, -1, wxEVT_COMMAND_FILEPICKER_CHANGED, "onSetNewTVPlayerPath")

  rect = txt1.GetRect()
  Dim st2 = wxStaticText(dl, -1, _("Set the parameters: (%f = file to be transferred):"), wxPoint(10, rect.GetBottom()+ 15))
  rect = st2.GetRect()
  Dim txt2 = wxTextCtrl(dl, -1, tvPlayerPara, wxPoint(10, rect.GetBottom()+ 5), wxSize(w - 20, -1))
  txt2.SetName("tvpara")

  rect = txt2.GetRect()
  Dim Ok = wxButton(dl, wxID_OK, _("Ok"), wxPoint(0, rect.GetBottom()+ 10), wxSize(w / 2, 25))
  Dim cl = wxButton(dl, wxID_CANCEL, _("Cancel"), wxPoint(w / 2, rect.GetBottom()+ 10), wxSize(w / 2, 25))
  rect = Ok.GetRect()
  dl.SetClientSizeWH(660, rect.GetBottom())

  If dl.ShowModal()= wxID_OK Then
    Dim path = txt1.GetPath()

    If !wxFileExists(path) Then
      Dim dlg = wxGenericMessageDialog(Nothing, _("The file does not exist on the disk"), _("Attention"), wxOK|wxCENTRE|wxICON_EXCLAMATION|wxDIALOG_NO_PARENT)
      dlg.ShowModal()

    Else

      tvPlayerPath = path
      tvPlayerPara = txt2.GetValue()

      Dim win As wxWindow = musicFrame.FindWindowByName("tvplayer")
      If win Then
        Dim pbtn As wxButton = DynamicCast("wxButton", win)
        pbtn.SetLabel(tvPlayerPath)
      End If
    End If
  End If

  dl.Destroy()
End Sub


'set parameters for different player
Sub onSetNewTVPlayerPath(event As wxCommandEvent)
  Dim win1 = wxFindWindowByName("path")
  Dim txt1 = DynamicCast("wxFilePickerCtrl", win1)
  Dim win2 = wxFindWindowByName("tvpara")
  Dim txt2 = DynamicCast("wxTextCtrl", win2)

  Dim FileName As wxFileName = wxFileName(txt1.GetPath())
  Dim vProg As String = FileName.GetName()

  If Left(vProg, 6)= "mpc-hc" Then
    tvPlayerPara = "/viewpreset 1 /close %f"

  Elseif Left(vProg, 6)= "mpc-be" Then
    tvPlayerPara = "/fullscreen %f"

  Elseif Left(vProg, 3)= "vlc" Then
    tvPlayerPara = "--one-instance %f"

  Else
    tvPlayerPara = "%f"
  End If

  txt2.SetValue(tvPlayerPara)
End Sub


'minimize wxEditor to tray
Sub onMinimizeToTray(event As wxCommandEvent) Handles musicframe.menuselected(ID_MEDIA_TO_TRAY)
  minimizeToTray()
End Sub


'set connections
Sub minimizeToTray()
  If musicFrame.IsShown() Then
    Connect(mediaTaskbarIcon, -1, wxEVT_TASKBAR_LEFT_DOWN, "onMusicTaskbarClick")
    Connect(mediaTaskbarIcon, -1, wxEVT_TASKBAR_RIGHT_DOWN, "onMusicTaskbarRightClick")
    Connect(musicFrame, -1, wxEVT_ICONIZE, "onMusicIconizeFrame")
    musicFrame.Iconize()

 Else

    Disconnect(mediaTaskbarIcon, -1, wxEVT_TASKBAR_LEFT_DCLICK)
    Disconnect(mediaTaskbarIcon, -1, wxEVT_TASKBAR_RIGHT_DOWN)
    Disconnect(musicFrame, -1, wxEVT_ICONIZE)
 End If
End Sub


'iconize frame to tray
Sub onMusicIconizeFrame(event)
  mediaTaskbarIcon.SetIcon(iList["taskbarIcon"], "dsmPlayer")
  musicFrame.Iconize(TRUE)
  musicFrame.Show(FALSE)
End Sub


'restore frame
Sub onMusicTaskbarClick(event As wxTaskBarIconEvent)
  restoreFromTray()
End Sub

Sub restoreFromTray()
  mediaTaskbarIcon.RemoveIcon()
  musicFrame.Iconize(FALSE)
  musicFrame.Show(TRUE)
  musicFrame.Raise()
  musicFrame.SetFocus()
End Sub


'show menu from tray
Sub onMusicTaskbarRightClick(event As wxTaskBarIconEvent)
  mediaTaskbarIcon.PopupMenu(musicTaskMenu)
End Sub


'show the options dialog
Sub onOptions(event As wxCommandEvent) Handles musicframe.menuselected(ID_OPTIONS)
  Dim cfg As wxFileConfig = wxFileConfig("", "", playerIni)

  Dim optDialog = wxDialog(musicFrame, -1, "dsmPlayer " &_("Settings..."), wxDefaultPosition, wxSize(800 / Scale, 410 / Scale))
  Dim x, y As Integer
  x, y = wxDisplaySize()
  optDialog.SetPosition(wxPoint(x / 2 - 400, y / 2 - 230))

  Dim font As wxFont = optDialog.GetFont()
  Dim fp As Integer = Round(font.GetPointSize() * ps * Scale)
  If fp < 9 Then fp = 9
  font.SetPointSize(fp)
  optDialog.SetFont(font)

  Dim notebook As wxListbook = wxListbook(optDialog, -1, wxDefaultPosition, wxDefaultSize, wxBK_LEFT)
  notebook.FitInside()

  Dim lv = notebook.GetListView()
  lv.SetColumnWidth(0, 150 / Scale)
  lv.SetBackgroundColor(wxSystemSettings_GetColour(4))
  lv.SetForegroundColor(wxBLUE)
  Deallocate(lv)

  '-------------------------------------------------------------------------------
  'create notebook pages

  'add page 1
  'general settings
  cfg.SetPath("/dsmPlayer")

  Dim panel1 = wxPanel(notebook, -1)
  Dim gb As wxGridBagSizer = wxGridBagSizer(5, 5)
  Dim sBox1 = wxStaticBox(panel1, -1, _("General settings") &":")
  gb.AddSpacer(2, 2, wxGBPosition(1, 0))

  Dim cb1 As wxCheckBox = wxCheckBox(sBox1, -1, _("Autoplay at startup"))
  gb.AddWindow(cb1, wxGBPosition(2, 1), wxDefaultSpan, wxEXPAND)
  cb1.SetValue(cfg.Read("Autoplay", FALSE))

  Dim cb2 As wxCheckBox = wxCheckBox(sBox1, -1, _("Dock playlist to player"))
  gb.AddWindow(cb2, wxGBPosition(2, 2), wxDefaultSpan, wxEXPAND)
  cb2.SetValue(dockList)

  Dim cb3 As wxCheckBox = wxCheckBox(sBox1, -1, _("Only one instance"))
  gb.AddWindow(cb3, wxGBPosition(3, 1), wxDefaultSpan, wxEXPAND)
  cb3.SetValue(cfg.Read("SingleInstance", FALSE))
  
  Dim cb4 As wxCheckBox = wxCheckBox(sBox1, -1, _("Use the top of screen to hide"))
  gb.AddWindow(cb4, wxGBPosition(3, 2), wxDefaultSpan, wxEXPAND)
  cb4.SetValue(cfg.Read("UseUpperPos", FALSE))

  Dim oldUseLine As Integer = cb4.IsChecked()
  Dim cb5 As wxCheckBox = wxCheckBox(sBox1, -1, _("Add to") &" " &Chr(34) &_("Open with...") &Chr(34) &" " &_("dialog"))
  gb.AddWindow(cb5, wxGBPosition(4, 1), wxDefaultSpan, wxEXPAND)
  Dim isOpenWith As Integer = testOpenWith()
  cb5.SetValue(isOpenWith)
  Dim oldOpenWith = isOpenWith
  gb.AddSpacer(10, 10, wxGBPosition(5, 0))

  Dim sText As wxStaticText = wxStaticText(sbox1, -1, _("Themes:"))
  gb.AddWindow(sText, wxGBPosition(6, 1), wxDefaultSpan, 0|wxALIGN_CENTER_VERTICAL)

  Dim oldTheme As Integer = theme
  Dim cols As wxArrayString = wxArrayString()
  cols.Add(_("Dark"))
  cols.Add(_("Black & White"))
  cols.Add(_("Grey"))
  cols.Add(_("Green"))
  cols.Add(_("Blue"))
  cols.Add(_("Red"))
  cols.Add(_("Brown"))

  Dim cbb1 As wxComboBox = wxComboBox3(sBox1, -1, "", wxDefaultPosition, wxSize(180 / Scale, -1), cols)
  cbb1.SetSelection(theme)
  Connect(cbb1, -1, wxEVT_COMMAND_COMBOBOX_SELECTED, "onSetTheme")
  cols.Clear()
  gb.AddWindow(cbb1, wxGBPosition(6, 2), wxDefaultSpan, 0)
  gb.AddSpacer(2, 2, wxGBPosition(7, 0))

  sText = wxStaticText(sbox1, -1, _("Language:"))
  gb.AddWindow(sText, wxGBPosition(8, 1), wxDefaultSpan, wxEXPAND|wxALIGN_CENTER_VERTICAL)

  'read all language files from the directory
  Dim langArray As wxArrayString = wxArrayString()
  langArray.Add("English")
  Dim langPath As String = playerPath &DELIMITER_CHAR &"Locale" &DELIMITER_CHAR
  If wxDirExists(langPath) Then
    Dim lDir As wxDir = wxDir()
    lDir.Open(langPath)
    Dim file As String = lDir.GetFirst("*", wxDIR_DIRS)
    Dim FileName As wxFileName = wxFileName("")
    Dim language As String

    While file <> ""
      FileName.AssignPath(file)
      language = wxLocale_GetLanguageName(languagecodeToId(FileName.GetName()))
      If langArray.INDEX(language)= -1 Then langArray.Add(language)
      file = lDir.GetNext()
    Wend
  End If

  Dim langName As String = wxLocale_GetLanguageName(languageid)
  Dim at = InStr(langName, "(")
  If at Then langName = langName[: at - 2]
  Dim sel As Integer = langArray.INDEX(langName)

  Dim cbb2 As wxComboBox = wxComboBox3(sBox1, -1, "", wxDefaultPosition, wxSize(180 / Scale, -1), langArray)
  cbb2.SetSelection(sel)
  langArray.Clear()
  gb.AddWindow(cbb2, wxGBPosition(8, 2), wxDefaultSpan, 0)
  gb.AddSpacer(2, 2, wxGBPosition(9, 0))

  oldPs = ps
  sText = wxStaticText(sbox1, -1, _("Player Size:"))
  gb.AddWindow(sText, wxGBPosition(10, 1), wxDefaultSpan, 0|wxALIGN_CENTER_VERTICAL)
  Dim pSize As wxArrayString = wxArrayString()
  pSize.Add(_("normal"))
  pSize.Add(_("larger"))
  pSize.Add(_("large"))
  pSize.Add(_("very large"))
  pSize.Add(_("Window caption height"))

  Dim cbb3 As wxComboBox = wxComboBox3(sBox1, -1, "", wxDefaultPosition, wxSize(180 / Scale, -1), pSize)
  Select Case ps
  Case 1:  cbb3.SetSelection(0)
  Case 1.2:  cbb3.SetSelection(1)
  Case 1.4:  cbb3.SetSelection(2)
  Case 1.6:  cbb3.SetSelection(3)
  Case Else: cbb3.SetSelection(4)
  End Select
  gb.AddWindow(cbb3, wxGBPosition(10, 2), wxDefaultSpan, 0)
  gb.AddSpacer(2, 2, wxGBPosition(11, 0))
  Connect(cbb3, -1, wxEVT_COMMAND_COMBOBOX_SELECTED, "onSetFrameSize")

  sText = wxStaticText(sbox1, -1, _("Connection timeout in Seconds (0...60)"))
  gb.AddWindow(sText, wxGBPosition(12, 1), wxDefaultSpan, wxEXPAND|wxALIGN_CENTER_VERTICAL)

  Dim nTimeout = wxSpinCtrl(sBox1, -1, timeout, wxDefaultPosition, wxSize(80, -1), wxSP_ARROW_KEYS, 1, 60)
  gb.AddWindow(nTimeout, wxGBPosition(12, 2), wxDefaultSpan, 0)
  
  sBox1.SetAutoLayout(TRUE)
  sBox1.SetSizerAndFit(gb)

  'set the new staticbox size
  Dim panel1Sizer As wxBoxSizer = wxBoxSizer(wxHORIZONTAL)
  panel1Sizer.AddWindow(sBox1, 1, wxEXPAND)
  panel1.SetAutoLayout(TRUE)
  panel1.SetSizerAndFit(panel1Sizer)

  pSize.Clear()
  notebook.AddPage(panel1, _("General settings"))

  'add page 2
  'web settings
  Dim w As Integer = optdialog.GetClientSizeWidth()
  Dim panel2 = wxPanel(notebook, -1)

  Dim sBox2 = wxStaticBoxSizerWithLabel(wxVERTICAL, panel2, _("General settings:"))

  'general settings
  Dim cb10 = wxCheckBox(sBox2.GetStaticBox(), -1, _("Show station logos"))
  cb10.SetValue(useIcons)
  sBox2.AddWindow(cb10, wxGROW, wxEXPAND|wxALIGN_LEFT)
  Dim oldUseIcons As Integer = useIcons

  Dim cb11 = wxCheckBox(sBox2.GetStaticBox(), -1, _("Transparent logos"))
  cb11.SetValue(useTransparency)
  sBox2.AddWindow(cb11, wxGROW, wxEXPAND|wxALIGN_LEFT)
  sBox2.AddSpacer(10)

  Dim oldTransparency As Integer = useTransparency
  sText = wxStaticText(sBox2.GetStaticBox(), -1, _("TV Player path and parameters:"))
  sBox2.AddWindow(sText, wxGROW, wxEXPAND|wxALIGN_LEFT)

  Dim bt As wxButton = wxButton(sBox2.GetStaticBox(), -1, tvplayerpath)
  bt.SetWindowStyle(wxBU_LEFT)
  bt.SetName("tvplayer")
  bt.SetToolTip(_("Set the path to the TV player"))
  Dim oldTVPlayerPath As String = tvPlayerPath
  Dim oldTvPlayerPara = tvPlayerPara

  Connect(bt, -1, wxEVT_COMMAND_BUTTON_CLICKED, "onSetTVPlayerPath")
  sBox2.AddWindow(bt, wxGROW, wxEXPAND|wxALIGN_LEFT)

  Dim sBox2a = wxStaticBox(panel2, -1, _("Record settings:"))
  Dim gb0 As wxGridBagSizer = wxGridBagSizer(5, 5)
  gb0.AddSpacer(2, 2, wxGBPosition(1, 0), wxGBSpan(1, 7))

  'record options
  sText = wxStaticText(sBox2a, -1, _("Path for the recordings:"))
  gb0.AddWindow(sText, wxGBPosition(2, 1), wxGBSpan(1, 7), wxEXPAND)

  Dim tcPath As wxDirPickerCtrl = wxDirPickerCtrl(sBox2a, -1, recordPath, "...", wxDefaultPosition, wxDefaultSize, wxDIRP_DEFAULT_STYLE)
  gb0.AddWindow(tcPath, wxGBPosition(3, 1), wxGBSpan(1, 7), wxEXPAND)
  gb0.AddSpacer(2, 2, wxGBPosition(4, 1))
'  gb0.AddSpacer(10, 2, wxGBPosition(4, 3))

  Dim tcRecTime = wxSpinCtrl(sBox2a, -1, recordTime, wxDefaultPosition , wxSize(60, -1), wxSP_ARROW_KEYS, 0, 10080)
  gb0.AddWindow(tcRecTime, wxGBPosition(5, 1), wxGBSpan(1, 1), 0)

  sText = wxStaticText(sBox2a, -1, _("Recording time in minutes (0 = until manual stop)"))
  gb0.AddWindow(sText, wxGBPosition(5, 2), wxGBSpan(1, 6), 0|wxALIGN_LEFT|wxALIGN_CENTER_VERTICAL)

  Dim cb15 = wxCheckBox(sBox2a, -1, _("save everything in one file"))
  gb0.AddSpacer(2, 2, wxGBPosition(6, 0), wxGBSpan(1, 7))
  gb0.AddWindow(cb15, wxGBPosition(7, 1), wxGBSpan(1, 7), wxEXPAND)

  Dim cb16 = wxCheckBox(sBox2a, -1, _("Convert the recording to"))
  cb16.SetValue(recConv)
  Connect(cb16, -1, wxEVT_COMMAND_CHECKBOX_CLICKED, "onActivateConvert")
  gb0.AddWindow(cb16, wxGBPosition(8, 1), wxGBSpan(1, 7), wxEXPAND)

  Dim conv[6]
  conv[1] = wxRadioButton(sBox2a, -1, "MP3 (.mp3)", wxDefaultPosition, wxDefaultSize, wxRB_GROUP): conv[1].SetName("convmp3"): conv[1].SetValue(recMode = 1)
  conv[2] = wxRadioButton(sBox2a, -1, "AAC (.aac)"): conv[2].SetName("convaac"): conv[2].SetValue(recMode = 2)
  conv[3] = wxRadioButton(sBox2a, -1, "AAC (.m4a)"): conv[3].SetName("convm4a"): conv[3].SetValue(recMode = 3)
  conv[4] = wxRadioButton(sBox2a, -1, "Vorbis (.ogg)"): conv[4].SetName("convogg"): conv[4].SetValue(recMode = 4)
  conv[5] = wxRadioButton(sBox2a, -1, "Opus (.opus)"): conv[5].SetName("convopus"): conv[5].SetValue(recMode = 5)
  conv[6] = wxRadioButton(sBox2a, -1, "Flac (.flac)"): conv[6].SetName("convflac"): conv[6].SetValue(recMode = 6)
  For i = 1 To 6
    conv[i].Enable(recConv)
    gb0.AddWindow(conv[i], wxGBPosition(9, i + 1))
  Next
  Dim cb17 = wxCheckBox(sBox2a, -1, _("delete source file after converting"))
  cb17.SetName("recdel")
  cb17.SetValue(recDel)
  cb17.Enable(recConv)
  gb0.AddWindow(cb17, wxGBPosition(10, 2), wxGBSpan(1, 6), wxEXPAND)

  gb0.AddSpacer(2, 5, wxGBPosition(11, 0), wxGBSpan(1, 6))
  gb0.AddSpacer(5, 5, wxGBPosition(11, 8))
  For i = 2 To 7
    gb0.AddGrowableCol(i)
  Next
  sBox2a.SetAutoLayout(TRUE)
  sBox2a.SetSizerAndFit(gb0)

'phiola does not support only record entire titles at the moment
'  Dim cb As wxCheckBox = wxCheckBox(sd, -1, _("only record entire titles"))
'  cb.SetValue(fullOnly)
  Dim panel2Sizer As wxBoxSizer = wxBoxSizer(wxVERTICAL)
  panel2Sizer.AddSizer(sBox2, 0, wxEXPAND)
  panel2Sizer.AddSpacer(10)
  panel2Sizer.AddWindow(sBox2a, 1, wxEXPAND)

  panel2.SetAutoLayout(TRUE)
  panel2.SetSizerAndFit(panel2Sizer)

  notebook.AddPage(panel2, _("Web Radio/TV"))

  'add page 3
  'file settings
  Dim panel3 = wxPanel(notebook, -1)
  Dim sBox3 = wxStaticBoxSizerWithLabel(wxVERTICAL, panel3, _("File player settings:"))

  sBox3.AddSpacer(5)
  sText = wxStaticText(sBox3.GetStaticBox(), -1, _("Path to editor program:"))
  sBox3.AddWindow(sText, 0, wxEXPAND|wxALIGN_LEFT)
  sBox3.AddSpacer(5)

  Dim bt10 As wxButton = wxButton(sBox3.GetStaticBox(), -1, editorpath)
  bt10.SetWindowStyle(wxBU_LEFT)
  bt10.SetName("editor")
  bt10.SetToolTip(_("Set the path to the editor program"))
  Connect(bt10, -1, wxEVT_COMMAND_BUTTON_CLICKED, "onSetEditorPath")
  Dim oldEditorPath = editorPath
  Dim oldEditorParam = editorParam
  Dim oldEditorTypes = editorTypes
  sBox3.AddWindow(bt10, wxGROW, wxEXPAND|wxALIGN_LEFT)
  sBox3.AddSpacer(15)

  Dim cb20 = wxCheckBox(sBox3.GetStaticBox(), -1, _("Show filenames"))
  cb20.SetValue(showMusicTitle)
  cb20.SetToolTip( _("Show played title in player"))
  sBox3.AddWindow(cb20, 0, wxEXPAND|wxALIGN_LEFT)
  sBox3.AddSpacer(10)
  Dim oldShowTitle As Integer = showMusicTitle

  Dim sBox4 = wxStaticBox(panel3, -1, _("Volume control settings"))
  Dim rb1 As wxRadioButton = wxRadioButton(sBox4, -1, _("No volume control"), wxPoint(10, 30), wxDefaultSize, wxRB_GROUP)
  Dim rect = rb1.GetRect()
  Dim rb2 As wxRadioButton = wxRadioButton(sBox4, -1, _("Automatic volume through the program"), wxPoint(10, rect.GetBottom()+ 5), wxDefaultSize)
  rb2.SetValue(gainMode = 1)
  rect = rb2.GetRect()
  Dim rb3 As wxRadioButton = wxRadioButton(sBox4, -1,  _("Replay gain tag volume control"), wxPoint(10, rect.GetBottom()+ 5), wxDefaultSize)
  rb3.SetValue(gainMode = 2)
  Dim oldGainMode = gainMode

  Dim panel3Sizer As wxBoxSizer = wxBoxSizer(wxVERTICAL)
  panel3Sizer.AddSizer(sBox3, 0, wxEXPAND)
  panel3Sizer.AddSpacer(10)
  panel3Sizer.AddWindow(sBox4, 1, wxEXPAND)

  panel3.SetAutoLayout(TRUE)
  panel3.SetSizerAndFit(panel3Sizer)
  notebook.AddPage(panel3, _("Local files"))

  'add page 4
  'podcast settings
  Dim panel4 = wxPanel(notebook, -1)
  Dim sBox5 = wxStaticBoxSizerWithLabel(wxVERTICAL, panel4, _("Downloads"))

  'get an separate path for podcast recordings
  sBox5.AddSpacer(5)
  sText = wxStaticText(sBox5.GetStaticBox(), -1, _("Path for downloads:"))
  sBox5.AddWindow(sText, 0, wxEXPAND|wxALIGN_LEFT)
  sBox5.AddSpacer(5)

  Dim tcPathPod As wxDirPickerCtrl = wxDirPickerCtrl(sBox5.GetStaticBox(), -1, recordPathPod, "...")
  sBox5.AddWindow(tcPathPod, 0, wxEXPAND|wxALIGN_LEFT)
  sBox5.AddSpacer(10)

  Dim sBox6 = wxStaticBox(panel4, -1, _("Podcast settings:"))
  Dim cb25 = wxCheckBox(sBox6, -1, _("Enable certificate verification"), wxPoint(10, 30))
  cb25.SetValue(checkCertAll)
  cb25.SetToolTip( _("Enable or disable certificate verification for all Podcasts"))
  Dim oldCheckcertAll As Integer = checkCertAll

  rect = cb25.GetRect()
  Dim cb26 = wxCheckBox(sBox6, -1, _("Show episodes in the player"), wxPoint(10, rect.GetBottom()+ 5))
  cb26.SetValue(showPodTitle)
  cb26.SetToolTip( _("Show the played episode in the player window"))
  Dim oldShowPodTitle As Integer = showPodTitle

  rect = cb26.GetRect()
  Dim cb27 = wxCheckBox(sBox6, -1, _("Automatically set completed episodes as heard"), wxPoint(10, rect.GetBottom()+ 5))
  cb27.SetValue(autoHeard)
  cb27.SetToolTip( _("When an episode has finished being listened to and ends automatically, it is marked as heard"))

  Dim panel4Sizer As wxBoxSizer = wxBoxSizer(wxVERTICAL)
  panel4Sizer.AddSizer(sBox5, 0, wxEXPAND)
  panel4Sizer.AddSpacer(10)
  panel4Sizer.AddWindow(sBox6, 1, wxEXPAND)

  panel4.SetAutoLayout(TRUE)
  panel4.SetSizerAndFit(panel4Sizer)
  notebook.AddPage(panel4, _("Podcast"))

  'add page 5
  'database tools
  Dim panel5 = wxPanel(notebook, -1)
  Dim sBox7 = wxStaticBox(panel5, -1, _("Database tools"))
  Dim gb1 As wxGridBagSizer = wxGridBagSizer(5, 5)
  gb1.AddSpacer(2, 3, wxGBPosition(1, 0))
  gb1.AddSpacer(2, 3, wxGBPosition(1, 3))

  Dim bt1 As wxButton = wxButton(sBox7, ID_DATABASE_EXPORT_KODI, _("Export database as Kodi IPTV list"))', wxDefaultPosition, wxSize()
  bt1.SetToolTip(_("Export the database to a Kodi compatible playlist"))
  Connect(bt1, ID_DATABASE_EXPORT_KODI, wxEVT_COMMAND_BUTTON_CLICKED, "onExportPlaylist")
  gb1.AddWindow(bt1, wxGBPosition(2, 1), wxDefaultSpan, wxEXPAND)

  Dim bt2 As wxButton = wxButton(sBox7, ID_DATABASE_EXPORT_MIXED, _("Export database as mixed IPTV list"))
  bt2.SetToolTip(_("Export the database to a Kodi playlist, but save the genre as well."))
  Connect(bt2, ID_DATABASE_EXPORT_MIXED, wxEVT_COMMAND_BUTTON_CLICKED, "onExportPlaylist")
  gb1.AddWindow(bt2, wxGBPosition(2, 2), wxDefaultSpan, wxEXPAND|wxALL)

  Dim bt3 As wxButton = wxButton(sBox7, ID_DATABASE_EXPORT_MUSIC, _("Export database as pure music playlist"))
  bt3.SetToolTip(_("Export the music database as a music playlist."))
  Connect(bt3, ID_DATABASE_EXPORT_MUSIC, wxEVT_COMMAND_BUTTON_CLICKED, "onExportPlaylist")
  gb1.AddWindow(bt3, wxGBPosition(3, 1), wxDefaultSpan, wxEXPAND)

  Dim bt4 As wxButton = wxButton(sBox7, ID_EXPORT_MUSIC, _("Export the visible music playlist"))
  bt4.SetToolTip(_("Export the currently visible music playlist from web radio mode."))
  Connect(bt4, ID_EXPORT_MUSIC, wxEVT_COMMAND_BUTTON_CLICKED, "onExportPlaylist")
  gb1.AddWindow(bt4, wxGBPosition(3, 2), wxDefaultSpan, wxEXPAND)

  Dim bt5 As wxButton = wxButton(sBox7, -1, _("Import web playlist"))
  bt5.SetToolTip(_("Import a new web playlist"))
  Connect(bt5, -1, wxEVT_COMMAND_BUTTON_CLICKED, "onImportPlaylistRadio")
  gb1.AddWindow(bt5, wxGBPosition(4, 1), wxDefaultSpan, wxEXPAND)
  
  Dim bt6 As wxButton = wxButton(sBox7, -1, _("Validate web addresses"))
  bt6.SetToolTip(_("Checks the web radio addresses from the database"))
  Connect(bt6, -1, wxEVT_COMMAND_BUTTON_CLICKED, "onValidateWebAdress")
  gb1.AddWindow(bt6, wxGBPosition(4, 2), wxDefaultSpan, wxEXPAND)

  Dim bt7 As wxButton = wxButton(sBox7, -1, _("Update web addresses"))
  bt7.SetToolTip(_("Update the web addresses for web radio and/or web TV"))
  Connect(bt7, -1, wxEVT_COMMAND_BUTTON_CLICKED, "onPlaylistsUpdate")
  gb1.AddWindow(bt7, wxGBPosition(5, 1), wxDefaultSpan, wxEXPAND)

  Dim bt8 As wxButton = wxButton(sBox7, -1, _("Download station logos"))
  bt8.SetToolTip(_("Download the station logos"))
  Connect(bt8, -1, wxEVT_COMMAND_BUTTON_CLICKED, "onIconsDownload")
  gb1.AddWindow(bt8, wxGBPosition(5, 2), wxDefaultSpan, wxEXPAND)
  gb1.AddSpacer(10, 10, wxGBPosition(6, 0))
  gb1.AddGrowableCol(1)
  gb1.AddGrowableCol(2)
  sBox7.SetAutoLayout(TRUE)
  sBox7.SetSizerAndFit(gb1)

  Dim sBox8 = wxStaticBox(panel5, -1, _("Database settings"), wxDefaultPosition)
  Dim cb30 = wxCheckBox(sBox8, -1, _("Create database backup"), wxPoint(10, 35))
  cb30.SetValue(cfg.Read("DatabaseBackup", TRUE))
  cb30.SetToolTip( _("Create a backup of the database when saving"))
  rect = cb30.GetRect()
  Dim bFiles As wxSpinCtrl = wxSpinCtrl(sBox8, -1, cfg.Read("BackupNum", 5), wxPoint(30, rect.GetBottom()+ 10), wxSize(50, -1), wxSP_VERTICAL, 1, 10)
  rect = bFiles.GetRect()
  sText = wxStaticText(sBox8, -1, _("Backups"), wxPoint(rect.GetRight()+ 10, rect.GetY()+ 2))

  notebook.AddPage(panel5, _("Database"))

  Dim panel5Sizer As wxBoxSizer = wxBoxSizer(wxVERTICAL)
  panel5Sizer.AddWindow(sBox7, 0, wxEXPAND)
  panel5Sizer.AddSpacer(10)
  panel5Sizer.AddWindow(sBox8, 1, wxEXPAND)
 
  panel5.SetAutoLayout(TRUE)
  panel5.SetSizerAndFit(panel5Sizer)

  'add page 6
  Dim panel6 = wxPanel(notebook, -1)
  Dim panel6Sizer As wxBoxSizer = wxBoxSizer(wxVERTICAL)
  Dim rt = wxRichTextCtrl(panel6, -1, "", wxPoint(10, 10), wxDefaultSize, wxRE_CENTRE_CARET|wxRE_MULTILINE|wxRE_READONLY)

  rt.SetDefaultStyle(wxRichTextAttrEmpty())
  rt.BeginAlignment(wxTEXT_ALIGNMENT_CENTER)
  rt.WriteImage(wxImageFromBitmap(wxBitmapFromIcon(iList["taskbarIcon"])))
  rt.NewLine()
  rt.BeginFontSize(11)
  rt.BeginBold()
  rt.BeginUnderline()
  rt.WriteText("About dsmPlayer " &ver.GetName() &" " &IIf(wxIsPlatform64Bit(), "64 bit", "32 bit"))
  rt.EndBold()
  rt.EndUnderline()
  rt.NewLine()
  rt.NewLine()
  rt.WriteText("dsmPlayer (duckes simple media player) is a small player for playing music and TV,")
  rt.LineBreak()
  rt.WriteText("both from local files and by streaming from the Internet.")
  rt.NewLine() 
  rt.WriteText("License: GPLv2")
  rt.NewLine() 
  rt.WriteText(ver.GetCopyright())
  rt.NewLine() 
  rt.NewLine() 

  rt.BeginUnderline()
  rt.BeginTextColour(wxBLUE)
  rt.BeginURL("mailto:dirk.noack@wxbasic.de")
  rt.WriteText("dirk.noack@wxbasic.de")
  rt.EndUnderline()
  rt.EndTextColour()
  rt.EndURL()
  rt.NewLine() 

  rt.BeginUnderline()
  rt.BeginTextColour(wxBLUE)
  rt.BeginURL("http://www.wxbasic.de")
  rt.WriteText("http://www.wxbasic.de")
  rt.EndUnderline()
  rt.EndTextColour()
  rt.EndURL()
  rt.NewLine() 
  rt.BeginUnderline()
  rt.BeginTextColour(wxBLUE)
  rt.BeginURL("http://www.forum.wxbasic.de")
  rt.WriteText("http://www.forum.wxbasic.de")
  rt.EndUnderline()
  rt.EndTextColour()
  rt.EndURL()
  rt.NewLine()
  rt.EndAlignment()
  Connect(rt, wxEVT_COMMAND_TEXT_URL, "onURL")

  Dim Button As wxButton = wxButton(panel6, -1, _("Check for Updates"), wxDefaultPosition, wxSize(-1, 40))
  Connect(Button, wxEVT_COMMAND_BUTTON_CLICKED, "onCheckVersion")

  panel6Sizer.AddWindow(rt, 1, wxEXPAND)
  panel6Sizer.AddWindow(Button, 0, wxEXPAND)

  panel6.SetAutoLayout(TRUE)
  panel6.SetSizerAndFit(panel6Sizer)
  notebook.AddPage(panel6, _("About"))

  Dim hSizerNB As wxBoxSizer = wxBoxSizer(wxHORIZONTAL)
  hSizerNB.AddSpacer(10)
  hSizerNB.AddWindow(notebook, 1, wxEXPAND)
  hSizerNB.AddSpacer(10)

  'horizontal sizer for ok an cancel button
  Dim okB As wxButton = wxButton(optDialog, wxID_OK, _("Ok"))
  Dim caB As wxButton = wxButton(optDialog, wxID_CANCEL, _("Cancel"))
  Dim hSizerButton As wxBoxSizer = wxBoxSizer(wxHORIZONTAL)
  hSizerButton.AddWindow(okb, wxEXPAND, 0)
  hSizerButton.AddWindow(cab, wxEXPAND, 0)


  'vertical sizer for notebook and button sizer
  Dim vSizer As wxBoxSizer = wxBoxSizer(wxVERTICAL)
  vSizer.AddSpacer(10)
  vSizer.AddSizer(hSizerNB, 1, wxEXPAND)
  vSizer.AddSpacer(5)
  vSizer.AddSizer(hSizerButton, 0, wxEXPAND)

  optDialog.SetAutoLayout(TRUE)
  optDialog.SetSizerAndFit(vSizer)
  optdialog.Layout()

  If optDialog.ShowModal()= wxID_OK Then
    'page 1, generel settings
    Dim autoplay As Integer = cb1.IsChecked()
    dockList = cb2.IsChecked()
    If dockList Then titleFrame.Move(wxPoint(titleFrame.GetPositionX(), musicFrame.GetPositionY()+ musicframe.GetSizeHeight()))
    Dim single As Integer = cb3.IsChecked()
    Dim useUpper As Integer = cb4.IsChecked()
    If oldUseLine <> useUpper Then UseUpperLine(useUpper)
    Dim openWith As Integer = cb5.IsChecked()
    If openWith <> oldOpenWith Then setOpenWith(openWith)
    timeout = nTimeout.GetValue()

    'the language code doesn't necessarily have to be supported by dsmplayer
    'there are many subcodes for a single language.
    'for example, "German (Germany)" is returned by the system
    'but dsmPlayer only supports "Germany"
    'therefore, the language code needs to be adapted
    Dim oldLanguageId As Integer = languageId
    Dim oldLanguage As String = wxLocale_GetLanguageName(oldLanguageId)
    at = InStr(oldLanguage, "(")
    If at Then oldLanguage = RTrim(oldLanguage[: at - 1])
    oldLanguageId = languagecodeToId(oldLanguage)

    Dim langCode As String = cbb2.GetStringSelection()
    languageId = languagecodeToId(langCode)

    'page 2, web radio and web TV
    useIcons = cb10.IsChecked()
    If oldUseIcons <> useIcons Then iconsShow()
    useTransparency = cb11.IsChecked()
    If oldTransparency <> useTransparency Then stationsIconsLoad()

    recordPath = tcPath.GetPath()
    FileName.AssignPath(recordPath)
    If !FileName.DirExists() Then FileName.MkDir(0777, wxPATH_MKDIR_FULL)
'    fullOnly = cb.GetValue()
    singleFile = cb15.GetValue()
    recordTime = tcRecTime.GetValue()
    recConv = cb16.GetValue()
    For i = 1 To 6
      If conv[i].GetValue() Then recMode = i
    Next
    recDel = cb17.GetValue()

    'page 3, local files
    showMusicTitle = cb20.GetValue()
    If (oldShowTitle <> showMusicTitle) And (playmode = ID_PLAY_FILE) Then showTitle(showMusicTitle)

    If rb1.GetValue() Then: gainMode = 0
    Elseif rb2.GetValue() Then: gainMode = 1
    Else: gainMode = 2
    End If

    'page 4, podcasts
    recordPathPod = tcPathPod.GetPath()
    FileName.AssignPath(recordPathPod)
    If !FileName.DirExists() Then FileName.MkDir(0777, wxPATH_MKDIR_FULL)

    checkcertAll = cb25.GetValue()
    showPodTitle = cb26.GetValue()
    If (oldShowPodTitle <> showPodTitle) And (playmode = ID_PLAY_PODCAST) Then showTitle(showPodTitle)

    autoHeard = cb27.GetValue()

    'page 5, databae
    Dim useBackup As Integer = cb30.GetValue()
    Dim backupNum As Integer = bFiles.GetValue()

    'save config
    'from page 1, generel settings
    cfg = wxFileConfig("", "", playerIni)
    cfg.SetPath("/dsmPlayer")
    cfg.Write("Autoplay", autoplay)
    cfg.Write("DockList", dockList)
    cfg.Write("SingleInstance", single)
    cfg.Write("UseUpperPos", useUpper)
    cfg.Write("Theme", theme)
    cfg.Write("DatabaseBackup", useBackup)
    cfg.Write("BackupNum", backupNum)
    cfg.Write("Timeout", timeout)
    cfg.Write("PlayerSize", ps)
    cfg.Write("Language", languageId)


    'from page 2, web radio and web TV
    cfg.SetPath("/TV")
    cfg.Write("TVPlayerPath", tvPlayerPath)
    cfg.Write("TVPlayerPara", tvPlayerPara)

    cfg.SetPath("/Web")
    cfg.Write("UseIcons", useIcons)
    cfg.Write("TransparentIcons", useTransparency)
    cfg.Write("RecordsPath", recordPath)
'  fullOnly = cfg.Read("RecordFull", fullOnly)
    cfg.Write("SingleFile", singleFile)
    cfg.Write("RecordTime", recordTime)
    cfg.Write("RecConvert", recConv)
    cfg.Write("RecMode", recMode)
    cfg.Write("DeleteSource", recDel)

    'page 3, local files
    cfg.SetPath("/File")
    cfg.Write("EditorPath", editorPath)
    cfg.Write("EditorParam", editorParam)
    cfg.Write("EditorTypes", editorTypes)
    cfg.Write("ShowTitle", showMusicTitle)
    cfg.Write("GainMode", gainMode)

    'page 4, podcasts
    cfg.SetPath("/Podcast")
    cfg.Write("CheckCert", checkCertAll)
    cfg.Write("ShowPodTitle", showPodTitle)
    cfg.Write("AutoHeard", autoHeard)

    'page 5, database
    cfg.SetPath("/Database")
    cfg.Write("DatabaseBackup", useBackup)
    cfg.Write("BackupNum", backupNum)
    ~cfg

    If languageId <> oldLanguageId Then
      Dim dl = wxGenericMessageDialog(Nothing, _("To activate the new language you must restart the program!") &"\n"  &
      _("Should the program be restarted now?"), _("Note"), wxYES_NO|wxYES_DEFAULT|wxCENTRE|wxICON_WARNING|wxDIALOG_NO_PARENT)

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

  Else

    If oldPs <> ps Then
      ps = oldPs
      setFrameSize(TRUE, FALSE)
    End If

    If oldUseLine <> cb4.GetValue() Then UseUpperLine(oldUseLine)
    checkCertAll = oldCheckCertAll

    If oldTheme <> theme Then
      theme = oldTheme
      setTheme()
    End If

    tvPlayerPath = oldTVPlayerPath
    tvPlayerPara = oldTVPlayerPara

    editorPath = oldEditorPath
    editorParam = oldEditorParam
    editorTypes = oldEditorTypes
  End If

  optDialog.Destroy()
End Sub


Sub onActivateConvert(event As wxCommandEvent)
  Dim c1 As wxWindow = wxFindWindowByName("convmp3")
  Dim c2 As wxWindow = wxFindWindowByName("convaac")
  Dim c3 As wxWindow = wxFindWindowByName("convm4a")
  Dim c4 As wxWindow = wxFindWindowByName("convogg")
  Dim c5 As wxWindow = wxFindWindowByName("convopus")
  Dim c6 As wxWindow = wxFindWindowByName("convflac")
  Dim del As wxWindow = wxFindWindowByName("recdel")
  c1.Enable(event.IsChecked())  
  c2.Enable(event.IsChecked())  
  c3.Enable(event.IsChecked())  
  c4.Enable(event.IsChecked())  
  c5.Enable(event.IsChecked())  
  c6.Enable(event.IsChecked())  
  del.Enable(event.IsChecked())  
End Sub


'the url in the about dialog is clicked
Sub OnURL(event As wxCommandEvent)
  wxLaunchDefaultApplication(event.GetString(), wxBROWSER_NEW_WINDOW)
End Sub


Sub onCheckVersion(event As wxCommandEvent)
  Dim prc = New wxProcessWithFlags(wxPROCESS_REDIRECT)
  Connect(prc, wxEVT_END_PROCESS, "onEndInfoProcess")
  If !wxFileExists(wgetPath) Then selectDownloadReader()
  If !wxFileExists(wgetPath) Then Return

  Dim pid As Integer = wxExecute(Chr(34) &wgetPath &Chr(34) &" --tries=5 -O- --no-verbose " &"https://files.wxbasic.de/", wxEXEC_ASYNC, prc)
  If !pid Then
    ~prc

  Else

    Dim buffer As String = ""
    If prc.IsInputOpened() Then
      Dim inStream As wxInputStream = prc.GetInputStream()
      Dim errStream As wxInputStream = prc.GetErrorStream()

      If inStream And inStream.IsOk() Then
        'read the input and error streams
        While !inStream.Eof()
          buffer &= instream.Read(1)
        Wend

        While !errStream.Eof()
          errstream.Read(1)
        Wend

        Dim at, at1 As Integer
        Dim major, minor As Integer
        Dim foundFile As String = ""
        Dim FileName As wxFileName = wxFileName("")
        Dim file As String
        Dim fVer As String

        at = InStr(buffer, "href=")
        While at > 0
          FileName.AssignPath(wordbetween(buffer[at: ], "\"","\""))
          file = FileName.GetName()

          If InStr(file, "dsmPlayer") And !InStr(file, "beta") Then
            fVer = file[11: ]
            at1 = InStr(fVer, ".")

            If at1 Then
              major = Val(fVer[: at1 - 1])
              minor = Val(Right(fVer, 1))
              If ((majOr > ver.GetMajOr()) Or ((majOr = ver.GetMajor()) And (minor > ver.GetMinor()))) or 
              ((majOr = ver.GetMajor() And (minor = ver.GetMinor())) And InStr(ver.GetName(), "beta")) Then foundFile = FileName.GetFullName()
            End If
          End If

          at = InStr(at + 1, buffer, "href=")
        Wend
      End If
    End If
  End If

  If foundFile <> "" Then
    Dim dl = wxGenericMessageDialog(Nothing, _("A new version is available.") &"\n\n" &foundFile &"\n\n" &
    _("Should the version be downloaded?"), _("Note"), wxYES_NO|wxYES_DEFAULT|wxCENTRE|wxICON_INFORMATION|wxDIALOG_NO_PARENT)

    'wxYes = 5103 in wxGenericMessageDialog
    If dl.ShowModal() = 5103 Then
      Dim dd As wxDirDialog = wxDirDialog(musicFrame)
      dd.SetPath(playerPath)
      Dim dlPath As String

      If dd.ShowModal()= wxID_OK Then
        dlPath = dd.GetPath()              

        infoPrc = New wxProcessWithFlags(wxPROCESS_REDIRECT)
        Connect(infoPrc, wxEVT_END_PROCESS, "onEndUpdateProcess")
        pid = wxExecute(Chr(34) &wgetPath &Chr(34) &" --local-encoding=UTF-8 --timeout=20 --tries=5 --remote-encoding=UTF-8 --no-verbose -P " &dlPath &" " &"https://files.wxbasic.de/" &foundFile, wxEXEC_ASYNC, infoPrc)
        If !pid Then
          ~infoPrc
          infoPrc = Nothing
        End If
      End If
    End If

  Else

    dl = wxGenericMessageDialog(Nothing, _("You are already using the current version."), _("Note"), wxOK|wxCENTRE|wxICON_INFORMATION|wxDIALOG_NO_PARENT)
    dl.ShowModal()
  End If
End Sub


'the download if the new version has finished
Sub onEndUpdateProcess(event As wxProcessEvent)
  Dim exitCode = event.GetExitCode()
  If exitCode = 0 Then
    Dim message As String = _("The file was downloaded successfully.")
  Else
    Message = _("Download error.")
  End If
  infoPrc = Nothing

  Dim dl = wxGenericMessageDialog(Nothing, message, _("Note"), wxOK|wxCENTRE|wxICON_INFORMATION|wxDIALOG_NO_PARENT)
  dl.ShowModal()
End Sub



'start phiola
Sub phiola(cmd As String, adress As String, opt As String)
  selectPhiolaPath()
  If !wxFileExists(phiolaPath) Then Return

  phiolaPrc = New wxProcess(musicFrame, -1)
  Connect(phiolaPrc, -1, wxEVT_END_PROCESS, "onEndPhiola")
  phiolaPrc.Redirect()

  phiolaPid = wxExecute(Chr(34) &phiolaPath &Chr(34) &" " &cmd &" "  &"\"" &adress &"\"" &" " &opt, wxEXEC_ASYNC, phiolaPrc)

  If !phiolaPid Then
    ~phiolaPrc
    phiolaPrc = Nothing
    wxMessageBox(_("Cannot execute Phiola."), _("Attention"), wxOK|wxCENTRE|wxICON_EXCLAMATION)
    Return
  End If

  isPlayed = TRUE
  musicFrame.Refresh()

  'in web mode the timer is started after the loading animation
  If (playmode = ID_PLAY_FILE) Or (playmode = ID_PLAY_PODCAST) Then
    If !timerMedia.IsRunning() Then timerMedia.Start(1000)
  End If
End Sub


'kill phiola
Sub killPhiola()
  If phiolaPrc Then wxProcess_Kill(phiolaPid, wxSIGKILL)
End Sub


'phiola was terminated, handle other actions
Sub onEndPhiola(event As wxProcessEvent)
  If loadingTimer.IsRunning() Then loadingTimer.Stop()
  If timerMedia.IsRunning() Then timerMedia.Stop()

  phiolaPid = -1

  'exitcode = -1 phiola would be terminated by the program (stop button)
  Dim exitCode As Integer = event.GetExitCode()

  If playmode = ID_PLAY_WEBRADIO Then
    'handle webradio
    phiolaPrc = Nothing
    Dim sel As Integer = mFileWebRadio
    If sel >= 0 Then sel = lcWeb.FindItem(0, "  " &sel)

    checkError(lcWeb.GetItemText(sel))
    If isRecord Then
      If recPrc Then wxProcess_Kill(recPrc.GetPid(), wxSIGKILL)
      recPrc = Nothing

      'convert recorded files, if checked in settings
      If recConv And (convPrc = Nothing) Then
        'hold the title to convert for the process end event
         recName = recordPath &DELIMITER_CHAR &oldpTitle &"."

        'convert the file
        convertFile()
      End If
    End If

    isPlayed = FALSE
    isRecord = FALSE

    pTitle = lcWeb.GetStringItem(sel, 2)
    If musicFrame != Nothing Then musicFrame.Refresh()

  'handle podcast
  Elseif playMode = ID_PLAY_PODCAST Then
    'phiola is termitated
    If exitcode = -1 Then
      phiolaPrc = Nothing
      If !isPaused And isPlayed Then
        podcastPlay(findPodcastItem(podUrl, FALSE))

      Elseif !isPaused And !isPlayed Then
        rects["mPos"].SetX(rects["mSlider"].GetX() - (5 * ps))
        podPos = 0
        podUrl = lcPod.GetItemText(lcPod.GetSelection(), 4)
        musicFrame.RefreshRect(wxRect(rects["mSlider"].GetX(), rects["mSlider"].GetY(), rects["mute"].GetX() - rects["next"].GetRight(), rects["mSlider"].GetHeight()))
      End If

    'phiola ends
    Elseif exitcode = 0 Then
      phiolaPrc = Nothing
      Dim Item As wxTreeListItem = findPodcastItem(podUrl, FALSE)
      nextMusicFilePod(TRUE)
      If autoHeard Then setEpisodeHeard(TRUE, Item)

    Else

      'phiola ends with an error
      checkError(lcPod.GetItemText(lcPod.GetSelection()))
      isPlayed = FALSE
      isRecord = FALSE
      podPos = 0
      rects["mPos"].SetX(rects["mSlider"].GetX() - (5 * ps))
      phiolaPrc = Nothing

      pTitle = lcPod.GetItemText(lcPod.GetSelection())
      musicFrame.Refresh()
    End If

  Else

    'playing the file has ended
    phiolaPrc = Nothing
    If exitCode > -1 Then
      mediapos = 0

      checkError(allMediaFiles.Item(musicFile - 1))
      isPaused = FALSE

      If exitcode = 0 Then
        If isPlayed Then
          If allmediafilesInt.Count()> (allmediafilesInt.INDEX(musicFile) + 1) Then
            nextFile(TRUE)

          Else

            isPlayed = FALSE
            mediapos = 0
            rects["mPos"].SetX(rects["mSlider"].GetX() - (5 * ps))
            musicFrame.Refresh()
          End If
        End If

      Else

        isPlayed = FALSE
        musicFrame.Refresh()
      End If

    Else

      'phiola was terminated
      'the position slider is moved
      'restart the file with the given position
      If !isPaused And isPlayed Then
        playMedia(musicFile)

      Elseif !isPaused And !isPlayed Then
        mediaPos = 0
      End If
      musicFrame.RefreshRect(wxRect(rects["mSlider"].GetX() - (3 * ps), rects["text"].GetY(), rects["mute"].GetX() - rects["next"].GetRight(), rects["text"].GetHeight()))
    End If
  End If
End Sub


'add the genres to the genres arraystring
Sub addGenres()
  Dim g = ["", "00s", "20s", "30s", "40s", "50s", "60s", "70s", "80s", "90s", "2000s", "Acoustic", "Adult", "African", "Afghanistan", "Alternative",
    "Albania", "Algeria", "Ambient", "Americana", "Anime", "Arabic", "Argentina", "Armenia", "Asian", "Australia", "Austria", "Belarus", "Belgium",
    "Big-Band", "Bluegrass", "Blues", "Bollywood", "Bosnia-and-herzegovina", "Bolivia", "Brazil", "Breakbeat", "Bulgaria", "Canada", "Celtic",
    "Chillout", "Chill-Step", "Children", "Christian", "Christmas", "Chile", "China", "Classical", "Club", "College", "Colombia", "Comedy",
    "Community", "Country", "Croatia", "Culture", "Cumbia", "Cyprus", "Czech", "Dance", "Dark", "Deep", "Denmark", "Deutsch", "Disco", "DiscoFox",
    "DJ", "DNB", "Dominica", "Downtempo", "Drum-and-Bass", "Dub", "Dubstep", "Easy-listening", "EBM", "Ecuador", "Education", "Egypt", "El-Salvador", 
    "Elector", "Electronic", "English", "Entertainment", "Estonia", "Ethnic", "Eurodance", "Europe", "Film", "Finland", "Folk", "France", "Funk", 
    "Ghana", "Goa", "Gospel", "Gothic", "Greek", "Guatemala", "Haiti", "Hardcore", "Hardrock", "Heavy-Metal", "Hip-Hop", "Hits", "Honduras", 
    "Hot-ac", "House", "Hungary", "India", "Indie", "Indonesia", "Industrial", "Information", "Instrumental", "Islam", "Italian", "Jamaica", 
    "Japan", "Jazz", "JPop", "Jungle", "Kazakhstan", "Kenya", "Korea", "Kosovo", "Kyrgyzstan", "Latin", "Latvia", "Lebanon", "Lithuania", "Local", 
    "Lounge", "Love", "Luxembourg", "Macedonia", "Malaysia", "Mali", "Malta", "Metal", "Mexico", "Misc", "Mixed", "Moldova", "Montenegro", 
    "Morocco", "Music", "Musical", "News", "Nepal", "Netherlands", "New-Age", "Nicaragua", "Nigeria", "Norway", "Oldies", "Opera", "Pakistan", 
    "Palestine", "Panama", "Paraguay", "Party", "Peru", "Philippines", "Polish", "Polka", "Pop", "Portugal", "Puerto-Rico", "Progressive", 
    "Punk", "Rap", "Reggae", "Retro", "RNB", "Rock", "Romanian", "Rumba", "Russian", "Salsa", "Samba", "Schlager", "Serbia", "SKA", "Slovakia", 
    "Slovenia", "Songs", "Soul", "Soundtrack", "South-Africa", "Spain", "Spiritual", "Sport", "Sri-Lanka", "Sweden", "Swing", "Switzerland", 
    "Symphonic", "Syria", "Taiwan", "Tamil", "Talk", "Techno", "Thailand", "Top-15", "Top-30", "Top-40", "Top-100", "Trance", "Tropical", 
    "Tunisia", "Turk", "Uganda", "Ukraine", "Underground", "United-Arab-Emirates", "United-Kingdom", "Urban", "Uruguay", "Usa", "Variety", 
    "Various" , "Venezuela", "Wave", "World"]

  For i = 1 To g.Count()
    genres.Add(g[i])
  Next
End Sub


'set the regkey for the 'open with' command
Sub setOpenWith(isSet As Integer)
  Dim noLog = wxLogNull()

  If isSet Then
    Dim regKey As wxRegKey = wxRegKey("HKEY_CLASSES_ROOT\\Applications\\dsmPlayer.exe\\shell\\open\\command")

    If !regkey.Exists() Then
      If !regKey.Create() Then
        Dim dl = wxGenericMessageDialog(Nothing, _("Error creating the registry entry!") &"\n" &_("dsmPlayer requires administrator rights for this action."), _("Error"), wxOK|wxCENTRE|wxICON_EXCLAMATION|wxDIALOG_NO_PARENT)
        dl.ShowModal()
      Else
        regKey.SetValue("command", Chr(34) &playerPath &DELIMITER_CHAR &"dsmPlayer.exe" &Chr(34) &" " &Chr(34) &"%1" &Chr(34))
      End If
    End If

  Else

    regKey = wxRegKey("HKEY_CLASSES_ROOT\\Applications\\dsmPlayer.exe")

    If regkey.Exists() Then
      regKey.DeleteSelf()

      If regKey.Exists() Then
        dl = wxGenericMessageDialog(Nothing, _("Error deleting registry entry!") &"\n" &_("dsmPlayer requires administrator rights for this action."), _("Error"), wxOK|wxCENTRE|wxICON_EXCLAMATION|wxDIALOG_NO_PARENT)
        dl.ShowModal()
      End If
    End If
  End If

  regkey.Close()
  ~noLog
End Sub


Sub onDisplayCanged(event As wxDisplayChangedEvent)
  Dim s As wxSize = wxGetDisplayPPI()
  ppiH = s.GetWidth()
  Scale = 96 / ppiH
  setFrameSize(TRUE, FALSE)
End Sub


'set the frame size from the options menu
Sub onSetFrameSize(event As wxCommandEvent)
  Dim sel As Integer = event.GetSelection()

  Select Case sel
  Case 0: ps = 1
  Case 1: ps = 1.2
  Case 2: ps = 1.4
  Case 3: ps = 1.6
  Case 4
    'set the size of a window caption
    ps = wxSystemSettings_GetMetric(wxSYS_CAPTION_Y)/ 24
  End Select

  setFrameSize(TRUE, FALSE)
End Sub


Sub setFrameSize(repaintTheme As Integer, createMenuCaption As Integer)
  'set the rect sizes for the player controls
  rects["expl"]= New wxRect(5 * ps, 5 * ps, 15 * ps, 15 * ps)
  rects["hide"]= New wxRect(560 * ps, 2 * ps, 11 * ps, 8 * ps)
  rects["tray"]= New wxRect(560 * ps, 13 * ps, 11 * ps, 8 * ps)
  rects["play"]= New wxRect(32 * ps, 3 * ps, 16 * ps, 16 * ps)
  rects["pause"]= New wxRect(rects["play"].GetRight() + (5 * ps), 3 * ps, 16 * ps, 16 * ps)
  rects["stop"]= New wxRect(rects["pause"].GetRight() + (5 * ps), 3 * ps, 16 * ps, 16 * ps)
  rects["prev"]= New wxRect(rects["stop"].GetRight() + (15 * ps), 3 * ps, 16 * ps, 16 * ps)
  rects["next"]= New wxRect(rects["prev"].GetRight() + (5 * ps), 3 * ps, 16 * ps, 16 * ps)
  rects["rec"]= New wxRect(rects["next"].GetRight() + (5 * ps), 3 * ps, 16 * ps, 16 * ps)
  rects["mSlider"]= New wxRect(rects["next"].GetRight() + (10 * ps), 7 * ps, 200 * ps, 12 * ps)
  rects["mPos"]= New wxRect(rects["mSlider"].GetX() - (5 * ps), 6 * ps, 12 * ps, 12 * ps)

  Dim sPos As Integer = 0
  If playmode = ID_PLAY_PODCAST Then
    If podlen Then spos = (podPos / podLen * 200 * ps)
  Else
    If medialen Then spos = (mediaPos / mediaLen * 200 * ps)
  End If
  rects["mPos"].SetX(rects["mSlider"].GetX() - (5 * ps)+ sPos)

  rects["time"]= New wxRect(rects["mSlider"].GetRight()+ (10 * ps), Round(4.5 * ps), 110 * ps, 13 * ps)
  rects["mute"]= New wxRect(rects["time"].GetRight()+ (10 * ps), 3 * ps, 20 * ps, 16 * ps)
  rects["vSlider"]= New wxRect(rects["mute"].GetRight() + (5 * ps), 7 * ps, 50 * ps, 12 * ps)
  rects["vPos"]= New wxRect(rects["vSlider"].GetX() - (5 * ps) + ((volume * ps) / 2), 6 * ps, 12 * ps, 12 * ps)

  'the text rect depends on the playmode
  Select Case playMode
  Case ID_PLAY_WEBRADIO, ID_PLAY_WEBTV
    rects["text"] = New wxRect(rects["rec"].GetRight()+ (5 * ps), 1 * ps, rects["mute"].GetX() - rects["rec"].GetRight() - (10 * ps), 20 * ps)

  Case ID_PLAY_PODCAST
    rects["text"] = New wxRect(1 * ps, 19 * ps, musicFrame.GetSizeWidth(), musicFrame.GetSizeHeight() - (19 * ps))

  Case ID_PLAY_FILE
    rects["text"] = New wxRect(1 * ps, 19 * ps, musicFrame.GetSizeWidth(), musicFrame.GetSizeHeight() - (19 * ps))
  End Select

  'set the frame size
  Dim sTitle As Integer = IIf(((showMusicTitle And (playMode = ID_PLAY_FILE)) Or (showPodTitle And (playMode = ID_PLAY_PODCAST))), TRUE, FALSE)
  musicFrame.SetSizeXY(580 * ps, IIf(sTitle, 45 * ps, 24 * ps))

  'delete the frame bitmap if exist
  If iList["frame"] != Nothing Then ~iList["frame"]
  'create frame bitmap in the right size
  iList["frame"] = New wxEmptyBitmap(musicFrame.GetSizeWidth(), musicFrame.GetSizeHeight(), 32)

  'draw the frame
  Dim memDC As wxMemoryDC = wxMemoryDCFromBitmap(iList["frame"])
  Dim gc = wxGraphicsContext_CreateFromMemoryDC(memDC)
  gc.SetAntialiasMode(wxANTIALIAS_DEFAULT)
  gc.SetInterpolationQuality(wxINTERPOLATION_BEST)
  Dim path As wxGraphicsPath = gc.CreatePath()
  path.AddRoundedRectangle(0, 0,  musicFrame.GetSizeWidth(), musicFrame.GetSizeHeight(), 6 * ps)
  musicFrame.SetShapeGraphicsPath(path)
  memDC.SelectObject(wxNullBitmap)
  ~gc

  'set the font size and set the font to the controls
  Dim font As wxFont = wxFontCopy(defaultFont)
  Dim fp As Integer = Round(font.GetPointSize() * ps * Scale)
  If fp < 9 Then fp = 9
  font.SetPointSize(fp)

  musicFrame.SetFont(font)
  Dim w As Integer = 25 * ps

  titleFrame.SetFont(font)
  lcpod.SetFont(font)
  lcMedia.SetFont(font)
  lcweb.SetFont(font)

  Dim explorerMedia As wxGenericDirCtrl = DynamicCast("wxGenericDirCtrl", musicFrame.FindWindowByName("explorermedia"))
  Dim tr = explorerMedia.GetTreeCtrl()
  tr.SetFont(font)
  tr.Refresh()
  Deallocate(tr)

  'set the size of the controls
  Dim sc As wxWindow = wxFindWindowByName("searchctrl")
  sc.SetFont(font)
  sc.SetSize(wxSize(sc.GetSizeWidth(), w))

  Dim btn As wxBitmapButton = DynamicCast("wxBitmapButton", wxFindWindowByName("select"))
  btn.SetBitmap(wxArtProvider_GetBitmap(wxART_GO_DOWN, wxART_OTHER, wxSize(w - 4, w - 4)), wxCENTER)
  btn.SetMinSize(wxSize(w, w))
  btn.SetMaxSize(wxSize(w, w))
  btn.Refresh()

  Dim st As wxWindow = wxFindWindowByName("results")
  If st Then
    st.SetFont(font)
    st.Refresh()
    st.MoveXY(btn.GetPositionX()+ w + 5, w - st.GetClientSizeHeight())
  End If

  btn = DynamicCast("wxBitmapButton", wxFindWindowByName("fullscreen"))
  btn.SetBitmap(wxArtProvider_GetBitmap(wxART_FULL_SCREEN, wxART_OTHER, wxSize(w - 4, w - 4)), wxCENTER)
  btn.SetMinSize(wxSize(w, w))
  btn.SetMaxSize(wxSize(w, w))

  btn = DynamicCast("wxBitmapButton", wxFindWindowByName("closetf"))
  btn.SetBitmap(wxArtProvider_GetBitmap(wxART_CLOSE, wxART_OTHER, wxSize(w - 4, w - 4)), wxCENTER)
  btn.SetMinSize(wxSize(w, w))
  btn.SetMaxSize(wxSize(w, w))

  'refresh the sizer
  Dim sizer = titleFrame.GetSizer()
  sizer.Layout()

  If repaintTheme Then
    'create the buttons is inside setTheme
    setTheme()
  Else
    'create the player controls
    createPlayerButtons()
  End If

  If createMenuCaption Then
    'create a title item in the main menu at first start
    'we can set a title directly in wxeMenu, but we cannot change the colours and font
    Dim mItem = New wxMenuItem(musicMenu, -1, _("dsmPlayer"))
    Dim bmp = wxBitmapFromIcon(iList["taskbarIcon"])
    Dim img = wxImageFromBitmap(bmp)
    img.Rescale(20, 20)
    mItem.SetBitmap(wxBitmapFromImage(img))

    font.SetFamily(wxFONTFAMILY_SWISS)
    font.SetWeight(wxBOLD)
    font.SetStyle(wxITALIC)
    font.SetPointSize(fp + 4)
    mItem.SetFont(font)
    mItem.SetTextColour(wxWHITE)
    mItem.SetBackgroundColour(wxBLUE)
    musicMenu.PrependMenuItem(mItem)
    musicMenu.InsertSeparator(1)
  End If

  'we need to set the font for the remaining menu items,
  'as they are changed by adding the first item
  Dim f
  For i = 0 To musicMenu.GetMenuItemCount() - 1
    mItem = musicMenu.FindItemByPosition(i)
    f = mItem.GetFont()
    f.SetPointSize(fp)
    mItem.SetFont(f)
  Next

  setColumnWidths()
  musicframe.Refresh()
End Sub
