#$Id: s.mixinStrategy.xotcl 1.8 01/03/23 22:07:19+01:00 neumann@somewhere.wu-wien.ac.at $
package provide xotcl::mixinStrategy 0.8

@ @File { description {
  These methods provide support for managing "strategies",  i.e. 
  mixin-classes, where only one kind of a family of conformant 
  mixins should be registered.
  <@p>
  Naming convertions for strategies:
  All strategies must follow the naming convention 'kind=implementation'. 
  Examples are the persistency strategy 'eager' specfied as 
  'persistent=eager' or the persistency strategy 'lazy' (specified as
  'persistent=lazy')
}}

@ Object instproc mixinStrategy {strategy "Strategy to be added" } {
  description {
    This method adds or replaces a new strategy from the mixin
    list. Strategies are named following the converntion mentioned 
    above.
  }
  return "old strategy"
}

Object instproc mixinStrategy {strategy} {
  ::regexp {^([^:]+)=} $strategy _ kind
  ::set mixins ""
  ::set oldStrategy ""
  foreach mixin [[self] info mixin] {
    if {[::string match ::$kind=* $mixin]} {
      ::lappend mixins $strategy
      ::set oldStrategy $mixin
    } else {
      ::lappend mixins $mixin
    }
  }
  if {$oldStrategy == ""} {
    ::lappend mixins $strategy
  }
  [self] mixin $mixins
  return $oldStrategy
}

@ Object instproc mixinQueryStrategy {kind "strategy kind"} {
  description {
    This method searches the mixin list for a mixin of this
    kind (starting with $kind=)
  }
  return "returns the maching strategy"
}

Object instproc mixinQueryStrategy {kind} {
  set m [[self] info mixin]
  return [::lindex $m [::lsearch -glob $m $kind=*]]
}

@ Object instproc add {construct "'filter' or 'mixin'" args "to be added"} {
  description "add the specified mixins or filters"
  return "empty"
}

Object instproc add {kind args} {
  if {$kind != {filter} && $kind != {mixin}} {
    error "Usage: <object> [self proc] <filter|mixin> ..."
  }
  ::set classes [[self] info $kind]
  eval ::lappend classes $args
  [self] $kind $classes
  #puts stderr "$kind of [self] are now: ´[[self] info $kind]´"
}
@ Object instproc remove {construct "'filter' or 'mixin'" args "to be removed"} {
  description "remove the specified mixins or filters"
  return "empty"
}
Object instproc remove {kind args} {
  if {$kind != {filter} && $kind != {mixin}} {
    error "Usage: <object> [self proc] <filter|mixin> ..."
  }
  ::set classes [[self] info $kind]
  foreach c $args {
    ::set pos [::lsearch $classes $c]
    if {$pos == -1} { 
      error "$kind ´$c´ could not be removed" 
    } else {
      set $classes [::lreplace $classes $pos $pos]
    }
  } 
  [self] $kind $classes
  # puts stderr "$kind of [self] are now: ´[[self] info $kind]´"
}
