#Region "Copyright © 2001-2003 Jean-Claude Manoli [jc@manoli.net]"
'
' * This software is provided 'as-is', without any express or implied warranty.
' * In no event will the author(s) be held liable for any damages arising from
' * the use of this software.
' * 
' * Permission is granted to anyone to use this software for any purpose,
' * including commercial applications, and to alter it and redistribute it
' * freely, subject to the following restrictions:
' * 
' *   1. The origin of this software must not be misrepresented; you must not
' *      claim that you wrote the original software. If you use this software
' *      in a product, an acknowledgment in the product documentation would be
' *      appreciated but is not required.
' * 
' *   2. Altered source versions must be plainly marked as such, and must not
' *      be misrepresented as being the original software.
' * 
' *   3. This notice may not be removed or altered from any source distribution.
'  
#End Region

Imports System.IO
Imports System.Text
Imports System.Text.RegularExpressions

Namespace Manoli.Utils.CSharpFormat
	''' <summary>
	''' Provides a base class for formatting most programming languages.
	''' </summary>
	Public MustInherit Class CodeFormat
		Inherits SourceFormat
		''' <summary>
		''' Must be overridden to provide a list of keywords defined in 
		''' each language.
		''' </summary>
		''' <remarks>
		''' Keywords must be separated with spaces.
		''' </remarks>
		Protected MustOverride ReadOnly Property Keywords() As String

		''' <summary>
		''' Can be overridden to provide a list of preprocessors defined in 
		''' each language.
		''' </summary>
		''' <remarks>
		''' Preprocessors must be separated with spaces.
		''' </remarks>
		Protected Overridable ReadOnly Property Preprocessors() As String
			Get
				Return ""
			End Get
		End Property

		''' <summary>
		''' Must be overridden to provide a regular expression string
		''' to match strings literals. 
		''' </summary>
		Protected MustOverride ReadOnly Property StringRegEx() As String

		''' <summary>
		''' Must be overridden to provide a regular expression string
		''' to match comments. 
		''' </summary>
		Protected MustOverride ReadOnly Property CommentRegEx() As String

		''' <summary>
		''' Determines if the language is case sensitive.
		''' </summary>
		''' <value><b>true</b> if the language is case sensitive, <b>false</b> 
		''' otherwise. The default is true.</value>
		''' <remarks>
		''' A case-insensitive language formatter must override this 
		''' property to return false.
		''' </remarks>
		Public Overridable ReadOnly Property CaseSensitive() As Boolean
			Get
				Return True
			End Get
		End Property

		''' <summary/>
		Protected Sub New()
			'generate the keyword and preprocessor regexes from the keyword lists
			Dim r As Regex
			r = New Regex("\w+|-\w+|#\w+|@@\w+|#(?:\\(?:s|w)(?:\*|\+)?\w+)+|@\\w\*+")
			Dim regKeyword As String = r.Replace(Keywords, "(?<=^|\W)$0(?=\W)")
			Dim regPreproc As String = r.Replace(Preprocessors, "(?<=^|\s)$0(?=\s|$)")
			r = New Regex(" +")
			regKeyword = r.Replace(regKeyword, "|")
			regPreproc = r.Replace(regPreproc, "|")

			If regPreproc.Length = 0 Then
				regPreproc = "(?!.*)_{37}(?<!.*)" 'use something quite impossible...
			End If

			'build a master regex with capturing groups
			Dim regAll As New StringBuilder()
			regAll.Append("(")
			regAll.Append(CommentRegEx)
			regAll.Append(")|(")
			regAll.Append(StringRegEx)
			If regPreproc.Length > 0 Then
				regAll.Append(")|(")
				regAll.Append(regPreproc)
			End If
			regAll.Append(")|(")
			regAll.Append(regKeyword)
			regAll.Append(")")

			Dim caseInsensitive As RegexOptions
			If CaseSensitive Then
				caseInsensitive = 0
			Else
				caseInsensitive = RegexOptions.IgnoreCase
			End If
			CodeRegex = New Regex(regAll.ToString(), RegexOptions.Singleline Or caseInsensitive)
		End Sub

		''' <summary>
		''' Called to evaluate the HTML fragment corresponding to each 
		''' matching token in the code.
		''' </summary>
		''' <param name="match">The <see cref="Match"/> resulting from a 
		''' single regular expression match.</param>
		''' <returns>A string containing the HTML code fragment.</returns>
		Protected Overrides Function MatchEval(ByVal match As Match) As String
			If match.Groups(1).Success Then 'comment
				Dim reader As New StringReader(match.ToString())
				Dim line As String
				Dim sb As New StringBuilder()
				line = reader.ReadLine()
				Do While line IsNot Nothing
					If sb.Length > 0 Then
						sb.Append(vbLf)
					End If
					sb.Append("<span class=""rem"">")
					sb.Append(line)
					sb.Append("</span>")
					line = reader.ReadLine()
				Loop
				Return sb.ToString()
			End If
			If match.Groups(2).Success Then 'string literal
				Return "<span class=""str"">" & match.ToString() & "</span>"
			End If
			If match.Groups(3).Success Then 'preprocessor keyword
				Return "<span class=""preproc"">" & match.ToString() & "</span>"
			End If
			If match.Groups(4).Success Then 'keyword
				Return "<span class=""kwrd"">" & match.ToString() & "</span>"
			End If
			System.Diagnostics.Debug.Assert(False, "None of the above!")
			Return "" 'none of the above
		End Function
	End Class
End Namespace

