Public Module MyFunctions
    Sub MyErrorHandler(ByVal uCalcHandle As IntPtr)
        Static DisplayAgain As Boolean = True
        Dim uc As New uCalc(uCalcHandle)

        If DisplayAgain Then
            Dim DisplayOption = MsgBox( _
                  "uCalc Error (this message box is part of the demo)" + vbCr + vbCr _
                + "Error Number: " + Str(uc.ErrorNumber()) + "  [" + [Enum].GetName(GetType(ErrorNumberEnum), uc.ErrorNumber()) + "]" + vbCr _
                + "Bad expression: " + uc.ErrorExpression() + vbCr _
                + "Error handler message: " + uc.ErrorMessage() + vbCr _
                + "Offending symbol: " + uc.ErrorSymbol() + vbCr _
                + "Error Location: " + Str(uc.ErrorLocation()) + vbCr + vbCr _
                + "See MyErrorHandler(), in MyFunctions.vb, for error handler source code." + vbCr + vbCr _
                + "Show this message next time?", MsgBoxStyle.YesNoCancel, "uCalc Error (this message box is part of the demo)")
            If DisplayOption = MsgBoxResult.No Then DisplayAgain = False
        End If
    End Sub

    Public Sub MyNumericFormat(ByVal ExprPartPtr As IntPtr)
        Dim ep As New uCalc.Callback(ExprPartPtr)
        Dim Value = ep.ArgStr(1)
        If Not {"inf", "-inf", "nan", "-nan"}.Contains(Value) Then Value = Format$(Val(Value), Form1.cmbNumericFormat.Text)
        ep.ReturnStr(Value)
    End Sub

    Public Sub MyArea(ByVal ExprPartPtr As IntPtr)
        Dim ep As New uCalc.Callback(ExprPartPtr)
        Dim MyLength = ep.Arg(1)
        Dim MyWidth = ep.Arg(2)

        If MyLength < 0 Then ep.ErrorRaiseMessage("Length cannot be negative")
        If MyWidth < 0 Then ep.ErrorRaiseMessage("Width cannot be negative")

        ep.ReturnDbl(MyLength * MyWidth) ' Same as uCalc.ReturnDlb(Expr, MyLength * MyWidth)
    End Sub

    Sub MyIIF_Numeric(ByVal ExprPartPtr As IntPtr)
        Dim ep As New uCalc.Callback(ExprPartPtr)
        Dim Condition = ep.Arg(1)
        Dim TruePart = ep.ArgExpr(2)
        Dim FalsePart = ep.ArgExpr(3)

        If Condition <> 0 Then
            ep.ReturnDbl(TruePart.Evaluate())
        Else
            ep.ReturnDbl(FalsePart.Evaluate())
        End If
    End Sub

    Sub MyIIF_String(ByVal ExprPartPtr As IntPtr)
        Dim ep As New uCalc.Callback(ExprPartPtr)

        Dim Condition = ep.Arg(1)
        Dim TruePart = ep.ArgExpr(2)
        Dim FalsePart = ep.ArgExpr(3)

        If Condition <> 0 Then
            ep.ReturnStr(TruePart.EvaluateStr())
        Else
            ep.ReturnStr(FalsePart.EvaluateStr())
        End If
    End Sub

    Sub MyMsgBox(ByVal ExprPartPtr As IntPtr)
        Dim ep As New uCalc.Callback(ExprPartPtr)
        ep.ReturnDbl(MsgBox(ep.ArgStr(1), CType(ep.Arg(2), MsgBoxStyle), ep.ArgStr(3)))
    End Sub

    Sub MyAverage(ByVal ExprPartPtr As IntPtr)
        Dim ep As New uCalc.Callback(ExprPartPtr)
        Dim x As Int32, Total As Double

        For x = 1 To ep.ArgCount()
            Total = Total + ep.Arg(x)
        Next

        ep.ReturnDbl(Total / ep.ArgCount())
    End Sub

    Sub MyLeft(ByVal ExprPartPtr As IntPtr)
        Dim ep As New uCalc.Callback(ExprPartPtr)
        ep.ReturnStr(Left$(ep.ArgStr(1), CInt(ep.Arg(2))))
    End Sub

    Sub StringRepeat(ByVal ExprPartPtr As IntPtr)
        Dim ep As New uCalc.Callback(ExprPartPtr)
        Dim x As Double, TotalString As String = ""

        For x = 1 To ep.Arg(2)
            TotalString = TotalString + ep.ArgStr(1)
        Next
        ep.ReturnStr(TotalString)
    End Sub

    Sub ucSum(ByVal ExprPartPtr As IntPtr)
        Dim ep As New uCalc.Callback(ExprPartPtr)
        Dim x As Double, Total As Double

        Dim Expression = ep.ArgExpr(1)
        Dim Start = ep.Arg(2)
        Dim Finish = ep.Arg(3)
        Dim sStep = ep.Arg(4)
        Dim Variable = ep.ArgObj(5)

        For x = Start To Finish Step sStep
            Variable.Value(x)
            Total = Total + Expression.Evaluate()
        Next

        ep.ReturnDbl(Total)
    End Sub

    Sub ucSolve(ByVal Expr As IntPtr)
        Dim ep As New uCalc.Callback(Expr)
        Dim Value As Double, tmp As Double
        Dim fa As Double, fb As Double, Iterations As Integer

        Dim Expression = ep.ArgExpr(1)
        Dim a = ep.Arg(2)
        Dim b = ep.Arg(3)
        Dim Variable = ep.ArgObj(4)

        Variable.Value(a) : fa = Expression.Evaluate()
        Variable.Value(b) : fb = Expression.Evaluate()

        If fb < fa Then tmp = a : a = b : b = tmp 'swap a, b

        Do While Math.Abs(b - a) > 0.000000000000001
            Variable.Value((a + b) / 2)

            Value = Expression.Evaluate()

            If Value = 0 Then a = (a + b) / 2 : Exit Do

            If Value < 0 _
            Then a = (a + b) / 2 _
            Else b = (a + b) / 2

            Iterations = Iterations + 1
            If Iterations = 100 Then Exit Do
        Loop

        If Math.Abs(Value) > 0.0000000001 Then ep.ErrorRaiseMessage("Solution not found")

        ep.ReturnDbl(a)
    End Sub
End Module
