%
'=======================================================================================================================
' IO Helpers
'=======================================================================================================================
Sub put(v)
    Select Case typename(v)
        Case "LinkedList_Class"       : response.write join(v.TO_Array, ", ")
        Case "DynamicArray_Class"     : response.write JoinList(v)
        Case "Variant()"              : response.write join(v, ", ")
        Case else                     : response.write v
    End Select
End Sub
Sub put_
    put "
"
End Sub
Sub putl(v)
    put v
    put_
End Sub
'accepts anything that can have an iterator, including lists, arrays, and recordsets
Sub putlist(col, prefix, suffix)
    dim it : set it = IteratorFor(col)
    Do While it.HasNext
        put prefix & it.GetNext & suffix
    Loop
End Sub
'same as join() for arrays, but for any arbitrary collection
Function JoinList(col)
    dim s : s = ""
    dim it : set it = IteratorFor(col)
    Do While it.HasNext
        s = s & ", "
    Loop
    JoinList = Left(s, Len(s) - 2)
End Function
'---------------------------------------------------------------------------------------------------------------------
'Wrapper for Server.HTMLEncode() -- makes it easier on the eyes when reading the HTML code
Function H(s)
    If Not IsEmpty(s) and Not IsNull(s) then
        H = Server.HTMLEncode(s)
    Else
        H = ""
    End If
End Function
'-----------------------------------------------------------------------------------------------------------------------
'allows tracing of output on demand without interfering with layout
Sub trace(s)
    comment s
End Sub
'-----------------------------------------------------------------------------------------------------------------------
'outputs an HTML comment, useful for tracing etc
Sub Comment(text)
    response.write vbcrlf & vbcrlf & "" & vbcrlf & vbcrlf
End Sub
'-----------------------------------------------------------------------------------------------------------------------
'pseudo-design-by-contract capability, allows strong-typing of methods and views
Sub ExpectType(obj_type, obj)
    if typename(obj) <> obj_type then Err.Raise 1, "lib.Helpers:ExpectType", "View expected object of type '" & obj_type & "' but received type '" & typename(obj) & "'."
End Sub
'=======================================================================================================================
' Dump* functions for dumping variables, objects, lists, etc for debugging purposes
'=======================================================================================================================
Class DataDumper_Class
    Public Sub Dump(V)
        put "
"
        DumpIt V
        put ""
    End Sub
    
    Private m_indent
    
    Private Sub Indent
        m_indent = m_indent + 1
        'putl "INDENT: " & m_indent
        'puti m_indent
        'put_
    End Sub
    
    Private Sub Dedent
        m_indent = m_indent - 1
        'putl "INDENT: " & m_indent
    End Sub
    
    Private Sub Class_Initialize
        m_indent = -1     'first indent takes it to 0
    End Sub
    
    'prepends indents
    Private Sub puti(v)
        put Spaces(m_indent) & v
    End Sub
    
    Private Sub DumpIt(V)
        If Typename(V) = "LinkedList_Class" then
            DumpList V
        ElseIf Instr(Typename(V), "_Class") > 0 then 
            DumpClass V
        ElseIf Typename(V) = "Variant()" then
            DumpArray V
        ElseIf Typename(V) = "Recordset" then
            DumpRecordset V
        Else
            put "«" & H(V) & "»" 
        End If
    End Sub
    Private Sub DumpList(V)
        Indent
        dim it : set it = V.Iterator
        dim item
        dim i : i = 1
        put_
        puti "[List:" & vbCR
        While it.HasNext
            Indent
                set item = it.GetNext()
                puti i & " => "
                DumpIt item
                put_
            Dedent
            i = i + 1
        Wend
        puti "]"
        Dedent
    End Sub
    
    Private Sub DumpArray(V)
        Indent
        dim i
        put_
        puti "[Array:" & vbCR
            Indent
            For i = 0 to UBound(V)
                puti i & " => " 
                DumpIt V(i)
                put_
            Next
            Dedent
        puti "]"
        Dedent
    End Sub
    
    Private Sub DumpClass(C)
        Indent
        dim i
        put_
        puti "{" & Typename(C) & ": " & vbCR
            Indent
        
            On Error Resume Next
                If Ubound(C.Class_Get_Properties) > 0 then
                    dim property_name, the_property
                    For i = 0 to UBound(C.Class_Get_Properties)
                        property_name = C.Class_Get_Properties(i)
                        Execute "Assign the_property, C." & C.Class_Get_Properties(i)
                        'put "property_name: " & property_name & " (" & typename(the_property) & ")" & vbCR
                        
                        If typename(the_property) = "LinkedList_Class" then
                            puti " " & property_name & " : LinkedList_Class => "
                            DumpList(the_property)
                        ElseIf InStr(typename(the_property), "_Class") then
                            puti " " & property_name & " : " & typename(the_property) & " => "
                            DumpClass(the_property)
                        Else
                            puti "    " & property_name & " : " & typename(the_property) & " => " '& Eval("C." & property_name)
                            DumpIt(the_property)
                            If i <> UBound(C.Class_Get_Properties) then put ", "
                            put vbCR
                        End If
                    Next
                Else
                    
                End If
            On Error Goto 0
            
            Dedent
        
        puti "}" & vbCR & vbCR
        Dedent
    End Sub
    
    Sub DumpRecordset(R)
        Indent
        dim field
        put "| " & field.Name & "" Next put " | 
|---|
| " & H(R(field.Name)) & "" Next put " |