
namespace eval ContextualEntity {
    variable selectedentity
    variable selectactive
    variable LastLabel ""
    variable UserDataCommand ""
}

proc ContextualEntity::RegisterUserDataCommand { command } {
    variable UserDataCommand
    set UserDataCommand $command
}

proc ContextualEntity::UnRegisterUserDataCommand {} {
    variable UserDataCommand
    set UserDataCommand ""
}

proc ContextualEntity::Activate { w x y } {
    if { [catch {
	ActivateDo $w $x $y
    }] } {
	#WarnWinText $::errorInfo
    }
}

proc ContextualEntity::ActivateDo { w x y } {
    variable selectedentity
    variable selectactive

    set DisableWarnLine [.central.s disable warnline]
    .central.s disable warnline 1

    set whatuse [lindex [.central.s info Project] 4]
    if { $whatuse == "POSTUSE" } {
	set selwhat Elements
    } else { set selwhat All }

    set niceword(Points) [_ "Point"]
    set niceword(Lines) [_ "Line"]
    set niceword(Surfaces) [_ "Surface"]
    set niceword(Volumes) [_ "Volume"]
    set niceword(Nodes) [_ "Node"]
    set niceword(Elements) [_ "Element"]

    .central.s process SelectEntities $selwhat
    .gid.central.s button 1 [expr $x-5] [expr $y-5]
    .gid.central.s button 1 [expr $x+5] [expr $y+5]
    after 0 .central.s process escape
    vwait ::GidPriv(selection)
    if { $selwhat == "All" } {
	set entities [lrange [lindex $::GidPriv(selection) 0] 1 end]
    } else { set entities [lindex $::GidPriv(selection) 0] }
    unset ::GidPriv(selection)
    set boxed 0
    if { [llength $entities] < 2 } {
	.central.s process SelectEntities $selwhat
	.gid.central.s button 1 $x $y
	vwait ::GidPriv(selection)
	if { $selwhat == "All" } {
	    set entities [lrange [lindex $::GidPriv(selection) 0] 1 end]
	} else { set entities [lindex $::GidPriv(selection) 0] }
	unset ::GidPriv(selection)
	set boxed 1
    }
    if { [llength $entities] < 2 } {
	if { !$DisableWarnLine } { .central.s disable warnline 0 }
	return
    }
    set numentities 0
    foreach i $entities {
	if { [string is integer -strict $i] } {
	    incr numentities
	} elseif { [scan $i %d:%d n1 n2] == 2 } {
	    incr numentities [expr {$n2-$n1+1}]
	}
    }
    if { $numentities > 1 && $numentities < 15 && !$boxed } {
	set selectedentity -1
	set selectactive 0
	catch { destroy $w.contextualentity }
	set menu [menu $w.contextualentity]
	foreach i $entities {
	    if { [string is integer -strict $i] } {
		$menu add command -label "$niceword($type) $i" -command \
		    [list set ContextualEntity::selectedentity [list $type $i]]
	    } elseif { [scan $i %d:%d n1 n2] == 2 } {
		for { set j $n1 } { $j <= $n2 } { incr j } {
		    $menu add command -label "$niceword($type) $j" -command \
		        [list set ContextualEntity::selectedentity [list $type $j]]
		}
	    } else { set type $i }
	}
	$menu add separator
	$menu add command -label [_ "All selected entities"] -command \
	    [list set ContextualEntity::selectedentity All]

	bind $menu <<MenuSelect>> "ContextualEntity::SelectingInMenu $menu"
	tk_popup $menu [winfo pointerx .gid] [winfo pointery .gid]
	if { $::tcl_platform(platform) != "windows" } {    
	    bind $menu <Unmap> "set ::pp done"
	    vwait ::pp
	}

	if { $selectactive } {
	    .central.s process escape
	}
	update
	if { $selectedentity == -1 } {
	    if { !$DisableWarnLine } { .central.s disable warnline 0 }
	    return
	}
	if { $selectedentity != "All" } {
	    set numentities 1
	    set entities "$selectedentity"
	}
    }
    if { !$DisableWarnLine } { .central.s disable warnline 0 }

    set menu [CreateFinalMenu $w $whatuse $numentities $entities]

    set DisableWarnLine [.central.s disable warnline]
    .central.s disable warnline 1

    eval .central.s process SelectEntities All $entities
    set selectactive 1

    if { !$DisableWarnLine } { .central.s disable warnline 0 }
    append text [_ "Selected %s %s. Choose operation" $niceword([lindex $entities 0]) [lindex $entities 1]]
    
    ChangeWarnLineVar $text
    PostFinalMenu $menu
}


proc ContextualEntity::SelectingInMenu { menu } {
    variable selectactive

    set comm [$menu entrycget active -command]
    set type ""
    foreach "type entity" [lindex $comm 2] break
    if { $type == "" } { return }
    
    if { $selectactive } {
	.central.s process escape
    }
    .central.s process SelectEntities $type $entity
    set selectactive 1
}

proc ContextualEntity::AddToMenu { menu label command } {
    variable LastLabel
    variable LastIndex
    variable mainmenu

    append command "; [list set ContextualEntity::LastLabel $label]"
    append command "; .central.s process escape"
    $menu add command -label $label -command $command
    if { $menu == $mainmenu && $label == $LastLabel } {
	set LastIndex [$menu index end]
    }
}

proc ContextualEntity::CreateFinalMenu { w whatuse numentities entities } {
    variable LastIndex
    variable mainmenu
    variable UserDataCommand

    set LastIndex 0

    catch { destroy $w.contextualentity }
    set menu [menu $w.contextualentity]
    set mainmenu $menu

    if { $whatuse == "GEOMETRYUSE" } {
	$menu add checkbutton -label [_ "Copy"] -variable ContextualEntity::CopyMoveIsCopy \
	    -command [list ContextualEntity::PostFinalMenu $menu]
	
	$menu add separator
	AddToMenu $menu [_ "Translate#C#geometry"] [list ContextualEntity::CopyMove $entities translation]
	$menu add cascade -label [_ "More"]... -menu $menu.m1
	menu $menu.m1
	$menu.m1 add command -label [_ "Align"] -command \
	    [list ContextualEntity::CopyMove $entities align]
	$menu.m1 add command -label [_ "Rotate"] -command \
	    [list ContextualEntity::CopyMove $entities rotation]
	
	$menu add separator
    }

    if { $whatuse != "POSTUSE" && $numentities == 1 } {
	if { $UserDataCommand == "" } {
	    eval AddDataItemsToMenu $menu $whatuse $entities
	} else {
	    uplevel #0 $UserDataCommand $menu $whatuse $entities
	}
    }

    if { $whatuse != "POSTUSE" } {
	set layer [_ "layer"]
	set layers [_ "layers"]
	set backcmd ContextualEntity::SendToBackPre
	set layerscmd ContextualEntity::LayersPre
    } else {
	set layer [_ "set"]
	set layers [_ "sets"]        
	set backcmd ContextualEntity::SendToBackPost
	set layerscmd ContextualEntity::LayersPost
    }

    AddToMenu $menu [_ "Send to back"] [list $backcmd $entities this]
    AddToMenu $menu [_ "Send others to back"] [list $backcmd $entities other]
    AddToMenu $menu [_ "Bring %s to front" $layer] [list $backcmd $entities thistofront]
    AddToMenu $menu [_ "Bring all to front"] [list $backcmd $entities front]

    $menu add separator

    AddToMenu $menu [_ "Other %s off" $layers] [list $layerscmd $entities otheroff]
    AddToMenu $menu [_ "This %s off" $layer] [list $layerscmd $entities thisoff]
    AddToMenu $menu [_ "All %s on" $layers] [list $layerscmd $entities allon]
    AddToMenu $menu [_ "Change 'layer to use'" $layers] [list $layerscmd $entities touse]
    return $menu
}

proc ContextualEntity::PostFinalMenu { menu } {
    variable LastIndex

    tk_popup $menu [winfo pointerx .gid] [winfo pointery .gid] $LastIndex
    if { $::tcl_platform(platform) != "windows" } {    
	bind $menu <Unmap> "set ::pp done"
	vwait ::pp
    }

    .central.s process escape
}

proc ContextualEntity::AddDataItemsToMenu { menu whatuse type entity } {

    switch $type Points { set ov ovpnt } Lines { set ov ovline } Surfaces { set ov ovsurf } \
	Volumes { set ov ovvol } Nodes { set ov ovpnt } Elements { set ov [list ovline ovsurf ovvol] }

    switch $type Points - Lines - Surfaces - Volumes { set where geometry } Nodes - \
	Elements { set where mesh }

    set books ""
    foreach "book -" [.central.s info Conditions BOOKS] {
	lappend books $book
    }
    catch { unset conds }
    foreach ovi $ov {
	foreach cnd [.central.s info Conditions $ovi] {
	    set book [.central.s info Conditions $cnd BOOK]
	    lappend conds($book) $cnd
	    if { [lsearch $books $book] == -1 } {
		lappend books $book
	    }
	}
    }

    set NotUsedBooks ""
    set needsseparator 0
    foreach book $books {
	if { ![info exists conds($book)] } { continue }
	set submenu ""
	foreach cnd $conds($book) {
	    set vals [lindex [.central.s info Conditions $cnd $where $entity] 0]
	    if { [lindex $vals 0] == 0 && [lindex $vals 1] == "-" } { continue }
	    if { $submenu == "" } {
		set j 1
		while { [winfo exists $menu.m$j] } { incr j }
		set submenu [menu $menu.m$j]
		set text $book
		if { $text == "Default" } { set text Conditions }
		$menu add cascade -label $text -menu $submenu
		set needsseparator 1
	    }
	    set text "$cnd -> [lrange $vals 3 end]"
	    if { [string length $text] > 50 } {
		set text "[string range $text 0 45] ..."
	    }
	    if { $whatuse != "POSTUSE" } {
		set command [list ContextualEntity::ViewCondition $book $cnd $vals]
	    } else { set command [list ContextualEntity::ErrorDataPost] }
	    AddToMenu $submenu $text $command
	}
	if { $submenu == "" } {
	    lappend NotUsedBooks $book
	} elseif { $whatuse != "POSTUSE" } {
	    $submenu add separator
	    AddToMenu $submenu "Open..." [list GidOpenConditions $book]
	}
    }
    if { [llength $NotUsedBooks] > 0 && $whatuse != "POSTUSE" } {
	set j 1
	while { [winfo exists $menu.m$j] } { incr j }
	set submenu [menu $menu.m$j]
	$menu add cascade -label [_ "Conditions"] -menu $submenu
	set needsseparator 1
	foreach book $NotUsedBooks {
	    set text $book
	    if { $text == "Default" } { set text "" }
	    AddToMenu $submenu "Open $text..." [list GidOpenConditions $book]
	}
    }
    if { $needsseparator } {
	$menu add separator
    }

    set needsseparator 0
    set books ""
    foreach "book -" [.central.s info Materials BOOKS] {
	lappend books $book
    }
    set mats [.central.s info Materials]
    if { $mats != "" } {
	if { $books == "" } { set books Materials }

	set list_ent [.central.s info list_entities $type $entity]
	regexp {material:\s+([0-9]+)} $list_ent {} mat_num
	if { $mat_num != 0 } {
	    set matname [lindex $mats [expr $mat_num-1]]
	    set entbook [.central.s info Materials $matname BOOK]
	    if { $entbook == "Default" } { set entbook Materials }
	} else { set entbook "" }

	foreach i $books {
	    if { $i != $entbook && $whatuse == "POSTUSE" } { continue }
	    set j 1
	    while { [winfo exists $menu.m$j] } { incr j }
	    set submenu [menu $menu.m$j]
	    $menu add cascade -label $i -menu $submenu
	    set needsseparator 1
	    if { $i == $entbook } {
		if { $whatuse != "POSTUSE" } {
		    set command [list ContextualEntity::ViewMaterial $i $matname]
		} else { set command [list ContextualEntity::ErrorDataPost] }
		AddToMenu $submenu $matname $command
	    }
	    set book $i
	    if { $i == "Materials" } { set book Default }
	    if { $whatuse != "POSTUSE" } {
		AddToMenu $submenu "Open..." [list GidOpenMaterials $book]
	    }
	}
    }
    if { $needsseparator } {
	$menu add separator
    }
}

proc ContextualEntity::ErrorDataPost {} {
    WarnWin [_ "This function is only usable in the preprocessing part"]
}

proc ContextualEntity::ViewMaterial { book mat } {

    if { $book == "Materials" } { set book Default }
    set GDN [GidOpenMaterials $book]
    global $GDN
    upvar \#0 $GDN GidData
    set _mat $mat
    set _mat [DWUnder2Space $_mat]
    set GidData(MAT,matname) $_mat
}
proc ContextualEntity::ViewCondition { book cnd vals } {

    set ov [lindex [.central.s info Conditions $cnd] 0]

    set GDN [GidOpenConditions $book]

    global $GDN
    upvar \#0 $GDN GidData

    array set PatternNames {
	ovpnt  POINT
	ovline LINE
	ovsurf SURFACE
	ovvol  VOLUME
	ovlayer LAYER
    }
    set _cnd $cnd
    regexp -nocase ^$PatternNames($ov)_(.+) $_cnd {} _cnd
    set _cnd [DWUnder2Space $_cnd]
#     set GidData(CND,level) $ov
#     set GidData(CND,condname) $_cnd
    DWUpdateConds $GDN $vals $ov $cnd
}

proc ContextualEntity::LayersPre { entities what } {

    set DisableGraphics [.central.s disable graphics]
    .central.s disable graphics 1

    if { $what == "otheroff" || $what == "thisoff" } {
	set layerslist ""
	foreach j $entities {
	    switch [scan $j %d:%d n1 n2] {
		0 {
		    set type $j
		    continue
		}
		1 { set n2 $n1 }
	    }
	    for { set k $n1 } { $k <= $n2 } { incr k } {
		set list_ent [.central.s info list_entities $type $k]
		if { [regexp {LAYER:\s+(\S+)} $list_ent {} layer] } {
		    if { [lsearch $layerslist $layer] == -1 } {
		        lappend layerslist $layer
		    }
		}
	    }
	}
	.central.s process layer
	foreach i [.central.s info Layers] {
	    set ipos [lsearch $layerslist $i]
	    if { $ipos == -1 && $what == "otheroff" } {
		.central.s process off $i
	    } elseif { $ipos != -1 && $what == "thisoff" } {
		.central.s process off $i
	    } 
	}
	.central.s process escape
    } elseif { $what == "allon" } {
	foreach i [.central.s info Layers] {
	    .central.s process layer on $i
	}
	.central.s process escape
    } elseif { $what == "touse" } {
	set found 0
	foreach j $entities {
	    switch [scan $j %d:%d n1 n2] {
		0 {
		    set type $j
		    continue
		}
		1 { set n2 $n1 }
	    }
	    for { set k $n1 } { $k <= $n2 } { incr k } {
		set list_ent [.central.s info list_entities $type $k]
		if { [regexp {LAYER:\s+(\S+)} $list_ent {} layer] } {
		    set found 1
		    break
		}
	    }
	    if { $found } { break }
	}
	.central.s process layer Touse $layer escape
	SetLayerAsSelection $layer
    }
    if { !$DisableGraphics } { .central.s disable graphics 0 }
    .central.s process redraw
    FillInfoLayers
}

proc ContextualEntity::LayersPost { entities what } {

    if { $what == "otheroff" || $what == "thisoff" } {
	set setslist ""
	foreach j $entities {
	    switch [scan $j %d:%d n1 n2] {
		0 {
		    set type $j
		    continue
		}
		1 { set n2 $n1 }
	    }
	    for { set k $n1 } { $k <= $n2 } { incr k } {
		set ent_set [lindex [.central.s info list_entities Elements $k] 5]
		if { [lsearch $setslist $ent_set] == -1 } {
		    lappend setslist ent_set
		}
	    }
	}

	foreach j "volumesets surfacesets cutsets" {
	    .central.s process escape escape escape escape select $j
	    set currents [.central.s info post get cur_$j]
	    foreach i [.central.s info post get all_$j] {
		if {  $what == "otheroff" && [lsearch $currents $i] != -1 && 
		      [lsearch $setslist $i] == -1 } {
		    .central.s process $i
		} elseif {  $what == "thisoff" && [lsearch $currents $i] != -1 && 
		            [lsearch $setslist $i] != -1 } {
		    .central.s process $i
		}
	    }
	    .central.s process escape
	}
    } else {
	foreach j "volumesets surfacesets cutsets" {
	    .central.s process escape escape escape escape select $j
	    set currents [.central.s info post get cur_$j]
	    foreach i [.central.s info post get all_$j] {
		if { [lsearch $currents $i] == -1 } {
		    .central.s process $i
		}
	    }
	    .central.s process escape
	}
    }
}

proc ContextualEntity::SendToBackPre { entities what } {

    if { $what == "other" } {
	if { $::GidPriv(LayersAlsoLower) == 0 } {
	    .central.s process layer SendToBackOpposite All $entities escape
	} else {
	    .central.s process layer SendToBackOpposite LowerEntities All $entities escape
	}
    } elseif { $what == "this" } {
	if { $::GidPriv(LayersAlsoLower) == 0 } {
	    .central.s process layer SendToBack All $entities escape
	} else {
	    .central.s process layer SendToBack LowerEntities All $entities escape
	}
    } elseif { $what == "thistofront" } {
	set layerslist ""
	foreach j $entities {
	    switch [scan $j %d:%d n1 n2] {
		0 {
		    set type $j
		    continue
		}
		1 { set n2 $n1 }
	    }
	    for { set k $n1 } { $k <= $n2 } { incr k } {
		set list_ent [.central.s info list_entities $type $k]
		if { [regexp {LAYER:\s+(\S+)} $list_ent {} layer] } {
		    if { [lsearch $layerslist $layer] == -1 } {
		        lappend layerslist $layer
		    }
		}
	    }
	}
	.central.s process layer
	foreach i $layerslist {
	    .central.s process layer bringtofront $i
	}
	.central.s process escape
    } else {
	.central.s process Layer BringToFrontAll escape
    }
    FillInfoLayers
}

proc ContextualEntity::SendToBackPost { entities what } {

    if { $what == "other" } {
	set DisableWarnLine [.central.s disable warnline]
	.central.s disable warnline 1
	set DisableGraphics [.central.s disable graphics]
	.central.s disable graphics 1

	.central.s process escape escape escape escape Select Elements 
	.central.s process 1:
	.central.s process SwapSelection
	eval .central.s process [lrange $entities 1 end]
	.central.s process escape MoveToNewSet ***** escape escape escape
	
	after 0 PDSendToBackEnd2 $DisableWarnLine $DisableGraphics

    } elseif { $what == "this" } {
	set DisableWarnLine [.central.s disable warnline]
	.central.s disable warnline 1
	set DisableGraphics [.central.s disable graphics]
	.central.s disable graphics 1
	.central.s process escape escape escape escape Select Elements 
	eval .central.s process [lrange $entities 1 end]
	.central.s process escape MoveToNewSet ***** escape escape escape
	
	after 0 PDSendToBackEnd2 $DisableWarnLine $DisableGraphics

    } elseif { $what == "thistofront" } {
	set setslist ""
	foreach j $entities {
	    switch [scan $j %d:%d n1 n2] {
		0 {
		    set type $j
		    continue
		}
		1 { set n2 $n1 }
	    }
	    for { set k $n1 } { $k <= $n2 } { incr k } {
		set ent_set [lindex [.central.s info list_entities Elements $entity] 5]
		if { [lsearch $setslist $ent_set] == -1 } {
		    lappend setslist ent_set
		}
	    }
	}
	PdSendToFront $setslist
    } else {
	PdSendToFront
    }
}

proc ContextualEntity::CopyMove { entities movement } {
    variable CopyMoveIsCopy 
    switch $movement {
	translation {
	    set lst [list [_ "Pick first point"] [_ "Pick second point"]]
	}
	align {
	    set lst [list [_ "Pick first source point"] [_ "Pick first destination point"] \
		         [_ "Pick second source point"] [_ "Pick second destination point"] \
		         [_ "Pick third source point"] [_ "Pick third destination point"]]
	}
	rotation {
	    set lst [list [_ "Pick vertex point"] [_ "Pick first point"] [_ "Pick second point"]]
	}
    }
    set inum 1
    foreach i $lst {
	set p($inum) [::GidUtils::GetCoordinates $i NoJoin]
	if { $p($inum) == "" } {
	    .central.s process escape escape escape escape
	    return 
	}
	incr inum
    }

    if { $movement == "rotation" } {
	set v1 [MathUtils::VectorDiff $p(2) $p(1)]
	set modul1 [MathUtils::VectorModulus $v1]
	if { $modul1<$MathUtils::Epsilon } return ""
	
	set v2 [MathUtils::VectorDiff $p(3) $p(1)]
	set modul2 [MathUtils::VectorModulus $v2]
	if { $modul2<$MathUtils::Epsilon } return ""
	
	set cosangle [expr [MathUtils::VectorDotProd $v1 $v2]/($modul1*$modul2)]
	set angle [expr 180.0/$MathUtils::Pi*acos($cosangle)]
	if { abs($angle) < $MathUtils::Epsilon } return ""
	set axe [MathUtils::VectorVectorialProd $v1 $v2]
	set axe1 $p(1)
	set axe2 [MathUtils::VectorSum $p(1) $axe]
	array unset p
	foreach "p(1) p(2) p(3)" [list $axe1 $axe2 $angle] break
    }

    foreach i [list Points Lines Surfaces Volumes] {
	set validentities($i) ""
    }
    set type ""
    foreach i $entities {
	if { [scan $i %d:%d n1 n2] >= 1 } {
	    lappend validentities($type) $i
	} elseif { $type == "" } {
	    set type $i
	} else { set type AllTypes }
    }
    foreach i [list Volumes Surfaces Lines Points] {
	if { [llength $validentities($i)] } {
	    set type $i
	    break
	}
    }
    switch $CopyMoveIsCopy {
	1 { set what Copy }
	0 { set what Move }
    }

    set comm [list .central.s process escape escape escape escape utilities $what AllTypes $movement]
    foreach i [lsort -integer [array names p]] {
	if { [llength $p($i)] > 1 } {
	    lappend comm FNoJoin [join $p($i) ,]
	} else { lappend comm $p($i) }
    }
    eval $comm $entities escape
}







