#############   Auto pick mode methods for PART & SUBSET ###########################

proc oncreatePartSelLoad {} {
    global auto_pick_mode
    if $auto_pick_mode { 
        createPartPick pick
    }
}

proc oncreatePartPickFinish {} {
    global auto_pick_mode
    if {$auto_pick_mode && $entityList != ""} {
        createPartDEZ apply
        createPartPick pick
    }
}

proc onCreatePartNameModify {dez val} {
    if {$val == "From screen"} {
        createPartDEZ set name [geo_select_part_from_screen 1]
    }
}

proc onmodifyPartSelLoad {} {
    global auto_pick_mode
    if $auto_pick_mode { 
        modifyPartPick pick
    }
}

proc onmodifyPartPickFinish {} {
    global auto_pick_mode
    if {$auto_pick_mode && $entityList != ""} {
        modifyPartDEZ apply
        modifyPartPick pick	
    }
}

proc oncreatePartBlkPickFinish {} {
    global auto_pick_mode
    if {$blocks != "" && $auto_pick_mode} { 
        createPartDEZ apply
        createPartBlkPick pick
    }
}

proc onmodifyPartBlkPickFinish {} {
    global auto_pick_mode
    if {$blocks != "" && $auto_pick_mode} { 
        modifyPartDEZ apply
        modifyPartBlkPick pick
    }
}

##################################################################

proc onModifyPartDEZApply {} {
    global part_types current_part_to_load

    if {$name == ""} return
    
    if [info exists LongList] {
        set thelist $LongList
    } else {
        set thelist $entityList
    }
    
    set dims ""
    set single_type ""
    foreach d {0 1 2 3} {
        if [set select_geo_${d}d] {
            if {$dims == ""} {
                set single_type [lindex {point curve surface body} $d]
            } else {
                set single_type ""
            }
            lappend dims $d
        }
    }
    set uns ""
    if [info exists modifyPartSelectVal] {
        if {$name == "VORFN" && $modifyPartSelectVal != 2} {
            msg ERROR "Part: VORFN can contain only block entities"
            return
        }
        switch $modifyPartSelectVal {
            0 {
                if {[ic_hex_blocking_loaded] && [lsearch $thelist body] < 0} {
                    if {[lsearch [string trimright [ic_hex_list_blocking_parts] \n] $name] > -1} {
                        set opt [tk_dialog .same_part "Add to same part ?" "Part $current_part_to_load(name)\
                            contains block entities, It is not recommended that a part contains geometry or mesh and blocks\
                            in the same part. This could cause problems! Do you want to continue?" "" 1 "Yes" "No"]
                        switch -- $opt {
                            -1 { if [winfo exists .same_part] { destroy .same_part; return } }
                            0 {}
                            1 { return }
                        }
                    }
                }
            }
            1 {
                set uns [ic_uns_create_selection_subset 0]
                set p1 "$minx $miny $minz"
                set p2 "$maxx $maxy $maxz"
		        set lcs [ic_csystem_get_current]
                if {$lcs != "global"} {
                    mess "Using active local coordinate system $lcs for add to part $name by region\n"
                }
                ic_uns_subset_add_region $uns $p1 $p2 $BoxFlag $dims
                set thelist "unsmap $uns"
            }
            2 {
                if {[ic_geo_is_loaded] && [format %d [ic_hex_mesh_dimension]] != "2"} {
                    if [ic_geo_count_in_family {surface curve point} $current_part_to_load(name)] {
                        set opt [tk_dialog .same_part "Add to same part ?" "Part $current_part_to_load(name)\
                            contains geometry objects, It is not recommended that a part contains geometry and blocks\
                            in the same part. This could cause problems! Do you want to continue?" "" 1 "Yes" "No"]
                        switch -- $opt {
                            -1 { if [winfo exists .same_part] { destroy .same_part; return } }
                            0 {}
                            1 { return }
                        }
                    }
                }
                aie_change_part_blocks $blocks $name
                mess "Added block(s) \"$blocks\" to part $name\n"
                return
            }
        }
    }
    if {$thelist == ""} return
    if {([lindex $thelist 0] != "unsmap") && ($single_type != "") && ([lindex $thelist 0] != $single_type)} {
        set thelist [list $single_type $thelist]
    }
    set ta [tdv_active 0]
    catch { unset in_type; unset never_ask_again }
    foreach {type objs} $thelist {
        eval lappend in_type($type) $objs
    }
    foreach type [array names in_type] {
    if {$type == "unsmap"} {
        set set_uns_part 1
        if {[info exists part_types] && $part_types != "" && [info exists current_part_to_load(name]} {
            foreach obj $in_type($type) {
                set types [ic_uns_subset_list_types $obj]
                if {([lsearch $types TRI_3] > -1) || ([lsearch $types QUAD_4] > -1)} {
                    if {([lsearch $part_types TETRA_4] > -1) || ([lsearch $part_types HEXA_8] > -1)} {
                        set opt [tk_dialog .same_part "Add to same part ?" "Part $current_part_to_load(name)\
                            contains volume elements, but the selected mesh contains shell elements. It is not\
                            recommended that a part contains shell and volume elements in the same part. This\
                            could cause problems! Do you want to continue?" "" 1 "Yes" "No"]
                        switch -- $opt {
                            -1 { if [winfo exists .same_part] { destroy .same_part; return } }
                            0 {}
                            1 { set set_uns_part 0 }
                        }
                    }
                } elseif {([lsearch $types TETRA_4] > -1) || ([lsearch $types HEXA_8] > -1)} {
                    if {([lsearch $part_types TRI_3] > -1) || ([lsearch $part_types QUAD_4] > -1)} {
                        set opt [tk_dialog .same_part "Add to same part ?" "Part $current_part_to_load(name)\
                            contains shell elements, but the selected mesh contains volume elements. It is not\
                            recommended that a part contains shell and volume elements in the same part. This\
                            could cause problems! Do you want to continue?" "" 1 "Yes" "No"]
                        switch -- $opt {
                            -1 { if [winfo exists .same_part] { destroy .same_part; return } }
                            0 {}
                            1 { set set_uns_part 0 }
                        }
                    }
                }
            }
        }
        if $set_uns_part {
            foreach obj $in_type($type) {
                ic_uns_set_part $in_type($type) $name
            }
        }
    } elseif {$type == "domain" || $type == "subface" || $type == "edge" || $type == "vertex"} {
        ic_str_change_family $type $in_type($type) $name
    } elseif {($type == "body") && [ic_geo_count_in_family {surface curve point} $name] && ![info exists never_ask_again]} {
        set opt [tk_dialog .same_part "Add to same part ?" "Part $name contains geometry,\
                but entity $in_type($type) is type body. It is not recommended that a part\
                contains geometry and body in the same part. This could cause problems!\
                Do you want to continue?" "" 1 "Yes" "No"]
        switch -- $opt {
            -1 { if [winfo exists .same_part] { destroy .same_part; return } }
            0 { set never_ask_again 1; ic_geo_set_part $type $in_type($type) $name $adjust_geo_names }
            1 {}
        }
    } elseif {($type == "surface" || $type == "curve" || $type == "point") && \
                   [ic_geo_count_in_family body $name] && ![info exists never_ask_again]} {
        set opt [tk_dialog .same_part "Add to same part ?" "Part $name contains bodies,\
                but entity $in_type($type) is type $type. It is not recommended that a part\
                contains geometry and body in the same part. This could cause problems!\
                Do you want to continue?" "" 1 "Yes" "No"]
        switch -- $opt {
                -1 { if [winfo exists .same_part] { destroy .same_part; return } }
                0 { set never_ask_again 1; ic_geo_set_part $type $in_type($type) $name $adjust_geo_names }
                1 {}
            }
        } else {
            ic_geo_set_part $type $in_type($type) $name $adjust_geo_names
        }
    }

    ::AIEnv::GUIManagement::Tree::ToggleGroupVisibility part $name same

    if {$uns != ""} { ic_uns_subset_delete $uns}
    foreach {type sub} $thelist {
        if [ic_uns_subset_exists $sub] {
            ic_uns_subset_delete $sub
        }
    }
    tdv_active $ta
    set entityList ""
    aie_delete_empty_parts
    mess "Done\n"
}

proc onCreatePartBlkLoad {} {
    global auto_pick_mode
    if $auto_pick_mode { createPartBlkPick pick }
}

proc onCreatePartDEZApply {} {
    global fam_visible

    if [info exists LongList] {
        set thelist $LongList
    } else {
        set thelist $entityList
    }
    
    if {$name == ""} { set name [ic_geo_get_unused_part PART] }
    set name [ic_geo_valid_name $name 1]
    
    if [ic_hex_subset_named_selection $name] {
        msg ERROR "A named selection subset with name $name already exists; use some other name"
        return
    }
    
    set dims ""
    set single_type ""
    foreach d {0 1 2 3} {
	    if [set select_geo_${d}d] {
	        if {$dims == ""} {
		        set single_type [lindex {point curve surface body} $d]
	        } else {
		        set single_type ""
	        }
	        lappend dims $d
	    }
    }
    set uns ""
    if [info exists createPartSelectVal] {
	    if {$name == "VORFN" && $createPartSelectVal != 3} {
	        msg ERROR "Part: VORFN can contain only block entities"
	        return
	    }
	    switch $createPartSelectVal {
	        0 { }
	        1 {
		        if {[string trim $location] == ""} {
		            mess "You must input an XYZ position with the numbers separated by spaces\n" red
		            return
		        }
		        set uns [ic_uns_create_selection_subset 0]
		        ic_uns_subset_add_near_pos $uns $location $dims
		        set thelist "unsmap $uns"
	        }
	        2 {
		        set uns [ic_uns_create_selection_subset 0]
		        set p1 "$minx $miny $minz"
		        set p2 "$maxx $maxy $maxz"
		        set lcs [ic_csystem_get_current]
                if {$lcs != "global"} {
                    mess "Using active local coordinate system $lcs for create part $name in region\n"
                }
		        ic_uns_subset_add_region $uns $p1 $p2 $BoxFlag $dims
		        set thelist "unsmap $uns"
	        }
	        3 {
		        aie_change_part_blocks $blocks $name
		        set blocks ""
		        return
	        }
	    }
    }
    if {$thelist == ""} return
    if {([lindex $thelist 0] != "unsmap") && ($single_type != "") && ([lindex $thelist 0] != $single_type)} {
	    set thelist [list $single_type $thelist]
    }
    catch { unset change_objs; unset never_ask_again }
    set count_body 0
    set count_geom 0

    foreach {type objs} $thelist {
        if {$type == "body" || $type == "material"} { incr count_body }
        if {$type == "surface" || $type == "curve" || $type == "point"} { incr count_geom }
        if {$count_body && $count_geom} break
    }
    foreach {type objs} $thelist {
        set count_geom [ic_geo_count_in_family {surface curve point} $name]
	    if {$type == "unsmap"} {
	        ic_uns_set_part $objs $name
	    } elseif {$type == "domain" || $type == "subface" || $type == "edge" || $type == "vertex"} {
	        ic_str_change_family $type $objs $name
	    } elseif {$count_body && $count_geom && ![info exists never_ask_again]} {
	        set opt [tk_dialog .same_part "Create part ?" "New part $name contains geometry entities\
                and body entities in same part. This is not recommended and could cause problems!\
                Do you want to continue?" "" 1 "Yes" "No"]
	        switch -- $opt {
                -1 {
                    if [winfo exists .same_part] { destroy .same_part }
                    set entityList ""
                    return
                }
                0 { eval lappend change_objs($type) $objs; set never_ask_again 1 }
                1 { set entityList ""; return }
            }
	    } else {
	        eval lappend change_objs($type) $objs
	    }
    }

    foreach type [array names change_objs] {
	    ic_geo_set_part $type $change_objs($type) $name $adjust_geo_names
	    if [::AIEnv::GUIManagement::Tree::GetVisibility $type] {
	        if {[info exists fam_visible($name)] && $fam_visible($name)} {
	            ic_geo_object_visible $type $change_objs($type) 1
            }
	    }
    }
    aie_create_parts_in_tree_if_needed
    aie_update_parts_in_tree_if_needed
    if {[info exists fam_visible($name)] && $fam_visible($name)} {
        ::AIEnv::GUIManagement::Tree::ToggleGroupVisibility part $name same
    }
    
    if {$uns != ""} { ic_uns_subset_delete $uns}
    set entityList ""
    aie_delete_empty_parts
}

proc onCreatePartDEZUnload {} {
    geo_select_either_set_prefix ""
    set entityList ""
    set blocks ""
    if [info exists LongList] { unset LongList }
}

proc onModifyPartDEZUnload {} {
    geo_select_either_set_prefix ""
    set entityList ""
    set blocks ""
    if [info exists LongList] { unset LongList }
}

# --------

proc aie_edit_part {name} {
    global current_part_to_load
    aie_clear_dez
    if {$name == "*"} {
        after 100 { createPartDEZ show }
    } else {
        set current_part_to_load(name) $name
        after 100 { modifyPartDEZ show }
    }
}

proc aie_info_part {names {what "all"}} {
    global beta_mode
    
    if {$what == "geom" && ![ic_geo_is_loaded]} return
    if {$what == "mesh" && (![ic_uns_is_loaded] && ![ic_str_is_loaded])} return
    if {$what == "block" && ![ic_hex_blocking_loaded]} return

    foreach name $names {
        if {$what == "all" || $what == "geom"} {
            set surfaces [llength [ic_geo_get_objects surface $name]]
            set curves [llength [ic_geo_get_objects curve $name]]
            set points [llength [ic_geo_get_objects point $name]]
            set bodies [llength [ic_geo_get_objects body $name]]
            if {[lsearch [ic_geo_non_empty_families] $name] >= 0} {
                set wb_objects 1
            } else {
                set wb_objects 0
            }
            set dormant_points [expr [llength [ic_geo_get_objects point $name 1]] - $points]
            set dormant_curves [expr [llength [ic_geo_get_objects curve $name 1]] - $curves]
        }
        if {$what == "all"} {
            mess "\n--------------------------------------------------------------------------\n"
            mess "Info for part $name\n"
            mess "--------------------------------------------------------------------------\n"
        }
        if {$what == "all" || ($what == "geom" && [ic_geo_count_in_family all $name])} {
           if {$what == "geom"} {
                mess "--------------------------------------------------------------------------\n"
                mess "Geometry Info for part $name\n"
                mess "--------------------------------------------------------------------------\n"
            }
            if {$what == "all"} { mess "Geometry Info ----\n" }
            set components [ic_geo_list_families_in_part $name]
            set comps_found ""
            set comps_count 0
            set count_point 0
            set count_curve 0
            set count_surface 0
            if {$components != "" && $what == "all"} {
                set surf_objs ""
                foreach comp $components {
                    if [regexp : $comp] {
                        set objs ""
                        set found_some 0
                        foreach t "point curve surface" {
                            set objs_num [ic_geo_count_in_family $t $comp]
                            if $objs_num {
                                append objs "$objs_num ${t}s "
                                incr count_$t $objs_num
                                incr found_some 
                            }
                            if {$t == "surface" && $objs_num} {
                                append surf_objs "[ic_geo_get_objects surface $comp] "
                            }
                        }
                        if $found_some {
                            append comps_found "\t$comp contains [string trimright ${objs}]\n"
                            incr comps_count
                        }
                    }
                }
                set points [expr $count_point + $points]
                set curves [expr $count_curve + $curves]
                set surfaces [expr $count_surface + $surfaces]
            }
            if $surfaces {
                mess "Part contains $surfaces surfaces ;"
                if {$count_surface && $components != "" && $surf_objs != ""} {
                    set surf_objs2 [ic_geo_get_objects surface $name]
                    if {$surf_objs2 != ""} {
                        mess "Total surface area is [expr [ic_geo_srf_area $surf_objs2] + [ic_geo_srf_area $surf_objs]]\n"
                    } else {
                        mess "Total surface area is [ic_geo_srf_area $surf_objs]\n"
                    }
                } else {
                    mess "Total surface area is [ic_geo_srf_area [ic_geo_get_objects surface $name]]\n"
                }
            }
            if {$curves || $dormant_curves} {
                if $dormant_curves {
                    set num_curves [expr $dormant_curves + $curves]
                    if !$curves {
                        mess "Part contains $dormant_curves (all dormant) curves\n"
                    } else {
                        mess "Part contains $num_curves ($dormant_curves dormant) curves\n"
                    }
                } else {
                    mess "Part contains $curves curves\n" 
                }
            }
            if {$points || $dormant_points} {
                if $dormant_points {
                    set num_points [expr $dormant_points + $points]
                    if !$points  {
                        mess "Part contains $dormant_points (all dormant) points\n"
                    } else {
                        mess "Part contains $num_points ($dormant_points dormant) points\n"
                    }
                } else {
                    mess "Part contains $points points\n"
                }
            }
            if $bodies {
                mess "Part contains $bodies bodies\n"
            }
            if {[expr $surfaces + $curves + $points] && $bodies} {
                mess "Part $name contains geometry and bodies in same part\n"
            }
            set solids [llength [ic_geo_solids_without_material_names $name]]
            if $solids {
                mess "Part contains $solids solid\n"
            }
            if ![expr $surfaces + $curves + $points + $bodies + $solids] {
                if {!$dormant_curves && !$dormant_points} {
                    mess "No geometry in part $name\n"
                }
            } else {
                set list ""
                foreach s [ic_geo_get_objects surface $name] {lappend list [list surface $s]}
                #if {$count_surface && $components != "" && $surf_objs != ""} {lappend list $surf_objs}
                foreach c [ic_geo_get_objects curve $name] {lappend list [list curve $c]}
                foreach p [ic_geo_get_objects point $name] {lappend list [list point $p]}
                set cmd [list ic_geo_bbox_of_entities $list]
                if {!$bodies && $name != "ORFN"} { mess "Bounding box around part is [eval $cmd ]\n" }
            }
            if {$components != "" && $comps_found != ""} {
                mess "Part $name contains $comps_count hidden component part(s):\n$comps_found\n"
            }
        }
        if {$what == "all" || ($what == "mesh" && ([ic_uns_count_in_families $name] || [ic_str_count_in_families $name]))} {
           if {$what == "mesh"} {
                mess "--------------------------------------------------------------------------\n"
                mess "Mesh Info for part $name\n"
                mess "--------------------------------------------------------------------------\n"
            }
            if {$what == "all"} { mess "Mesh Info ----\n" }
            if [ic_uns_is_loaded] {
                set num [ic_uns_count_in_families $name]
                if {!$num || ([ic_boco_is_loaded] && [llength [ic_geo_list_families_in_part $name]] > 1)} {
                    set parts [ic_geo_list_families_in_part $name]
                    if {$parts != $name && $name != "VORFN" && $name != "ORFN"} {
                        set nn 0
                        set types ""
                        set comps_found ""
                        set comps_count 0
                        foreach in_part $parts {
                            set nelms [ic_uns_count_in_families $in_part]
                            if $nelms {
                                incr nn $nelms
                                set sub [ic_uns_subset_create_family_type [list $in_part] __all__ 1 0]
                                set t [ic_uns_subset_list_types $sub]
                                append types "$t "
                                if {$in_part != $name} {
                                    append comps_found "\t$in_part contains $nelms elements of type(s) [lsort -unique $t]\n"
                                    incr comps_count
                                }
                                ic_uns_subset_delete $sub
                            }
                        }
                        if $nn {
                            mess "Part contains $nn element(s)\n"
                            set types [lsort -unique $types]
                            if {[llength $types] > 1} {
                                foreach t $types {
                                    set sub [ic_uns_subset_create_family_type $parts $t 1 0 1]
                                    append types2 "$t ([ic_uns_subset_count_elements $sub $t]) "
                                    ic_uns_subset_delete $sub
                                }
                                mess "Part contains types $types2\n"
                            } else {
                                mess "Part contains type $types\n"
                            }
                            set sub [ic_uns_subset_create_family_type $parts __all__ 1 0 1]
                            if {([lsearch $types TRI_3] > -1) || ([lsearch $types QUAD_4] > -1)} {
                                mess "Mesh area of part is [ic_uns_area $sub]\n"
                            }
                            if {([lsearch $types TETRA_4] > -1) || ([lsearch $types HEXA_8] > -1)} {
                                mess "Mesh volume of part is [ic_uns_volume $sub]\n"
                            }
                            mess "Bounding box around part is [ic_uns_subset_bbox $sub]\n"
                            if $comps_count {
                                mess "Part $name contains $comps_count hidden component parts:\n$comps_found\n"
                            }
                            ic_uns_subset_delete $sub
                        }
                    } else {
                        mess "No mesh in part $name\n"
                    }
                } elseif {$num} {
                    mess "Part contains $num element(s)\n"
                    set sub [ic_uns_subset_create_family_type [list $name] __all__ 1 0 1]
                    set types [ic_uns_subset_list_types $sub]
                    if {[llength $types] > 1} {
                        foreach t $types {
                            append types2 "$t ([ic_uns_subset_count_elements $sub $t]) "
                        }
                        mess "Part contains types $types2\n"
                    } else {
                        mess "Part contains type $types\n"
                    }
                    if {([lsearch $types TRI_3] > -1) || ([lsearch $types QUAD_4] > -1)} {
                        mess "Mesh area of part is [ic_uns_area $sub]\n"
                    }
                    if {([lsearch $types TETRA_4] > -1) || ([lsearch $types HEXA_8] > -1)} {
                        mess "Mesh volume of part is [ic_uns_volume $sub]\n"
                    }
                    mess "Bounding box around part is [ic_uns_subset_bbox $sub]\n"
                    ic_uns_subset_delete $sub
                } else {
                    mess "No mesh in part $name\n"
                }
            } elseif {[ic_str_is_loaded]} {
                set num [ic_str_count_in_families $name]
                if $num {
                    mess "Part contains $num elements\n"
                    set found 0
                    foreach type {domain subface edge vertex} {
                        set nums ""
                        foreach n [ic_str_list_entities $type] {
                            set info [ic_str_get_topo_info $type $n 0]
                            if {[lindex [lindex $info 0] 2] == $name} {
                                lappend nums $n
                            }
                        }
                        if {$nums != ""} {
                            set found 1
                            mess "Part contains [llength $nums] ${type}(s)\n"
                        }
                    }
                } else {
                    mess "No mesh in part $name\n"
                }
            } else {
                mess "No mesh is loaded\n"
            }
        }
        if {$what == "all" || ($what == "block" && ([llength [ic_hex_get_block_families_and_types $name]] > 0 || \
                                                    [llength [ic_hex_get_block_families_and_types $name output_blocks]] > 0))} {
            if {$what == "block"} {
                mess "--------------------------------------------------------------------------\n"
                mess "Blocking Info for part $name\n"
                mess "--------------------------------------------------------------------------\n"
            }
            if [ic_hex_blocking_loaded] {
                global use_output_blocks
                if {$what == "all"} { mess "Blocking Info ----\n" }
                set num_blk 0
                set num_comp 0
                set comps_found ""
                set mapped 0; set free 0; set swept 0
                set parts [ic_geo_list_families_in_part $name]
                if {$parts != "" && $parts != $name} {
                    foreach f $parts {
                        if [regexp : $f] {
                            if $use_output_blocks {
                                set blks [eval ic_hex_get_block_families_and_types $f output_blocks]
                            } else {
                                set blks [eval ic_hex_get_block_families_and_types $f]
                            }
                            set nn [llength $blks]
                            incr num_blk $nn
                            incr mapped [llength [lsearch -all $blks "*mapped*"]]
                            incr free [llength [lsearch -all $blks "*free*"]]
                            incr swept [llength [lsearch -all $blks "*swept*"]]
                            incr num_comp
                            append comps_found "\t$f contains $nn block(s)\n"
                        }
                    }
                } else {
                    if $use_output_blocks {
                        set blks [eval ic_hex_get_block_families_and_types $name output_blocks]
                    } else {
                        set blks [eval ic_hex_get_block_families_and_types $name]
                    }
                    set num_blk [llength $blks]
                    set mapped [llength [lsearch -all $blks "*mapped*"]]
                    set free [llength [lsearch -all $blks "*free*"]]
                    set swept [llength [lsearch -all $blks "*swept*"]]
                }
                if $num_blk {
                    mess "Part contains $num_blk block(s)\n"
                    if $free {
                        mess "Number of free blocks: $free\n"
                    }
                    if $mapped {
                        mess "Number of mapped blocks: $mapped\n"
                    }
                    if $swept {
                        mess "Number of swept blocks: $swept\n"
                    }
                    if $num_comp {
                        mess "Part $name contains $num_comp hidden component part(s): \n$comps_found\n"
                    }
                } else {
                    mess "No blocking in part $name\n"
                }
            }
        }
        if {$beta_mode && ($what == "all" || $what == "bc" )} {
            if [ic_boco_is_loaded] {
                set found_some 0
                set components ""
                foreach p [ic_geo_list_families_in_part $name] {
                    set bc [ic_boco_get $p]
                    set types ""
                    if {$bc != ""} {
                        foreach c $bc {
                            if {[lindex $c 1] == "color"} continue
                            append types "[lindex $c 1] "
                        }
                        if {$types != ""} {
                            append components "Part $p contains bc type(s) $types\n"
                            incr found_some
                        }
                    }
                }
                if $found_some {
                    mess "Boundary Condition Info ----\n"
                    mess "$components\n"
                }
            }
        }
        if {$what == "all"} { mess "--------------------------------------------------------------------------\n" }
    }
}

proc aie_info_all_part {type} {
    set parts [lsort [ic_geo_list_families]]
    foreach part $parts {
        if {[lsearch [aie_find_base_assemblies] $part] >= 0} continue
        if [::AIEnv::GUIManagement::Tree::GroupExists part $part] {
            aie_info_part $part $type
            set parts_info($part) 1
        } else {
            if [regexp ":" $part] {
                set p [lindex [split $part :] 0]
                if {$type == "all"} {
                    if [info exists parts_info($p)] continue
                    aie_info_part $p $type
                } else {
                    if [info exists parts_info($part)] continue
                    aie_info_part $part $type
                }
                if {$type == "all"} {
                    set parts_info($p) 1
                } else {
                    set parts_info($part) 1
                }
            }
        }
    }
}

proc aie_break_up_part { names } {
    global beta_mode
    
    if ![ic_geo_is_loaded] {
        if !$beta_mode {
            mess "This function only works on geometry\n" red
        } else {
            mess "This function only works together with geometry\n" red
        }
        return
    }
    
    foreach name $names {
        set surfaces [ic_geo_get_objects surface $name]
        if {$surfaces == ""} {
            mess "No surfaces in this part. Returning\n" red
            return
        }
        set groups [ic_geo_make_conn_regions surface $surfaces]
        set n 0
        set len [llength $groups]
        foreach g $groups {
            incr n
            set new_name $name/PART$n
            ic_geo_set_part surface $g $new_name 0
            if {$beta_mode && [ic_uns_is_loaded]} {
                set new [ic_uns_subset_create]
                foreach surface $g {
                    set s [ic_uns_get_attached_elements surface $surface] 
                    if ![ic_uns_subset_count_elements $s] {
                        ic_uns_subset_delete $s
                        continue
                    }
                    ic_uns_subset_add_from $new $s
                    ic_uns_subset_delete $s
                }
                ic_uns_set_part $new $new_name
                ic_uns_subset_delete $new
            }
            set curves [ic_geo_get_attached_entities boundary surface $g]
            ic_geo_set_part curve $curves $new_name 0
            if {$beta_mode && [ic_uns_is_loaded]} {
                set new [ic_uns_subset_create]
                foreach c $curves {
                    set s [ic_uns_get_attached_elements curve $c]
                    if ![ic_uns_subset_count_elements $s] {
                        ic_uns_subset_delete $s
                        continue
                    }
                    ic_uns_subset_add_from $new $s
                    ic_uns_subset_delete $s
                }
                ic_uns_set_part $new $new_name
                ic_uns_subset_delete $new
            }
            set points [ic_geo_get_attached_entities boundary curve $curves]
            ic_geo_set_part point $points $new_name 0
            if {$beta_mode && [ic_uns_is_loaded]} {
                set new [ic_uns_subset_create]
                foreach p $points {
                    set s [ic_uns_get_attached_elements point $p]
                    if ![ic_uns_subset_count_elements $s] {
                        ic_uns_subset_delete $s
                        continue
                    }
                    ic_uns_subset_add_from $new $s
                    ic_uns_subset_delete $s
                }
                ic_uns_set_part $new $new_name
                ic_uns_subset_delete $new
            }
        }
        if {$beta_mode && [ic_uns_is_loaded]} {
            # put the remaining mesh elements from the original part into a seperate part
            set new [ic_uns_subset_create]
            ic_uns_subset_visible $new 0
            ic_uns_subset_make_families $new $name
            ic_uns_uniqify $new
            ic_uns_set_part $new $name/$name
            ic_uns_subset_delete $new
        }
        foreach p [ic_geo_get_objects body $name] {
            incr n
            set new_name $name/PART$n
            ic_geo_set_part body $p $new_name 0
        }
  }
  aie_create_initial_assemblies
  #it seems bizarre that this should be needed, but if you just do one aie_create_initial_assmbly, 
  # Other assemblies get removed.  The second one seems to rebuild these that get removed
  #  Wayne probably needs to fix this  -->Ben
  aie_create_initial_assemblies
}

proc aie_merge_assembly_to_part { names } {

    foreach name $names {
        set l [expr [string length $name] - 1]
        set col ""
        foreach p [aie_list_parts 0] {
	        if {[string range $p 0 $l] != $name} continue
	        if {$p == $name} continue
	        if {[string last / $p] == -1} continue
	        mess "Merging assembly part $p into part $name\n"
	        if {$col == ""} { set col [family_color_for_name $p] }
	        aie_rename_part $p $name 1 $col
        }
    }
    aie_create_initial_assemblies
}

proc aie_create_assembly {{name ""}} {
    global current_asembly_to_load
    aie_clear_dez
    if {$name == ""} {
	    after 100 { createAssemDEZ show }
	} else {
	    set current_asembly_to_load $name
	    after 100 { createSubAssemDEZ show }
	}
}

proc aie_remove_assembly {} {
    aie_clear_dez
    set assem [aie_find_base_assemblies]
    if {$assem == ""} {
        mess "No assembly found\n"
        return
    }
    set num 0
    foreach p [aie_list_parts 0] {
        set start [string last / $p]
        if {$start == -1} continue
        set p1 [string range $p 0 [expr $start - 1]]
        set p2 [string range $p [expr $start + 1] end]
        set p3 "$p1\#$p2"
        set col [family_color_for_name $p3]
        aie_rename_part $p $p3 1 $col
        incr num  
    }
    mess "$num assemblies renamed\n"
}

proc aie_find_base_assemblies {{list ""} } {
    if {$list == ""} { set list [ic_geo_list_parts] }
    set ret ""
    foreach p $list {
	    set start [string last / $p]
	    if {$start != -1} {
	        lappend ret [string range $p 0 [expr $start - 1]]
	    }	
    }
    return [lsort -unique $ret]
}

proc oncreateAssemDEZLoad {} {
    set assembly [ic_geo_get_unused_part ASM]
    if {$wildcard == ""} {set wildcard PART}
}

proc oncreateSubAssemDEZLoad {} {
    global current_asembly_to_load
    set assembly $current_asembly_to_load/[ic_geo_get_unused_part ASM]
}

proc oncreateAssemDEZOK {} {
    if {$assembly == ""} return
    set name [ic_geo_valid_name $assembly 1]  
    ic_geo_new_family $name
    switch $createAssemSelectVal {
	    0 {
	        if {$parts == ""} {
		        mess "No parts selected\n" red
		        return
	        }
	        foreach p $parts {
		        set col [family_color_for_name $p]
		        set start [string last / $p]
		        if {$start > -1} {
		            set part [string range $p [expr $start + 1] end]
		        } else {
		            set part $p
		        }
		        set new_name $name/$part
		        aie_rename_part $p $new_name 1 $col
	        }
	        set parts ""
	    }
	    1 {
	        set assems [aie_find_base_assemblies]
	        foreach p [ic_geo_list_parts] {
		        if {[lsearch $assems $p] != -1} continue
		        if {$p == $name} continue
		        set start [string last / $p]
		        if {$start != -1} {
		            set part [string range $p [expr $start + 1] end]
		        } else {
		            set part $p
		        }
		        if {[string first $wildcard $part] != -1} {
		            set col [family_color_for_name $p]
		            set new_name $name/$part
		            aie_rename_part $p $new_name 1 $col
		        } 
	        }
	    }
	    2 {
	    }
	    default {
	        return
	    }
    }
    ::AIEnv::GUIManagement::Tree::AddGroup part $name 1 0 black
    ::AIEnv::GUIManagement::Tree::ToggleGroupVisibility part $name same
}

proc oncreateSubAssemDEZOK {} {
    if {$assembly == ""} return
    set name [ic_geo_valid_name $assembly 1]
    ic_geo_new_family $name
    switch $createSubAssemSelectVal {
        0 {
	        if {$parts == ""} {
		        mess "No parts selected\n" red
		        return
	        }
	        foreach p $parts {
		        set col [family_color_for_name $p]
		        set start [string last / $p]
		        if {$start > -1} {
		            set part [string range $p [expr $start + 1] end]
		        } else {
		            set part $p
		        }
		        set new_name $name/$part
		        aie_rename_part $p $new_name 1 $col
	        }
	        set parts ""
	    }
	    default {
	        return
	    }
    }
    ::AIEnv::GUIManagement::Tree::AddGroup part $name 1 0 black
    ::AIEnv::GUIManagement::Tree::ToggleGroupVisibility part $name same
}

proc onCreatePartDEZLoad {} {
    global current_part_to_load tdv_default

    if [info exists current_part_to_load(name)] {
	    set name $current_part_to_load(name)
    } else {
	    set name [ic_geo_get_unused_part PART]
    }
    if [info exists LongList] { unset LongList }
    
	#        0   1   2   3    
    set buts {createPartSel createPartPos createPartBox createPartBlk}
	set stats {disabled normal}
	set stat(0) [expr [ic_geo_is_loaded] || [ic_uns_is_loaded] || [ic_str_is_loaded]]
	set stat(1) [expr [ic_uns_is_loaded] || [ic_str_is_loaded]]
	set stat(2) [expr [ic_uns_is_loaded] || [ic_str_is_loaded]]	
	set stat(3) [ic_hex_blocking_loaded]
	foreach n {0 1 2 3} {
		set but [lindex $buts $n]
		set sta [lindex $stats $stat($n)]
	    $toolBarInfo($but-tool) configure -state $sta
	}

    set entityList ""
    set PartList [aie_list_parts 1]
    foreach st {geo mesh} {
	    set select_${st}_0d 0
	    foreach sd {1 2 3} {
	        set select_${st}_${sd}d 1
	    }
    }
    
    set bb [$tdv_default bbox interesting]
    if {$bb != ""} {
	    foreach c $bb m {min max} {
	        foreach v $c x {x y z} {
		        set $m$x [format %g $v]
	        }
	    }
    }
    geo_select_either_set_prefix ::AIEnv::DEZ::createPartDEZ::select_
    set AllowActiveReload 1
    set adjust_geo_names 0
}

proc onCreatePartDEZAfterLoad {} {
    set entityList ""
    set blocks ""
    if {[info exists createPartSelectVal] && ($createPartSelectVal == 3)} {
	    oncreatePartBlkLoad
    }
}

proc oncreatePartBlkLoad {} {
     global auto_pick_mode
     if [ic_hex_blocking_loaded] {
	    lappend PartList VORFN
	    ::AIEnv::GUIManagement::ToggleGrey createPartBlk 0
	    if $auto_pick_mode { 
	        createPartBlkPick pick
	    }
     } else {
	    ::AIEnv::GUIManagement::ToggleGrey createPartBlk 1
	    createPartDEZ setclean
	    msg ERROR "No blocking available"
     }
}

proc onModifyPartDEZAfterLoad {} {
    global auto_pick_mode
    set entityList ""
    set blocks ""
    if {[info exists modifyPartSelectVal] && ($modifyPartSelectVal == 2)} {
        onmodifyPartBlkLoad
    }
}

proc onmodifyPartBlkLoad {} {
    global auto_pick_mode
    if [ic_hex_blocking_loaded] {
        ::AIEnv::GUIManagement::ToggleGrey modifyPartBlk 0
        if $auto_pick_mode { 
            modifyPartBlkPick pick
        }
    } else {
        ::AIEnv::GUIManagement::ToggleGrey modifyPartBlk 1
        modifyPartDEZ setclean
        msg ERROR "No blocking available"
    }
}

proc onModifyPartDEZLoad {} {
    global current_part_to_load tdv_default toolBarInfo
    global auto_pick_mode part_types

    set name ""
    if [info exists current_part_to_load(name)] {
        set name $current_part_to_load(name)
    }
    if [info exists LongList] { unset LongList }
    
    set buts {modifyPartSel modifyPartBox modifyPartBlk}
    set stats {disabled normal}
    set stat(0) [expr [ic_geo_is_loaded] || [ic_uns_is_loaded]]
    set stat(1) [expr [ic_uns_is_loaded] || [ic_str_is_loaded]]
    set stat(2) [ic_hex_blocking_loaded]
    if {$name == "VORFN"} {
        set stat(0) 0
        set stat(1) 0
    }
    foreach n {0 1 2} {
        set but [lindex $buts $n]
        set sta [lindex $stats $stat($n)]
        $toolBarInfo($but-tool) configure -state $sta
    }

    set PartList [aie_list_parts 1]
    foreach st {geo mesh} {
        set select_${st}_0d 0
        foreach sd {1 2 3} {
            set select_${st}_${sd}d 1
        }
    }
    set bb [$tdv_default bbox interesting]
    if {$bb != ""} {
        foreach c $bb m {min max} {
            foreach v $c x {x y z} {
                set $m$x [format %g $v]
            }
        }
    }
    set part_types ""
    geo_select_either_set_prefix ::AIEnv::DEZ::modifyPartDEZ::select_
    if [ic_uns_is_loaded] {
        set sub [ic_uns_subset_create]
        ic_uns_subset_add_families_and_types $sub $name all
        set part_types [ic_uns_subset_list_types $sub]
        ic_uns_subset_delete $sub
    }
    set AllowActiveReload 1
}

proc aie_rename_part {name {newname ""} {force_newname 1} {not_black ""} {rename_entities 1} {check 1}} {
    global fam_visible
    global ::AIEnv::GUIManagement::ActiveDEZ

    if {$::AIEnv::GUIManagement::ActiveDEZ == "modifyPartDEZ"} {
        lpopup "Please dismiss the Modify Part dialog before renaming parts"
        return
    }
    if $check {
        if {$newname == ""} {
            set base [lindex [split $name /] end]
            set newbase [question_box .newname "New name" "New name for part $name" $base]
            if {$newbase == ""} return
            set newname [join [concat [lrange [split $name /] 0 end-1] [list $newbase]] /]
            set force_newname 0
        }
        set maxlen [ic_geo_get_valid_namelen]
        if {[string len $newname] > $maxlen} {
            msg ERROR "Part name too long; max $maxlen characters allowed"
            return
        }
        if {$newname == "vorfn" || $newname == "VORFN"} {
            msg ERROR "VORFN name can not be used; please use some other name"
            return
        }
        if !$force_newname {
            set newname2 [ic_geo_valid_name $newname 1]
            if {[string len $newname2] > $maxlen} {
                mess "Part name too long; max $maxlen characters allowed\n" red
                return
            }
            if {$newname2 != $newname} {
                mess "Name \"$newname\" is not valid - changed to \"$newname2\"\n" red
                set newname $newname2
            }
            if [ic_geo_check_part $newname] {
                set newname1 [ic_geo_get_unused_part $newname]
                mess "Part name \"$newname\" is already in use : renaming part to \"$newname1\" instead\n" red
                set newname $newname1
            }
        }
        if {[string len $newname] > $maxlen} {
            msg ERROR "Part name too long; max $maxlen characters allowed\n"
            return
        }
        set len [string length $name/]
        set oldparts [list $name]
        set newparts [list $newname]
        foreach part [ic_geo_list_parts] {
	        if {$part == $name} {
	            set newname2 $newname
	        } elseif {[string match $name/* $part]} {
	            set newname2 $newname/[string range $part $len end]
	        } else {
	            continue
	        }
	        foreach fam [ic_geo_list_families_in_part $part] {
	            set newfam [join [concat [list $newname2] [lrange [split $fam :] 1 end]] :]
	            if ![info exists ::fam_visible($fam)] {
	                if [info exists ::fam_visible($name)] {
	                    set ::fam_visible($fam) $::fam_visible($name)
	                } else {
	                    set ::fam_visible($fam) 1
	                }
	            }
	            set ::fam_visible($newfam) $::fam_visible($fam)
	            set rename_ents 0
                # Fix problem for invalid command name "" error
	            catch { ic_geo_rename_family $fam $newfam $rename_ents }
	        }
	        lappend oldparts $part
	        lappend newparts $newname2
        }
        # it might be an asm ...
        if [info exists ::fam_visible($name)] {
            set ::fam_visible($newname) $::fam_visible($name)
        }
    } else {
        set oldparts [list $name]
        set newparts [list $newname]
    }
    ic_geo_rename_family $name $newname $rename_entities
    if {[lsearch [ic_uns_list_families] $name] != -1} { ic_uns_rename_family $name $newname }
    if {$not_black != ""} {
        set col $not_black
    } elseif {[::AIEnv::GUIManagement::Tree::GetColor part $name] == "black"} {
        set col black
    } else {
        set col [family_color_for_name $newname]
    }
    set rr ""
    foreach op $oldparts np $newparts {
	    if ![aie_valid_name $np] continue
        set np [string toupper $np]
        set vis ""
        if [info exist ::fam_visible($np)] {set vis $::fam_visible($np)}
        set col [::AIEnv::GUIManagement::Tree::GetColor part $op]
        #::AIEnv::GUIManagement::Tree::RenameGroup part $op $np $vis
        lappend rr $op $np $vis $col
    }
    foreach {op np vis col} $rr {
        set vci [::AIEnv::GUIManagement::Tree::DeleteGroup part $op 0]
        if {$vis == ""} {set vis [lindex $vci 0]}
        if {$col == ""} {set col [lindex $vci 1]}
        ::AIEnv::GUIManagement::Tree::AddGroup part $np $vis 1 $col
        aie_update_partbcs_one $np
    }
    if [info exist ::fam_visible($name)] {
        set geo_nonempty 0; set uns_nonempty 0; set str_nonempty 0
        if {[ic_geo_is_loaded] && [ic_geo_count_in_family all $::fam_visible($name)]} {
             set geo_nonempty 1
        }
        if {[ic_uns_is_loaded] && [ic_uns_count_in_families $::fam_visible($name)]} {
             set uns_nonempty 1
        }
        if {[ic_str_is_loaded] && [ic_str_count_in_families $::fam_visible($name)]} {
             set str_nonempty 1
        }
        if {!$geo_nonempty && !$uns_nonempty && !$str_nonempty} {
            if ![ic_hex_subset_named_selection $name] {
                unset ::fam_visible($name)
            }
        }
    }
    return $newname
}

proc aie_delete_part {names} {
    global fam_visible aie_bctypes_used fam_visible_color

    set loaded 0
    set mess "Delete all "
    if [ic_geo_is_loaded] {
        append mess "geometry "
        set loaded 1
    }
    if {([ic_uns_is_loaded] || [ic_str_is_loaded])} {
        if $loaded {
            append mess "and mesh "
        } else {
            append mess "mesh "
        }
    }
    if [ic_hex_blocking_loaded] {
        append mess "and blocking "
    }
    append mess "in $names?"
    if [tk_dialog .confirm Delete "$mess" "" -1 Delete Cancel] { return }
    if [winfo exists .confirm] { top_destroy .confirm; return }
    ic_undo_group_begin
    ic_start_bigunsop
    ic_undo_resume
    foreach part [ic_geo_list_parts] {
	foreach name $names {
	    if {($part == $name) || [string match $name/* $part]} {
		set fams [ic_geo_list_families_in_part $part]
        set part_delete 1
		if [ic_boco_is_loaded] {
		   foreach fam $fams {
		      foreach type [array names aie_bctypes_used] {
		         if {[info proc aie_apply_icons_$type] == ""} continue
		         foreach b $aie_bctypes_used($type) {
		            set bc [ic_boco_get $fam $b]
                    if {$bc != ""} { set part_delete 0 }
		         }
		      }
		   }
		}
		if !$part_delete {
            tk_messageBox -message "Part $part has attached BCs!\nPlease delete the attached BCs before deleting the part." -type ok -icon error
        } else {
		    foreach fam $fams {
		       ic_delete_elements family $fam no_undo 1
               set fam_visible_color($fam) [family_color_for_name $fam]
		       if [info exists fam_visible($fam)] {
		           if ![ic_hex_subset_named_selection $fam] {
		               unset fam_visible($fam)
		           }
		       }
		    }
		    ic_delete_geometry all families $fams 1 1
		    if [ic_hex_blocking_loaded] {
		       aie_delete_blocks_by_parts $fams
		    }
            if {![ic_uns_is_loaded] && ![ic_str_is_loaded]} {
		        ic_geo_delete_family $fams
            }
		    ::AIEnv::GUIManagement::Tree::DeleteGroup part $part 0
            }
	    }
	}
    }
    ic_finish_bigunsop
    ic_undo_group_end
    update_uns_visible
}

proc aie_delete_blocks_by_parts {parts} {
    global last_line 
    if ![ic_hex_blocking_loaded] return
    set blocks ""
    foreach p $parts {
        hex_command "select_blocks 1 no_highlight all m $p"
        append blocks "[string trimright $last_line \n] "
    }
    set numbers ""
    foreach i $blocks {
        set p [string trimright [ic_hex_get_block_family $i] \n]
        if {[lsearch "$parts" $p] >= 0} { lappend numbers $i }
    }
    if {$numbers == ""} return
    aie_change_part_blocks $numbers VORFN
    mess "Blocking: [llength $numbers] block(s) moved to VORFN\n" blue
    get_indices 0
    hex_update_display
    index_update_all
}

proc aie_blank_part { names} {
    foreach name $names {
        ::AIEnv::GUIManagement::Tree::ToggleGroupVisibility part $name 0 0
    }
    aie_update_visible
}

proc aie_unblank_part { names } {
    foreach name $names {
        ::AIEnv::GUIManagement::Tree::ToggleGroupVisibility part $name 2 0
    }
    aie_update_visible
}

proc aie_update_partbcs_one {part} {
    global env aie_bctypes_used aie_bcclass_is_part fam_visible
    
    foreach type [array names aie_bctypes_used] {
	    if {[info proc aie_apply_icons_$type] == ""} continue
	    foreach b $aie_bctypes_used($type) {
	        if [info exists aie_bcclass_is_part($type)] {
		        set used [ic_boco_get $part $b]
		        set vis [aie_is_group_type_visible $type]
		        set nn [aie_apply_icons_$type $part geometry_or_mesh $vis $vis]
		        if $nn {
		            if {![::AIEnv::GUIManagement::Tree::PartBCExists $type $part]} {
			            ::AIEnv::GUIManagement::Tree::AddPartBC $type $part $vis
		            }
		        }
	        }
	    }
    }
}

proc aie_color_part {names {new ""}} {
    foreach name $names {
	if {$new == ""} {
	    set cur [family_color_for_name [lindex [split $name /] end]]
	    set new [SelectColor .select_color -color $cur]
	    if {$new == ""} return
	}
	
	# SelectColor returns stuff like #ed25fefedb4b
	if {[string length $new] > 7} {
	    set new \#[string range $new 1 2][string range $new 5 6][string range $new 9 10]
	}
	foreach fam [ic_geo_list_families_in_part $name] {
	    ic_set_family_color_for_name $fam $new
	}
	::AIEnv::GUIManagement::Tree::ChangeColor part $name $new
    }
}

# --------

proc aie_move_assembly {name into} {
    if {$into == "*"} {
        aie_rename_part $name [file tail $name]
    } else {
        aie_rename_part $name $into/[file tail $name]
    }
}

# A part is a singleton family that has only element property bc's in it

proc aie_list_parts {fs} {
    global aie_bcclass_is_part aie_bctypes_used
    
    aie_get_parts_and_families ispart
    if $fs {
        return [concat {"From screen"} [lsort [array names ispart]]]
    } else {
        return [lsort [array names ispart]]
    }
}

proc aie_get_parts_and_families {var} {
    global aie_bctypes_used aie_bcclass_is_part
    
    upvar 1 $var ispart
    
    foreach f [ic_uns_non_empty_families] {
	    set p [lindex [split $f :] 0]
	    lappend ispart($p) $f
	    set got_fam($f) 1
    }
    foreach p [array names ispart] {
	    if ![info exists got_fam($p)] {
	        #puts "Warning: part $p should have existed..  creating it"
	        ic_geo_new_family $p
	    }
    }
    # But... If there is just a node holding a constraint (i.e. the family is
    # like CN1) then it's not a part.
    foreach t [array names aie_bctypes_used] {
	    foreach b $aie_bctypes_used($t) {
	        set type_of_bc($b) $t
	    }
    }
    foreach f [ic_uns_list_families 0] {
	    if ![info exists ispart($f)] continue
	    set isg 0; set isp 0
	    foreach bc [ic_boco_get $f] {
	        if ![info exists type_of_bc([lindex $bc 1])] continue
	        set isg 1
	        set t $type_of_bc([lindex $bc 1])
	        if ![info exists aie_bcclass_is_part($t)] continue
	        set isp 1
	    }
        if {$isg && !$isp} { unset ispart($f) }
    }
    foreach f [ic_geo_non_empty_families] {
	    set p [lindex [split $f :] 0]
	    lappend ispart($p) $f
    }
    foreach f [ic_hex_non_empty_families] {
	    set p [lindex [split $f :] 0]
	    lappend ispart($p) $f
    }
    foreach f [ic_str_list_families] {
	    set p [lindex [split $f :] 0]
	    lappend ispart($p) $f
    }
}

# --------------------------------------------------

# what is the bctype
# bcs are the list of bc's to apply
# nprefix is the short prefix for the bctype
# name is the name of the group being edited
# type is the type of objects to apply to, or the word "existing"
# objects is the list of objects to apply to if type is not "existing"
# parts_or_subsets is a list of {part PART1 part PART2 subset SS1 ...} if that was the
#    selection option.  If this is "" and the type is part or subset then it will be
#    taken from the name/objects values

proc aie_apply_attribute {what bcs nprefix name type objects parts_or_subsets} {
    global fam_visible
    global bc_name_list
    
    if ![info exists bc_name_list] { set bc_name_list "" }

#    puts [list aie_apply_attribute $what $bcs $nprefix $name $type $objects $parts_or_subsets]
    
    if {$parts_or_subsets == ""} {
	if {($type == "part") || ($type == "subset")} {
	    foreach obj $objects {
		lappend parts_or_subsets $type $obj
	    }
	}
    }
    set name2 [ic_geo_valid_name $name 1]
    if {$name2 != $name} {
	#lpopup "Name \"$name\" is not valid - changed to \"$name2\""
         mess "Name \"$name\" is not valid - changed to \"$name2\"\n" red
	set name $name2
    }
    
    if {$type == "surf"} { set type surface } ;# sloppy...
    if {$name == ""} { set name [ic_boco_get_unused_group $nprefix] }
    set name [string toupper [string trim $name]]
    
    set ta [tdv_active 0]
    busy 1
    
    if {$objects == ""} {
	if {$what == "mpcdisp"} {
            foreach fam [ic_boco_list_families] {
               if [string match *:$name:* :$fam:] {
                  set unsmap  [ic_uns_subset_create]
                  ic_uns_subset_make_families $unsmap $fam
                  foreach p {C1 A1 C2 A2} {
                     set param_name "Nastran:MPC:$p"
                     ic_uns_bcfield_define $param_name 0
                     set val 0
                     if {$p == "C1"} {set val [lindex [lindex $bcs 0] 3]}
                     if {$p == "A1"} {set val [lindex [lindex $bcs 0] 4]}
                     if {$p == "C2"} {set val [lindex [lindex $bcs 0] 5]}
                     if {$p == "A2"} {set val [lindex [lindex $bcs 0] 6]}
                     if {$val == ""} {set val 0}
                     ic_uns_bcfield_set $param_name $unsmap $val
                  }
                  ic_uns_subset_delete $unsmap
               }
	   }
	   set newfams [ic_boco_replace_in_group $bcs $name]
	} else {
	   set newfams [ic_boco_replace_in_group $bcs $name]
	}
    } else {
	if {$type == "point"} {
              if {$what == "mpcdisp"} {
                  # Do the dependent DOF
	        set unsmap [lindex $objects 0]
	        set fam [ic_geo_get_part point $unsmap]
	        if { $fam == ""} {set fam [aie_new_part DEP_POINTS]}
	        set unsmap2 [ic_uns_subset_create]
	        ic_uns_create_element NODE $fam $unsmap 0 $unsmap2 0
	        ic_uns_subset_delete $unsmap
	        set unsmap_dep $unsmap2
                 foreach p {DEP C1 A1 C2 A2} {
                    set param_name "Nastran:MPC:$p"
	           ic_uns_bcfield_define $param_name 0
                    set val 0
                    if {$p == "DEP"} {set val 1}
                    if {$p == "C1"} {set val [lindex [lindex $bcs 0] 3]}
                    if {$p == "A1"} {set val [lindex [lindex $bcs 0] 4]}
                    if {$val == ""} {set val 0}
	           ic_uns_bcfield_set $param_name $unsmap_dep $val
                 }
                  # Do the independent DOF
	        set unsmap [lindex $objects 1]
	        set fam [ic_geo_get_part point $unsmap]
	        if { $fam == ""} {set fam [aie_new_part POINTS]}
	        set unsmap2 [ic_uns_subset_create]
	        ic_uns_create_element NODE $fam $unsmap 0 $unsmap2 0
	        ic_uns_subset_delete $unsmap
	        set unsmap_indep $unsmap2
                 foreach p {DEP C1 A1 C2 A2} {
                    set param_name "Nastran:MPC:$p"
	           ic_uns_bcfield_define $param_name 0
                    set val 0
                    if {$p == "DEP"} {set val 0}
                    if {$p == "C2"} {set val [lindex [lindex $bcs 0] 5]}
                    if {$p == "A2"} {set val [lindex [lindex $bcs 0] 6]}
                    if {$val == ""} {set val 0}
	           ic_uns_bcfield_set $param_name $unsmap_indep $val
                 }
	        # Apply MPC to selected NODE elements.
	        set objects [list unsmap $unsmap_dep]
	        set newfams [ic_boco_set_for_objects $objects $bcs $nprefix $name]
	        set objects [list unsmap $unsmap_indep]
	        set newfams [concat $newfams [ic_boco_set_for_objects $objects $bcs $nprefix $name]]
              } else {
	        set unsmap [lindex $objects 1]
	        if {$unsmap == ""} { set unsmap [lindex $objects 0] }
	        #puts "unsmap has [ic_uns_subset_count_elements $unsmap] el [ic_uns_subset_count_nodes $unsmap] node"
	        set fam [ic_geo_get_part point $unsmap]
	        if { $fam == ""} {set fam [aie_new_part POINTS]}
	        if ![string match uns_* $unsmap] {
		  # In this case we are applying a force to a geometric point.
		  set objects [list $type $objects]
		  ic_uns_create_node_element_near_point $unsmap $fam
	        }  else {
		  set unsmap2 [ic_uns_subset_create]
		  #puts "ic_uns_create_element NODE $fam $unsmap 0 $unsmap2 1"
		  ic_uns_create_element NODE $fam $unsmap 0 $unsmap2 1
		  ic_uns_subset_delete $unsmap
		  set unsmap $unsmap2
		  puts "unsmap has [ic_uns_subset_count_elements $unsmap] el [ic_uns_subset_count_nodes $unsmap] node"
		  set objects [list unsmap $unsmap]
	        }
	        set newfams [ic_boco_set_for_objects $objects $bcs $nprefix $name]
	    }
	} elseif {$type == "contact"} {
	    error "this should not happen"
	    
	    #for existing contacts
	    if {$objects==""} {
		set newfams [ic_boco_set_for_objects $objects $bcs $nprefix ""]
	    } else {
		#targets/masters
		set sel [lindex $objects 0]
		#for manual select
		if $sel {
		    set unsmap [lindex $objects 1]
		    set newtargets [ic_boco_set_for_objects [list surface $unsmap] [list "1 TARGET_FOR_CONTACT $name"] TG ${name}_TG]
		    
		    #contact faces/slaves
		    set unsmap [lindex $objects 2]
		    set objects [list surface $unsmap]
		    set newfams [ic_boco_set_for_objects $objects $bcs $nprefix $name]
		} else {
		    #auto-detect here...
		    set pairs [ic_uns_contact_sets [lindex $objects 1]]
		    set bcs1 $bcs
		    set bcs2 $bcs
		    mess "pairs: $pairs\n"				
		    foreach {uns1 uns2} $pairs {
			#					set a1 [lindex $p 0]
			#					set a2 [lindex $p 1]
			#set n1 ${a1}__VS__$a2
			#set n2 ${a2}__VS__$a1
			# set n1 [ic_boco_get_unused_group CT]
			# set n2 [ic_boco_get_unused_group CT $n1]
			set n1 $name
			set n2 ${name}_TG
			
			lappend bcs1 [list 1 TARGET_FOR_CONTACT $n2]
			lappend bcs2 [list 1 TARGET_FOR_CONTACT $n1]
			#set uns1 [ic_uns_subset_create_family_type [list $a1] __all__ 0 0]
			#set uns2 [ic_uns_subset_create_family_type [list $a2] __all__ 0 0]
			
			#puts "uns1 [ic_uns_subset_count_elements $uns1]"
			#puts "uns2 [ic_uns_subset_count_elements $uns2]"
			set f1 [ic_boco_set_for_objects "unsmap $uns1" $bcs1 CT $n1]
			set f2 [ic_boco_set_for_objects "unsmap $uns2" $bcs2 CT $n2]
			#puts "F1 $f1"
			#puts "F2 $f2"
			::AIEnv::GUIManagement::Tree::AddGroup $what $n1 1 1
			::AIEnv::GUIManagement::Tree::AddGroup $what $n2 1 1
		    }
		    
		    set newfams ""
		    set name ""
		}
	    }
	} else {
	    set objects [list $type $objects]
	    set newfams [ic_boco_set_for_objects $objects $bcs $nprefix $name]
	}
    }
    set vis [::AIEnv::GUIManagement::Tree::NodeVisibleStatus $what * "" 1]
    set nfam 0
    foreach f $newfams {
	if {$what == "mpcdisp"} {
	   aie_apply_icons_$what $f $type $vis $vis $nfam
            incr nfam
	} else {
	   aie_apply_icons_$what $f $type $vis $vis
	}
    }
    # So that the bc code knows that this name has an icon of a specific type
    if {$newfams != ""} {
	aie_apply_icons_$what $name $type $vis $vis
	if {$name != ""} {
	    #puts [list ::AIEnv::GUIManagement::Tree::AddGroup $what $name $vis 1]
	    ::AIEnv::GUIManagement::Tree::AddGroup $what $name $vis 1
	}
    } else {
	#mess "No objects selected for $what $name\n" red
    }

    puts "POS $parts_or_subsets"
    if {$parts_or_subsets != ""} {
	ic_boco_add_parts_and_subsets_to_group $name $parts_or_subsets
    }
    
    if {([ic_uns_is_loaded]) || ([ic_str_is_loaded])} { update_uns_visible }

    busy 0
    tdv_active $ta

    if {[info exists bc_name_list] && [lsearch $bc_name_list $name] < 0} {
       lappend bc_name_list $name
    }
    
    return [list name $name]
}

proc aie_edit_attribute {name what dezname} {
    global current_${what}_to_load aie_bctypes_used
    global pressure_type
    
    #puts [list aie_edit_attribute $name $what $dezname]
    
    # In case the user clicked on the Set node by accident
    if [string match "Set *" $name] return
    
    set bcs [ic_boco_get $name]
    if {$bcs == ""} {
	user_error "No such group $name found"
	return
    }
    #puts [list aie_parse_bcs_$what $bcs]
    set parsed [aie_parse_bcs_$what $bcs]
    #puts $parsed
    if {$parsed == ""} { error "No $what stuff in $name" }
    
    if {$what == "pressure"} {
        set pressure_type($name) 0
        foreach bc $bcs {
	  switch [lindex $bc 1] {
	    PLOAD2 {set pressure_type($name) 0}
	    PLOAD4 {set pressure_type($name) 1}
	  }
        }
    }
    
    foreach {n v} $parsed {
	set current_${what}_to_load($n) $v
    }
    
    if [info exists aie_bcclass_is_part($what)] {
	set current_${what}_to_load(name) ""
    } else {
	set current_${what}_to_load(name) $name
    }
    set l1 [split $name /]
    if [lmember {Points Lines Surfaces Volumes} [lindex $l1 0]] {
	set l1 [lrange $l1 1 end]
    }
    set current_${what}_to_load(part_name) [join $l1 /]

    if {[info command createExisting${dezname}DEZ] != ""} {
	set dez createExisting${dezname}DEZ
    } elseif {[info command modify${dezname}DEZ] != ""} {
	set dez modify${dezname}DEZ
    } else {
	# should this happen?
	puts "should this happen?  no modify${dezname}DEZ"
	set dez create${dezname}DEZ
    }
    
    #parray current_${what}_to_load
    
    $dez show
    
    unset current_${what}_to_load
}

proc aie_delete_property {type name} {
    global fam_visible aie_subents aie_bcclass_is_part aie_bctypes_used
    global bc_name_list

    ::AIEnv::GUIManagement::Tree::ToggleGroupVisibility $type $name 0
    
    if [info exists aie_bcclass_is_part($type)] {
	    foreach fam [ic_geo_list_families_in_part $name] {
	        ic_boco_delete_bctypes $fam $aie_bctypes_used($type)
	        #FIXME - this seems wrong
	        ic_boco_delete_icons_for_bctypes $fam $type
	        #ic_boco_delete_icons_for_bctypes $fam $aie_bctypes_used($type)
	    }
    } else {
	    set ofams [ic_boco_delete_group $name]
	    if {$type=="contact"} {
	        append ofams [ic_boco_delete_group_with_bcs [list TARGET_FOR_CONTACT $name]]
	    }
	    foreach fam $ofams { 
	        ic_boco_clear_family $fam
	        if ![ic_hex_subset_named_selection $fam] {
	            catch { unset fam_visible($fam) }
	        }
	    }
    }

    if [info exists bc_name_list] {
       set pos [lsearch $bc_name_list $name]
       if { $pos >= 0} {
            set bc_name_list [lreplace $bc_name_list $pos $pos]
       }
    }

    ::AIEnv::GUIManagement::Tree::DeleteGroup $type $name 1
}

proc aie_rename_property {type name {newname ""}} {
    global fam_visible bc_name_list

    set types {load force temperature pressure displacement impdisp mpcdisp}
    if {$newname == ""} {
        set newname [question_box .newname "New name" "New name for $type $name" $name]
    }
    if {$newname == ""} return
    set newname [aie_get_valid_name $newname]
    foreach fam [ic_geo_list_families_with_group $name] {
        set gg [ldelete [split $fam :] $name]
        lappend gg $newname
        set newfam [join $gg :]
        if [info exists fam_visible($fam)] {
	        set fam_visible($newfam) $fam_visible($fam)
	    }

	    ic_geo_rename_family $fam $newfam
	    ic_boco_rename_family $fam $newfam
    }
    if {[info exists bc_name_list] && [lsearch $types $type] >= 0} {
       set pos [lsearch $bc_name_list $name]
       if { $pos >= 0} {
          set bc_name_list [lreplace $bc_name_list $pos $pos]
       }
       if {[lsearch $bc_name_list $newname] < 0} {
          lappend bc_name_list $newname
       }
    }
    ::AIEnv::GUIManagement::Tree::RenameGroup $type $name $newname
    ::AIEnv::GUIManagement::Tree::Parts
}

proc aie_toggle_all_labels {type name} {
    global aie_all_labels
    if ![info exists aie_all_labels($type,$name)] { set aie_all_labels($type,$name) 0 }
    set ids [ic_boco_list_attr_symbols $type $name]
    if {$ids == ""} return
    set vis [ic_boco_get_attr_symbol_visible [lindex $ids 0]]
    if [lindex $vis 1] {
	    foreach id $ids {
	        ic_boco_modify_attr_symbol_visible $id [lindex $vis 0] [expr 1 + $aie_all_labels($type,$name)]
        }
    }
}

proc aie_convert_part_names_to_families {partnames} {
    set ret ""
    foreach pn $partnames {
        foreach ff [ic_geo_list_families_in_part $pn] {
            lappend ret $pn
        }
    }
    return $ret
}

proc aie_set_group_or_part_vis {type names on update} {
    global fam_visible aie_bctypes_used aie_all_labels
    global aie_prop_subtype aie_bcclass_is_part
    
    #puts [list aie_set_group_or_part_vis $type $names $on $update]
    
    if {$type == "part"} {
	    # This is an optimization
	    foreach n $names { set got($n) 1 }
	    set fams [ic_boco_list_families]
	    foreach fam $fams {
	        if [info exists got([lindex [split $fam :] 0])] {
		        set fam_visible($fam) $on
	        }
	    }
	    if $update {
	        if [ic_geo_is_loaded] { update_geom_visible all v 0 }
	        if {([ic_uns_is_loaded]) || ([ic_str_is_loaded])} { update_uns_visible }
	    }
	    return
    }
    
    set fams ""
    
    if {$type == "partbc"} {
	    foreach f [ic_boco_list_with_bctype $names] {
	        lappend fams [lindex $f 0]
	    }
	    foreach bb [array names aie_bctypes_used] {
	        if [lmember $aie_bctypes_used($bb) $names] {
		        set type $bb
		        break
	        }
	    }
	    set alltypes [list $type]
	
    } else {
	    set alltypes [list $type]
	    foreach t2 [array names aie_prop_subtype] {
	        if {$aie_prop_subtype($t2) == $type} { lappend alltypes $t2 }
	    }
	
	    foreach type $alltypes {
	        if {[info exists aie_bcclass_is_part($type)] && $type != "connector"} {
		        foreach name $names {
		            set fams [concat $fams [ic_geo_list_families_in_part $name]]
		        }
	        } else {
		        foreach name $names {
		            set fams [concat $fams [ic_geo_list_families_with_group $name]]
		        }
	        }
	    }
    }
    
    switch $type {
	part {
	    foreach f $fams {
		set fam_visible([lindex $f 0]) $on
	    }
	    if $update {
		update_geom_visible all v 0
		if [ic_uns_is_loaded] update_uns_visible
		hex_update_display
	    }
	}
	connector {
	    foreach f $fams {
		ic_meshdirect_icons_visibility $f $on
	    }
	}
	contact {
	    #FIXME
	    # Need to highlight both these families and the ones they reference
	    foreach f $fams {
		foreach bc [ic_boco_list_with_bctype [list TARGET_FOR_CONTACT $f]] {
		    set cfam_found([lindex $bc 0]) 1
		}
	    }
	    set tfams [array names cfam_found]
	    # This is a temporary measure -Wayne
	    global contact_highlight_subsets
	    set ntot 0
	    foreach f $fams {
		if {[info exists contact_highlight_subsets($f,f)] && !$on} {
		    ic_uns_subset_delete $contact_highlight_subsets($f,f)
		    unset contact_highlight_subsets($f,f)
		} elseif {![info exists contact_highlight_subsets($f,f)] && $on} {
		    set m [ic_uns_subset_create_family_type [list $f] __all__ 1]
		    ic_uns_subset_color $m white
		    ic_uns_subset_configure $m -width 2
		    set contact_highlight_subsets($f,f) $m
		    set ne [ic_uns_subset_count_elements $m]
		    incr ntot $ne
		}
	    }
	    if $on { mess "$ntot elements in $names contact group (white)\n" }
	    
	    set ntot 0
	    foreach f $tfams {
		if {[info exists contact_highlight_subsets($f,t)] && !$on} {
		    ic_uns_subset_delete $contact_highlight_subsets($f,t)
		    unset contact_highlight_subsets($f,t)
		} elseif {![info exists contact_highlight_subsets($f,t)] && $on} {
		    set m [ic_uns_subset_create_family_type [list $f] __all__ 1]
		    ic_uns_subset_color $m \#ccc
		    ic_uns_subset_configure $m -width 2
		    set contact_highlight_subsets($f,t) $m
		    set ne [ic_uns_subset_count_elements $m]
		    incr ntot $ne
		}
	    }
	    if $on { mess "$ntot elements in $names target group (gray)\n" }
	    
#	    if ![info exists contact_highlight_subsets(mess)] {
#		mess "The contact family is white; the target family is red.\n"
#		set contact_highlight_subsets(mess) 1
#	    }
	    
	    #ic_boco_set_family_visible $fams contact $on
	    #ic_boco_set_family_visible $tfams target_for_contact $on
	}
	unused__contact {
	    # Need to highlight both these families and the ones they reference
	    foreach f $fams {
		#FIXME
		set cf [lindex [lindex [ic_boco_get $f CONTACT] 0] 2]
		if {$cf != ""} {
		    foreach bc [ic_boco_list_with_bctype [list TARGET_FOR_CONTACT $cf]] {
			set cfam_found([lindex $bc 0]) 1
		    }
		}
	    }
	    set tfams [array names cfam_found]
	    
	    # This is a temporary measure -Wayne
	    global contact_highlight_subsets
	    foreach f $fams {
		if {[info exists contact_highlight_subsets($f,f)] && !$on} {
		    ic_uns_subset_delete $contact_highlight_subsets($f,f)
		    unset contact_highlight_subsets($f,f)
		} elseif {![info exists contact_highlight_subsets($f,f)] && $on} {
		    set m [ic_uns_subset_create_family_type [list $f] __all__ 1]
		    ic_uns_subset_color $m white
		    ic_uns_subset_configure $m -width 2
		    set contact_highlight_subsets($f,f) $m
		}
	    }
	    foreach f $tfams {
		if {[info exists contact_highlight_subsets($f,t)] && !$on} {
		    ic_uns_subset_delete $contact_highlight_subsets($f,t)
		    unset contact_highlight_subsets($f,t)
		} elseif {![info exists contact_highlight_subsets($f,t)] && $on} {
		    set m [ic_uns_subset_create_family_type [list $f] __all__ 1]
		    ic_uns_subset_color $m red
		    ic_uns_subset_configure $m -width 2
		    set contact_highlight_subsets($f,t) $m
		}
	    }
	    
	    if ![info exists contact_highlight_subsets(mess)] {
		mess "The contact family is white; the target family is red.\n"
		set contact_highlight_subsets(mess) 1
	    }
	    
	    #ic_boco_set_family_visible $fams contact $on
	    #ic_boco_set_family_visible $tfams target_for_contact $on
	}
	default {
	    # This is the obsolete way to do it
	    ic_boco_set_family_visible $fams $alltypes $on
	    
	    # This is the new way
	    foreach name $names {
		    set all 0
		    if [info exists aie_all_labels($type,$name)] {
		        set all $aie_all_labels($type,$name)
		    }
		    ic_boco_set_attr_symbol_group_visible $name $type $on [expr $on + $all]
	    }
	}
    }
}

# Any time something is created in this part or a node is moved that affects
# this family, call this function.

proc aie_reset_icons {part} {
    global env aie_bctypes_used aie_bcclass_is_part fam_visible
    global aie_tree_param_nodes

    set fams [ic_geo_list_families_in_part $part]
    
    foreach f $fams {
	foreach b [ic_boco_get $f] {
	    set got([lindex $b 1]) 1
	}
	set dobc ""
	foreach type [array names aie_bctypes_used] {
	    if {[info proc aie_apply_icons_$type] == ""} continue
	    foreach bc $aie_bctypes_used($type) {
		if [info exists got($bc)] { lappend dobc $type }
	    }
	}
	foreach type $dobc {
	    set vis [aie_is_group_type_visible $type]
	    aie_apply_icons_$type $f geometry_or_mesh $vis $vis
	}
    }
}

# Update all the icons connected to elements or nodes in a given map

proc aie_reset_icons_subset {map} {
    # For all the elements and nodes in this map, reset the icons
    foreach part [ic_uns_subset_families_used $map 1] {
	aie_reset_icons $part
    }
}

proc aie_reset_fam_visible {vis} {
    global fam_visible
    if {[array get fam_visible] == $vis} return
    array set fam_visible $vis
    update_geom_visible all v 0
    if [ic_uns_is_loaded] update_uns_visible
    ::AIEnv::GUIManagement::Tree::SetPartVisibleIcons
}

proc aie_reset_type_visible {vis} {
    global aie_meshTypeVis
    if {[array get aie_meshTypeVis] == $vis} return
    array set aie_meshTypeVis $vis
    aie_updateMeshVis
}

proc aie_update_parts_vis {{update 1}} {
    global fam_visible

    foreach name [aie_list_parts 0] {
	set vis [aie_is_group_type_visible part]
	foreach f [ic_geo_list_families_in_part $name] {
	    if {$f == "VORFN"} continue
	    if $update {
	        set fam_visible([lindex $f 0]) $vis
	    } else {
	        if {[info exists fam_visible([lindex $f 0])] && \
	            $fam_visible([lindex $f 0])} {
	            set fam_visible([lindex $f 0]) $vis
	        }
	    }
	}
    }
    aie_update_visible
}


# Utility function to get, say, the spcSet for a particular family.

proc aie_get_bc_argument {fam type what} {
    set bcs [ic_boco_get $fam]
    if {$bcs == ""} { return "" }
    set parsed [aie_parse_bcs_$type $bcs]
    if {$parsed == ""} { return "" }
    foreach {n v} $parsed {
	if {$n == $what} { return $v }
    }
    return ""
}

# ---------------------------------------------------------

proc aie_list_sets {type} {
    global aie_bctypes_used
    return [ic_boco_list_bcargs_for_bctypes $aie_bctypes_used($type) 2]
}

proc aie_change_set {type name newset} {
    global aie_bctypes_used
    
    set fams [ic_geo_list_families_with_group $name]
    ic_boco_replace_arg $fams $aie_bctypes_used($type) 2 $newset
    
    ::AIEnv::GUIManagement::Tree::AddGroup $type $name 1 1
    ::AIEnv::GUIManagement::Tree::ToggleGroupVisibility $type $name same
}

# ---------------------------------------------------------

proc aie_get_geometry_in_part {type name} {
    set ret ""
    foreach fam [ic_geo_list_families_in_part $name] {
	foreach obj [ic_geo_lookup $type families [list $fam]] {
	    lappend ret [lindex $obj 1]
	}
    }
    return $ret
}

# ---------------------------------------------------------

# Any singleton family becomes a part
# Except exclude those which come after the : in some other group unless
# in that other group there are no bc's

proc aie_create_initial_assemblies {{quiet 0} {later 0} {del_empty 1}} {
    # only new and active parts (see onyx 57999)   
    set parts [aie_update_parts_in_tree_if_needed]
    if {$parts != ""} {
        ::AIEnv::GUIManagement::Tree::Parts show $parts
    }
    # don't change the original functionality - Ganesan
    set aieTree [set ::AIEnv::GUIManagement::Tree::aieTree]
    if {([ic_geo_is_loaded]) && (![$aieTree exists geomNode])} {
        ::AIEnv::GUIManagement::Tree::UpdateGeoVisibility
    }
}

# Return the group of the part that has this user-visible name,
# and create it if necessary.

proc aie_new_part {name} {
    global fam_visible

    if {$name == ""} {
	    msg ERROR "No part name specified"
	    return
    }
    # If part exists do not use ic_geo_new_family; it creates line in replay
	if [ic_geo_check_family $name] {return [string toupper $name]}
    set name [string toupper [ic_geo_valid_name $name 1]]
    set create_orfn 0
    if {$name == "ORFN" && [lsearch [aie_list_parts 0] ORFN] < 0} {
	    set create_orfn 1
    }
    if {([ic_geo_new_family $name]) || $create_orfn == 1} {
	    ic_boco_set_part_color $name
	    set fam_visible($name) 1
	    ::AIEnv::GUIManagement::Tree::AddGroup part $name    
    }
    return $name
}

proc aie_is_group_type_visible {type} {
    global aie_prop_subtype

    if [info exists aie_prop_subtype($type)] {
	set type $aie_prop_subtype($type)
    }
    return [expr {([::AIEnv::GUIManagement::Tree::NodeVisibleStatus $type *] != -1) ||
		  ([::AIEnv::GUIManagement::Tree::NodeVisibleStatus ${type}_partbc *] != -1)}]
}

proc aie_create_parts_in_tree_if_needed {} {
    set np 0
    foreach p [aie_list_parts 0] {
	    if {![::AIEnv::GUIManagement::Tree::GroupExists part $p] && ![aie_connnectors_does_group_have_directives $p] } {
	        ::AIEnv::GUIManagement::Tree::AddGroup part $p
	        incr np
	    }
    }
    if $np { ic_uns_families_changed }
}

proc aie_update_parts_in_tree_if_needed {{force ""}} {
    global fam_visible
    set ret ""
    if {$force != ""} {
        set vis $force
    } else {
        set vis [aie_is_group_type_visible part]
    }
    foreach p [aie_list_parts 0] {
        foreach pp [ic_geo_list_families_in_part $p] {
            if {$pp == "VORFN" || $pp == "ORFN"} continue
            if [::AIEnv::GUIManagement::Tree::GroupExists part $pp] {
                if ![info exists fam_visible($pp)] {
                    set fam_visible($pp) $vis
                }
            } else {
                if ![info exists fam_visible($pp)] {
                    set fam_visible($pp) $vis
                }
            }
            if $fam_visible($pp) { lappend ret $pp }
        }
    }
    return $ret
}

# ---------------------------------

# This means delete all singleton groups that have no stuff in them and only
# element property bc's

proc aie_delete_empty_parts {{message 0}} {
    global fam_visible fam_visible_color batch_mode

    if $batch_mode return 
    if {(![ic_geo_is_loaded] && ![llength [ic_geo_non_empty_families_except_dormant]]) && \
        ![ic_uns_is_loaded] && ![ic_hex_blocking_loaded] && ![ic_str_is_loaded] && ![ic_boco_is_loaded]} {
        # In this case there should be no part node in the tree
        foreach p [::AIEnv::GUIManagement::Tree::GetChildren partNode] {
            set p [string trimleft $p part-]
            foreach pp [::AIEnv::GUIManagement::Tree::GetChildren $p] {
                set pp [string trimleft $pp part-]
                ::AIEnv::GUIManagement::Tree::DeleteGroup part $pp 1
            }
            ::AIEnv::GUIManagement::Tree::DeleteGroup part $p 1
        }
        aie_part_update_nodes
        return
    }
    
    busy 1
    foreach f [ic_geo_non_empty_families] {
        set used($f) 1 
        set used([lindex [split $f :] 0]) 1
    }
    foreach f [ic_uns_non_empty_families] {
        set used($f) 1 
        set used([lindex [split $f :] 0]) 1
    }
    foreach f [ic_hex_non_empty_families] { 
        set used($f) 1 
        set used([lindex [split $f :] 0]) 1
    }
    if [ic_str_is_loaded] {
        foreach f [ic_str_list_families] {
            if [ic_str_count_in_families $f] {
                set used($f) 1 
                set used([lindex [split $f :] 0]) 1
            }
        }
    }
    foreach u [array names used] {
        set p [split $u /]
        for {set i [expr [llength $p] - 2]} {$i >= 0} {incr i -1} {
            set p2 [join [lrange $p 0 $i] /]
            set used($p2) 1
        }
    }
  
    set parts {}
    set assemblies 0
    foreach p [::AIEnv::GUIManagement::Tree::GetChildren partNode] {
        lappend parts [string trimleft $p part-]
        foreach pp [::AIEnv::GUIManagement::Tree::GetChildren $p] {
            lappend parts [string trimleft $pp part-]
            set assemblies 1
        }
    }  
    
    foreach f [ic_boco_list_families] {
        if {[ic_boco_get $f] != ""} {
            set keep($f) 1
        }
    }
    
    set parts [lsort -unique [concat [aie_list_parts 0] $parts]]
    if [ic_hex_blocking_loaded] {
        if ![catch {ic_hex_list_blocking_parts} ret] {
	        foreach p [split $ret \n] {
	            if {$p != "" && [lsearch $parts $p] < 0} {
	                lappend parts $p
                }
	        }
        }
    }
    # add VORFN if it is used by hexa
    if {[lsearch [ic_hex_non_empty_families] VORFN] > -1} {
        lappend parts VORFN
        set keep(VORFN) 1
    }
    if {[lsearch $parts ORFN] > -1} {
        set keep(ORFN) 1
    }

    set parts [lsort -unique $parts]
    
    foreach p $parts {
        if [info exists used($p)] {
            set keep($p) 1
            continue
        }
        foreach f [ic_geo_list_families_in_part $p] {
            if [info exists keep($p)] break
            if {[info exists used($f)] || ([ic_meshdirect_get_directive_of_fam $f] != "")} {
                set keep($p) 1
            }
        }
    }

    foreach u [array names keep] {
        set p [split $u /]
        for {set i [expr [llength $p] - 2]} {$i >= 0} {incr i -1} {
            set p2 [join [lrange $p 0 $i] /]
            set keep($p2) 1
        }
    }
        
    set parts_to_delete ""
    foreach p $parts {
        if ![info exists keep($p)] {
            foreach f [ic_geo_list_families_in_part $p] {
                ic_geo_delete_family $f
                if ![ic_hex_subset_named_selection $f] {
                    if [info exists fam_visible($f)] { unset fam_visible($f) }
                    if [info exists fam_visible_color($f)] { unset fam_visible_color($f) }
                }
                ::AIEnv::GUIManagement::Tree::DeleteGroup part $f 0
                lappend parts_to_delete $f
           }
        }
    }
    
    set parts_to_delete2 [ic_delete_empty_parts]
    set i [llength $parts_to_delete2]
    
    set n_parts_delete [llength $parts_to_delete]
    if $n_parts_delete {
        if $assemblies { aie_create_parts_in_tree_if_needed }
        if $message {
            if {$n_parts_delete < 10 } {
                mess "Deleted part(s) $parts_to_delete\n"
            } else {
                mess "Deleted $n_parts_delete parts\n"
            }
        }
    }
    if $message {
        if $i {
            if {$i < 10 } {
                mess "Deleted part(s) $parts_to_delete2 (not visible in the tree)\n"
            } else {
                 mess "Deleted $i parts (not visible in the tree)\n" 
            }
        } else {
            if !$n_parts_delete {
                mess "No empty parts found, please use right click options Info, or Delete if you suspect a part should be empty\n" 
            }
        }
    }
    aie_part_update_nodes
    busy 0
}

proc aie_unique_parts {{message 0}} {
    global fam_visible fam_visible_color 

    ic_undo_suspend
    set i 0
    set only_numbers 0
    set parts [aie_list_parts 0]
    if {[llength $parts] > 100} { set only_numbers 1 }
    foreach p $parts {
        foreach f [ic_geo_list_families_in_part $p] {
            if {[ic_meshdirect_get_directive_of_fam $f] != ""} continue
            if [aie_is_bctype_used $f 1] continue
            if [regexp : $f] {
                set split [split $f :]
                set idx [llength $split]
                set pp [lindex $split 0]
                set ff [lindex $split 1]
                for { set n 2 } { $n < $idx } { incr n } {
                    append ff \#[lindex $split $n]
                }
                set pp_ff ${pp}#${ff}
                aie_rename_part $f $pp_ff 0 "" 0 1
                if $only_numbers {
                    if {$i && [expr $i % 50] == 0} {
                        mess "$i part(s) renamed\n"
                        update
                     }
                } else {
                    mess "Part $f renamed to $pp_ff\n"
                    if {$i && [expr $i % 20] == 0} update
                }
                if ![ic_hex_subset_named_selection $f] {
                    if [info exists fam_visible($f)] { unset fam_visible($f) }
                    if [info exists fam_visible_color($f)] { unset fam_visible_color($f) }
                }
                incr i
           }
        }
    }
    mess "\n$i part(s) renamed\n" blue
    busy reset
    ic_undo_resume
}

proc aie_move_parts {{message 0}} {
    global use_output_blocks

    ic_undo_suspend
    set i 0
    set only_numbers 0
    set parts [aie_list_parts 0]
    if {[llength $parts] > 100} { set only_numbers 1 }
    set geo [ic_geo_is_loaded]
    set uns [ic_uns_is_loaded]
    set hex [ic_hex_blocking_loaded]
    set types [ic_geo_get_types]
    set parts_to_delete ""
    foreach p $parts {
        foreach f [ic_geo_list_families_in_part $p] {
            if {$p == $f} continue
            if {[ic_meshdirect_get_directive_of_fam $f] != ""} continue
            if [aie_is_bctype_used $f 1] continue
            if [regexp : $f] {
                if $geo {	        		        
                    foreach type $types {
                        set objs [ic_geo_get_objects $type $f 1]
                        if {$objs != ""} {
                            ic_geo_set_family $type $p names $objs 0
                        }
                    }
                }
                if $uns {
                    ic_uns_move_family_elements $f $p 1
                }
                if $hex {
                    if $use_output_blocks {
                        set blocks [string trimright [ic_hex_list_block_numbers $f output_blocks] \n]
                    } else {
                        set blocks [string trimright [ic_hex_list_block_numbers $f] \n]
                    }
                    if {$blocks != ""} { aie_change_part_blocks $blocks $p 0 }
                }
                lappend parts_to_delete $f
                if $only_numbers {
                    if {$i && [expr $i % 50] == 0} {
                        mess "$i part(s) moved\n"
                        update
                     }
                } else {
                    mess "Part $f moved to part $p\n"
                    if {$i && [expr $i % 20] == 0} update
                }
                incr i
           }
        }
    }
    if {$parts_to_delete != ""} {
        aie_delete_part_if_empty $parts_to_delete
    }
    mess "\n$i part(s) moved\n" blue
    busy reset
    ic_undo_resume
}

proc aie_delete_part_if_empty {{names ""}} {
    global fam_visible fam_visible_color
    
    if {$names == ""} { return 0 }
    set ret 0
    set geo_parts [ic_geo_non_empty_families]
    set uns_parts [ic_uns_non_empty_families]
    set hex_parts [ic_hex_non_empty_families]
    foreach p $names {
        foreach f [ic_geo_list_families_in_part $p] {
            if {$f == "ORFN" || $f == "VORFN"} continue
            if {[ic_meshdirect_get_directive_of_fam $f] != ""} continue
            if [aie_is_bctype_used $f 0] continue
            if {[lsearch $geo_parts $f] >= 0} continue
            if {[lsearch $uns_parts $f] >= 0} continue
            if {[lsearch $hex_parts $f] >= 0} continue
            if [ic_uns_count_in_families $f] continue
            if [ic_str_count_in_families $f] continue
            if [ic_geo_count_in_family all $f] continue
            set bocos [ic_boco_get $f]
            if {$bocos != ""} {
                if {[llength $bocos] == 3} {
                     if {![string match *color* $bocos]} continue
                }
            }
            ic_geo_delete_family $f
            if ![ic_hex_subset_named_selection $f] {
                if [info exists fam_visible($f)] { unset fam_visible($f) }
                if [info exists fam_visible_color($f)] { unset fam_visible_color($f) }
            }
            set ret 1
        }
    }
    aie_part_update_nodes
    return $ret
}

proc aie_is_bctype_used {name {out 0}} {
    global fam_visible fam_visible_color aie_bctypes_used
    
    foreach type [array names aie_bctypes_used] {
        if {[info proc aie_apply_icons_$type] != ""} {
            foreach b $aie_bctypes_used($type) {
                set bc [ic_boco_get $name $b]
                if {$bc != ""} {
                    if $out {
                        mess "Part $name has attached BCs of type $b, skipping\n"
                    }
                    return 1
                }
		    }
		}
    }
    return 0
}

proc aie_get_boco_type_name {name} {

    if ![ic_boco_is_loaded] { return "" }
    set icon ""
    set types {load force temperature pressure displacement impdisp mpcdisp}
    set bcs [ic_boco_get $name]
    if {$bcs != ""} {
        set type [ic_boco_list_icons $name]
        if {[llength $type] == 1 && [lsearch $types $type] >= 0} {
            set icon $type
        }
    }
    return $icon
}

# this is needed to work around a bug where the new elements disappear
# from the part they were displayed in

proc aie_refresh_parts {} { ::AIEnv::GUIManagement::Tree::RefreshParts }

# This is called from the batch interpreter when there is new stuff available.

proc aie_new_families_or_elem_types {} {
    aie_updateMeshVis
    aie_create_parts_in_tree_if_needed
}

# For getting good colors

proc aie_good_colors {by_mat} {
    set k 0
    foreach name [aie_list_parts 0] {
	    # Skip assemblies
	    if {[::AIEnv::GUIManagement::Tree::GetColor part $name] == "black"} continue
	    if $by_mat {
	        set bcs [ic_boco_get $name]
	        set gotmat ""
	        foreach d {0 1 2 3} {
		        foreach {bname val} [aie_parse_bcs_element_prop_${d}d $bcs] {
		            if {$bname == "mat"} {
			            set gotmat $val
			            break
		            }
		        }
		        if {$gotmat != ""} break
	        }
	        if {$gotmat != ""} {
		        set newcolor [family_color_for_name $gotmat]
		        set matcol($gotmat) $newcolor
		        if [info exists matcount($gotmat)] {
		            incr matcount($gotmat)
		        } else {
		            set matcount($gotmat) 1
		        }
	        } else {
		        set newcolor gray
	        }
	    } else {
	        set newcolor [family_color_for_angle $k]
	    }
	
        foreach f [ic_geo_list_families_in_part $name] {
	        ic_set_family_color_for_name $f $newcolor
	    }
	
	    ::AIEnv::GUIManagement::Tree::ChangeColor part $name $newcolor
	    incr k 100
    }
    foreach mat [array names matcol] {
	    mess "$mat: " $matcol($mat); mess "$matcount($mat) part[expr {($matcount($mat) > 1) ? "s" : ""}]\n"
    }
}

proc aie_show_selected_parts {on} {
    set geo_select 0
    if [ic_geo_is_loaded] {
	    foreach g {point curve surface body density} {
	        set gg [::AIEnv::GUIManagement::Tree::GetVisibility $g]
	        if $gg {set geo_select 1 ; break}
	    }
    }
    set fams ""
    if $geo_select {
	    foreach item [geo_select entity] {
	        set type [lindex $item 0]
	        set ent [lindex $item 1]
	        lappend fams [ic_geo_get_family $type $ent]
	        ic_show_geo_selected $type $ent 0
	    }
	    set fams [lsort -unique $fams]
    } else {
	    set subset [select_unstruct element]
	    set fams [ic_uns_subset_list_families $subset]
	    ic_uns_subset_delete $subset
    }
    # find parts from fams
    set parts ""
    foreach fam $fams {
	    lappend parts [ic_boco_get_part_of_fam $fam]
    }
    set parts [lsort -unique $parts]
    mess "Parts are $parts\n"
    set PartList [aie_list_parts 0]
    set parts_to_blank ""
    foreach p $PartList {
	    if $on {
	        if {[lsearch $parts $p] != -1} continue
	    } else {
	        if {[lsearch $parts $p] == -1} continue
	    }
	lappend parts_to_blank $p
    }
    set ta [tdv_active 0]
    foreach p $parts_to_blank {
	    ::AIEnv::GUIManagement::Tree::ToggleGroupVisibility part $p 0 0
    }
    tdv_active $ta
    aie_update_visible
}

proc aie_reverse_parts {{parts ""}} {
    global fam_visible

    if {$parts == ""} {set parts [aie_list_parts 0]}
    foreach p $parts {
	if $fam_visible($p) {
	    ::AIEnv::GUIManagement::Tree::ToggleGroupVisibility part $p 0 0
	} else {
	    ::AIEnv::GUIManagement::Tree::ToggleGroupVisibility part $p 2 0
	}
    }
    aie_update_visible
}

# ---------------------------------------------------------------------

proc aie_get_parts_with_field {key} {
    foreach name [aie_list_parts 0] {
	set bcs [ic_boco_get $name]
	set gotmat ""
	foreach d {0 1 2 3} {
	    foreach {bname val} [aie_parse_bcs_element_prop_${d}d $bcs] {
		if {$bname == $key} {
		    set gotmat $val
		    break
		}
	    }
	    if {$gotmat != ""} break
	}
	if {$gotmat != ""} {
	    lappend hasmat($gotmat) $name
	}
    }
    return [array get hasmat]
}

proc aie_select_families_with_bcs {what} {
    switch $what {
	mater {
	    array set parts_with [aie_get_parts_with_field mat]
	    set desc "materials"
	}
	prop {
	    array set parts_with [aie_get_parts_with_field etype]
	    set desc "element types"
	}
    }
    if ![array size parts_with] {
	user_error "There are no $desc defined"
	return ""
    }
    
    set vals [choose_multiple "Select $desc." [lsort [array names parts_with]]]
    set ret ""
    foreach val $vals {
	foreach p $parts_with($val) {
	    eval lappend ret [ic_geo_list_families_in_part $p]
	}
    }
    return $ret
}

proc aie_get_bc_names {} {
    global bc_name_list

    if ![info exists bc_name_list] { set bc_name_list "" }
    set bctypes {MOMENT FORCE PLOAD2 PLOAD4 TEMP ISPC}
    set fams [ic_boco_list_families]
    foreach fam $fams {
       set bcs [ic_boco_get $fam]
       foreach bc $bcs {
          set type [lindex $bc 1]
          if {[lsearch $bctypes $type] >= 0} {
             set name1 [lindex [split $fam :] 0]
             set name2 [lindex [split $fam :] 1]
             if {$name2 != ""} {
                set name $name2
             } else {
                set name $name1
             }
             if {[lsearch $bc_name_list $name] < 0} {
                lappend bc_name_list $name
             }
          }
       }
    }
}    

#=========================================================
# fast tree procedures for multiple parts
#==========================
proc aie_part_update_nodes {{parent modelNode} {node partNode} {nodename Parts} {parts ""}} {
	# recursive function; if !names - using non-empty part names
	# 1. Check existing parts. Set array "" if part, "tail" if assembly
	# 
	global aie_part_has_boco_arr
	
	set aieTree [set ::AIEnv::GUIManagement::Tree::aieTree]
	foreach im {notVisImg isVisInactiveImg notVisInactiveImg someVisImg isVisImg} {
		set $im [set ::AIEnv::GUIManagement::Tree::VisibilityImages($im)]
	}
	if {$node == "partNode"} {set data {part *}} else {
		set data [string replace $node 4 4 " "]
	}	

	set node_created 0
	if ![$aieTree exists $node] {
		$aieTree insert end $parent $node -text $nodename -image $isVisImg -data $data
		set node_created 1
	}
    set part_list ""
    if [info exists ass_arr] {unset ass_arr}
    if [info exists nodes_arr] {unset nodes_arr}
    if {$parts == ""} {
		aie_get_parts_and_families tmp_parts_arr
		set parts [array names tmp_parts_arr]
		if [info exists tmp_parts_arr] {unset tmp_parts_arr}
		if [info exists aie_part_has_boco_arr] {unset aie_part_has_boco_arr}    	
	}
	foreach part $parts {
			set n_split [string first / $part]
			incr n_split -1
			if {$n_split >= 0} {
				set ass [string range $part 0 $n_split]
				incr n_split 2								
				set tail [string range $part $n_split end]
				lappend ass_arr($ass) $tail
			} else {
				lappend part_list $part
			}
			if [llength [ic_boco_get $part]] {
					set aie_part_has_boco_arr($part) 1
			}
	}
	set parts [lsort -unique "$part_list [array names ass_arr]"]	
	
	# 3. Compare with existing nodes. Modify tree if necessary to match actual parts
	#    if any modifications - sort tree (instead of delete/create node)
	#    Note: 
	set sorttree 0
	foreach pnode [$aieTree nodes $node] {
		set nodes_arr($pnode) ""
	} 
	foreach part $parts {
		if {$node == "partNode"} {
			set nname part-$part
		} else {
			set nname ${node}/$part
		}

		if [info exists ass_arr($part)] {
			incr sorttree [aie_part_update_nodes $node $nname $part $ass_arr($part)]
			if [info exists nodes_arr($nname)] {unset nodes_arr($nname)}
			continue
		} 		
		if ![info exists nodes_arr($nname)] {
			set color [family_color_for_name [string range $nname 5 end]]
		    set data [string replace $nname 4 4 " "] 			
			$aieTree insert end $node $nname -text $part -image $isVisImg -data $data -fill $color		
			set sorttree 1
		} else {
			unset nodes_arr($nname)
		}		
	}
	
	#3.1 Delete unused nodes:
		foreach unused [array names nodes_arr] {
			set thepart [string range $unused 5 end]
			if [info exists ass_arr($thepart)] continue 
			$aieTree delete $unused
			set sorttree 1
		}
	# 4. sort nodes 
	
	if $sorttree {
		set tree_nodes [$aieTree nodes $node]
		$aieTree reorder $node [lsort -unique $tree_nodes]
	}
	return $node_created
}
#=====================
proc aie_part_names_from_tree {parts_or_ass {toplevel 1}} {
	# Note: use after "aie_part_update_nodes"
	global aie_part_has_boco_arr
	# Recursive, call with default toplevel
	global tmp_parts_arr  
	if $toplevel {
		if [info exists tmp_parts_arr] {unset tmp_parts_arr}
	}
	set aieTree [set ::AIEnv::GUIManagement::Tree::aieTree]
	set parts ""
	foreach name $parts_or_ass {
		if ![$aieTree exists part-$name] continue
		set ch_ch [$aieTree nodes part-$name]
		if {$ch_ch == "" || [info exists aie_part_has_boco_arr($name)]} {
			set tmp_parts_arr($name) 1
		} else {
			set ch_names ""
			foreach ch $ch_ch {
				lappend ch_names [string range $ch 5 end]
			}
			aie_part_names_from_tree $ch_names 0
		}
	}
	if $toplevel {
		set res [array names tmp_parts_arr]
		if {$res != ""} {unset tmp_parts_arr}
		return $res
	} 
} 
#=========================	
proc aie_part_change_visibility {ims on parts} {
	global fam_visible aie_part_has_boco_arr display_flag

	foreach "im1 im2" $ims ""	
	# Note: use after "aie_part_update_nodes"
	set aieTree [set ::AIEnv::GUIManagement::Tree::aieTree]
	if {$parts == ""} {
	    aie_get_parts_and_families tmp_parts_arr
	    # don't show VORFN
	    if {$on == 1 && ([info exists tmp_parts_arr(VORFN)])} {
		    unset tmp_parts_arr(VORFN)
	    }
	    set parts [array names tmp_parts_arr]	   
	    if [info exists tmp_parts_arr] {unset tmp_parts_arr}
	}
	if {$on < 2} {
		set im [lindex $ims $on]
		foreach part $parts {
			$aieTree itemconfigure part-$part -image $im
			set fam_visible($part) $on
		}
		aie_set_group_or_part_vis part $parts $on 0			
	} else {
		#reverse visibility
		set parts_on ""
		set parts_off ""
		foreach part $parts {
			set old_im [$aieTree itemcget part-$part -image]
			if {$old_im == $im1} {
				$aieTree itemconfigure part-$part -image $im2
				set fam_visible($part) 1						
				lappend parts_on $part
			} else {
				$aieTree itemconfigure part-$part -image $im1
				set fam_visible($part) 0				
				lappend parts_off $part			
			}
		}	
		aie_set_group_or_part_vis part $parts_on 1 0			
		aie_set_group_or_part_vis part $parts_off 0 0				
	}
	if [ic_geo_is_loaded] { update_geom_visible all v 0 }
	if {([ic_uns_is_loaded]) || ([ic_str_is_loaded])} { 
	    update_uns_visible
	}
	if [ic_hex_blocking_loaded] {
        foreach type {vert edge face block mesh} {
            if {[info exists display_flag($type)] && $display_flag($type)} {
                hex_update_display $type
            }
        }
	}
}
#============================
proc aie_part_set_assemblies {im {node partNode}} {
	# set the same "image" for all assemblies starting from "node" 
	set aieTree [set ::AIEnv::GUIManagement::Tree::aieTree]
	$aieTree itemconfigure $node -image $im
	foreach ch [$aieTree nodes $node] {
		set ch_ch [$aieTree nodes $ch]
		if {$ch_ch == ""} continue
		aie_part_set_assemblies $im $ch
	}
}
#============================
proc aie_part_check_assemblies {im0 im1 im2 {node partNode}} {
	# set im0 or im1 if all children have im0 or im1; im2 otherwise
	# do not change image if no children  
	global aie_part_has_boco_arr
	
	set aieTree [set ::AIEnv::GUIManagement::Tree::aieTree]
	set nodes [$aieTree nodes $node]
	if ![llength $nodes] return
	set the_im ""
	foreach ch $nodes {
		set ch_ch [$aieTree nodes $ch]
		set data [$aieTree itemcget $ch -data]
		set type [lindex $data 0]
		set data [lindex $data 1]		
		if {$ch_ch == ""} { 
			if {$data == "ORFN" || $data == "VORFN"} continue		 
# Wild mix of assemblies and parts.
			if {$the_im == $im2} continue
			set im [$aieTree itemcget $ch -image]				
		} else {
			if {$type != "part"} continue
			if {$data == "ORFN" || $data == "VORFN"} continue
			if [info exists aie_part_has_boco_arr($data)] {
				#it's a real part, do not change part image, but change boco visibility & images
				set im [$aieTree itemcget $ch -image]
			} else {		
				#assembly					
			set im [aie_part_check_assemblies $im0 $im1 $im2 $ch]
			}
		}
		if {$the_im == ""} {
			set the_im $im
			continue
		}
		if {$the_im != $im} {
			set the_im $im2
		}	
	} 
	 
	if {$the_im == ""} {return ""}
	$aieTree itemconfigure $node -image $the_im
	return $im
}
#=========================
proc aie_part_set_boco_icons {partbc im} {
# Turn on/off part->boco all $partbc icon if properties visibility was toggled
	global aie_part_has_boco_arr
	set aieTree [set ::AIEnv::GUIManagement::Tree::aieTree]
	if ![info exists aie_part_has_boco_arr] return
	set bctypenode [$aieTree parent partbc-$partbc]
	set bctype [lindex [$aieTree itemcget $bctypenode -data] 1]
	foreach part [array names aie_part_has_boco_arr] {
		# node may be moved.GUI will update aie_part_update_nodes on any visibility change
		# DB may be update on node drop. 
		if ![$aieTree exists part-$part] continue
		foreach ch [$aieTree nodes part-$part] {
			set id [lindex [$aieTree itemcget $ch -data] 2]
			if {$id == ""} {
				aie_set_prop_names_for_part $part
				set id [lindex [$aieTree itemcget $ch -data] 2]
				# must have id now 
				if {$id == ""} continue
			}
			if {$id == $partbc} {
				$aieTree itemconfigure $ch -image $im
			}
		}
	}
}
#=========================
proc aie_prop_check_bocos {partbc im} {
# Link between part->prop icons and partbc icons 
	global aie_part_has_boco_arr
	if ![info exists aie_part_has_boco_arr] return	
	set aieTree [set ::AIEnv::GUIManagement::Tree::aieTree]
	foreach part [array names aie_part_has_boco_arr] {
		foreach boco [ic_boco_get $part] {
			set id [lindex [lindex $boco 1] 0]
			# ignore invalid ids
			if ![$aieTree exists partbc-$id] continue
			
			
			set im $aieTree itemconfigure $ch -image
			if ![info exists tmp_arr($id)] {
			
			#
			
			}
			if {$id == $partbc} {
				# may be several bocos. Check which one has "bctype"
				foreach ch [$aieTree nodes part-$part] {
					set part_bctype [lindex [$aieTree itemcget $ch -data] 0]
					if {$part_bctype != $bctype} continue
					$aieTree itemconfigure $ch -image $im
				}
			}
		}
	}
}
#========================				
proc aie_set_prop_names_for_part {{parts ""}} {
# set boco -text, e.g. Rigid beam (RBE2) + -data "type part RBE2"
# Note: with parts = "" use after "aie_part_update_nodes" & UpdateElemPropNodes
	global aie_bcclass_title aie_part_has_boco_arr
	if {$parts == ""} {
		set parts [array names aie_part_has_boco_arr]
		if {$parts == ""} return
	}	
	set aieTree [set ::AIEnv::GUIManagement::Tree::aieTree]
	if ![$aieTree exists partbcNode] return
	set propnodes [$aieTree nodes partbcNode]
	if {$propnodes == ""} return
	foreach pnode $propnodes {
		set partbctype [lindex [$aieTree itemcget $pnode -data] 1]
		foreach bcnode [$aieTree nodes $pnode] {
			set the_bc [lindex [$aieTree itemcget $bcnode -data] 1] 
			set tmp_bctype_arr($the_bc) $partbctype
		}
	} 			

	foreach part $parts {
		set bocos [ic_boco_get $part]
		if {$bocos == ""} return
		foreach ch [$aieTree nodes part-$part] {
			set data [$aieTree itemcget $ch -data]
			set part_bctype [lindex $data 0]
			foreach boco $bocos { 
 				set id [lindex [lindex $boco 1] 0]
 				if ![info exists tmp_bctype_arr($id)] continue
 				if {$part_bctype != $tmp_bctype_arr($id)} continue
 				set data "$part_bctype $part $id"  
 				$aieTree itemconfigure $ch -text "$aie_bcclass_title($id) ($id)" -data $data
 			}
 		}
 	}
 }
