'  
'   Rebex Sample Code License
' 
'   Copyright 2025, REBEX CR s.r.o.
'   All rights reserved.
'   https://www.rebex.net/
' 
'   Permission to use, copy, modify, and/or distribute this software for any
'   purpose with or without fee is hereby granted.
' 
'   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
'   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
'   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
'   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
'   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
'   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
'   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
'   OTHER DEALINGS IN THE SOFTWARE.
' 

Imports System
Imports System.IO
Imports System.Text

Imports Rebex.TerminalEmulation

''' <summary>
''' The ANSI convertor class converts a text file containing ANSI escape sequences 
''' to another format (image, HTML or plain text) using VirtualTerminal class. 
''' ANSI escape sequences are interpreted by the VirtualTerminal class and
''' rendered on the VirtualTerminal's screen. Thenn, the VirtualTerminal's screen
''' is saved in the specified format.
''' </summary>
Public Class AnsiConvertor
    ''' <summary>Default terminal width in columns.</summary>
    Private Const DEFAULT_TERMINAL_COLUMNS As Integer = 80

    ''' <summary>Default terminal height in rows.</summary>
    Private Const DEFAULT_TERMINAL_ROWS As Integer = 25

    ''' <summary>
    ''' Class that stores parsed program arguments.
    ''' </summary>
    Private Class ProgramArguments
        ''' <summary>
        ''' Gets or sets the path of the source file.
        ''' </summary>
        Public Property SourcePath() As String
            Get
                Return _sourcePath
            End Get
            Set(value As String)
                _sourcePath = Value
            End Set
        End Property
        Private _sourcePath As String

        ''' <summary>
        ''' Gets or sets the path of the output file.
        ''' </summary>
        Public Property OutputPath() As String
            Get
                Return _outputPath
            End Get
            Set(value As String)
                _outputPath = Value
            End Set
        End Property
        Private _outputPath As String

        ''' <summary>
        ''' Gets or sets the capture format of the output file.
        ''' </summary>
        Public Property CaptureFormat() As TerminalCaptureFormat
            Get
                Return _captureFormat
            End Get
            Set(value As TerminalCaptureFormat)
                _captureFormat = Value
            End Set
        End Property
        Private _captureFormat As TerminalCaptureFormat

        ''' <summary>
        ''' Gets or sets the number of columns of the Virtual terminal.
        ''' </summary>
        Public Property Columns() As Integer
            Get
                Return _columns
            End Get
            Set(value As Integer)
                _columns = Value
            End Set
        End Property
        Private _columns As Integer

        ''' <summary>
        ''' Gets or sets the number of rows of the Virtual terminal.
        ''' </summary>
        Public Property Rows() As Integer
            Get
                Return _rows
            End Get
            Set(value As Integer)
                _rows = Value
            End Set
        End Property
        Private _rows As Integer
    End Class

    ''' <summary>
    ''' The main entry point for the application.
    ''' </summary>
    ''' <param name="args">Program arguments.</param>
    ''' <returns>Exit code.</returns>
    <STAThread()> _
    Public Shared Function Main(ByVal args As String()) As Integer

            ' set the trial license key
            Rebex.Licensing.Key = Rebex.Samples.TrialKey.Key


        ' if bad number of arguments was specified, show help and return
        If args.Length <> 3 AndAlso args.Length <> 5 Then
            ShowHelp()
            Return 1
        End If

        ' get parsed program arguments
        Dim arguments As ProgramArguments = GetProgramArguments(args)

        ' if program arguments were not parsed successfully, return
        If arguments Is Nothing Then
            Return 1
        End If

        ' create a new virtual (off-screen) terminal
        Dim terminal As New VirtualTerminal(arguments.Columns, arguments.Rows)

        ' ANSI text file may contains a terminal screen size change sequence that triggers the RemoteResize event.
        ' By default, this event is ignored, but because we wish support these screen size changes, we have to 
        ' register the RemoteResize event handler and change the terminal screen size accordingly.
        If args.Length = 3 Then
            AddHandler terminal.RemoteResize, AddressOf terminal_RemoteResize
        End If

        Dim reader As StreamReader = Nothing
        Try
            ' open the file for reading
            reader = New StreamReader(arguments.SourcePath)

            ' read the whole file to the string
            Dim data As String = reader.ReadToEnd()

            ' write the data to the terminal screen
            terminal.Screen.Write(data)

            ' save terminal to specified outputPath
            terminal.Save(arguments.OutputPath, arguments.CaptureFormat)

            Console.WriteLine("Successfully converted.")
        Catch e As Exception
            Console.WriteLine("Exception occured: {0}", e)
            Return 1
        Finally
            If Not reader Is Nothing Then reader.Close()
        End Try

        Return 0
    End Function

    ''' <summary>
    ''' Handles the terminal RemoteResize event.
    ''' </summary>
    ''' <param name="sender">Event sender.</param>
    ''' <param name="e">Event arguments.</param>
    Private Shared Sub terminal_RemoteResize(ByVal sender As Object, ByVal e As RemoteResizeEventArgs)
        If TypeOf sender Is VirtualTerminal Then
            Dim terminal As VirtualTerminal = CType(sender, VirtualTerminal)

            ' set the size of the terminal screen according to the event values
            terminal.SetScreenSize(e.Columns, e.Rows)
        End If
    End Sub

    ''' <summary>
    ''' Shows syntax and examples.
    ''' </summary>
    Private Shared Sub ShowHelp()
        Console.WriteLine("---------------------------------------------------------------------------------")
        Console.WriteLine("Rebex ANSI Convertor - converts ANSI text file to the file of 'another' format")
        Console.WriteLine("---------------------------------------------------------------------------------")
        Console.WriteLine("Formats available: Ansi, Text, Html, Bmp, Jpeg, Png, Gif, Tiff.")
        Console.WriteLine()
        Console.WriteLine("Syntax: AnsiConvertor sourcePath outputPath format [terminalColumns terminalRows]")
        Console.WriteLine("If terminalColumns and terminalRows are not specified explicitly, it will be taken")
        Console.WriteLine("from the source file if available. If terminal resolution is not stored within the file,")
        Console.WriteLine("the default values will be used ({0} for terminalColumns and {1} for terminalRows).", DEFAULT_TERMINAL_COLUMNS, DEFAULT_TERMINAL_ROWS)
        Console.WriteLine()
        Console.WriteLine("Example: AnsiConvertor ansiFile.ans imageFile.png png 80 25")
        Console.WriteLine("Example: AnsiConvertor ansiFile.ans imageFile.png png")
    End Sub

    ''' <summary>
    ''' Parses program arguments and returns them in the ProgramArguments class.
    ''' </summary>
    ''' <param name="args">Program arguments.</param>
    ''' <returns>
    ''' Initialized ProgramArguments class filled with parsed program arguments;
    ''' null if the arguments can't be parsed.
    ''' </returns>
    Private Shared Function GetProgramArguments(ByVal args As String()) As ProgramArguments
        Dim arguments As New ProgramArguments

        arguments.SourcePath = args(0)
        arguments.OutputPath = args(1)

        ' check whether the source file exist
        If Not File.Exists(arguments.SourcePath) Then
            Console.WriteLine("Specified input file ({0}) doesn't exist.", arguments.SourcePath)
            Return Nothing
        End If

        ' parse TerminalCaptureFormat
        Select Case args(2).ToLower()
            Case "bmp"
                arguments.CaptureFormat = TerminalCaptureFormat.Bmp
                Exit Select
            Case "gif"
                arguments.CaptureFormat = TerminalCaptureFormat.Gif
                Exit Select
            Case "htm", "html"
                arguments.CaptureFormat = TerminalCaptureFormat.Html
                Exit Select
            Case "jpg", "jpeg"
                arguments.CaptureFormat = TerminalCaptureFormat.Jpeg
                Exit Select
            Case "png"
                arguments.CaptureFormat = TerminalCaptureFormat.Png
                Exit Select
            Case "txt", "text"
                arguments.CaptureFormat = TerminalCaptureFormat.Text
                Exit Select
            Case "tif", "tiff"
                arguments.CaptureFormat = TerminalCaptureFormat.Tiff
                Exit Select
            Case "ans", "ansi"
                arguments.CaptureFormat = TerminalCaptureFormat.Ansi
                Exit Select
            Case Else
                ShowHelp()
                Console.WriteLine()
                Console.WriteLine("Unrecognized output format ({0}).", args(2))
                Return Nothing
        End Select

        ' parse terminalColumns and terminalRows if specified
        If args.Length = 5 Then
            Try
                arguments.Columns = Integer.Parse(args(3))
            Catch
                arguments.Columns = 0
            End Try

            If arguments.Columns <= 0 Then
                Console.WriteLine("TerminalColumns must be positive number, but was ({0}).", args(3))
                Return Nothing
            End If

            Try
                arguments.Rows = Integer.Parse(args(4))
            Catch
                arguments.Rows = 0
            End Try

            If arguments.Rows <= 0 Then
                Console.WriteLine("TerminalRows must be positive number, but was ({0}).", args(4))
                Return Nothing
            End If
        Else
            arguments.Columns = DEFAULT_TERMINAL_COLUMNS
            arguments.Rows = DEFAULT_TERMINAL_ROWS
        End If

        Return arguments
    End Function
End Class
