Imports System.ComponentModel
Imports System.Drawing.Design
Imports System.Text
Imports System.Runtime.Serialization
Imports System.Reflection

Imports Stax
Imports Stax.ComponentModel
Imports Stax.UI

<Serializable()> _
Public Class AviSynthDocument
    Inherits Profile

    <NonSerialized()> Private Framerate As Single
    <NonSerialized()> Private Frames As Integer
    <NonSerialized()> Private Size As Size
    <NonSerialized()> Private SynchronizeString As String = ""
    <NonSerialized()> Private FourCC As String = ""

    Public Sub New()
        Me.New(Nothing)
    End Sub

    Public Sub New(ByVal name As String)
        MyBase.New(name, "Script Profile")
    End Sub

    Private FiltersValue As New List(Of AviSynthFilter)

    Public ReadOnly Property Filters() As List(Of AviSynthFilter)
        Get
            Return FiltersValue
        End Get
    End Property

    Private PathValue As String = ""

    Public Overridable Property Path() As String
        Get
            Return PathValue
        End Get
        Set(ByVal Value As String)
            PathValue = Value
        End Set
    End Property

    Public Overridable Function GetScript() As String
        Return GetScript(Nothing)
    End Function

    Public Overridable Function GetScript(ByVal skipCategory As String) As String
        Dim sb As New StringBuilder()

        For Each i As AviSynthFilter In Filters
            If i.Active Then
                If skipCategory Is Nothing OrElse i.Category <> skipCategory Then
                    sb.Append(i.Script + vbCrLf)
                End If
            End If
        Next

        Return sb.ToString
    End Function

    Public Function IsFilterActive(ByVal category As String) As Boolean
        Return Not GetFilter(category) Is Nothing AndAlso GetFilter(category).Active
    End Function

    Public Function GetFilter(ByVal category As String) As AviSynthFilter
        For Each i As AviSynthFilter In Filters
            If i.Category = category Then
                Return i
            End If
        Next

        Return Nothing
    End Function

    Public Sub Synchronize()
        If Path <> "" Then
            Dim script As String = Macro.Solve(GetScript())
            Dim current As String = Path + script

            If current <> SynchronizeString Then
                If Directory.Exists(Filepath.GetDir(Path)) Then
                    StringHelp.WriteFile(Path, script)
                    Dim a As New AVIFile
                    a.Open(Path)
                    Framerate = a.FrameRate
                    Frames = a.FrameCount
                    FourCC = a.FourCC
                    Size = a.FrameSize
                    a.Close()
                    SynchronizeString = current
                End If
            End If
        End If
    End Sub

    Public Function Contains(ByVal value As String) As Boolean
        For Each i As AviSynthFilter In Filters
            If i.Active AndAlso i.Script.Contains(value) Then
                Return True
            End If
        Next

        Return False
    End Function

    Public Function IsValid() As Boolean
        Synchronize()

        If GetFrames() = 0 OrElse GetFrames() = 240 Then Return False

        Return True
    End Function

    Public Function GetFramerate() As Double
        Synchronize()
        Return Framerate
    End Function

    Public Function GetFourCC() As String
        Synchronize()
        Return FourCC
    End Function

    Public Function GetSeconds() As Integer
        Return CInt(GetFrames() / GetFramerate())
    End Function

    Public Function GetFrames() As Integer
        Synchronize()
        Return Frames
    End Function

    Public Function GetSize() As Size
        Synchronize()
        Return Size
    End Function

    Public Shared Function GetDefaults() As List(Of TargetAviSynthDocument)
        Dim ret As New List(Of TargetAviSynthDocument)

        Dim mpeg2 As New TargetAviSynthDocument("MPEG-2")
        mpeg2.Filters.Add(New AviSynthFilter("Source", "MPEG-2", "MPEG2Source(""%source_file%"")", True))
        mpeg2.Filters.Add(New AviSynthFilter("Crop", "Crop Borders", "Crop(%crop_left%,%crop_top%,-%crop_right%,-%crop_bottom%)", True))
        mpeg2.Filters.Add(New AviSynthFilter("Field", "Deinterlace", "FieldDeinterlace()", False))
        mpeg2.Filters.Add(New AviSynthFilter("Resize", "Neutral", "BicubicResize(%target_width%,%target_height%,0,0.5)", True))
        ret.Add(mpeg2)

        Dim avi As New TargetAviSynthDocument("AVI")
        avi.Filters.Add(New AviSynthFilter("Source", "AVI", "AVISource(%source_files_comma%,audio=false)", True))
        avi.Filters.Add(New AviSynthFilter("Crop", "Crop Borders", "Crop(%crop_left%,%crop_top%,-%crop_right%,-%crop_bottom%)", True))
        avi.Filters.Add(New AviSynthFilter("Field", "Deinterlace", "FieldDeinterlace()", False))
        avi.Filters.Add(New AviSynthFilter("Resize", "Neutral", "BicubicResize(%target_width%,%target_height%,0,0.5)", True))
        ret.Add(avi)

        Dim dshow As New TargetAviSynthDocument("DirectShow")
        dshow.Filters.Add(New AviSynthFilter("Source", "DirectShow", "DirectShowSource(""%source_file%"")", True))
        dshow.Filters.Add(New AviSynthFilter("Crop", "Crop Borders", "Crop(%crop_left%,%crop_top%,-%crop_right%,-%crop_bottom%)", True))
        dshow.Filters.Add(New AviSynthFilter("Field", "Deinterlace", "FieldDeinterlace()", False))
        dshow.Filters.Add(New AviSynthFilter("Resize", "Neutral", "BicubicResize(%target_width%,%target_height%,0,0.5)", True))
        ret.Add(dshow)

        Return ret
    End Function

    Public Overrides Function GetInfoValues() As System.Collections.Generic.Dictionary(Of String, String)
        Dim ret As New Dictionary(Of String, String)

        For Each i As AviSynthFilter In Filters
            ret(i.Category) = i.Script
        Next

        Return ret
    End Function

    Public Overrides Function Edit() As DialogResult
        Dim f As New ProfileControlForm(Name)

        If EditControl Is Nothing Then
            Dim c As New AviSynthListView
            c.Dock = DockStyle.Fill
            c.GetProfileMethod = AddressOf GetDocument
            c.Load()
            EditControlValue = c
        End If

        f.pControl.Controls.Add(EditControl)
        f.ShowDialog()
        f.Dispose()

        Return DialogResult.OK
    End Function

    Private Function GetDocument() As AviSynthDocument
        Return Me
    End Function
End Class

<Serializable()> _
Public Class TargetAviSynthDocument
    Inherits AviSynthDocument

    Public Sub New(ByVal name As String)
        MyBase.New(name)
        CanEditValue = True
    End Sub

    Public Overrides Property Path() As String
        Get
            If p.SourceFile = "" Then
                Return ""
            End If

            Return Filepath.GetDir(p.SourceFile) + p.Name + ".avs"
        End Get
        Set(ByVal value As String)
        End Set
    End Property
End Class

<Serializable()> _
Public Class SourceAviSynthDocument
    Inherits AviSynthDocument

    Public Sub New()
        Me.New(Nothing)
    End Sub

    Public Sub New(ByVal name As String)
        MyBase.New(name)
    End Sub

    Public Overrides Property Path() As String
        Get
            If p.SourceFile = "" Then
                Return ""
            End If

            Return Paths.GetTempDir + p.Name + "_Source.avs"
        End Get
        Set(ByVal value As String)
        End Set
    End Property

    Public Overrides Function GetScript() As String
        Dim l As Integer
        Dim found As Boolean = False

        For Each i As AviSynthFilter In p.TargetAVSDoc.Filters
            If i.Active AndAlso i.Category = "Source" Then
                found = True
                l += i.Script.Length + vbCrLf.Length
            End If
        Next

        Dim sb As New StringBuilder(l)

        For Each i As AviSynthFilter In p.TargetAVSDoc.Filters
            If i.Active AndAlso i.Category = "Source" Then
                sb.Append(i.Script + vbCrLf)
            End If
        Next

        Return sb.ToString
    End Function
End Class

<Serializable(), _
TypeConverter(GetType(PropertyConverter)), _
ListItemEditor(GetType(PropertyControl))> _
Public Class AviSynthFilter
    Public Sub New()
        Me.new("???", "???", "???", True)
    End Sub

    Public Sub New(ByVal category As String, ByVal name As String, ByVal script As String, ByVal active As Boolean)
        Me.Name = name
        Me.Script = script
        Me.Category = category
        Me.Active = active
    End Sub

    Private ActiveValue As Boolean

    <Browsable(False)> _
    Public Property Active() As Boolean
        Get
            Return ActiveValue
        End Get
        Set(ByVal Value As Boolean)
            ActiveValue = Value
        End Set
    End Property

    Private CategoryValue As String

    <Browsable(False)> _
    Public Property Category() As String
        Get
            Return CategoryValue
        End Get
        Set(ByVal Value As String)
            CategoryValue = Value
        End Set
    End Property

    Private NameValue As String

    <Order(0), _
    Name("Name:"), _
    Description("Name of this filter.")> _
    Public Property Name() As String
        Get
            Return NameValue
        End Get
        Set(ByVal Value As String)
            NameValue = Value
        End Set
    End Property

    Private ScriptValue As String

    <Order(1), _
    Name("Script:"), _
    DefaultValues("Height=70"), _
    Description("Code of this filter.")> _
    Public Property Script() As String
        Get
            Return ScriptValue
        End Get
        Set(ByVal Value As String)
            ScriptValue = StringHelp.FixBreak(Value)
        End Set
    End Property

    Public Function GetCopy() As AviSynthFilter
        Return New AviSynthFilter(Category, Name, Script, Active)
    End Function

    Public Overrides Function ToString() As String
        Return Name
    End Function
End Class

<Serializable(), _
TypeConverter(GetType(PropertyConverter))> _
Public Class AviSynthCategory
    Public Sub New()
        Name = "???"
    End Sub

    Public Sub New(ByVal name As String)
        Me.Name = name
    End Sub

    Private NameValue As String

    <Order(0), _
    Name("Name"), _
    Description("Name of this filter category.")> _
    Public Property Name() As String
        Get
            Return NameValue
        End Get
        Set(ByVal Value As String)
            NameValue = Value
        End Set
    End Property

    Private FitersValue As New ArrayList

    <Order(1), _
    Name("Filters"), _
    ListEditorProperties(GetType(AviSynthFilter), "Filters"), _
    Editor(GetType(ListEditor), GetType(UITypeEditor)), _
    Description("Filters of this filter category.")> _
    Public Property Filters() As ArrayList
        Get
            Return FitersValue
        End Get
        Set(ByVal Value As ArrayList)
            FitersValue = Value
        End Set
    End Property

    Public Overrides Function ToString() As String
        Return Name
    End Function
End Class