namespace eval gen_cs {

variable g_primitives {byte sbyte char short ushort int uint long ulong \
Byte SByte Char Int16 UInt16 Int32 UInt32 Int64 UInt64 \
Guid DateTime TimeSpan decimal Decimal }
	
	

# Autogenerated with DRAKON Editor 1.27

proc add { field this element indent } {
    #item 650
    set field_name [ ufield_name $field ]
    #item 651
    a "$this.$field_name.Add\($element\);" $indent
}

proc add_to_index { item indent class } {
    #item 435
    set index [ dict get $item "index" ]
    #item 437
    set index_name [ index_collection_name $index ]
    #item 438
    a "$index_name\[_record_\] = _record_;" $indent
}

proc assemble { item indent class } {
    #item 350
    set indexed [ dict get $item "indexed" ]
    #item 352
    set classes [ dict keys $indexed ]
    set base [ lindex $classes 0 ]
    set class_name [ tab::get_class_name $class ]
    #item 361
    a "var _record_ = new $class_name\(id\);" $indent
    foreach class $classes {
        #item 353
        set fields [ dict get $indexed $class ]
        foreach field $fields {
            #item 359
            set field_name [ tab::get_field_name $field ]
            set link [ tab::get_field2_link $field ]
            #item 594
            set arg_name [ first_lower $field_name ]
            set uname [ first_underscore $field_name ]
            #item 1148
            if {$link == {}} {
                
            } else {
                #item 1151
                set arg_name "_${arg_name}_"
            }
            #item 595
            a "_record_.$uname = $arg_name;" $indent
        }
    }
    #item 852
    set chain [ tab::inheritance_chain $class ]
    foreach cls $chain {
        #item 855
        set main_index [ pk_index_name $cls ]
        #item 856
        a "$main_index\[id\] = _record_;" $indent
    }
}

proc build_argument { field } {
    #item 995
    set type [ field_type $field ]
    set fname [ tab::get_field_name $field ]
    set name [ first_lower $fname ]
    #item 996
    return "$type $name"
}

proc can_delete { item indent class } {
    #item 384
    a "item.EnsureCanDelete\(deletionList\);" $indent
}

proc check_change { item indent class } {
    #item 465
    set field [ dict get $item "field" ]
    set field_name [ tab::get_field_name $field ]
    set uname [ first_underscore $field_name ]
    set type [ field_type $field ]
    #item 1054
    if {[is_primitive $type]} {
        #item 1057
        a "if \(_record_.$uname == newValue\) \{" $indent
        a "    return;" $indent
        a "\}" $indent
    } else {
        #item 466
        a "if \(Object.Equals\(_record_.$uname, newValue\)\) \{" $indent
        a "    return;" $indent
        a "\}" $indent
    }
}

proc check_deleted { item indent class } {
    #item 405
    a "if \(deletionList.Contains\(this\)\) \{" $indent
    a "    return;" $indent
    a "\} else \{" $indent
    a "    deletionList.Add\(this\);" $indent
    a "\}" $indent
}

proc check_id { item indent class } {
    #item 337
    set class [ dict get $item "class" ]
    set name [ tab::get_class_name $class ]
    set next [ next_name $class ]
    set main_index [ pk_index_name $class ]
    #item 338
    a "if \( id == 0 \) \{" $indent
    a "    id = $next;" $indent
    a "\} else \{" $indent
    a "    if \($main_index.ContainsKey\(id\)\) \{" $indent
    a "        string className = $main_index\[id\].GetType\(\).Name;" $indent
    a "        throw new ArgumentException\(String.Format\(" $indent
    a "            \"'\{0\}' with id '\{1\}' already exists.\"," $indent
    a "            className, id\)\);" $indent
    a "    \}" $indent
    a "\}" $indent
    a "if \( id >= $next \) \{" $indent
    a "    $next = id + 1;" $indent
    a "\}" $indent
}

proc check_not_deleted { var indent } {
    #item 757
    a "if \( !deletionList.Contains\($var\)\) \{" $indent
}

proc check_ref_count { item indent class } {
    #item 549
    set class [ dict get $item "class" ]
    set master [ dict get $item "master" ]
    #item 552
    if {$master} {
        #item 558
        a "if \( master && _refCount > 1 || " $indent
        a "  !master && _refCount > 0 \) \{" $indent
    } else {
        #item 555
        a "if \( _refCount > 0 \) \{" $indent
    }
    #item 556
    ref_count_error $class "    $indent"
    #item 557
    a "\}" $indent
}

proc check_self { item indent class } {
    #item 459
    ensure_exists $class "record" "_record_" 0 $indent
}

proc check_target_not_deleted { field target indent } {
    #item 747
    set getter [ getter_name $field ]
    set field_name [ ufield_name $field ]
    #item 749
    check_not_deleted "_record_.$field_name" $indent
}

proc class_field { field } {
    #item 303
    set in "        "
    #item 292
    set field_name [ tab::get_field_name $field ]
    set link [ tab::get_field2_link $field ]
    set indexes [ tab::get_field2_indexes $field ]
    set type [ tab::get_field2_type $field ]
    set real_name [ first_underscore $field_name ]
    #item 2930001
    if {$type == "data"} {
        #item 307
        set ftype [ field_type $field ]
        #item 328
        field_def $ftype $real_name $in
        #item 304
        if {$indexes == {}} {
            #item 308
            a "public $ftype $field_name \{" $in
            a "    get \{ return $real_name; \}" $in
            a "    set \{ $real_name = value; \}" $in
            a "\}" $in
        } else {
            #item 320
            getter_only $ftype $field_name $real_name $in
        }
    } else {
        #item 2930002
        if {$type == "reference"} {
            #item 300
            set target [ tab::get_target $link ]
            #item 301
            set target_name [ tab::get_class_name $target ]
            #item 329
            field_def $target_name $real_name $in
            #item 321
            getter_only "I$target_name" $field_name $real_name $in
        } else {
            #item 2930003
            if {$type == "collection"} {
                
            } else {
                #item 2930004
                error "Unexpected switch value: $type"
            }
            #item 310
            lassign \
            [tab::get_other_side $field] \
            target target_field
            #item 311
            set target_name [ tab::get_class_name $target ]
            set collection "ReadOnlyCollection<I$target_name>"
            set wrapper "${real_name}_Wrapper"
            #item 330
            field_def $collection $wrapper $in
            set list "List<I$target_name>"
            a "public readonly $list $real_name = new $list\(\);" $in
            #item 309
            getter_only $collection $field_name $wrapper $in
        }
    }
}

proc compare { class field_name } {
    #item 156
    set in "            "
    #item 158
    set field [ tab::find_field $class $field_name ]
    set type [ field_type $field ]
    set link [ tab::get_field2_link $field ]
    #item 163
    set real_name [ first_underscore $field_name ]
    #item 159
    if {[is_primitive $type]} {
        #item 162
        a "if \(x.$real_name != y.$real_name\) return false;" $in
    } else {
        #item 164
        if {$link == {}} {
            #item 168
            a "if \(!Object.Equals\(x.$real_name, y.$real_name\)\) return false;" $in
        } else {
            #item 169
            a "if \(x.$real_name != null && y.$real_name != null\) \{" $in
            a "    if \(x.$real_name._id != y.$real_name._id\) return false;" $in
            a "\} else \{" $in
            a "    if \(!Object.ReferenceEquals\(x.$real_name, y.$real_name\)\) return false;" $in
            a "\}" $in
        }
    }
}

proc comparer { index } {
    #item 92
    set name [ comparer_name $index ]
    set class [ tab::get_index_class $index ]
    set class_name [ tab::get_class_name $class ]
    set fields [ tab::get_index_fields $index ]
    #item 93
    a "    private class $name : IEqualityComparer<$class_name> \{"
    #item 95
    a "        public bool Equals\($class_name x, $class_name y\) \{"
    foreach field_name $fields {
        #item 172
        compare $class $field_name
    }
    #item 96
    a "            return true;"
    a "        \}"
    #item 97
    a "        public int GetHashCode\($class_name obj\) \{"
    #item 176
    set first 1
    foreach field_name $fields {
        #item 175
        hash $first $class $field_name
        #item 177
        set first 0
    }
    #item 94
    a "            return code;"
    a "        \}"
    a "    \}"
}

proc comparer_name { index } {
    #item 85
    set name [ index_name $index ]
    #item 86
    return "${name}_Comparer"
}

proc connect { item indent class } {
    #item 532
    set field [ dict get $item "field" ]
    set op [ dict get $item "op" ]
    set link [ dict get $item "link" ]
    #item 539
    set field_name [ tab::get_field_name $field ]
    set uname [ first_underscore $field_name ]
    #item 540
    a "if \(_record_.$uname != null \) \{" $indent
    #item 5330001
    if {$op == "ref_count"} {
        #item 541
        a "    _record_.$uname._refCount++;" $indent
    } else {
        #item 5330002
        if {$op == "collection"} {
            
        } else {
            #item 5330003
            error "Unexpected switch value: $op"
        }
        #item 543
        do_connect_col $link "_record_.$uname" "    $indent"
    }
    #item 531
    a "\}" $indent
}

proc create_wrapper { field } {
    #item 258
    set field_name [ tab::get_field_name $field ]
    set read_field_name [ first_underscore $field_name ]
    set wrapper "${read_field_name}_Wrapper"
    #item 259
    a "            $wrapper = $read_field_name.AsReadOnly\(\);"
}

proc data_classes { classes db_class_name methods } {
    #item 240
    set in "    "
    foreach class $classes {
        #item 1260
        if {[dict exists $methods $class]} {
            #item 1263
            set class_methods [ dict get $methods $class ]
        } else {
            #item 1264
            set class_methods {}
        }
        #item 233
        set class_name [ tab::get_class_name $class ]
        set base [ tab::get_class2_base $class ]
        set fields [ tab::get_class_fields $class ]
        #item 234
        if {$base == {}} {
            #item 237
            a "private class $class_name : I$class_name, IDelRecord \{" $in
            a "    public readonly int _id;" $in
            a "    public int Id \{ get \{ return _id; \} \}" $in
            a "    public $class_name\(int id\) \{" $in
            a "        _id = id;" $in
        } else {
            #item 239
            set base_name [ tab::get_class_name $base ]
            #item 238
            a "private class $class_name : $base_name, I$class_name, IDelRecord \{" $in
            a "    public $class_name\(int id\) : base\(id\) \{" $in
        }
        foreach field $fields {
            #item 247
            set type [ tab::get_field2_type $field ]
            #item 248
            if {$type == "collection"} {
                #item 252
                create_wrapper $field
            } else {
                
            }
        }
        #item 260
        a "    \}" $in
        #item 1265
        set fhandle [ get_current_file ]
        print_procs $fhandle $class_methods "" 2
        #item 1125
        if {($base == {}) && ([has_arrow $class])} {
            #item 1123
            a "    public int _refCount = 0;" $in
        } else {
            
        }
        foreach field $fields {
            #item 244
            class_field $field
        }
        #item 939
        gen_can_delete $class
        gen_do_delete $class $db_class_name
        gen_pre_delete $class
        gen_pre_delete_inner $class
        #item 241
        a "\}" $in
        #item 997
        gen_key_record $class
    }
}

proc del_list_name { } {
    #item 870
    return "System.Collections.Generic.HashSet<IDelRecord>"
}

proc disconnect { item indent class } {
    #item 513
    set field [ dict get $item "field" ]
    set op [ dict get $item "op" ]
    set link [ dict get $item "link" ]
    set target [ dict get $item "target" ]
    #item 520
    set field_name [ ufield_name $field ]
    set target_name [ tab::get_class_name $target ]
    set indent2 "    $indent"
    set indent3 "    $indent2"
    #item 521
    a "if \($field_name != null \) \{" $indent
    #item 523
    a "if \( !deletionList.Contains\($field_name\)\) \{" $indent2
    #item 5140001
    if {$op == "ref_count"} {
        #item 522
        a "$field_name._refCount--;" $indent3
    } else {
        #item 5140002
        if {$op == "collection"} {
            
        } else {
            #item 5140003
            error "Unexpected switch value: $op"
        }
        #item 1159
        do_disconnect_col $link "$field_name" "this" $indent3
    }
    #item 512
    a "\}" $indent2
    a "\}" $indent
}

proc disconnect_m2m { item indent class } {
    #item 590
    set field [ dict get $item "field" ]
    set target_field [ dict get $item "target_field" ]
    set target_class [ tab::get_field_class $target_field ]
    #item 592
    check_not_deleted "_that_" $indent
    #item 591
    remove $target_field "_that_" "this" "    $indent"
    #item 593
    a "\}" $indent
}

proc disconnect_old { item indent class } {
    #item 565
    set field [ dict get $item "field" ]
    set op [ dict get $item "op" ]
    set link [ dict get $item "link" ]
    set target [ dict get $item "target" ]
    #item 572
    set field_name [ tab::get_field_name $field ]
    set uname [ first_underscore $field_name ]
    set indent2 "    $indent"
    #item 573
    
    a "if \(_record_.$uname != null \) \{" $indent
    #item 5660001
    if {$op == "ref_count"} {
        #item 575
        a "_record_.$uname._refCount--;" $indent2
    } else {
        #item 5660002
        if {$op == "collection"} {
            
        } else {
            #item 5660003
            error "Unexpected switch value: $op"
        }
        #item 576
        do_disconnect_col $link "_record_.$uname" "_record_" $indent2
    }
    #item 564
    a "\}" $indent
}

proc do_connect_col { link that indent } {
    #item 643
    set src_class [ tab::get_link_src_table $link ]
    set many_field_name [ tab::get_link_src_field $link ]
    set many_field [ tab::find_field $src_class $many_field_name ]
    #item 644
    add $many_field $that "_record_" $indent
}

proc do_delete { item indent class } {
    #item 390
    a "item.DoDelete\(this, deletionList\);" $indent
}

proc do_disconnect_col { link that element indent } {
    #item 620
    set src_class [ tab::get_link_src_table $link ]
    set many_field_name [ tab::get_link_src_field $link ]
    set many_field [ tab::find_field $src_class $many_field_name ]
    #item 621
    remove $many_field $that $element $indent
}

proc ensure_deleted { item indent this_class } {
    #item 581
    set field [ dict get $item "field" ]
    set class [ dict get $item "class" ]
    set this_name [ tab::get_class_name $this_class ]
    #item 584
    a "if \(!deletionList.Contains\(_that_\)\) \{" $indent
    a "    throw new ArgumentException\(String.Format\(" $indent
    a "      \"'$this_name' with id '\{0\}' is referenced by other record.\"," $indent
    a "      _id\)\);" $indent
    a "\}" $indent
}

proc ensure_exists { class var out_var null indent } {
    #item 609
    set class_name [ tab::get_class_name $class ]
    set main_index [ pk_index_name $class ]
    #item 612
    if {$null} {
        #item 610
        a "if \($var == null \) \{" $indent
        a "    $out_var = null;" $indent
        a "\} else if \(!$main_index.TryGetValue\($var.Id, out $out_var\)\) \{" $indent
    } else {
        #item 611
        a "if \( !$main_index.TryGetValue\($var.Id, out $out_var\)\) \{" $indent
    }
    #item 608
    a "    throw new ArgumentException\(String.Format\(" $indent
    a "        \"'$class_name' with id '\{0\}' does not exist.\"," $indent
    a "        $var.Id\)\);" $indent
    a "\}" $indent
}

proc fetch_field { item indent class } {
    
}

proc field_def { type field in } {
    #item 327
    a "public $type $field;" $in
}

proc field_real_type { field } {
    #item 1168
    set iface [ field_type $field ]
    set type [ string range $iface 1 end ]
    #item 1169
    return $type
}

proc field_type { field } {
    #item 123
    set field_name [ tab::get_field_name $field ]
    set properties [ tab::get_field_properties $field ]
    #item 124
    if {$properties == {}} {
        #item 127
        set class [ tab::get_field_class $field ]
        set class_name [ tab::get_class_name $class ]
        #item 128
        tab::report_error_class $class_name \
        "Field '$field_name' has no type."
        #item 130
        return {}
    } else {
        #item 129
        set type [ lindex $properties 0 ]
        #item 1131
        if {$type == "link"} {
            #item 1173
            set type2 [ tab::get_field2_type $field ]
            set link [ tab::get_field2_link $field ]
            #item 1170
            if {$type2 == "collection"} {
                #item 1176
                set target [ tab::get_collection_target $field $link ]
            } else {
                #item 1134
                set target [ tab::get_target $link ]
            }
            #item 1174
            set target_name [ tab::get_class_name $target ]
            set iface "I$target_name"
            #item 1135
            return $iface
        } else {
            #item 1133
            return $type
        }
    }
}

proc find_name { index } {
    #item 977
    set class [ tab::get_index_class $index ]
    set fields [ tab::get_index_fields $index ]
    set class_name [ tab::get_class_name $class ]
    #item 978
    set parts_begin [ list "Find" $class_name "By" ]
    set parts [ concat $parts_begin $fields ]
    #item 979
    return [ join $parts "" ]
}

proc first_lower { text } {
    #item 41
    set first [ string index $text 0 ]
    set first_low [ string tolower $first ]
    #item 42
    set rest [ string range $text 1 end ]
    #item 43
    return "${first_low}${rest}"
}

proc first_underscore { text } {
    #item 44
    set low [ first_lower $text ]
    #item 45
    return "_$low"
}

proc foreign_check { item indent class } {
    #item 506
    set field [ dict get $item "field" ]
    set target [ dict get $item "class" ]
    set action [ dict get $item "action" ]
    set field_name [ tab::get_field_name $field ]
    set target_name [ tab::get_class_name $target ]
    #item 1142
    if {$action == "update"} {
        #item 1126
        a "$target_name _that_;" $indent
        #item 505
        ensure_exists $target "newValue" "_that_" 1 $indent
    } else {
        #item 1147
        set arg_name [ first_lower $field_name ]
        set var_name "_${arg_name}_"
        #item 1146
        a "$target_name $var_name;" $indent
        #item 1145
        ensure_exists $target $arg_name $var_name 1 $indent
    }
}

proc gen_add_remove { link add } {
    #item 1189
    set dst [ tab::get_link_dst_table $link ]
    set src [ tab::get_link_src_table $link ]
    set dst_field [ tab::get_link_dst_field $link ]
    set src_field [ tab::get_link_src_field $link ]
    set dst_name [ tab::get_class_name $dst ]
    set src_name [ tab::get_class_name $src ]
    set src_f [ tab::find_field $src $src_field ]
    set dst_f [ tab::find_field $dst $dst_field ]
    #item 1210
    if {$add} {
        #item 1213
        set action "AddTo"
    } else {
        #item 1214
        set action "RemoveFrom"
    }
    #item 1191
    set name "${action}${src_name}${src_field}"
    #item 1190
    set arguments [ list "I$src_name left" "I$dst_name right" ]
    set indent "        "
    #item 1194
    proc_head "void" $name $arguments "    "
    #item 1207
    a "$src_name _left_;" $indent
    a "$dst_name _right_;" $indent
    #item 1205
    a "if \(left == null || right == null\) return;" $indent
    #item 1206
    ensure_exists $src "left" "_left_" 0 $indent
    ensure_exists $dst "right" "_right_" 0 $indent
    #item 1215
    if {$add} {
        #item 1209
        add $src_f "_left_" "_right_" $indent
        add $dst_f "_right_" "_left_" $indent
    } else {
        #item 1218
        remove $src_f "_left_" "_right_" $indent
        remove $dst_f "_right_" "_left_" $indent
    }
    #item 1192
    a "    \}"
}

proc gen_can_delete { class } {
    #item 913
    set method [ tab::core_can_delete $class ]
    #item 914
    set body [ dict get $method "body" ]
    #item 941
    set arguments [ list "[del_list_name] deletionList" ]
    #item 1236
    set modifier [ method_modifier $class ]
    #item 940
    proc_head "$modifier void" "EnsureCanDelete" $arguments "        "
    #item 918
    render_list $body "            " $class
    #item 917
    a "        \}"
}

proc gen_complex_setter { method } {
    #item 1039
    set field [ dict get $method "field" ]
    set class [ dict get $method "class" ]
    set body [ get_optional $method "body" ]
    #item 1041
    set name [ setter_name $field ]
    set type [ field_type $field ]
    set class_name [ tab::get_class_name $class ]
    set iface "I$class_name"
    #item 1040
    set arguments [ list "$iface record" "$type newValue" ]
    set indent "        "
    #item 1045
    proc_head "void" $name $arguments "    "
    a "$class_name _record_;" $indent
    #item 1043
    render_list $body "        " $class
    #item 1042
    a "    \}"
}

proc gen_count { class } {
    #item 813
    set name [ tab::get_class_name $class ]
    set main_index [ pk_index_name $class ]
    #item 814
    proc_head "int" "${name}Count" {} "    "
    #item 816
    set indent "        "
    #item 817
    a "return $main_index.Count;" $indent
    #item 815
    a "    \}"
}

proc gen_delete { class } {
    #item 841
    set name [ tab::get_class_name $class ]
    set iface "I$name"
    set main_index [ pk_index_name $class ]
    #item 833
    set method [ tab::core_delete $class ]
    #item 834
    set body [ dict get $method "body" ]
    #item 842
    set indent "        "
    #item 835
    proc_head "void" "Delete${name}" [ list "$iface record" ] "    "
    #item 839
    a "if \(record == null\) return;" $indent
    a "$name _record_;" $indent
    a "var deletionList = new [ del_list_name ]\(\);" $indent
    #item 838
    render_list $body "        " $class
    #item 837
    a "    \}"
}

proc gen_do_delete { class db_class_name } {
    #item 924
    set method [ tab::core_do_delete $class ]
    #item 957
    set body [ dict get $method "body" ]
    #item 960
    set arguments [ list "$db_class_name db" \
     "[del_list_name] deletionList" ]
    #item 1237
    set modifier [ method_modifier $class ]
    #item 958
    proc_head "$modifier void" "DoDelete" $arguments "        "
    #item 929
    set indent "            "
    render_list $body $indent $class
    #item 936
    set chain [ tab::inheritance_chain $class ]
    set chain [ lreverse $chain ]
    foreach cls $chain {
        #item 930
        set main_index [ pk_index_name $cls ]
        #item 959
        a "db.$main_index.Remove\(_id\);" $indent
    }
    #item 928
    a "        \}"
}

proc gen_find { class } {
    #item 969
    set indexes [ tab::get_class_indexes $class ]
    set key [ key_name $class ]
    #item 982
    set class_name [ tab::get_class_name $class ]
    set iface "I$class_name"
    set indent "        "
    foreach index $indexes {
        #item 980
        set name [ find_name $index ]
        set fields [ tab::index_fields $index ]
        set collection [ index_collection_name $index ]
        #item 981
        set arguments [ map2 $fields gen_cs::build_argument ]
        #item 983
        proc_head $iface $name $arguments "    "
        a "$class_name _record_;" $indent
        #item 1152
        set key_name [ key_name $class ]
        gen_key_insert $key_name $fields $indent
        #item 989
        a "if \($collection.TryGetValue\($key, out _record_\)\) \{" $indent
        a "    return _record_;" $indent
        a "\} else \{" $indent
        a "    return null;" $indent
        a "\}" $indent
        #item 984
        a "    \}"
    }
}

proc gen_foreach { class } {
    #item 823
    set name [ tab::get_class_name $class ]
    set iface "I$name"
    set main_index [ pk_index_name $class ]
    #item 824
    proc_head "IEnumerable<$iface>" "Each${name}" {} "    "
    #item 826
    set indent "        "
    #item 827
    a "foreach \(KeyValuePair<int, $name> record in $main_index\) \{" $indent
    a "    yield return record.Value;" $indent
    a "\}" $indent
    #item 825
    a "    \}"
}

proc gen_get { class } {
    #item 803
    set name [ tab::get_class_name $class ]
    set iface "I$name"
    set main_index [ pk_index_name $class ]
    #item 804
    proc_head $iface "Get${name}" {"int id"} "    "
    #item 806
    set indent "        "
    #item 807
    a "$name _record_;" $indent
    a "if \(!$main_index.TryGetValue\(id, out _record_\)\) \{" $indent
    a "    return null;" $indent
    a "\}" $indent
    a "return _record_;" $indent
    #item 805
    a "    \}"
}

proc gen_insert { class } {
    #item 775
    set method [ tab::core_insert $class gen_cs::has_ctr ]
    #item 776
    set args [ get_optional $method "args" ]
    set body [ get_optional $method "body" ]
    #item 777
    set init_fields [ map2 $args gen_cs::build_argument ]
    set arguments [ linsert $init_fields 0 "int id" ]
    #item 779
    set name [ tab::get_class_name $class ]
    set iface "I$name"
    #item 778
    proc_head $iface "Insert${name}" $arguments "    "
    #item 781
    render_list $body "        " $class
    #item 780
    a "        return _record_;"
    a "    \}"
}

proc gen_key { fields changed indent } {
    #item 665
    set first [ lindex $fields 0 ]
    set class [ tab::get_field_class $first ]
    set key_name [ key_name $class ]
    #item 1059
    if {$changed == ""} {
        #item 657
        gen_key_insert $key_name $fields $indent
    } else {
        #item 1077
        set changed_name [ tab::get_field_name $changed ]
        #item 1076
        gen_key_update $key_name $fields $changed_name $indent
    }
}

proc gen_key_insert { key_name fields indent } {
    foreach field $fields {
        #item 1136
        set fname [ tab::get_field_name $field ]
        set link [ tab::get_field2_link $field ]
        #item 1008
        set uname [ first_underscore $fname ]
        set lname [ first_lower $fname ]
        #item 1137
        if {$link == {}} {
            #item 675
            a "$key_name.$uname = $lname;" $indent
        } else {
            #item 1140
            set type [ field_real_type $field ]
            #item 1141
            a "$key_name.$uname = \($type\)$lname;" $indent
        }
    }
}

proc gen_key_record { class } {
    #item 1003
    set indexes [ tab::get_class_indexes $class ]
    set name [ tab::get_class_name $class ]
    set key [ key_name $class ]
    #item 1004
    if {$indexes == {}} {
        
    } else {
        #item 1007
        a "    private readonly $name $key = new $name\(0\);"
    }
}

proc gen_key_update { key_name fields changed_name indent } {
    foreach field $fields {
        #item 1071
        set fname [ tab::get_field_name $field ]
        set uname [ first_underscore $fname ]
        #item 1072
        if {$fname == $changed_name} {
            #item 1153
            set link [ tab::get_field2_link $field ]
            #item 1154
            if {$link == {}} {
                #item 1075
                a "$key_name.$uname = newValue;" $indent
            } else {
                #item 1155
                set type [ field_real_type $field ]
                #item 1158
                a "$key_name.$uname = \($type\)newValue;" $indent
            }
        } else {
            #item 1070
            a "$key_name.$uname = _record_.$uname;" $indent
        }
    }
}

proc gen_pre_delete { class } {
    #item 876
    set method [ tab::core_pre_delete_outer $class ]
    #item 942
    set body [ dict get $method "body" ]
    #item 946
    set arguments [ list "[del_list_name] deletionList" "bool master"]
    #item 1235
    set modifier [ method_modifier $class ]
    #item 945
    proc_head "$modifier void" "PreDeleteOuter" $arguments "        "
    #item 944
    render_list $body "            " $class
    #item 943
    a "        \}"
}

proc gen_pre_delete_inner { class } {
    #item 902
    set method [ tab::core_pre_delete_inner $class ]
    set base [ tab::get_class2_base $class ]
    #item 947
    set body [ dict get $method "body" ]
    #item 951
    set arguments [ list "[del_list_name] deletionList" ]
    #item 1238
    set modifier [ method_modifier $class ]
    #item 950
    proc_head "$modifier void" "PreDeleteInner" $arguments "        "
    #item 949
    render_list $body "            " $class
    #item 1240
    if {$base == {}} {
        
    } else {
        #item 1239
        a "base.PreDeleteInner\(deletionList\);" "            "
    }
    #item 948
    a "        \}"
}

proc gen_setters { class } {
    #item 1014
    set class_name [ tab::get_class_name $class ]
    set fields [ tab::get_class_fields $class ]
    foreach field $fields {
        #item 1033
        set setter [ tab::core_update $field ]
        #item 1023
        if {$setter == {}} {
            
        } else {
            #item 1026
            set type [ dict get $setter "type" ]
            #item 1044
            if {$type == "complex"} {
                #item 1028
                gen_complex_setter $setter
            } else {
                
            }
        }
    }
}

proc generate_data_struct { db_class_name methods } {
    #item 4
    set classes [ tab::class_name_keys ]
    set links [ tab::link_type_keys ]
    #item 12
    if {$classes == {}} {
        
    } else {
        #item 178
        interfaces $classes $db_class_name
        #item 15
        pk_indexes $classes
        #item 16
        indexes $classes
        #item 331
        data_classes $classes $db_class_name $methods
        #item 761
        methods $classes $links
    }
}

proc get_class_id { item indent class } {
    
}

proc getter_only { type property field in } {
    #item 319
    a "public $type $property \{" $in
    a "    get \{ return $field; \}" $in
    a "\}" $in
}

proc has_arrow { class } {
    #item 1091
    set links [ tab::get_class_links $class ]
    
    set normal_1096 1
    foreach link $links {
        #item 1098
        set type [ tab::get_link_type $link ]
        set dst  [ tab::get_link_dst_table $link ]
        #item 1103
        if {($type == "arrow") && ($dst == $class)} {
            #item 1109
            set result 1
            set normal_1096 0
            break
        } else {
            
        }
    }
    if {$normal_1096 == 1} {
        #item 1111
        set derived [ tab::get_class2_derived $class ]
        
        set normal_1112 1
        foreach cls $derived {
            #item 1114
            if {[has_arrow $cls]} {
                #item 1117
                set result 1
                set normal_1112 0
                break
            } else {
                
            }
        }
        if {$normal_1112 == 1} {
            #item 1118
            set result 0
        }
    }
    #item 1120
    return $result
}

proc has_ctr { field } {
    #item 1248
    set props [ tab::get_field_properties $field ]
    #item 1249
    return [ contains $props "ctr" ]
}

proc hash { first class field_name } {
    #item 149
    set value [ hash_value $class $field_name ]
    #item 146
    if {$first} {
        #item 150
        a "            int code = $value;"
    } else {
        #item 151
        a "            code = (code * 397) ^ $value;"
    }
}

proc hash_value { class field_name } {
    #item 117
    set field [ tab::find_field $class $field_name ]
    set type [ field_type $field ]
    set link [ tab::get_field2_link $field ]
    #item 135
    set real_name [ first_underscore $field_name ]
    #item 131
    if {[is_primitive $type]} {
        #item 134
        return "obj.$real_name.GetHashCode\(\);"
    } else {
        #item 136
        if {$link == {}} {
            #item 140
            return "\(\(obj.$real_name == null\) ? 0 : obj.$real_name.GetHashCode\(\))"
        } else {
            #item 139
            return "\(\(obj.$real_name == null\) ? 0 : obj.$real_name._id.GetHashCode\(\)\)"
        }
    }
}

proc index_collection { index } {
    #item 103
    set collection [ index_collection_name $index ]
    set comparer [ comparer_name $index ]
    set class [ tab::get_index_class $index ]
    set class_name [ tab::get_class_name $class ]
    set type "Dictionary<$class_name, $class_name>"
    #item 104
    a "    private readonly $type $collection = new $type\(new $comparer\(\)\);"
}

proc index_collection_name { index } {
    #item 76
    set name [ index_name $index ]
    #item 77
    return [ first_underscore $name ]
}

proc index_name { index } {
    #item 83
    set class [ tab::get_index_class $index ]
    set fields [ tab::get_index_fields $index ]
    set class_name [ tab::get_class_name $class ]
    set fields_str [ join $fields "_" ]
    #item 84
    set name "${class_name}_${fields_str}"
}

proc index_not_exists { item indent class } {
    #item 424
    set index [ dict get $item "index" ]
    set fields [ dict get $item "fields" ]
    set changed [ dict get $item "changed" ]
    #item 676
    set fnames [ map2 $fields tab::get_field_name ]
    #item 427
    set index_name [ index_collection_name $index ]
    set class [ tab::get_index_class $index ]
    set class_name [ tab::get_class_name $index ]
    set key [ key_name $class ]
    #item 429
    gen_key $fields $changed "        "
    #item 426
    a "if \( $index_name.ContainsKey\($key\)\) \{" $indent
    a "    throw new ArgumentException\(" $indent
    a "      \"Fields '$fnames' are not unique for '$class_name'.\"\);" $indent
    a "\}" $indent
}

proc indexes { classes } {
    #item 60
    set indexes [ tab::index_name_keys ]
    foreach index $indexes {
        #item 63
        comparer $index
        #item 64
        index_collection $index
    }
}

proc insert_possible { item indent class } {
    #item 343
    set method [ tab::core_insert_possible $class "" ]
    set body [ get_optional $method "body" ]
    #item 345
    render_list $body $indent $class
}

proc interface_field { field } {
    #item 277
    set in "        "
    #item 266
    set field_name [ tab::get_field_name $field ]
    set link [ tab::get_field2_link $field ]
    set indexes [ tab::get_field2_indexes $field ]
    set type [ tab::get_field2_type $field ]
    #item 2670001
    if {$type == "data"} {
        #item 281
        set ftype [ field_type $field ]
        #item 278
        if {$indexes == {}} {
            #item 282
            a "$ftype $field_name \{ get; set; \}" $in
        } else {
            #item 286
            a "$ftype $field_name \{ get; \}" $in
        }
    } else {
        #item 2670002
        if {$type == "reference"} {
            #item 274
            set target [ tab::get_target $link ]
            #item 275
            set target_name [ tab::get_class_name $target ]
            #item 276
            a "I$target_name $field_name \{ get; \}" $in
        } else {
            #item 2670003
            if {$type == "collection"} {
                
            } else {
                #item 2670004
                error "Unexpected switch value: $type"
            }
            #item 284
            lassign \
            [tab::get_other_side $field] \
            target target_field
            #item 285
            set target_name [ tab::get_class_name $target ]
            #item 283
            a "ReadOnlyCollection<I$target_name> $field_name \{ get; \}" $in
        }
    }
}

proc interfaces { classes db_class_name } {
    #item 194
    set in "    "
    set list "[ del_list_name ] deletionList"
    #item 184
    a "    public interface IBaseRecord"
    a "    \{"
    a "        int Id \{ get; \}"
    a "    \}"
    a "    private interface IDelRecord"
    a "    \{"
    a "        void PreDeleteOuter\($list, bool master\);"
    a "        void EnsureCanDelete\($list\);"
    a "        void DoDelete\($db_class_name db, $list\);"
    a "    \}"
    foreach class $classes {
        #item 187
        set class_name [ tab::get_class_name $class ]
        set base [ tab::get_class2_base $class ]
        set fields [ tab::get_class_fields $class ]
        #item 188
        if {$base == {}} {
            #item 191
            a "public interface I$class_name : IBaseRecord \{" $in
        } else {
            #item 193
            set base_name [ tab::get_class_name $base ]
            #item 192
            a "public interface I$class_name : I$base_name \{" $in
        }
        foreach field $fields {
            #item 1257
            if {[is_private $field]} {
                
            } else {
                #item 198
                interface_field $field
            }
        }
        #item 195
        a "\}" $in
    }
}

proc is_primitive { type } {
    #item 110
    variable g_primitives
    #item 111
    return [ contains $g_primitives $type ]
}

proc is_private { field } {
    #item 1255
    set props [ tab::get_field_properties $field ]
    #item 1256
    return [ contains $props "private" ]
}

proc key_name { class } {
    #item 671
    set class_name [ tab::get_class_name $class ]
    set uclass_name [ first_underscore $class_name ]
    set key_name "${uclass_name}_Key"
    #item 672
    return $key_name
}

proc method_modifier { class } {
    #item 1229
    set base [ tab::get_class2_base $class ]
    #item 1230
    if {$base == {}} {
        #item 1234
        return "virtual"
    } else {
        #item 1233
        return "override"
    }
}

proc methods { classes links } {
    foreach class $classes {
        #item 769
        gen_insert $class
        gen_get $class
        gen_count $class
        gen_foreach $class
        gen_delete $class
        gen_find $class
        gen_setters $class
    }
    foreach link $links {
        #item 1179
        set type [ tab::get_link_type $link ]
        #item 1180
        if {$type == "m2m"} {
            #item 1183
            gen_add_remove $link 1
            gen_add_remove $link 0
        } else {
            
        }
    }
}

proc next_name { class } {
    #item 53
    set name [ tab::get_class_name $class ]
    set name_low [ first_lower $name ]
    #item 54
    return "_next_$name_low"
}

proc pk_index_name { class } {
    #item 30
    set name [ tab::get_class_name $class ]
    set name_pk ${name}_pk
    #item 46
    return [ first_underscore $name_pk ]
}

proc pk_indexes { classes } {
    foreach class $classes {
        #item 22
        set next [ next_name $class ]
        set class_name [ tab::get_class_name $class ]
        set collection [ pk_index_name $class ]
        set type "Dictionary<int, $class_name>"
        #item 1219
        set base [ tab::get_class2_base $class ]
        #item 1220
        if {$base == {}} {
            #item 1221
            a "    private int $next = 1;"
        } else {
            
        }
        #item 47
        a "    private readonly $type $collection = new $type\(\);"
    }
}

proc pre_delete_inner { item indent class } {
    #item 416
    a "PreDeleteInner\(deletionList\);" $indent
}

proc pre_delete_middle { item indent class } {
    #item 758
    a "PreDeleteInner\(deletionList\);" $indent
}

proc pre_delete_outer { item indent class } {
    #item 366
    set cls [ dict get $item "class" ]
    set field_name [ dict get $item "field_name" ]
    set master [ dict get $item "master" ]
    set field_name [ first_underscore $field_name ]
    #item 857
    if {$field_name == "_id"} {
        #item 860
        set target "_record_"
    } else {
        #item 1160
        if {$field_name == "_that"} {
            #item 1162
            set target "_that_"
        } else {
            #item 861
            set target "$field_name"
        }
    }
    #item 863
    if {$master == "none"} {
        #item 377
        set master "false"
    } else {
        
    }
    #item 862
    a "$target.PreDeleteOuter\(deletionList, $master\);" $indent
}

proc proc_head { type name arguments indent } {
    #item 796
    set arg_str [ join $arguments ", " ]
    #item 797
    a "${indent}public $type $name\($arg_str\) \{"
}

proc ref_count_error { class indent } {
    #item 601
    set class_name [ tab::get_class_name $class ]
    #item 602
    a "string className = GetType\(\).Name;" $indent
    a "throw new ArgumentException\(String.Format\(" $indent
    a "    \"'\{0\}' with id '\{1\}' is referenced by other record.\"," $indent
    a "    className, _id\)\);" $indent
}

proc remove { field this element indent } {
    #item 627
    set field_name [ ufield_name $field ]
    #item 629
    a "$this.$field_name.Remove\($element\);" $indent
}

proc remove_from_index { item indent class } {
    #item 445
    set index [ dict get $item "index" ]
    set fields [ dict get $item "fields" ]
    #item 447
    set index_name [ index_collection_name $index ]
    #item 760
    a "db.$index_name.Remove\(this\);" $indent
}

proc remove_from_index_old { item indent class } {
    #item 1079
    set index [ dict get $item "index" ]
    #item 1080
    set index_name [ index_collection_name $index ]
    #item 1081
    a "$index_name.Remove\(_record_\);" $indent
}

proc render_action { items indent class } {
    #item 700
    set name [ lindex $items 1 ]
    set handler "gen_cs::$name"
    #item 702
    $handler $items $indent $class
}

proc render_foreach { items indent class } {
    #item 724
    set condition [ dict get $items "foreach" ]
    set body [ dict get $items "do" ]
    #item 725
    if {[dict exists $condition "variable"]} {
        #item 728
        set var [ dict get $condition "variable" ]
        #item 729
        if {$var == "del_list"} {
            #item 731
            a "foreach \(IDelRecord item in deletionList\) \{" $indent
            #item 733
            render_action $body "    $indent" $class
            #item 732
            a "\}" $indent
        } else {
            
        }
    } else {
        #item 734
        if {[dict exists $condition "field"]} {
            #item 737
            set field [ dict get $condition "field" ]
            set field_name [ ufield_name $field ]
            set type [ field_real_type $field ]
            #item 741
            a "foreach \($type _that_ in $field_name\) \{" $indent
            #item 740
            render_action $body "    $indent" $class
            #item 739
            a "\}" $indent
        } else {
            
        }
    }
}

proc render_if { items indent class } {
    #item 708
    set condition [ dict get $items "if" ]
    set then [ dict get $items "then" ]
    #item 709
    if {[dict exists $condition "is_not_deleted"]} {
        #item 713
        set field [ dict get $condition "is_not_deleted" ]
        set target [ dict get $condition "target" ]
        check_target_not_deleted $field $target $indent
    } else {
        #item 716
        if {[dict exists $condition "field_not_null"]} {
            #item 718
            set field [ dict get $condition "field_not_null" ]
            fetch_field [ list "field" $field ] $indent $class
            set field_name [ tab::get_field_name $field ]
            a "if \( $field_name != null \) \{" $indent
        } else {
            #item 712
            error "Unexpected condition: $condition"
        }
    }
    #item 714
    render_action $then "    $indent" $class
    #item 715
    a "\}" $indent
}

proc render_list { items indent class } {
    foreach item $items {
        #item 684
        set type [ lindex $item 0 ]
        #item 6850001
        if {$type == "action"} {
            #item 693
            render_action $item $indent $class
        } else {
            #item 6850002
            if {$type == "if"} {
                #item 694
                render_if $item $indent $class
            } else {
                #item 6850003
                if {$type == "foreach"} {
                    
                } else {
                    #item 6850004
                    error "Unexpected switch value: $type"
                }
                #item 695
                render_foreach $item $indent $class
            }
        }
    }
}

proc replace { item indent class } {
    #item 496
    set class [ dict get $item "class" ]
    set field [ dict get $item "field" ]
    #item 499
    set field_name [ tab::get_field_name $field ]
    set ufield_name [ first_underscore $field_name ]
    set link [ tab::get_field2_link $field ]
    #item 1127
    if {$link == {}} {
        #item 759
        a "_record_.$ufield_name = newValue;" $indent
    } else {
        #item 1130
        a "_record_.$ufield_name = _that_;" $indent
    }
}

proc setter_name { field } {
    #item 1051
    set class [ tab::get_field_class $field ]
    set field_name [ tab::get_field_name $field ]
    set class_name [ tab::get_class_name $class ]
    #item 1052
    set parts [ list "Set" $class_name $field_name ]
    #item 1053
    return [ join $parts "" ]
}

proc ufield_name { field } {
    #item 635
    set name [ tab::get_field_name $field ]
    set uname [ first_underscore $name ]
    #item 636
    return $uname
}

}
