Imports System
Imports uCalcSoftware
Public Module Program
   
   Public Sub GetCurrentDate(ByVal cb As uCalc.Callback)
      '// In a real application, this would return the system's current date.
      '// For this example, we'll use a fixed date for consistent output.
      '// Let's pretend today is January 15, 2026 (a Thursday).
      cb.Return(46036) '// Using Excel-style date serial number for simplicity
   End Sub
   
   Public Sub AddDuration(ByVal cb As uCalc.Callback)
      Dim startDate = cb.Arg(1)
      Dim number = cb.Arg(2)
      Dim unit = cb.ArgStr(3)
      Dim result = startDate
      
      If unit = "day" Or unit = "days" Then
         result = startDate + number
         ElseIf unit = "week" Or unit = "weeks" Then
         result = startDate + (number * 7)
         ElseIf unit = "month" Or unit = "months" Then
         result = startDate + (number * 30) '// Approximation for example
      End If
      cb.Return(result)
   End Sub
   
   Public Sub GetNextDayOfWeek(ByVal cb As uCalc.Callback)
      Dim dayName = cb.ArgStr(1)
      Dim today = 46036 '// Thursday, Jan 15, 2026
      Dim todayDayOfWeek = 5 '// 1=Sun, 2=Mon, ..., 5=Thu
      
      Dim targetDay = 0
      If dayName = "Sunday" Then targetDay = 1
         If dayName = "Monday" Then targetDay = 2
            If dayName = "Tuesday" Then targetDay = 3
               If dayName = "Wednesday" Then targetDay = 4
                  If dayName = "Thursday" Then targetDay = 5
                     If dayName = "Friday" Then targetDay = 6
                        If dayName = "Saturday" Then targetDay = 7
                           
                           Dim daysToAdd = (targetDay - todayDayOfWeek + 7) Mod 7
                           '// Always get the *next* week's day
                           If daysToAdd = 0 Then daysToAdd = 7
                              
                              cb.Return(today + daysToAdd)
                           End Sub
                           
                           Public Sub FormatDate(ByVal cb As uCalc.Callback)
                              '// This is a simplified formatter for the example.
                              '// A real implementation would be more robust.
                              Dim dateSerial = cb.Arg(1)
                              If dateSerial = 46036 Then cb.ReturnStr("2026-01-15")
                                 If dateSerial = 46037 Then cb.ReturnStr("2026-01-16")
                                    If dateSerial = 46039 Then cb.ReturnStr("2026-01-18")
                                       If dateSerial = 46043 Then cb.ReturnStr("2026-01-22")
                                          If dateSerial = 46050 Then cb.ReturnStr("2026-01-29")
                                             If dateSerial = 46096 Then cb.ReturnStr("2026-03-16")
                                                End Sub 
                                                   
                                                   Public Sub Main()
                                                      Dim uc As New uCalc()
                                                      '// 1. Define the helper functions in the uCalc engine
                                                      uc.DefineFunction("GetCurrentDate()", AddressOf GetCurrentDate)
                                                      uc.DefineFunction("AddDuration(date, num, unit As String)", AddressOf AddDuration)
                                                      uc.DefineFunction("GetNextDayOfWeek(dayName As String)", AddressOf GetNextDayOfWeek)
                                                      uc.DefineFunction("FormatDate(date) As String", AddressOf FormatDate)
                                                      
                                                      '// 2. Create the transformer and define the DSL rules
                                                      Using t As New uCalc.Transformer(uc)
                                                         '// Set case-insensitivity for all rules
                                                         t.DefaultRuleSet.CaseSensitive = false
                                                         
                                                         '// Define the rules
                                                         t.FromTo("today", "{@Eval: FormatDate(GetCurrentDate())}")
                                                         t.FromTo("tomorrow", "{@Eval: FormatDate(AddDuration(GetCurrentDate(), 1, 'day'))}")
                                                         t.FromTo("next {@Alpha:day}", "{@Eval: FormatDate(GetNextDayOfWeek(day))}")
                                                         t.FromTo("in {@Number:num} {@Alpha:unit}", "{@Eval: FormatDate(AddDuration(GetCurrentDate(), Double(num), unit))}")
                                                         
                                                         '// 3. Process the input strings
                                                         Console.WriteLine($"Input: 'today' -> Output: {t.Transform("today")}")
                                                         Console.WriteLine($"Input: 'tomorrow' -> Output: {t.Transform("tomorrow")}")
                                                         Console.WriteLine($"Input: 'next Sunday' -> Output: {t.Transform("next Sunday")}")
                                                         Console.WriteLine($"Input: 'in 2 weeks' -> Output: {t.Transform("in 2 weeks")}")
                                                         Console.WriteLine($"Input: 'in 60 days' -> Output: {t.Transform("in 60 days")}")
                                                      End Using
                                                   End Sub
                                                End Module