Imports System.IO
Imports System.ComponentModel
Imports System.Globalization
Imports System.Text.RegularExpressions
Imports DevExpress
Imports DevExpress.Spreadsheet
Imports DevExpress.XtraRichEdit.Commands
Imports DevExpress.XtraRichEdit
Imports DevExpress.Office.Utils
Imports GdPicture14
Imports DigitalData.Modules.Logging
Imports DigitalData.Modules.Messaging

Public Class DocumentViewer
    Private Enum ZoomMode
        Zoom50
        Zoom100
        Zoom150
        Zoom200
        ZoomSelectedArea
        ZoomFitToViewer
        ZoomFitWidth
        ZoomFitHeight
    End Enum

    Private Enum ViewerMode
        GDPicture
        RichText
        Excel
    End Enum

    Private _ViewerMode As ViewerMode
    Private _currentSearchOccurence As Integer = 0
    Private _toggleGamma As Boolean = True
    Private _licenseKey As String = String.Empty
    Private _licenseManager As New GdPicture14.LicenseManager()
    Private _logConfig As LogConfig
    Private _logger As Logger
    Private _email As Email2

    Private _hide_file_info_from_user As Boolean = False
    Private _FilePath As String
    Private _Fileinfo As FileInfo

    ' List of all created temp files when converting msg files
    Private _TempFiles As New List(Of String)

    Private Sub DocumentViewer_Load(sender As Object, e As EventArgs) Handles Me.Load
        _TempFiles.Clear()

        UpdateMainUi()
    End Sub


    Public Property FileLoaded As Boolean = False

    ''' <summary>
    ''' Initialize the Viewer
    ''' </summary>
    ''' <param name="pLogConfig">A LogConfig object</param>
    ''' <param name="pLicenseKey">The GDPicture.NET License Key</param>
    Public Sub Init(pLogConfig As LogConfig, pLicenseKey As String)
        _logConfig = pLogConfig
        _logger = pLogConfig.GetLogger()
        _email = New Email2(pLogConfig)
        _licenseKey = pLicenseKey
        _licenseManager.RegisterKEY(_licenseKey)
    End Sub

    ''' <summary>
    ''' Terminate Viewer, freeing up resources and deleting temp files
    ''' </summary>
    Public Sub Done()
        _logger.Debug("Done: Deleting Temp Files")
        DeleteTempFiles()

        _logger.Debug("Done: Closing Documents")
        FreeFile()

        _logger.Debug("Done: Triggering GC")
        GC.Collect()
    End Sub

    ''' <summary>
    ''' Load a file and display it
    ''' </summary>
    ''' <param name="FilePath"></param>
    Public Sub LoadFile(FilePath As String)
        FileLoaded = False

        If _licenseKey = String.Empty Then
            _logger.Warn("License key was not provided. File {0} not loaded.", FilePath)
            Exit Sub
        End If

        If FilePath Is Nothing OrElse FilePath.Trim().Length = 0 Then
            _logger.Warn("FilePath was not provided. File not loaded.")
            Exit Sub
        End If

        _logger.Info("Loading File {0}", FilePath)

        FileLoaded = DoLoadFile(FilePath)
        _FilePath = FilePath
        _Fileinfo = New FileInfo(FilePath)

        SetViewerMode(_Fileinfo.Extension)
        UpdateMainUi()
    End Sub

    Public Sub LoadFile(FileName As String, Stream As Stream)
        FileLoaded = False

        If _licenseKey = String.Empty Then
            _logger.Warn("License key was not provided. File [{0}] not loaded.", FileName)
            Exit Sub
        End If

        Dim oExtension As String = FileName.Substring(FileName.LastIndexOf("."))

        _logger.Info("Loading File [{0}]", FileName)

        FileLoaded = DoLoadFile(Stream, oExtension)

        SetViewerMode(oExtension)
        UpdateMainUi()
    End Sub

    Public Sub CloseDocument()
        GdViewer.CloseDocument()
        UpdateMainUi()
    End Sub

    Public Sub DeleteTempFiles()
        For Each oFile In _TempFiles
            Try
                IO.File.Delete(oFile)
            Catch ex As Exception
                _logger.Warn("Could not delete temp file {0}", oFile)
            End Try
        Next
        _TempFiles.Clear()
    End Sub

    Private Sub SetViewerMode(Extension As String)
        Select Case Extension.ToUpper
            Case ".MSG"
                _ViewerMode = ViewerMode.RichText
            Case ".EML", ".DOC", ".DOCX", ".ODT", ".RTF", ".TXT"
                _ViewerMode = ViewerMode.RichText
            Case ".XLSX", ".XLS", "CSV"
                _ViewerMode = ViewerMode.Excel
            Case Else
                _ViewerMode = ViewerMode.GDPicture
        End Select
    End Sub


    Private Sub FreeFile()
        Try
            If Len(_FilePath) = 0 OrElse _Fileinfo Is Nothing Then
                Exit Sub
            End If
            Dim oExtension As String = _Fileinfo.Extension.ToUpper
            Select Case _ViewerMode
                Case ViewerMode.RichText
                    RichEditControl1.CreateNewDocument()

                Case ViewerMode.Excel
                    SpreadsheetControl1.CreateNewDocument()

                Case Else
                    GdViewer.CloseDocument()

            End Select
        Catch ex As Exception
            _logger.Warn($"Unexpected error in FreeFile: {ex.Message}")
        End Try
    End Sub
    Private Function DoLoadFile(FilePath As String) As Boolean
        Try
            Dim oFileInfo = New FileInfo(FilePath)
            Dim oExtension As String = oFileInfo.Extension.ToUpper

            RichEditControl1.Visible = False
            RichEditControl1.Dock = DockStyle.None

            SpreadsheetControl1.Visible = False
            SpreadsheetControl1.Dock = DockStyle.None

            Select Case oExtension.ToUpper
                Case ".MSG"
                    Dim oEmlPath As String = _email.Convert_ToEml(FilePath)
                    DoLoadFile(oEmlPath)

                Case ".EML", ".DOC", ".DOCX", ".ODT", ".RTF", ".TXT"
                    RichEditControl1.LoadDocument(FilePath, GetDocumentFormat(oExtension))

                    RichEditControl1.Visible = True
                    RichEditControl1.Dock = DockStyle.Fill

                Case ".XLSX", ".XLS", ".CSV"
                    Dim oFormat = GetSpreadsheetFormat(oExtension)
                    SpreadsheetControl1.LoadDocument(FilePath, oFormat)

                    Dim oRange = SpreadsheetControl1.ActiveWorksheet.GetUsedRange()
                    oRange.AutoFitColumns()

                    SpreadsheetControl1.Visible = True
                    SpreadsheetControl1.Dock = DockStyle.Fill

                Case Else
                    'ToolbarDocumentViewer.Visible = True

                    GdViewer.ZoomMode = ViewerZoomMode.ZoomModeWidthViewer
                    GdViewer.DocumentAlignment = ViewerDocumentAlignment.DocumentAlignmentTopCenter

                    GdViewer.DisplayFromFile(FilePath)
            End Select

            UpdateMainUi()

            Return True
        Catch ex As Exception
            _logger.Error(ex)
            Return False
        End Try
    End Function

    Private Function DoLoadFile(Stream As Stream, Extension As String) As Boolean
        Try
            RichEditControl1.Visible = False
            RichEditControl1.Dock = DockStyle.None

            SpreadsheetControl1.Visible = False
            SpreadsheetControl1.Dock = DockStyle.None

            Select Case Extension.ToUpper
                Case ".MSG"

                    Dim oTempFileName = Path.Combine(IO.Path.GetTempPath(), Guid.NewGuid.ToString & ".msg")
                    Using oFileStream As New FileStream(oTempFileName, FileMode.Create)
                        Stream.Seek(0, SeekOrigin.Begin)
                        Stream.CopyTo(oFileStream)
                        Stream.Flush()
                    End Using

                    Dim oEmlPath As String = _email.Convert_ToEml(oTempFileName)
                    DoLoadFile(oEmlPath)

                Case ".EML", ".DOC", ".DOCX", ".ODT", ".RTF", ".TXT"
                    RichEditControl1.LoadDocument(Stream, GetDocumentFormat(Extension))

                    RichEditControl1.ActiveViewType = XtraRichEdit.RichEditViewType.PrintLayout
                    RichEditControl1.Visible = True
                    RichEditControl1.Dock = DockStyle.Fill

                Case ".XLSX", ".XLS", ".CSV"
                    SpreadsheetControl1.LoadDocument(Stream, GetSpreadsheetFormat(Extension))

                    Dim oRange = SpreadsheetControl1.ActiveWorksheet.GetUsedRange()
                    oRange.AutoFitColumns()

                    SpreadsheetControl1.Visible = True
                    SpreadsheetControl1.Dock = DockStyle.Fill

                Case Else
                    'ToolbarDocumentViewer.Visible = True

                    GdViewer.ZoomMode = ViewerZoomMode.ZoomModeWidthViewer
                    GdViewer.DocumentAlignment = ViewerDocumentAlignment.DocumentAlignmentTopCenter

                    GdViewer.DisplayFromStream(Stream)
            End Select

            UpdateMainUi()

            Return True
        Catch ex As Exception
            _logger.Error(ex)
            Return False
        End Try
    End Function

    Private Function GetSpreadsheetFormat(Extension) As Spreadsheet.DocumentFormat
        Dim oFormat As Spreadsheet.DocumentFormat = Spreadsheet.DocumentFormat.Undefined

        Select Case Extension.ToUpper
            Case ".XLSX" : oFormat = Spreadsheet.DocumentFormat.Xlsx
            Case ".XLS" : oFormat = Spreadsheet.DocumentFormat.Xls
            Case ".CSV" : oFormat = Spreadsheet.DocumentFormat.Csv
        End Select

        Return oFormat
    End Function

    Private Function GetDocumentFormat(Extension) As XtraRichEdit.DocumentFormat
        Dim oFormat As XtraRichEdit.DocumentFormat = XtraRichEdit.DocumentFormat.Undefined

        Select Case Extension.ToUpper
            Case ".EML" : oFormat = XtraRichEdit.DocumentFormat.Mht
            Case ".DOC" : oFormat = XtraRichEdit.DocumentFormat.Doc
            Case ".DOCX" : oFormat = XtraRichEdit.DocumentFormat.OpenXml
            Case ".ODT" : oFormat = XtraRichEdit.DocumentFormat.OpenDocument
            Case ".RTF" : oFormat = XtraRichEdit.DocumentFormat.Rtf
            Case ".TXT" : oFormat = XtraRichEdit.DocumentFormat.PlainText
        End Select

        Return oFormat
    End Function


    Private Sub btnOpen_Click(sender As Object, e As EventArgs)
        GdViewer.ZoomMode = ViewerZoomMode.ZoomModeWidthViewer
        GdViewer.DocumentAlignment = ViewerDocumentAlignment.DocumentAlignmentTopCenter

        If OpenFileDialog.ShowDialog() = DialogResult.OK Then
            GdViewer.DisplayFromFile(OpenFileDialog.FileName)
        End If

        GdViewer.Focus()
        UpdateMainUi()
    End Sub

    ''' <summary>
    ''' Configures the viewer to hide the file path to the end-user.
    ''' </summary>
    ''' <param name="ViewOnly">
    ''' True means that all file info should be hidden from the end-user
    ''' False means the end user may see the filepath or other info about the file
    ''' </param>
    Public Sub SetViewOnly(ViewOnly As Boolean)
        If ViewOnly Then
            buttonPrint.Visibility = XtraBars.BarItemVisibility.Never
        Else
            buttonPrint.Visibility = XtraBars.BarItemVisibility.Always
        End If

        _hide_file_info_from_user = ViewOnly
    End Sub

    Public Sub SetAllowAnnotations(AllowAnnotations As Boolean)

    End Sub

    ''' <summary>
    ''' DEPRECATED: Use SetViewOnly
    ''' </summary>
    Public Sub RightViewOnly(ViewOnly As Boolean)
        SetViewOnly(ViewOnly)
    End Sub

    ''' <summary>
    ''' DEPRECATED: Use SetViewOnly
    ''' </summary>
    Public Sub RightOnlyView(ViewOnly As Boolean)
        SetViewOnly(ViewOnly)
    End Sub

    Private Sub UpdateMainUi()

        Select Case _ViewerMode
            Case ViewerMode.GDPicture
                buttonPrint.Enabled = True
                buttonFitWidth.Enabled = True
                buttonFitPage.Enabled = True
                buttonZoomIn.Enabled = True
                buttonZoomOut.Enabled = True
                buttonRotateLeft.Enabled = True
                buttonRotateRight.Enabled = True
                buttonFlipX.Enabled = True
                buttonFlipY.Enabled = True
                buttonFirstPage.Enabled = True
                buttonPrevPage.Enabled = True
                buttonNextPage.Enabled = True
                buttonLastPage.Enabled = True
                buttonSettings.Enabled = True
                txtCurrentPage.Enabled = True

            Case ViewerMode.RichText
                buttonFitPage.Enabled = True
                buttonZoomIn.Enabled = True
                buttonZoomOut.Enabled = True
                buttonFitWidth.Enabled = True
                buttonNextPage.Enabled = True
                buttonPrevPage.Enabled = True

                buttonPrint.Enabled = False
                buttonRotateLeft.Enabled = False
                buttonRotateRight.Enabled = False
                buttonFlipX.Enabled = False
                buttonFlipY.Enabled = False
                buttonFirstPage.Enabled = False
                buttonLastPage.Enabled = False
                buttonSettings.Enabled = False
                txtCurrentPage.Enabled = False

            Case ViewerMode.Excel
                buttonPrint.Enabled = False
                buttonFitWidth.Enabled = False
                buttonFitPage.Enabled = False
                buttonZoomIn.Enabled = False
                buttonZoomOut.Enabled = False
                buttonRotateLeft.Enabled = False
                buttonRotateRight.Enabled = False
                buttonFlipX.Enabled = False
                buttonFlipY.Enabled = False
                buttonFirstPage.Enabled = False
                buttonPrevPage.Enabled = False
                buttonNextPage.Enabled = False
                buttonLastPage.Enabled = False
                buttonSettings.Enabled = False
                txtCurrentPage.Enabled = False

        End Select

    End Sub

    Private Sub btnFirstPage_Click(ByVal sender As System.Object, ByVal e As EventArgs) Handles buttonFirstPage.ItemClick
        GdViewer.DisplayFirstPage()
    End Sub

    Private Sub btnPreviousPage_Click(ByVal sender As System.Object, ByVal e As EventArgs) Handles buttonPrevPage.ItemClick
        If _ViewerMode = ViewerMode.GDPicture Then
            GdViewer.DisplayPreviousPage()
        ElseIf _ViewerMode = ViewerMode.RichText Then
            Dim oCmd As New PreviousPageCommand(RichEditControl1)
            oCmd.Execute()
        End If
    End Sub

    Private Sub btnNextPage_Click(ByVal sender As System.Object, ByVal e As EventArgs) Handles buttonNextPage.ItemClick
        If _ViewerMode = ViewerMode.GDPicture Then
            GdViewer.DisplayNextPage()
        ElseIf _ViewerMode = ViewerMode.RichText Then
            Dim oCmd As New NextPageCommand(RichEditControl1)
            oCmd.Execute()
        End If
    End Sub

    Private Sub btnLastPage_Click(ByVal sender As System.Object, ByVal e As EventArgs) Handles buttonLastPage.ItemClick
        GdViewer.DisplayLastPage()
    End Sub

    Private Sub tbCurrentPage_Leave(ByVal sender As System.Object, ByVal e As EventArgs) Handles txtCurrentPage.EditValueChanged
        Dim page As Integer = 0
        If Integer.TryParse(txtCurrentPage.EditValue, page) Then
            If page > 0 And page <= GdViewer.PageCount Then
                GdViewer.DisplayPage(page)
                UpdateaNavigationToolbar()
            End If
        End If
    End Sub

    Private Sub GdViewer1_PageChanged() Handles GdViewer.PageChanged
        UpdateaNavigationToolbar()
    End Sub

    Private Sub GdViewer1_AfterZoomChange() Handles GdViewer.AfterZoomChange
        UpdateaNavigationToolbar()
        If GdViewer.MouseMode = ViewerMouseMode.MouseModeAreaZooming Then
            GdViewer.MouseMode = ViewerMouseMode.MouseModePan
        End If
    End Sub

    Private Sub btnZoomOut_Click(sender As Object, e As EventArgs) Handles buttonZoomOut.ItemClick
        If _ViewerMode = ViewerMode.GDPicture Then
            GdViewer.ZoomOUT()
        ElseIf _ViewerMode = ViewerMode.RichText Then
            Dim oCmd As New ZoomOutCommand(RichEditControl1)
            oCmd.Execute()
        End If
    End Sub

    Private Sub btnZoomIn_Click(sender As Object, e As EventArgs) Handles buttonZoomIn.ItemClick
        If _ViewerMode = ViewerMode.GDPicture Then
            GdViewer.ZoomIN()
        ElseIf _ViewerMode = ViewerMode.RichText Then
            Dim oCmd As New ZoomInCommand(RichEditControl1)
            oCmd.Execute()
        End If
    End Sub

    Private Sub btnPrint_Click(sender As Object, e As EventArgs) Handles buttonPrint.ItemClick
        If GdViewer.PageCount = 0 Then
            Return
        End If

        GdViewer.PrintDialog()
    End Sub

    Private Sub btnRotateLeft_Click(sender As Object, e As EventArgs) Handles buttonRotateLeft.ItemClick
        GdViewer.Rotate(RotateFlipType.Rotate270FlipNone)
    End Sub

    Private Sub btnRotateRight_Click(sender As Object, e As EventArgs) Handles buttonRotateRight.ItemClick
        GdViewer.Rotate(RotateFlipType.Rotate90FlipNone)
    End Sub

    Private Sub btnFlipX_Click(sender As Object, e As EventArgs) Handles buttonFlipX.ItemClick
        GdViewer.Rotate(RotateFlipType.RotateNoneFlipX)
    End Sub

    Private Sub btnFlipY_Click(sender As Object, e As EventArgs) Handles buttonFlipY.ItemClick
        GdViewer.Rotate(RotateFlipType.RotateNoneFlipY)
    End Sub

    Private Sub GdViewer1_TransferEnded(ByVal status As GdPictureStatus, ByVal download As System.Boolean) Handles GdViewer.TransferEnded
        GdViewer.Focus()
        UpdateMainUi()
    End Sub

    Private Sub AddSearchRegion(ByVal occurence As Integer, ByVal leftCoordinate As Single, ByVal topCoordinate As Single, ByVal regionWidth As Single, ByVal regionheight As Single, ByVal ensureVisibility As Boolean)
        Dim searchRegion As Integer = GdViewer.AddRegionInches("SearchResult" & occurence, leftCoordinate, topCoordinate, regionWidth, regionheight, ForegroundMixMode.ForegroundMixModeMASKPEN, Color.Yellow)
        GdViewer.SetRegionEditable(searchRegion, False)
        If ensureVisibility Then
            GdViewer.EnsureRegionVisibility(searchRegion)
        End If
    End Sub

    Private Sub btnSettings_Click(ByVal sender As Object, ByVal e As EventArgs) Handles buttonSettings.ItemClick
        Using frmSettings As New frmViewerSettings(GdViewer)
            frmSettings.ShowDialog(Me)
        End Using
        UpdateaNavigationToolbar()
    End Sub

    Private Sub UpdateaNavigationToolbar()
        Try
            Dim oCurrentZoom As Double = GdViewer.Zoom
            Dim oCurrentPage As Integer = GdViewer.CurrentPage
            Dim oPageCount As Integer = GdViewer.PageCount
            txtCurrentPage.EditValue = oCurrentPage
            labelPageCount.Caption = $"/ {oPageCount}"

            If oCurrentPage = oPageCount Then
                buttonLastPage.Enabled = False
                buttonNextPage.Enabled = False
                buttonPrevPage.Enabled = True
                buttonFirstPage.Enabled = True
            ElseIf oCurrentPage = 1 Then
                buttonPrevPage.Enabled = False
                buttonFirstPage.Enabled = False
                buttonLastPage.Enabled = True
                buttonNextPage.Enabled = True
            Else
                buttonPrevPage.Enabled = True
                buttonFirstPage.Enabled = True
                buttonLastPage.Enabled = True
                buttonNextPage.Enabled = True
            End If
        Catch ex As Exception
            _logger.Error(ex)
        End Try
    End Sub

    Private Sub btnFitWidth_Click(ByVal sender As Object, ByVal e As EventArgs) Handles buttonFitWidth.ItemClick
        If _ViewerMode = ViewerMode.GDPicture Then
            GdViewer.ZoomMode = ViewerZoomMode.ZoomModeWidthViewer
        ElseIf _ViewerMode = ViewerMode.RichText Then
            Dim oCmd As New FitWidthCommand(RichEditControl1)
            oCmd.Execute()
        End If
    End Sub

    Private Sub btnFitPage_Click(ByVal sender As Object, ByVal e As EventArgs) Handles buttonFitPage.ItemClick
        If _ViewerMode = ViewerMode.GDPicture Then
            GdViewer.ZoomMode = ViewerZoomMode.ZoomModeFitToViewer
        ElseIf _ViewerMode = ViewerMode.RichText Then
            Dim oCmd As New FitToPageCommand(RichEditControl1)
            oCmd.Execute()
        End If
    End Sub

    Private Sub RichEditControl1_SizeChanged(sender As Object, e As EventArgs) Handles RichEditControl1.SizeChanged
        Dim oControlWidth = RichEditControl1.Width - 100
        Dim oPageWidth = Units.DocumentsToPixelsF(RichEditControl1.Document.Sections(0).Page.Width, RichEditControl1.DpiX)
        RichEditControl1.Views.PrintLayoutView.ZoomFactor = oControlWidth / oPageWidth
    End Sub
End Class
