' Gambas module file

Public Struct MarkupList
  sType As String
  iIndent As Integer
End Struct

Public EnableCode As Integer

Private $aMarkup As String[]
Private $cLink As Collection
Private $aIndex As String[]
Private $aTable As String[]
Private $aTableClass As String[]
Private $aTablePos As Integer[]
Private $hMarkdown As Markdown
Private $hLink As New MarkdownLink
Private $bComment As Boolean

Private Sub GetIndent(sLine As String) As Integer
  
  Return Len(sLine) - Len(LTrim(sLine))
  
End

Public Sub Convert(sMarkup As String, hMarkdown As Markdown) As String
  
  $hMarkdown = hMarkdown
  $cLink = New Collection
  $aIndex = New String[]
  EnableCode = 0
  
  Return ConvertMarkup(Split(sMarkup, "\n"))
  
End

Private Sub IsWordLimit(sCar As String) As Boolean

  If IsLetter(sCar) Or If IsDigit(sCar) Or If Len(sCar) >= 2 Then Return
  Return True

End

Private Sub ConvertMarkup(aLine As String[], Optional bDoNotSetLine As Boolean) As String
  
  Dim iLine As Integer
  Dim aResult As String[]
  Dim sLine As String
  Dim sText As String
  Dim I As Integer
  Dim bCode As Boolean
  Dim iBlockQuote As Integer
  Dim sCar As String
  Dim bInsidePar As Boolean
  Dim bIgnorePar As Boolean
  Dim bAddPar As Boolean
  Dim iIndent, iCurrentIndent As Integer
  Dim hMarkupList As MarkupList
  Dim bJustList As Boolean
  Dim sLink As String
  Dim iPos As Integer
  Dim aList As New MarkupList[]
  Dim sTable As String
  Dim iIndexPos As Integer = -1
  Dim aCommand As String[]
  Dim aSaveMarkup As String[]
  Dim aSaveTable As String[]
  Dim aSaveTablePos As Integer[]
  Dim aSaveTableClass As String[]
  Dim sClass As String
  
  aResult = New String[]
  
  aSaveMarkup = $aMarkup
  $aMarkup = New String[]
  aSaveTable = $aTable
  $aTable = New String[]
  aSaveTableClass = $aTableClass
  $aTableClass = New String[]
  aSaveTablePos = $aTablePos
  $aTablePos = New Integer[]
  
  ' iLine = 0
  ' Do
  '   If iLine >= aLine.Count Then Break
  '   sLine = LTrim(aLine[iLine])
  '   If Left(sLine) = "%" Then
  '     If sLine Begins "%IF " Then
  '     Else If sLine Begins "%ELSE " Then
  '     
  '     Endif
  '   Endif
  '   Inc iLine
  ' Loop
  
  For iLine = 0 To aLine.Max
    
    sLine = LTrim(aLine[iLine])
    If Not sLine Then Continue
    If Left(sLine) <> "[" Then Continue
    I = InStr(sLine, "]:")
    If I = 0 Then Continue
    If I >= 3 Then
      sLink = Trim(Mid$(sLine, I + 2))
      $cLink[Mid$(sLine, 2, I - 2)] = sLink
      If Left(sLink) = "#" Then
        iPos = InStr(sLink, " ")
        If iPos Then sLink = Left(sLink, iPos - 1)
        aLine[iLine] = "<a name=\"" & Html$(sLink) & "\"></a>"
        Continue
      Endif
    Endif
    aLine[iLine] = ""
    
  Next
    
  iLine = -1
  While iLine < aLine.Max
    
    Inc iLine
    sLine = aLine[iLine]
    
    If Not bDoNotSetLine Then 
      $hMarkdown.Line = iLine
      $hMarkdown.Current = sLine
    Endif
    
    'If $aMarkup.Count Then
    '  aResult.Add(ConvertLine(sLine))
    '  Continue
    'Endif
    
    sLine = RTrim(sLine)
    If Not sLine Then sLine = aLine[iLine]
  
    If $bComment Then
      iPos = InStr(sLine, "-->")
      If iPos = 0 Then Continue
      $bComment = False
      sLine = Mid$(sLine, iPos + 4)
    Endif
  
    ' Special command
    
    If Left(sLine, 2) = "@{" And If Right(sLine) = "}" Then
      If sLine = "@{index}" Then 
        iIndexPos = aResult.Count
        aResult.Add(sLine)
      Else
        aCommand = $hMarkdown.Command(Mid$(sLine, 3, -1))
        If aCommand And If aCommand.Count Then
          aLine.Insert(aCommand, iLine + 1)
        Endif
      Endif
      Continue
    Endif
    
    ' Blockquote
    
    I = 0
    Do
      If Left(sLine) <> ">" Then Break
      sCar = Mid$(sLine, 2, 1)
      If sCar <> " " And If sCar <> gb.Tab Then Break
      Inc I
      sLine = LTrim(Mid$(sLine, 3))
    Loop
    
    If I > iBlockQuote Then
      While I > iBlockQuote
        aResult.Add("<blockquote>")
        Inc iBlockQuote
      Wend
    Else If I < iBlockQuote Then
      While I < iBlockQuote
        aResult.Add("</blockquote>")
        Dec iBlockQuote
      Wend
    Endif
    
    ' Lists
    
    If Trim(sLine) Then
    
      iIndent = GetIndent(sLine)
      GoSub CLOSE_LIST
    
      sLine = Mid$(sLine, iCurrentIndent + 1)
      
      ' Horizontal lines
      
      If Left(sLine) = "*" And If Right(sLine) = "*" Then
        sText = Replace(sLine, " ", "")
        If Len(sText) >= 3 And If sText = String$(Len(sText), "*") Then
          GoSub CLOSE_PARA
          aResult.Add("<hr />")
          Continue
        Endif
      Endif
  
      If Left(sLine) = "-" And If Right(sLine) = "-" Then
        sText = Replace(sLine, " ", "")
        If Len(sText) >= 3 And If sText = String$(Len(sText), "-") Then
          GoSub CLOSE_PARA
          aResult.Add("<hr />")
          Continue
        Endif
      Endif
      
      If sLine Begins "* " Or If sLine Begins "- " Then
        
        hMarkupList = New MarkupList
        hMarkupList.sType = "ul"
        hMarkupList.iIndent = iIndent + 1 + GetIndent(Mid$(sLine, 2))
        aList.Add(hMarkupList)
        bJustList = True
        If aResult.Count And If Trim(aResult[aResult.Max]) = "</ul>" Then
          If Not Trim(aLine[iLine - 1]) Then
            If iLine < aLine.Max And If GetIndent(aLine[iLine + 1]) >= hMarkupList.iIndent Then
              bJustList = False
            Endif
            aResult[aResult.Max - 1] = "<p></p>\n" & aResult[aResult.Max - 1]
          Endif
          aResult.Remove(aResult.Max)
        Else
          GoSub CLOSE_PARA
          aResult.Add(Space$(iCurrentIndent) & "<ul>")
        Endif
        iCurrentIndent = hMarkupList.iIndent
        aResult.Add(Space$(iCurrentIndent) & "<li>")
        sLine = Mid$(sLine, 3)
        
      Else If sLine Begins "+ " Then
        
        hMarkupList = New MarkupList
        hMarkupList.sType = "ol"
        hMarkupList.iIndent = iIndent + 1 + GetIndent(Mid$(sLine, 2))
        aList.Add(hMarkupList)
        bJustList = True
        If aResult.Count And If Trim(aResult[aResult.Max]) = "</ol>" Then
          If Not Trim(aLine[iLine - 1]) Then
            If iLine < aLine.Max And If GetIndent(aLine[iLine + 1]) >= hMarkupList.iIndent Then
              bJustList = False
            Endif
            aResult[aResult.Max - 1] = "<p></p>\n" & aResult[aResult.Max - 1]
          Endif
          aResult.Remove(aResult.Max)
        Else
          GoSub CLOSE_PARA
          aResult.Add(Space$(iCurrentIndent) & "<ol>")
        Endif
        iCurrentIndent = hMarkupList.iIndent
        aResult.Add(Space$(iCurrentIndent) & "<li>")
        sLine = Mid$(sLine, 3)
      Endif
      
    Endif
    
    ' Blockquote again!
    
    I = iBlockQuote
    Do
      If Left(sLine) <> ">" Then Break
      sCar = Mid$(sLine, 2, 1)
      If sCar <> " " And If sCar <> gb.Tab Then Break
      Inc I
      sLine = LTrim(Mid$(sLine, 3))
    Loop
    
    If I > iBlockQuote Then
      While I > iBlockQuote
        aResult.Add("<blockquote>")
        Inc iBlockQuote
      Wend
    Else If I < iBlockQuote Then
      While I < iBlockQuote
        aResult.Add("</blockquote>")
        Dec iBlockQuote
      Wend
    Endif
    
    If sLine = "[[" Or If sLine Begins "[[ " Then
      
      GoSub CLOSE_PARA
      iIndent = GetIndent(sLine)
      GoSub CLOSE_LIST
      GoSub CLOSE_CODE
      
      $aTable.Push("[[")
      sLine = Trim(Mid$(sLine, 3))
      $aTableClass.Push(sLine)
      $aTablePos.Push(aResult.Count)
      If sLine Then
        aCommand = $hMarkdown.Enter(sLine)
        If aCommand Then aResult.Insert(aCommand)
        aResult.Add("<table class=\"" & sLine & "\">")
      Else
        aResult.Add("<table class=\"table\">")
      Endif
      aResult.Add("<tr><th>")
      bIgnorePar = False
      bInsidePar = False
      Continue
      
    Endif
    
    If $aTable.Count Then
      
      If sLine = "]]" Then
        
        GoSub CLOSE_PARA
        iIndent = GetIndent(sLine)
        GoSub CLOSE_LIST
        GoSub CLOSE_CODE
        
        sTable = $aTable.Pop()
        sClass = $aTableClass.Pop()
        iPos = $aTablePos.Pop()
        
        If iPos >= 0 Then
          aResult[iPos] = Replace(aResult[iPos], "<table", "<div class=\"table\"><div")
          aResult.Remove(iPos + 1)
          aResult.Add("</div></div>")
        Else
          aResult.Add("</td></tr>")
          aResult.Add("</table>")
        Endif
        
        aCommand = $hMarkdown.Leave(sClass)
        If aCommand Then aResult.Insert(aCommand)
        
        Continue
      
      Else If sLine = "--" Then
        
        GoSub CLOSE_PARA
        iIndent = GetIndent(sLine)
        GoSub CLOSE_LIST
        GoSub CLOSE_CODE
        
        sTable = $aTable[$aTable.Max]
        If sTable = "[[" Then
          aResult.Add("</th><th>")
        Else
          aResult.Add("</td><td>")
        Endif
        bIgnorePar = True
        bInsidePar = True
        $aTablePos[$aTablePos.Max] = -1
        Continue
        
      Else If sLine = "==" Then
        
        GoSub CLOSE_PARA
        iIndent = GetIndent(sLine)
        GoSub CLOSE_LIST
        GoSub CLOSE_CODE
        
        sTable = $aTable[$aTable.Max]
        If aResult[aResult.Max] = "<tr><th>" Then
          aResult[aResult.Max] = "<tr><td>"
        Else If sTable = "[[" Then
          aResult.Add("</th></tr><tr><td>")
        Else
          aResult.Add("</td></tr><tr><td>")
        Endif
        $aTable[$aTable.Max] = "=="
        $aTablePos[$aTablePos.Max] = -1
        bIgnorePar = True
        bInsidePar = True
        Continue
        
      Endif
      
    Endif
    
    If sLine Begins "==" And If sLine = String$(Len(sLine), "=") Then
      sLine = aResult[aResult.Max]
      If sLine Not Begins "<h" Then
        If sLine Begins "<p>" Then
          sLine = Mid$(sLine, 4)
          bInsidePar = False
        Endif
        GoSub CLOSE_PARA
        aResult[aResult.Max] = "<h1>" & sLine & "</h1>"
      Endif
      Continue
    Endif
    
    If sLine Begins "--" And If sLine = String$(Len(sLine), "-") Then
      sLine = Trim(aResult[aResult.Max])
      If sLine Then
        If sLine Not Begins "<h" Then
          If sLine Begins "<p>" Then
            sLine = Mid$(sLine, 4)
            bInsidePar = False
          Endif
          GoSub CLOSE_PARA
          aResult[aResult.Max] = "<h2>" & sLine & "</h2>"
        Endif
        Continue
      Endif
    Endif
    
    ' Code
    
    If EnableCode >= 0 Then
      If sLine Begins "    " Or If sLine Begins gb.Tab Then
      
        If Left(sLine) = gb.Tab Then
          sLine = Mid$(sLine, 2)
        Else
          sLine = Mid$(sLine, 5)
        Endif
        If sLine = "----" Then
          sLine = "<hr/>"
        Else
          sLine = Html$(sLine)
        Endif
        If Not bCode Then
          GoSub CLOSE_PARA
          bCode = True
          sLine = "<div><pre><code>" & sLine
        Endif
        aResult.Add(sLine)
        Continue
        
      Endif
    Endif
    
    GoSub CLOSE_CODE
  
    ' Title
    
    If Left(sLine) = "#" Then
      I = InStr(sLine, " ")
      If I <= 7 Then
        Dec I
        If Left(sLine, I) = String$(I, "#") Then
          sLine = Mid$(sLine, I + 2)
          While sLine Ends "#"
            sLine = Left(sLine, -1)
          Wend
          sLine = RTrim(sLine)
          If Left(sLine) = "[" And If Right(sLine) = "]" Then
            sLine = ConvertLine(Mid$(sLine, 2, -1))
            $aIndex.Add(String$(I - 1, "  ") & "- [" & sLine & "] (#t" & CStr($aIndex.Count + 1) & ")")
            sLine = "<a name=\"t" & CStr($aIndex.Count) & "\"></a>" & "<h" & CStr(I) & ">" & sLine & "</h" & CStr(I) & ">"
          Else
            sLine = "<h" & CStr(I) & ">" & ConvertLine(sLine) & "</h" & CStr(I) & ">"
          Endif
          GoSub CLOSE_PARA
          aResult.Add(sLine)
          Continue
        Endif
      Endif
    Endif
      
    If Trim(sLine) Then
      If Not bInsidePar And If LTrim(sLine) Not Begins "<h" Then
        If bIgnorePar Then
          bIgnorePar = False
        Else 'If Not bJustList Then
          bAddPar = True
        'Else
        '  bAddPar = Not Trim(aLine[iLine - 1])
        Endif
      Endif
    Else
      bJustList = False
      GoSub CLOSE_PARA
      Continue
    Endif
    
    sLine = ConvertLine(sLine)
    
    If bAddPar Then
      sLine = Left(sLine, GetIndent(sLine)) & "<p>" & LTrim(sLine)
      bInsidePar = True
      bAddPar = False
    Endif
    
    aResult.Add(sLine)
    
  Wend
  
  GoSub CLOSE_CODE
  GoSub CLOSE_BLOCKQUOTE
  iIndent = 0
  GoSub CLOSE_LIST
  'If $aMarkup.Count Then Error.Raise("Missing markup: " & $aMarkup[$aMarkup.Max])
  
  If $aIndex.Count And If iIndexPos >= 0 Then
    iIndent = GetIndent($aIndex[0])
    For I = 1 To $aIndex.Max
      iIndent = Min(iIndent, GetIndent($aIndex[I]))
    Next
    If iIndent Then
      For I = 0 To $aIndex.Max
        $aIndex[I] = Mid$($aIndex[I], iIndent + 1)
      Next
    Endif
    aResult[iIndexPos] = "<div class=\"index\">\n" & ConvertMarkup($aIndex) & "</div>\n"
  Endif
  
  $aMarkup = aSaveMarkup
  $aTable = aSaveTable
  $aTableClass = aSaveTableClass
  $aTablePos = aSaveTablePos
  Return aResult.Join("\n")
  
CLOSE_CODE:

  If bCode Then
    aResult.Add("</code></pre></div>")
    bCode = False
  Endif
  Return
  
CLOSE_BLOCKQUOTE:

  While iBlockQuote
    aResult.Add("</blockquote>")
    Dec iBlockQuote
  Wend
  Return

CLOSE_LIST:

  While iIndent < iCurrentIndent
    GoSub CLOSE_PARA
    GoSub CLOSE_CODE
    aResult.Add(Space$(iCurrentIndent) & "</li>")
    bJustList = False
    aResult.Add(Space$(aList[aList.Max].iIndent) & "</" & aList[aList.Max].sType & ">")
    aList.Remove(aList.Max)
    If aList.Count Then
      iCurrentIndent = aList[aList.Max].iIndent
    Else
      iCurrentIndent = 0
    Endif
  Wend
  Return

CLOSE_PARA:

  If bInsidePar Then
    If Not bIgnorePar Then aResult[aResult.Max] &= "</p>"
    'aResult.Add("")
    bInsidePar = False
    bIgnorePar = False
  Else If iLine > 0 And If aResult[aResult.Max] Then
    'aResult.Add("")
  Endif
  Return
  
'Catch
  
'  Error.Raise("Line " & CStr(iLine + 1) & ": " & Error.Text)

End


Private Sub ConvertLine(sLine As String) As String
  
  Dim sResult As String
  Dim I, L As Integer
  Dim sCar As String
  Dim I1, I2 As Integer
  Dim sPattern As String
  Dim bCode As Boolean
  Dim bEmph As Boolean
  Dim bStrong As Boolean
  Dim sText, sTitle, sLink As String
  Dim bBlank As Boolean
  Dim bUnderline As Boolean
  Dim bLimitBefore, bLimitAfter As Boolean
  
MAIN_LOOP:
  
  If I >= String.Len(sLine) Then 
    If bEmph Then 
      sResult &= "</em>"
    Else If bStrong Then 
      sResult &= "</strong>"
    Endif
    If bCode Then sResult &= "</code>"
    Return sResult
  Endif
  
  GoSub NEXT_CAR
  
  If sCar = "\\" Then
    If I = String.Len(sLine) Then
      sResult &= "<br>"
    Else
      GoSub NEXT_CAR
      sResult &= Html(sCar)
    Endif
    Goto MAIN_LOOP
  Endif
  
  If sCar = "<" Then Goto ENTER_MARKUP
  
  'If $aMarkup.Count = 0 Then
  
    If sCar = "&" Then Goto ENTER_AMPERSAND
    
    If sCar = "[" And If String.Mid$(sLine, I + 1, 1) <> " " Then Goto ENTER_LINK
    
  'Endif
  
  If I = 1 Or If IsWordLimit(String.Mid$(sLine, I - 1, 1)) Then
    bLimitBefore = True
  Else
    bLimitBefore = False
  Endif
  
  If IsWordLimit(String.Mid$(sLine, I + 1, 1)) Then
    bLimitAfter = True
  Else
    bLimitAfter = False
  Endif
  
  If bLimitBefore Or If bLimitAfter Then
    If sCar = "`" Then Goto ENTER_CODE
    If sCar = "'" Then Goto ENTER_LIGHT_CODE
    If sCar = "*" Then Goto ENTER_STAR
    If sCar = "~" Then Goto ENTER_UNDERLINE
  Endif
  
  If sCar = ">" Then 
    sCar = "&gt;"
  Endif
  
  sResult &= sCar
  
  Goto MAIN_LOOP
  
NEXT_CAR:

  Inc I
  If I > Len(sLine) Then Error.Raise(("Unexpected end of line"))
  sCar = String.Mid$(sLine, I, 1)
  Return
  
LOOK_CAR:

  sCar = String.Mid$(sLine, I + 1, 1)
  Return
  
ENTER_MARKUP:

  If String.Mid$(sLine, I, 4) = "<!--" Then
    I = String.Len(sLine)
    $bComment = True
    Goto MAIN_LOOP
  Endif
  
  I1 = I
  GoSub NEXT_CAR
  
  If sCar <> "/" And If Not IsLetter(sCar) Then
    sResult &= "&lt;"
    Dec I
    Goto MAIN_LOOP
  Endif
  
  Repeat
    GoSub NEXT_CAR
  Until sCar = ">"
  sPattern = String.Mid$(sLine, I1 + 1, I - I1 - 1)
  
  'sPattern = LCase(sPattern)
  
  If Left$(sPattern) = "/" Then
    sPattern = Mid$(sPattern, 2)
    If Not ["img", "hr", "br"].Exist(sPattern) Then 
      
      Do
        
        If $aMarkup.Count = 0 Then 
          sResult &= "<div class=\"error\">" & Html("Mismatched markup: </" & sPattern & ">") & "</div>"
          Break
        Endif
        
        If LCase($aMarkup[$aMarkup.Max]) = LCase(sPattern) Then 
          sResult &= "</" & sPattern & ">"
          $aMarkup.Remove($aMarkup.Max)
          Break
        Endif

        If LCase($aMarkup[$aMarkup.Max]) = "p" Then
          sResult &= "</p>"
          $aMarkup.Remove($aMarkup.Max)
          Continue
        Endif

        sResult &= "<div class=\"error\">" & Html("Mismatched markup: </" & sPattern & "> against <" & $aMarkup[$aMarkup.Max] & ">") & "</div>"
        Break
        
      Loop
        
    Endif
  Else
    sResult &= "<" & sPattern & ">"
    If Right$(sPattern) <> "/" Then
      I1 = InStr(sPattern, " ")
      If I1 Then sPattern = Left(sPattern, I1 - 1)
      If Not ["img", "hr", "br"].Exist(sPattern) Then $aMarkup.Add(sPattern)
    Endif
  Endif
  Goto MAIN_LOOP
  
ENTER_AMPERSAND:

  For I1 = I To I + 6
    sCar = String.Mid$(sLine, I1, 1)
    If sCar = ";" Then
      sResult &= String.Mid$(sLine, I, I1 - I + 1)
      I = I1
      Goto MAIN_LOOP
    Else If sCar = "\n" Then 
      Break
    Endif
  Next
  sResult &= "&amp;"
  Goto MAIN_LOOP
  
ENTER_CODE:

  sResult &= "<code style=\"white-space:nowrap;\">"
  Do
    GoSub NEXT_CAR
    If sCar = "`" Then 
      GoSub LOOK_CAR
      If sCar <> "`" Then Break
      Inc I
    Endif
    sResult &= Html(sCar)
  Loop
  
  sResult &= "</code>"
  Goto MAIN_LOOP
  
ENTER_LIGHT_CODE:
  
  If bCode And If bLimitAfter Then
    sResult &= "</code>"
    bCode = False
  Else If bLimitBefore Then
    sResult &= "<code style=\"white-space:nowrap;\">"
    bCode = True
  Else
    sResult &= "'"
  Endif
  
  Goto MAIN_LOOP
  
ENTER_STAR:

  GoSub LOOK_CAR
  If sCar = "*" Then 
    Inc I
    Goto ENTER_STRONG
  Endif
  
  If bEmph And If bLimitAfter Then
    sResult &= "</em>"
    bEmph = False
  Else If Not bStrong And If bLimitBefore Then
    sResult &= "<em>"
    bEmph = True
  Else
    sResult &= "*"
  Endif
  Goto MAIN_LOOP

ENTER_STRONG:

  If bStrong And If bLimitAfter Then
    sResult &= "</strong>"
    bStrong = False
  Else If Not bEmph And If bLimitBefore Then
    sResult &= "<strong>"
    bStrong = True
  Else
    sResult &= "**"
  Endif
  Goto MAIN_LOOP
  
ENTER_UNDERLINE:

  If bUnderline And If bLimitAfter Then
    sResult &= "</u>"
    bUnderline = False
  Else If bLimitBefore Then
    sResult &= "<u>"
    bUnderLine = True
  Else
    sResult &= "~"
  Endif
  Goto MAIN_LOOP
  
ENTER_LINK:

  I1 = I
  L = 0
  Do
    Inc I1
    sCar = String.Mid$(sLine, I1, 1)
    If Not sCar Then
      sResult &= "["
      Goto MAIN_LOOP
    Endif
    If sCar = "[" Then
      Inc L
    Else If sCar = "]" Then
      If L = 0 Then Break
      Dec L
    Endif
  Loop

  If I1 = (I + 1) Then
    sResult &= "[]"
    Inc I
    Goto MAIN_LOOP
  Endif
  
  sLink = ""
  sTitle = ""
  sText = String.Mid$(sLine, I + 1, I1 - I - 1)
  I = I1
  I2 = I
  Do
    GoSub LOOK_CAR
    If Not sCar Then Break
    Inc I
    If Len(sCar) >= 2 Or If Asc(sCar) > 32 Then Break
  Loop
  If sCar = "(" Then
    I1 = String.InStr(sLine, ")", I + 1)
    If I1 > 0 Then
      sLink = String.Mid$(sLine, I + 1, I1 - I - 1)
      I = I1
    Endif
  Else If sCar = "[" Then
    I1 = String.InStr(sLine, "]", I + 1)
    If I1 > 0 Then
      sLink = $cLink[String.Mid$(sLine, I + 1, I1 - I - 1)]
      I = I1
    Endif
  Else
    I = I2
  Endif
  
  If sLink Then
    
    I1 = String.InStr(sLink, Chr$(34))
    If I1 And If String.Right(sLink) = Chr$(34) Then
      sTitle = String.Mid$(sLink, I1 + 1, -1)
      sLink = Trim(String.Left$(sLink, I1 - 1))
    Else
      sTitle = ""
      sLink = Trim$(sLink)
    Endif
    
  Endif
  
  If Not sLink And If InStr(sText, "/") Then
    sLink = sText
    sText = ""
  Endif
  
  $hLink.Link = sLink
  $hLink.Text = sText
  $hLink.Title = sTitle
  $hLink.Html = ""
  $hLink.Query = ""
  
  $hMarkdown.Link($hLink)
  
  If $hLink.Html Then
    sResult &= $hLink.Html
    Goto MAIN_LOOP
  Endif
  
  sLink = $hLink.Link
  sText = $hLink.Text
  sTitle = $hLink.Title
  
  If Not sText Then sText = sLink
  
  If sLink Then
    
    If $hLink.Query Then sLink &= "?" & $hLink.Query
    
    bBlank = sLink Like "*://*" 
    
    sResult &= "<a href=\"" & Html$(sLink) & "\""
    If sTitle Then sResult &= " title=\"" & Html$(sTitle) & "\""
    If bBlank Then sResult &= " target=\"_blank\""
    sResult &= ">" & sText & "</a>"
    
  Endif
    
  Goto MAIN_LOOP

End
