# $Id: s.AgentManagement.xotcl 1.11 01/03/23 21:55:32+01:00 neumann@somewhere.wu-wien.ac.at $
package provide xotcl::mos::agentManagement 0.8

package require xotcl::rdf::parser
package require xotcl::rdf::triple
package require xotcl::mos::agent

Class AgentInfo -parameter {
  {name ""}
  {changed 1}
}

AgentInfo instproc init args {
  next
  #
  # array providing info on a (migrated) agent
  #
  [self] array set agentData {}
  RDFTripleDB [self]::db
  trace variable [self]::agentData w [list [self] changeOccured]
  trace variable [self]::name w [list [self] changeOccured]
}

AgentInfo instproc getXMLScript {name} {
  [self] showCall
  set s {<?xml version="1.0"?>
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
         xmlns:xotcl="http://www.xotcl.org/agent">
  <rdf:Description about="$name">}
  set s [subst -nobackslashes $s]
  foreach n [array name [self]::agentData] {
      append s "
    <agent:$n> [set [self]::agentData($n)] </agent:$n>"
  }
  append s "  
  </rdf:Description>
</rdf:RDF>"
}

AgentInfo instproc changeOccured args {[self] set changed 1}

AgentInfo instproc getTriples {} {
  #[self] showCall
  if {[[self] set changed]} {
    # build up the triple-db
    [self]::db reset
    set place [Place getInstance]
    set subject "http://[$place set host]:[$place set port]/[[self] name]"
    foreach n [[self] array names agentData] {
      [self]::db add $n $subject [[self] set agentData($n)]
    }
  }
  return [[self]::db getTriples]
}

AgentInfo instproc print {} {
  puts "AGENT-INFO:"
  puts "Name == [set [self]::name]"
  foreach a [[self] array names agentData] {
    puts "$a == [[self] set agentData($a)]"
  }
}

Class AgentVisitor -superclass NodeTreeVisitor -parameter {
  {openProperty ""}
  {agentInfo ""}
  {rdfNS {[[self] info parent]::rdfNS}}
}

AgentVisitor instproc fullName {obj n} {
  set ns [$obj resolveNS]
  return [$ns getFullName $n]
}

AgentVisitor instproc visit {objName} {
  #puts stderr "AgentVisitor visit -- $objName"
  set ai [[self] set agentInfo]
  set cl [$objName info class]
  #puts stderr "AgentVisitor visit -- $objName cl=$cl <[$ai name]>"
  if {[$ai name] == ""} {
    #### not fixed yet
    puts stderr "[self] fixme (AgentManagement)"
    if {$cl == "::About" &&
	[string first "::Description" [[$objName info parent] info class]] == 0} {
      $ai name [$objName set content]
    }
  } else {  
    #puts stderr C=<[$objName content]>
    #$cl showVars
    switch -exact $cl {
      ::RDFProperty {
	set c [$objName content]
	#$objName showVars
	if {[$objName exists pcdata]} {
	  $ai set agentData($c) [$objName getPCdataList]
	} else {
	  #puts stderr "empty PCDATA"
	}
      }
    }
  }
}

AgentVisitor instproc interpretNodeTree node {
  if {[[self] set agentInfo] == "" } {
    error "Agent Visitor: no agent info provided."
  } 
  $node accept [self]
}

Class AgentMgr -superclass Agent \
  -parameter {
    {acceptedData [list script startcmd senderPlace senderPort senderHost]}
  }

AgentMgr instproc init args {
  next
  [self] array set agents {}
  #
  # this ns class holds the prefix/Rdf-ns pairs used by this
  # agent mgr (with default values)
  #
  XMLNamespace [self]::rdfNS
  [self]::rdfNS add agent {http://www.xotcl.org/schema/agent#}
  [self]::rdfNS add service {http://www.xotcl.org/schema/service#}
  [self]::rdfNS add xotcl {http://www.xotcl.org/schema/xotcl#}
  RDFParser [self]::rdfParser 
  AgentVisitor [self]::agentVisitor
    
    #package require xotcl::xml::printVisitor 
    #PrintVisitor [self]::pv
}

AgentMgr instproc register {name} {
  set ai [AgentInfo [self]::[[self] autoname agentInfo]]
  [self] set agents($name) $ai
  $ai name $name
  return $ai
}

AgentMgr instproc deregister {name} {
  if {[[self] info agents $name]} {
    # destroy the agents info objects
    #[self] showMsg "calling destroy on [set [self]::agents($name)]"
    [[self] set agents($name)] destroy
    # unset the var
    [self] unset agents($name)
  }
}

AgentMgr instproc info args {
  if {[lindex $args 0] == "agents"} {
    if {[llength $args] > 1} {
      return [[self] exists agents([lindex $args 1])]
    } else {
      return [[self] array names agents]
    }
  }
  next
}

#
# parses the data of a migration request into a new agent
# info object
#
# name must be stringleft : !!
AgentMgr instproc parseData {name data} {
  set ai [[self] register $name]
  next

  [self]::rdfParser reset
  [self]::rdfParser parse $data

  #puts stderr ===========================================================
  #[self]::pv interpretAll [self]::rdfParser
  #puts stderr ===========================================================

  [self]::agentVisitor agentInfo $ai
  #foreach tn [[self]::rdfParser info children topNode*] {
  #  [self]::agentVisitor interpretNodeTree $tn
  #}

  [self]::agentVisitor interpretAll [self]::rdfParser
  
  #puts "************** Received Agent:"
  #$ai print
  
  return $ai
}

AgentMgr instproc immigrate {AI} {
  #[self] showCall
  #set ns [[self]::rdfNS searchPrefix agent]
  #::eval [set ${AI}::agentData(${ns}script)]
  puts stderr [info command CloneableClass]
  #puts stderr "EVAL>>>>>>>>>>>>> [set ${AI}::agentData(agent:script)]<<<<<<<<<<<<<<<<"
  ::eval [lindex [$AI set agentData(agent:script)] 0]
  #puts stderr " ---Eval done--[$AI info vars]---[$AI name]--"
  set n [$AI name]
  foreach v [$n info vars] { $n persistent $v }
  if {[$AI exists agentData(agent:startcmd)]} {
    return [::eval $n [$AI set agentData(agent:startcmd)]]
  }
  return ""
}
