﻿Public Class Emoticonizer
    Private Declare Function SendMessage Lib "user32.dll" Alias "SendMessageA" (ByVal winHandle As IntPtr, ByVal wMsg As Int32, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As Int32
    Private Const WM_SETREDRAW As Integer = &HB

    Private Shared emoticontable As Hashtable
    Private Shared maxlength As Integer = 0
    Public Shared Sub Init(Optional ByVal smileyfolder As String = "smileys")
        emoticontable = New Hashtable(21) 'initial capacity to speed up loading
        emoticontable.Add(";)", New Bitmap(smileyfolder & "\smiley1.gif"))
        emoticontable.Add(":)", New Bitmap(smileyfolder & "\smiley2.gif"))
        emoticontable.Add(":p", New Bitmap(smileyfolder & "\smiley3.gif"))
        emoticontable.Add("+o", New Bitmap(smileyfolder & "\smiley4.gif"))
        emoticontable.Add(":-o", New Bitmap(smileyfolder & "\smiley5.gif"))
        emoticontable.Add("(r)", New Bitmap(smileyfolder & "\smiley6.gif"))
        emoticontable.Add("(n)", New Bitmap(smileyfolder & "\smiley7.gif"))
        emoticontable.Add("(y)", New Bitmap(smileyfolder & "\smiley8.gif"))
        emoticontable.Add("(l)", New Bitmap(smileyfolder & "\smiley9.gif"))
        emoticontable.Add(":$", New Bitmap(smileyfolder & "\smiley10.gif"))
        emoticontable.Add(":'(", New Bitmap(smileyfolder & "\smiley11.gif"))
        emoticontable.Add(":s", New Bitmap(smileyfolder & "\smiley12.gif"))
        emoticontable.Add("|-)", New Bitmap(smileyfolder & "\smiley13.gif"))
        emoticontable.Add("8-)", New Bitmap(smileyfolder & "\smiley14.gif"))
        emoticontable.Add("*-)", New Bitmap(smileyfolder & "\smiley15.gif"))
        emoticontable.Add("^o)", New Bitmap(smileyfolder & "\smiley16.gif"))
        emoticontable.Add(":-#", New Bitmap(smileyfolder & "\smiley17.gif"))
        emoticontable.Add("(^)", New Bitmap(smileyfolder & "\smiley18.gif"))
        emoticontable.Add("(})", New Bitmap(smileyfolder & "\smiley19.gif"))
        emoticontable.Add("({)", New Bitmap(smileyfolder & "\smiley20.gif"))
        emoticontable.Add("(8)", New Bitmap(smileyfolder & "\smiley21.gif"))
        For Each key As String In emoticontable.Keys
            If key.Length > maxlength Then maxlength = key.Length
        Next
    End Sub
    Public Shared Sub Dispose()
        For Each img As Image In emoticontable.Values
            img.Dispose()
        Next
        emoticontable.Clear()
        emoticontable = Nothing
    End Sub
    Public Shared Sub Emoticonize(ByVal RTB As RichTextBox, Optional ByVal startindex As Integer = 0)
        SendMessage(RTB.Handle, WM_SETREDRAW, False, 0)

        'store previous states and clipboard before setting them
        Dim prevreadonly As Boolean = RTB.ReadOnly
        Dim prevenabled As Boolean = RTB.Enabled
        Dim prevselstart As Integer = RTB.SelectionStart
        Dim prevsellength As Integer = RTB.SelectionLength
        Dim prevdata As DataObject = Clipboard.GetDataObject
        RTB.ReadOnly = False
        RTB.Enabled = True

        'Loop through all indices (chars) of the Rich text box
        Dim i As Integer = startindex
        Do While i < RTB.TextLength
            Dim length As Integer = RTB.TextLength - i
            If maxlength < length Then length = maxlength
            Dim remainder As String = RTB.Text.Substring(i, length)
            For Each key As String In emoticontable.Keys
                If remainder.StartsWith(key, StringComparison.CurrentCultureIgnoreCase) Then
                    RTB.Select(i, key.Length)
                    Clipboard.SetDataObject(GetEmoticon(key))
                    RTB.Paste()
                    Exit For
                End If
            Next
            i += 1
        Loop

        'reset previous states
        RTB.ReadOnly = prevreadonly
        RTB.Enabled = prevenabled
        RTB.Select(prevselstart, prevsellength)
        Clipboard.SetDataObject(prevdata, True)

        SendMessage(RTB.Handle, WM_SETREDRAW, True, 0)
        RTB.Invalidate()
    End Sub
    Public Shared Sub AddMessage(ByVal RTB As RichTextBox, ByVal message As String)
        Dim selstart As Integer = RTB.TextLength
        RTB.Select(selstart, 0)
        RTB.SelectedText = vbNewLine & message
        Emoticonize(RTB, selstart)
    End Sub
    Public Shared Function GetEmoticon(ByVal emoticontext As String) As Image
        Return emoticontable.Item(emoticontext.ToLower)
    End Function
End Class