Imports System
Imports System.Collections
Imports System.ComponentModel
Imports System.Drawing
Imports System.Threading
Imports System.Windows.Forms

Public Class FibonacciPPForm
    Inherits System.Windows.Forms.Form

    Private numberToCompute As Integer = 0
    Private numberToCompute1 As Integer = 0
    Private highestPercentageReached As Integer = 0

    Public cancelreq As Integer
    Const npmax = 5
    Public nnin(npmax) As Integer
    Public nnout(npmax) As Long
    Public state(npmax), np, nfact As Integer
    Public Const StartSt As Integer = 1, ActiveSt As Integer = 2, StopSt As Integer = 0, CancelSt As Integer = 3, Endst = 0
    Public Const Trace = 1

    Public Sub New()
        InitializeComponent()
        InitializeForm()
        Init()
    End Sub 'New

    Private Sub StartAsyncButton_Click(ByVal sender As System.Object, _
      ByVal e As System.EventArgs) Handles StartAsyncButton.Click
        If Trace = 1 Then Debug.Print("StartAsyncButton")

        ' Reset the text in the result label.
        Me.progressBar1.Value = 0
        resultLabel1.Text = [String].Empty
        resultLabel2.Text = [String].Empty
        cancelreq = 0

        ' Disable the UpDown control until 
        ' the asynchronous operation is done.
        Me.numericUpDown1.Enabled = False


        ' Reset the variable for percentage tracking.
        highestPercentageReached = 0

        StartAsyncButton.Visible = False
        CancelAsyncButton.Text = "Cancel Async"

        Master()

        CancelAsyncButton.Text = "End Async"


    End Sub

    Sub Master()

        Dim Duration, time1, time2 As Long
        Dim val1 As Long
        Dim npreq, cyc, cnt As Single
        npreq = 0
        ' Get the value from the UpDown control.
        numberToCompute = CInt(numericUpDown1.Value)
        If numberToCompute < 9 Then
            numberToCompute = 9
            numericUpDown1.Value = 9
        End If
        npreq = CInt(numericUpDown2.Value)   ' request n
        If npreq > numberToCompute Then
            npreq = numberToCompute
            numericUpDown2.Value = npreq
        End If
        cyc = CInt(numericUpDown3.Value)
        Debug.Print("Main1 npreq " + Str(npreq) + " np " + Str(np) + " numberToCompute " + Str(numberToCompute) + " cyc" + Str(cnt))
        If npreq <> np Then
            Assign(npreq)
        End If
        time1 = Hour(Now) * 3600 + Minute(Now) * 60 + Second(Now)
        nnin(1) = numberToCompute - 4    ' * 1
        nnin(2) = numberToCompute - 5    ' * 4
        nnin(3) = numberToCompute - 6    ' * 6
        nnin(4) = numberToCompute - 7    ' * 4
        nnin(5) = numberToCompute - 8    ' * 1
        nfact = 5
        cnt = 0
        Do
            Me.resultLabel3.Text = cnt
            cnt = cnt + 1
            If np > 1 Then
                For j = 2 To np
                    state(j) = StartSt
                Next
            End If
            ' Compute Fibonacci numbers  pp=1
            Select Case np
                Case Is = 1
                    nnout(1) = ComputeFibonacci(nnin(1))
                    nnout(2) = ComputeFibonacci(nnin(2))
                    nnout(3) = ComputeFibonacci(nnin(3))
                    nnout(4) = ComputeFibonacci(nnin(4))
                    nnout(5) = ComputeFibonacci(nnin(5))
                Case Is = 2
                    nnout(1) = ComputeFibonacci(nnin(1))
                    nnout(4) = ComputeFibonacci(nnin(4))
                    nnout(5) = ComputeFibonacci(nnin(5))
                Case Else
                    nnout(1) = ComputeFibonacci(nnin(1))
            End Select
            If np > 1 Then
                Do
                    Application.DoEvents()
                Loop Until state(2) = StopSt And state(3) = StopSt And state(4) = StopSt And state(5) = StopSt
            End If
            If cancelreq = 0 Then progressBar1.Value = cnt * 100 / cyc
            val1 = nnout(1) + 4 * nnout(2) + 6 * nnout(3) + 4 * nnout(4) + nnout(5)

            time2 = Hour(Now) * 3600 + Minute(Now) * 60 + Second(Now)
            Duration = time2 - time1
            If cancelreq = 0 Then
                resultLabel1.Text = val1
                resultLabel2.Text = Duration / cnt
                resultLabel3.Text = cnt
            ElseIf cnt = 1 Then
                resultLabel1.Text = "Cancelled"
                resultLabel2.Text = "Cancelled"
            End If
        Loop Until cnt = cyc Or cancelreq = 1

        If Trace = 1 Then
            Dim a As String
            a = "Main1 "
            For i = 1 To nfact Step 1
                a = a + " " + Str(i) + " " + Str(nnout(i))
            Next
            Debug.Print(a)
            Debug.Print("Main1 " + " val1 " + Str(val1) + " Duration " + Str(Duration) + " " + Str(Duration / cnt))

        End If
        StartAsyncButton.Visible = Visible
        Me.numericUpDown1.Enabled = True
        If cancelreq = 1 Then np = 1

    End Sub

    Function ComputeFibonacci(ByVal n As Integer) As Long

        ' The parameter n must be >= 0 and <= 91.
        ' Fib(n), with n > 91, overflows a long.
        Dim result As Long = 0
        If n < 0 OrElse n > 91 Then
            Throw New ArgumentException("value must be >= 0 and <= 91", "n")
        End If

        If n > 25 Then Application.DoEvents()
        ' Debug.Print("ComputeFibonacci" + Str(n))


        If cancelreq = 0 Then
            If n < 2 Then
                If n = 0 Then result = 0 Else result = 1
            Else
                result = ComputeFibonacci(n - 1) + ComputeFibonacci(n - 2)
            End If
        Else
            ' Report progress as a percentage of the total task.
            ' Dim percentComplete As Integer = _
            '       CSng(n) / CSng(nnin(1)) * 100 * (cnt / cyc)
            ' Debug.Print(Str(n) + " " + Str(percentComplete))
            ' worker.ReportProgress(percentComplete)
            ' If percentComplete > highestPercentageReached Then
            '      highestPercentageReached = percentComplete
            '      progressBar1.Value = highestPercentageReached
            ' End If
        End If


        Return result

    End Function



    Private Sub CancelAsyncButton_Click(ByVal sender As System.Object, _
    ByVal e As System.EventArgs) Handles CancelAsyncButton.Click


        If CancelAsyncButton.Text = "Cancel Async" Then

            cancelreq = 1
            ' Enable the End button.
            numericUpDown1.Enabled = True
            CancelAsyncButton.Text = "End Async"

        Else

            End

        End If

    End Sub 'CancelAsyncButton

    ' This event handler is where the actual work is done.
    Private Sub backgroundWorker1_DoWork(ByVal sender As Object, ByVal e As DoWorkEventArgs) Handles backgroundWorker1.DoWork

        ' Get the BackgroundWorker object that raised this event.
        Dim worker As BackgroundWorker = CType(sender, BackgroundWorker)
        Const pp As Single = 2

        Do
            If state(pp) = StartSt Then
                state(pp) = ActiveSt
                ' Compute Fibonacci numbers  pp=2
                Select Case np
                    Case Is = 2
                        nnout(2) = ComputeFibonacci(nnin(2))
                        nnout(3) = ComputeFibonacci(nnin(3))
                    Case Is = 3
                        nnout(2) = ComputeFibonacci(nnin(2))
                        nnout(5) = ComputeFibonacci(nnin(5))
                    Case Is = 4, 5
                        nnout(2) = ComputeFibonacci(nnin(2))
                End Select
                state(pp) = StopSt
            Else
                System.Threading.Thread.Sleep(1)
            End If
        Loop Until cancelreq = 1 Or state(pp) = CancelSt

        state(pp) = Endst

    End Sub 'backgroundWorker1_DoWork




    ' This event handler is where the actual work is done.
    Private Sub backgroundWorker2_DoWork(ByVal sender As Object, ByVal e As DoWorkEventArgs) Handles backgroundWorker2.DoWork

        ' Get the BackgroundWorker object that raised this event.
        Dim worker As BackgroundWorker = CType(sender, BackgroundWorker)
        Const pp As Single = 3

        Do
            If state(pp) = StartSt Then
                state(pp) = ActiveSt
                ' Compute Fibonacci numbers  pp=3
                Select Case np
                    Case Is = 3
                        nnout(3) = ComputeFibonacci(nnin(3))
                        nnout(4) = ComputeFibonacci(nnin(4))
                    Case Is = 4, 5
                        nnout(3) = ComputeFibonacci(nnin(3))
                End Select
                state(pp) = StopSt
            Else
                System.Threading.Thread.Sleep(1)
            End If
        Loop Until cancelreq = 1 Or state(pp) = CancelSt

        state(pp) = Endst

    End Sub 'backgroundWorker2_DoWork


    ' This event handler is where the actual work is done.
    Private Sub backgroundWorker3_DoWork(ByVal sender As Object, ByVal e As DoWorkEventArgs) Handles backgroundWorker3.DoWork

        ' Get the BackgroundWorker object that raised this event.
        Dim worker As BackgroundWorker = CType(sender, BackgroundWorker)
        Const pp As Single = 4

        Do
            If state(pp) = StartSt Then
                state(pp) = ActiveSt
                ' Compute Fibonacci numbers  pp=4
                Select Case np
                    Case Is = 4
                        nnout(4) = ComputeFibonacci(nnin(4))
                        nnout(5) = ComputeFibonacci(nnin(5))
                    Case Is = 5
                        nnout(4) = ComputeFibonacci(nnin(4))
                End Select
                state(pp) = StopSt
            Else
                System.Threading.Thread.Sleep(1)
            End If
        Loop Until cancelreq = 1 Or state(pp) = CancelSt

        state(pp) = Endst

    End Sub 'backgroundWorker3_DoWork

    ' This event handler is where the actual work is done.
    Private Sub backgroundWorker4_DoWork(ByVal sender As Object, ByVal e As DoWorkEventArgs) Handles BackgroundWorker4.DoWork

        ' Get the BackgroundWorker object that raised this event.
        Dim worker As BackgroundWorker = CType(sender, BackgroundWorker)
        Const pp As Single = 5

        Do
            If state(pp) = StartSt Then
                state(pp) = ActiveSt
                ' Compute Fibonacci numbers  pp=5
                Select Case np
                    Case Is = 5
                        nnout(5) = ComputeFibonacci(nnin(5))
                End Select
                state(pp) = StopSt
            Else
                System.Threading.Thread.Sleep(1)
            End If
        Loop Until cancelreq = 1 Or state(pp) = CancelSt

        state(pp) = Endst

    End Sub 'backgroundWorker4_DoWork

    Private Sub Init()

        np = 0    'Number of processors
        For i = 1 To npmax : nnout(i) = 0 : Next i
        If Trace = 1 Then Debug.Print("Init Trace = " + Str(Trace))

    End Sub

    Private Sub Assign(ByVal npreq)
        ' npreq = np request        np = actual 
        For i = 1 To npmax
            If npreq >= i And np < i Then
                Select Case i
                    Case Is = 1
                        If Trace = 1 Then Debug.Print("Assign " + Str(i))
                    Case Is = 2
                        backgroundWorker1.RunWorkerAsync(i)
                        If Trace = 1 Then Debug.Print("Assign " + Str(i))
                    Case Is = 3
                        backgroundWorker2.RunWorkerAsync(i)
                        If Trace = 1 Then Debug.Print("Assign " + Str(i))
                    Case Is = 4
                        backgroundWorker3.RunWorkerAsync(i)
                        If Trace = 1 Then Debug.Print("Assign " + Str(i))
                    Case Is = 5
                        BackgroundWorker4.RunWorkerAsync(i)
                        If Trace = 1 Then Debug.Print("Assign " + Str(i))
                End Select
            End If
            If npreq < i And np >= i Then
                Select Case i
                    Case Is = 1
                        If Trace = 1 Then Debug.Print("Cancel " + Str(i))
                    Case Is = 2
                        state(i) = CancelSt
                        If Trace = 1 Then Debug.Print("Cancel " + Str(i))
                    Case Is = 3
                        state(i) = CancelSt
                        If Trace = 1 Then Debug.Print("Cancel " + Str(i))
                    Case Is = 4
                        state(i) = CancelSt
                        If Trace = 1 Then Debug.Print("Cancel " + Str(i))
                    Case Is = 5
                        state(i) = CancelSt
                        If Trace = 1 Then Debug.Print("Cancel " + Str(i))
                End Select
            End If
        Next i
        np = npreq
    End Sub


    Private Sub InitializeForm()

        Dim dd, hh As Single

        '
        'numericUpDown1
        '
        dd = 16 : hh = 16
        Me.numericUpDown1.Location = New System.Drawing.Point(dd, hh)
        '
        'resultLabel1
        '
        Me.resultLabel1.Location = New System.Drawing.Point(112, hh)
        Me.resultLabel1.Size = New System.Drawing.Size(70, 20)

        Me.resultLabel2.Location = New System.Drawing.Point(200, hh)
        Me.resultLabel2.Size = New System.Drawing.Size(70, 20)
        '
        'progressBar1
        '
        hh = 48
        Me.progressBar1.Location = New System.Drawing.Point(18, hh)
        Me.progressBar1.Size = New System.Drawing.Size(256, 8)

        hh = hh + 24
        dd = 10
        Me.Label1.Location = New System.Drawing.Point(dd, hh)
        Me.Label1.Size = New System.Drawing.Size(30, 20)

        dd = dd + 30 + 10
        Me.numericUpDown2.Location = New System.Drawing.Point(dd, hh)
        Me.numericUpDown2.Size = New System.Drawing.Size(40, 20)
        Me.numericUpDown2.Maximum = New Decimal(New Integer() {npmax, 0, 0, 0})

        dd = dd + 40 + 10
        Me.Label2.Location = New System.Drawing.Point(dd, hh)
        Me.Label2.Size = New System.Drawing.Size(33, 20)

        dd = dd + 33 + 10
        Me.numericUpDown3.Location = New System.Drawing.Point(dd, hh)
        Me.numericUpDown3.Size = New System.Drawing.Size(40, 20)

        dd = dd + 40 + 15
        Me.resultLabel3.Location = New System.Drawing.Point(dd, hh)
        '
        'startAsyncButton
        '
        hh = hh + 30
        dd = 16
        Me.StartAsyncButton.Location = New System.Drawing.Point(dd, hh)
        Me.StartAsyncButton.Size = New System.Drawing.Size(80, 20)
        '
        'CancelAsyncButton
        '
        dd = dd + 80 + 10
        Me.CancelAsyncButton.Location = New System.Drawing.Point(dd, hh)
        Me.CancelAsyncButton.Size = New System.Drawing.Size(80, 20)

        '
        'FibonacciForm
        '
        Me.ClientSize = New System.Drawing.Size(292, hh + 30)

    End Sub 'InitializeComponent

     _
    Shared Sub Main()
        Application.Run(New FibonacciPPForm)
    End Sub 'Main

End Class 'FibonacciPPForm