#!/usr/bin/env rexx
/**
 * A stringTable subclass that will support indexes of one word
 * strings in any case (lower- upper- or mixed-case) and treat
 * them as being the same when processing.
 * ----------------------------------------------------------------
 * Originally by Ruurd J. Idenburg 
 * 
 * No copyright, no licence, no guarantees or warrantees, be it 
 * explicit, implicit or whatever. Usage is totally and completely 
 * at the users own risk, the author shall not be liable for any
 * damages whatsoever, for any reason whatsoever.
 * 
 * Please keep this comment block intact when modifying this code
 * and add a note with date and a description.
 * ----------------------------------------------------------------
 * 2023/02/08 - Initial version requires ooRexx version 5.0.0 or 
 *              later
 * 2023/04/02 - Added catering for multi-word indexes by removing
 *              the spaces between words when processing them (rji)
 * 2023/05/04 - Added a (perhaps) more common example (rji)
 * 2023/05/05 - Removed unneccesary exit statements in method
 *              definitions (rji)  
 *
 */----------------------------------------------------------------

-- A simple sample
cst = .caselessStringTable~new
say "HELLO =>" cst~hello
cst["Blonde On Blonde"] = "An album by Bob Dylan"
cst~blonde = "My Hair"
--say cst~allIndexes
say "blond On Blonde => "cst["blonde On blonde"]
say "Blonde =>" cst["Blonde"]
say "Real indexes =>" cst~makeArray~toString(,", ")
say "Index BLONDE ONBLONDE =>" cst~hasIndex("BLONDE ONBLONDE")
say "Removing bLoNdE =>" cst~remove("bLoNdE")
say "-"~copies(40)
-- A more common (perhaps) sample
memberList = .routines~createMemberList~call
say "Actual indexes:" memberList[0]~allIndexes~sort~toString(,",  ")
say "Used indexes..: ~first, ~last, ~middle" 
say "-"~copies(40)
do m over memberList
  if m~middle==.nil
    then say m~last"," m~first"," "middle name to be done"
    else say m~last"," m~first"," m~middle
end
say "-"~copies(40)

/**
 * Do not execute above code when invoked via a "::requires" directive
 */
::options noprolog

/**
 * All indexes are maintained in the .caselessStringTable superclass
 * (i.e the .stringTable class). All methods with an index as argument
 * are first checked for a caseless match before being forwarded to
 * the superclass .stringTable methods.
 */
::class "caselessStringTable" public subclass "stringTable"

/**
 * Just let the superclass initiate the instance
 */
::method "init"
  self~init:super
exit

/**
 * Will check if there is already an index exactly the same in mixed- 
 * or lower- or upper-case and return the matched index, otherwise
 * will return the index given as the parameter.
 */
::method "caselessIndex" private
  use strict arg key
/**
 * Make sure the index will be one word only
 */
  key = key~space(0)
  tmpString = self~makeArray~toString(," ")
  wp = tmpString~caselessWordPos(key)
  if wp=0
    then tableIndex = key
    else tableIndex = tmpString~word(wp)
return tableIndex

/**
 * This is the same as method "at", so let the"at' method handle it
 */ 
::method "[]"
  forward to (self) message ("at")
exit

/**
 * This the same method as "put", so let the "put' method handle it
 */
::method "[]="
  forward to (self) message ("put")
exit

/**
 * Same as the super class, but with the caseless match
 * for it's indexes.
 */ 
::method "at"
  use strict arg key
  index = self~caselessIndex(key)
return self~at:super(index)

/**
 * Same as the super class, but with the caseless match
 * for it's indexes.
 */ 
::method "hasIndex"
  use strict arg key
  index = self~caselessIndex(key)
return self~hasIndex:super(index)  

/**
 * Same as the super class, but with the caseless for it's
 * indexes.If a caseless match exists the item value will be
 * updated. If no match is found the index will be as provided.
 */ 
::method "put"
  use strict arg value, key
  index = self~caselessIndex(key)
  self~put:super(value, index)
exit

/**
 * Same as the super class, but with the caseless match
 */ 
::method "remove"
  use strict arg key
  index = self~caselessIndex(key)
return self~remove:super(index)

/**
 * The "unknown" method allows processing as for an ooRexx standard
 * .stringTable, like myCaselessStringtable~firstName="Mike"
 */
::method "unknown"
  use arg key, args
  index = self~caselessIndex(key~strip('T','='))
  if key~endsWith("=")
    then self~put:super(args[1],index)
    else return self~at:super(index)
exit

/**
 * Following are the methods to support the .stringTable "ENTRY" methods.
 * I have not tested these.
 */
::method "setEntry"
  use strict arg key, value=.nil
  index = self~caselessIndex(key)
  self~setEntry:super(index, value)
exit

::method "entry"
  use strict arg key
  index = self~caselessIndex(key)
return self~entry:super(index)

::method "hasEntry"
  use strict arg key
  index = self~caselessIndex(key)
  return self~hasEntry:super(index)  
exit

::method "removeEntry"
  use strict arg key
  index = self~caselessIndex(key)
return self~removeEntry:super(index)

::routine createMemberList
  members = (("Zimmerman", "Robert", "Allen"),("Zappa","Frank",),("Cale","J.J.",),("Clapton","Eric","Patrick"))
  memberList = .list~new
  do m over members
    member = .caselessStringTable~new
    member["Last"] = m[1] 
    member~first = m[2]
    member["middle"] = m[3]
    memberList~append(member)
  end
return memberList 


