%
%       moz - The "Moo in OZ" project.
%       Version: 1.0.C025
%       Copyright (C) 2003 Robin Lee Powell.  All rights reserved.
%       Written by rlpowell@digitalkingdom.org
%
%       Redistribution and use in source and binary forms, with or without
%       modification, are permitted provided that the following conditions are
%       met:
%
%        1. Redistributions of source code must retain the above copyright
%        notice, this list of conditions and the following disclaimer.
%
%        2. Redistributions in binary form must reproduce the above copyright
%        notice, this list of conditions and the following disclaimer in the
%        documentation and/or other materials provided with the distribution.
%
%       THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
%       IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
%       WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
%       DISCLAIMED. IN NO EVENT SHALL THE AUTHER OR CONTRIBUTORS BE LIABLE FOR
%       ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
%       DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
%       OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
%       HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
%       STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
%       ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
%       POSSIBILITY OF SUCH DAMAGE.
%
MozBase = class $ from BaseObject
    %%%%%%%%%%%%
    %
    % Attributes
    %
    %%%%%%%%%%%%
    attr

    % name:
    %
    % A localized string containing the object's name in the MOZ.
    name

    % The storage attribute just holds an object type attribute for the
    % MOZ's central Storage object.  _Every_ object in the MOZ needs to
    % talk to Storage at some point.
    storageRef

    % Holds the global set of localized strings, which all system
    % object should use.
    languageStringsObjectRef
    % A boolean declaring if the object's name is a proper name
    % (like Alice or Bob) or a generic name (like couch or door or
    % puppy).
    hasProperName

    % A place to store the list of input verbs that this class recognizes.
    verbs: allVerbs()

    % A place to store the list of input verbs control objects for
    % objects of this class will recognize.
    controlVerbs: allVerbs()

    % These are the methods we let *everybody* see.  In other words,
    % when rooms and such ask for capablities on us, these are the
    % methods we give them.  Set in init.
    publicMethods: nil

    % A reference to the server object.  Used for changing passwords
    % and the like.
    serverRef

    %%%%%%%%%%%%
    %
    % Features
    %
    %%%%%%%%%%%%
    feat

    % The exports feature holds a list of 2-tuples detailing the
    % attributes to be handled by toRecord and fromRecord.  It would be
    % keyed on ozName to stop other objects from handling it directly,
    % except that no object should ever get a direct handle to another
    % object, only to its ActiveObject wrapper.
    %
    % The 2-tuples are the name of the attribute and its type.  Most
    % type atoms are ignored, but some must be specially handled (i.e.
    % object references, which must be mediated by the Storage object).
    exports: [ 
	storageRef#objectRef
	serverRef#objectRef
	languageStringsObjectRef#objectRef
	hasProperName#bool
	name#string 
    ]

    % featExports is just like exports, except for features instead of
    % attributes.
    featExports: [ capabilityDict#dict ozName#name ]

    % The methodList feature just holds a list of the names of the
    % methods that the wrapper should make capabilities for, i.e. the
    % externally available methods.  Note that those methods that the
    % wrapper does its own handling on should not be in here.  Those are
    % currently just 'upgrade'.
    %% was: 'fromRecord', 'toRecord', 'revoke' and 'upgrade'.
    methodList: [
	init start stop ozName className toRecord fromRecord revoke
	hasProperName getName setName deLocalize
	getVerbs getControlVerbs addVerb addControlVerb
	enhanceStorage publicSelfReference
	selfReference selfMatch getArticledName
	setHasProperName getArticledStarterName
	teleportVerb getMethodList renameVerb
    ]

    % The class name has to be stored as an atom for later usage upon
    % loading.
    className: 'MozBase'

    % The ozName feature; holds an Oz Name used to uniquely identify
    % an object in the MOZ.
    ozName

    % The capability dictionary for this object.
    capabilityDict

    % The active object wrapper procedure for this object.
    wrapper

    %%%%%%%%%%%%
    %
    % Methods
    %
    %%%%%%%%%%%%




    %%%%%%%%%%%%%%%%%%%%
    %
    % init()
    %
    % One-time object initialization sets ozName and storage from its
    % arguments.
    %
    % ozName:  Our new Oz name.
    %
    % storageRef:  An object record for the Storage object.
    %
    % languageStringsObjectRef: An object record for the LanguageStrings
    % objet.
    %
    % name:  Our printable name.
    %
    %%%%%%%%%%%%%%%%%%%%
    meth init(
	    storageRef: StorageRef
	    serverRef: ServerRef <= nil
	    ozName: OzName <= nil
	    name: StrName <= string( any: "unnamed object" )
	    languageStringsObjectRef: LanguageStringsObjectRef <= nil ...
	)

	if OzName \= nil then
	    self.ozName = OzName
	end

	storageRef <- StorageRef
	languageStringsObjectRef <- LanguageStringsObjectRef
	hasProperName <- false
	serverRef <- ServerRef

	name <- nil % To prevent blocking later
	{self setName( name: StrName )}

	% Set public methods.
	{self addPublicMethod( method: ozName ) }
	{self addPublicMethod( method: className ) }
	{self addPublicMethod( method: hasProperName ) }
	{self addPublicMethod( method: getName ) }
	{self addPublicMethod( method: getArticledName ) }
	{self addPublicMethod( method: getArticledStarterName ) }
	{self addPublicMethod( method: deLocalize ) }
	{self addPublicMethod( method: getVerbs) }
	{self addPublicMethod( method: selfMatch) }
	{self addPublicMethod( method: publicSelfReference) }


        %%%%%%%%%%%%%
        % teleport
        %%%%%%%%%%%%%
        {self
            addControlVerb(
                verb: teleport
                language: en

		parse: controlTelepert(
		    method: teleportVerb
		    mayHaveArticle: article(
			wordFound: unused
			rest: rest(
			    stringUntil: stringUntil(
				string: fromString
				until:  "to"
				rest: rest(
				    string: toString
				)
			    )
			)
		    )
		)
	    )
	}

	{self
	    addControlVerb(
		verb: muvgau
		language: lb

		parse: controlTeleport(
		    method: teleportVerb
		    mayHaveArticle: article(
			wordFound: unused
			rest: rest(
			    stringUntil: stringUntil(
				string: fromString
				until:  [ "vau" "ku" ]
				rest: rest(
				    string: toString
				)
			    )
			)
		    )
		)
	    )
	}

        %%%%%%%%%%%%%
        % rename
        %%%%%%%%%%%%%
        {self
            addControlVerb(
                verb: rename
                language: en

		parse: mozBaseRenameVerb(
		    method: renameVerb
		    mayHaveArticle: article(
			wordFound: unused
			rest: rest(
			    stringUntil: stringUntil(
				string: nameString
				until:  "to"
				rest: rest(
				    string: newNameString
				)
			    )
			)
		    )
		)
	    )
	}

	{self
	    addControlVerb(
		verb: tercme
		language: lb

		parse: mozBaseRenameVerb(
		    method: renameVerb
		    mayHaveArticle: article(
			wordFound: unused
			rest: rest(
			    stringUntil: stringUntil(
				string: nameString
				until:  [ "vau" "ku" ]
				rest: rest(
				    string: newNameString
				)
			    )
			)
		    )
		)
	    )
	}

    end




    %%%%%%%%%%%%%%%%%%%%
    %
    % start() is run when the object is fully attached to the MOZ (i.e.
    % fromRecord has been done, etc) to start any concurrent processing
    % that might be needed for the lifetime of the object.  For MozBase
    % itself, this does nothing.
    %
    %%%%%%%%%%%%%%%%%%%%
    meth start( ... )
	skip
    end
    


    %%%%%%%%%%%%%%%%%%%%
    %
    % start() is run when the object is fully detached from the MOZ.
    % For MozBase itself, this does nothing.
    %
    %%%%%%%%%%%%%%%%%%%%
    meth stop( ... )
	skip
    end



    %%%%%%%%%%%%%%%%%%%%
    % Just returns the Oz name.  No big deal.
    %%%%%%%%%%%%%%%%%%%%
    meth ozName( ozName: N )
	N = self.ozName
    end
    



    %%%%%%%%%%%%%%%%%%%%
    % Just returns the class name.  No big deal.
    %%%%%%%%%%%%%%%%%%%%
    meth className( className: N )
	N = self.className
    end
    



    %%%%%%%%%%%%%%%%%%%%
    % Just returns the method list.  No big deal.
    %%%%%%%%%%%%%%%%%%%%
    meth getMethodList( methodList: N )
	N = self.methodList
    end
    



    %%%%%%%%%%%%%%%%%%%%
    %
    % toRecord() is a very important method that runs through the
    % elements of the exports feature and constructs a record using the
    % information therein.  This record can be pickled, saved to disk,
    % and later loaded in with fromRecord.
    %
    % Arguments:
    %
    % isForUpgrade: Set this to allow the record to include
    % non-persistent data, which cannot be saved to disk (such as
    % the Player object's output port).
    %
    % Returns:
    %
    % record: The resulting record.
    %
    %%%%%%%%%%%%%%%%%%%%
    meth toRecord(
	    isForUpgrade: IsForUpgrade <= false
	    record: ExportRecord
    )
	proc {ConvertToRecord Type Value Return}
	    case Value of Head|Tail then
		Return = {ConvertToRecord Type Head $}|{ConvertToRecord Type Tail $}
	    else
		if Value == nil then
		    Return = nil
		else
		    % Here we go through the list of items to export
		    % and convert them to the appropriat format.
		    case Type of array then 
			Return = {Array.toRecord array Value $}
		    []	dict then 
			Return = {Dictionary.toRecord dict Value}
		    []	objectRefDict then 
			Return = {Record.map
			    {Dictionary.toRecord dict Value}
			    proc {$ RecVal Out}
				Out = objectRef(
				    ozName: {RecVal ozName($)}
				    capabilities: {RecVal capabilities($)}
				)
			    end
			}
		    []	objectRef then
			Return = objectRef(
			    ozName: {Value ozName($)}
			    capabilities: {Value capabilities($)}
			)
		    []	notPersistent then 
			Return = nil
		    []	_ then 
			Return = Value
		    end
		end
	    end
	end
    in
	ExportRecord = {List.toRecord exports
	    % Drop all elements with Type = nil
	    {Filter
		% Map the list of tuples into another list of tuples
		{Map
		    self.exports 
		    fun {$ Name#Type}
			if IsForUpgrade then
			    Name#(Type#@Name)
			else
			    % If the type is notPersistent, we shouldn't go
			    % anywhere near it unless this is for an
			    % upgrade.
			    if Type == notPersistent then 
				Name#(nil#nil)
			    else
				if {IsDet Name} then
				    if {IsDet @Name} then
					if @Name \= nil then
					    Name#(Type#{ConvertToRecord Type @Name $})
					else	
					    Name#(Type#nil)
					end
				    else
					Name#(Type#nil)
				    end
				else
				    Name#(Type#nil)
				end
			    end
			end
		    end
		    $ 
		} % Map self.exports 
		fun {$ A#(B#C) }
		    if B == nil then
			false
		    else
			true
		    end
		end
	    }

	$ }
	#
	{List.toRecord featExports
	    % Drop all elements with Type = nil
	    {Filter
		% Map the list of tuples into another list of tuples
		{Map self.featExports 

		    fun {$ Name#Type}
			% If the type is notPersistent, we shouldn't go
			% anywhere near it unless this is for an
			% upgrade.
			if Type == notPersistent then
			    Name#(nil#nil)
			else
			    if {IsDet Name} then
				if {IsDet self.Name} then
				    if self.Name \= nil then
					Name#(Type#{ConvertToRecord Type self.Name $})
				    else	
					Name#(Type#nil)
				    end
				else
				    Name#(Type#nil)
				end
			    else
				Name#(Type#nil)
			    end
			end
		    end
		$ } % Map self.featExports
		fun {$ A#(B#C) }
		    if B == nil then
			false
		    else
			true
		    end
		end
	    }
	$ }

    end




    %%%%%%%%%%%%%%%%%%%%
    %
    % fromRecord is the inverse operation to toRecord.  It takes the output
    % of toRecord and sets attributes appropriately.  Note that this is a
    % pure procedure: it is only called for its side effects.  Yech.
    %
    % Arguments:
    %
    % record: The input record, generated from toRecord.
    % convert:  The procedure to convert stored attributes of type
    % 	'objectRef' into something useful.
    % objectRef: An object reference to the newly initialized object,
    % 	with all capabilities.
    %
    %%%%%%%%%%%%%%%%%%%%
    meth fromRecord( record: WholeRecord
	    convert: ObjectRefFromRecord
	    objectRef: ObjectRef
	    isForUpgrade: IsForUpgrade <= false
	) = MethHead
	% The procedure that handles the record items.
	proc {ConvertFromRecord Type#Value Return}
	    case Value of Head|Tail then
		Return = {ConvertFromRecord Type#Head $}|{ConvertFromRecord Type#Tail $}
	    else
		if Value == nil then
		    Return = nil
		else
		    % Here we go through the list of export items to
		    % extract, performing any necessary conversion as we
		    % go along.
		    case Type
			of	dict then 
			    Return = {Record.toDictionary Value $}

		    []	objectRefDict then 
			Return = {Record.toDictionary
			    {Record.map
				Value
				ObjectRefFromRecord
			    }
			    $
			}

		    % This section is for object references, which
		    % are specially encoded as a record with the
		    % fields ozName, wrapper, and capabilities.
		    []	objectRef then
			Return = {ObjectRefFromRecord Value $}

		    []	_ then 
			Return = Value
		    end
		end
	    end
	end

	proc {ConvertFeatFromRecord Feat Type#Value}
	    % Here we go through the list of export items to
	    % extract, performing any necessary conversion as we
	    % go along.
	    case Type
		of	dict then 
		    {Dictionary.removeAll self.Feat}
		    {Record.forAllInd Value
			proc {$ A B}
			    {Dictionary.put self.Feat A B}
			end
		    }
	    []	_ then 
		self.Feat = Value
	    end
	end

	ExportRecord FeatExportRecord 
    in
	WholeRecord = ExportRecord#FeatExportRecord

	{MozLog
	    "Starting fromRecord on MozBase."
	    debug
	    MethHead
	}

	%{MozLog
	%"In fromRecord on MozBase, Export Record: " #
	%{Value.toVirtualString ExportRecord 50 50 }
	%debug
	%MethHead
	%}

	%{MozLog
	%"In fromRecord on MozBase, FeatExport Record: " #
	%{Value.toVirtualString FeatExportRecord 50 50 }
	%debug
	%MethHead
	%}

	% Run through the record.
	{Record.forAllInd ExportRecord
	    proc {$ A B}
		%{MozLog
		%"In fromRecord on MozBase, Converting value: " #
		%{Value.toVirtualString A 50 50 } # " " #
		%{Value.toVirtualString B 50 50 }
		%debug
		%MethHead
		%}
		if IsForUpgrade then
		    A <- B.2
		else
		    A <- {ConvertFromRecord B $}
		end
	    end
	}

	{MozLog
	    "In fromRecord on MozBase, done exportRecord."
	    debug
	    MethHead
	}

	% Run through the record.
	{Record.forAllInd FeatExportRecord
	    proc {$ A B}
		{ConvertFeatFromRecord A B}
	    end
	}

	{MozLog
	    "In fromRecord on MozBase, done featExportRecord."
	    debug
	    MethHead
	}

	ObjectRef = {self selfReference( selfRef: $ ) }
    end


    %%%%%%%%%%%%%%%%%%%%
    %
    % revoke is used to revoke a particular capability.
    %
    % Arguments:
    %
    % method: The method name to revoke.
    %
    % capability: The capability for that method.
    %
    % newCapability: The new capability for that method, sent
    %               as an unbound variable.
    %
    %%%%%%%%%%%%%%%%%%%%%
    meth revoke( method: Method capability: Capability
	    newCapability: NewCapability )
        % Here we generate a new capability for the
        % capability named, then return that
        % capability.
        NewCapability = {NewName}

        try
	    if Capability \= {Dictionary.get self.capabilityDict Method}
            then
		raise
		    mozError( permission_denied(
			"Revoke: That capability does not
			exist!"#Method ) )
		end
            else
                {Dictionary.put
                    self.capabilityDict
                    Method
                    NewCapability
                }
            end

        catch X then
	    raise
		mozError( permission_denied(
		    "Revoke: That capability does not exist!" X ) )
	    end
        end
    end




    %%%%%%%%%%%%%%%%%%%%
    %
    % activeObjectInform is called whenever an object's Active Object
    % wrapper information has changed.
    % 
    % Arguments:
    %
    % wrapper:  Our own wrapper.
    % capabilities:  Our new capabilities.
    %
    %%%%%%%%%%%%%%%%%%%%
%    meth activeObjectInform( object: Object )
%	selfObject <- Object
%    end

    %%%%%%%%%%%%%%%%%%%%
    %
    % Returns a boolean declaring if the object's name is a proper name
    % (like Alice or Bob) or a generic name (like couch or door or
    % puppy).
    % 
    % Arguments:
    %
    % hasProperName: A boolean (just a straight attr lookup)
    %
    %%%%%%%%%%%%%%%%%%%%
    meth hasProperName( hasProperName: HasProperName )
	HasProperName = @hasProperName
    end

    %%%%%%%%%%%%%%%%%%%%
    %
    % Sets the 'hasProperName' variable.
    % 
    % Arguments:
    %
    % hasProperName: A boolean (just a straight attr lookup)
    %
    %%%%%%%%%%%%%%%%%%%%
    meth setHasProperName( hasProperName: HasProperName )
	hasProperName <- HasProperName
    end

    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    %
    % deLocalize:
    %
    % Returns a bare string from a localized string, based on a
    % language argument.
    %
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    meth deLocalize( inputString: LocString outputString: String
	language: Language <= nil server: Server <= nil )
	ServerDefault
    in
	% String might be a list of strings.
	if {IsList LocString} then
	    String = {Flatten
		{Map
		    LocString
		    fun {$ A}
			{self
			    deLocalize(
				inputString: A
				language: Language
				server: Server
				outputString: $
			    )
			}
		    end
		}
	    }
	else
	    % Deal with LanguageStrings calls.
	    if {IsAtom LocString} then
		String = 
		{self
		    deLocalize(
			inputString: 
			{@languageStringsObjectRef
			    getLanguageString(
				key: LocString
				string: $
			    )
			}

			language: Language
			server: Server
			outputString: $
		    )
		}
	    else
		% MozBase by itself does *not* have visilibity to the Server
		% class, although all the classes above it do.
		if Server == nil then
		    ServerDefault = 'any'
		else
		    ServerDefault = Server.defaultLanguage
		end

		% If we have a language that we would prefer, use that
		% if we can, otherwise use whatever's available.
		if Language \= nil then
		    if {HasFeature LocString Language} then
			String = LocString.Language
		    else
			% Use the server default, or whatever's first.
			if {HasFeature LocString ServerDefault} then
			    String = LocString.(ServerDefault)
			else
			    String = {Nth {Record.toList LocString} 1}
			end
		    end
		else
		    % Use the server default, or whatever's first.
		    if {HasFeature LocString ServerDefault} then
			String = LocString.(ServerDefault)
		    else
			String = {Nth {Record.toList LocString} 1}
		    end
		end
	    end
	end
    end

    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    %
    % getName:
    %
    % Returns the object's name string.
    %
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    meth getName( name: StrName )
	StrName = @name
    end



    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    %
    % getArticledName:
    %
    % Returns the object's name string with the appropriate article
    % prepended.
    %
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    meth getArticledName( name: StrName )
	Article
	HasProperName
    in
	% First we get the right article, as that is rather
	% an involved process.
	%
	% hasProperName returns a bool
	HasProperName = {self
	    hasProperName( hasProperName: $ )
	}

	if HasProperName then
	    Article= properNameArticle
	else
	    % English A/An
	    if {HasFeature
		{self getName( name: $ ) }
		en
	    } andthen
	    {Member
		{self getName( name: $ ) }.en.1
		"aeiouAEIOU"
	    } then
		Article= indefiniteVowelArticle
	    else
		Article= indefiniteArticle
	    end
	end

	StrName = {Flatten
	    [
		Article
		{self getName( name: $ ) }
	    ]
	}
    end



    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    %
    % getArticledStarterName:
    %
    % Returns the object's name string with the appropriate article
    % prepended.  Assumes the article will be the first word in a
    % sentence.
    %
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    meth getArticledStarterName( name: StrName )
	Article
	HasProperName
    in
	% First we get the right article, as that is rather
	% an involved process.
	%
	% hasProperName returns a bool
	HasProperName = {self
	    hasProperName( hasProperName: $ )
	}

	if HasProperName then
	    Article= properNameStarterArticle
	else
	    % English A/An
	    if {HasFeature
		{self getName( name: $ ) }
		en
	    } andthen
	    {Member
		{self getName( name: $ ) }.en.1
		"aeiouAEIOU"
	    } then
		Article= indefiniteStarterVowelArticle
	    else
		Article= indefiniteStarterArticle
	    end
	end

	StrName = {Flatten
	    [
		Article
		{self getName( name: $ ) }
	    ]
	}
    end



    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    %
    % setName:
    %
    % Sets the object's name string, localizing as necessary.
    %
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    meth setName( name: StrName <= string( any: "unnamed object" ))
	LocName
    in
	% Make sure our name is localized.
	if {IsString StrName} orelse {IsVirtualString StrName} then
	    LocName = string( any: StrName )
	else
	    LocName = StrName
	end

	% Make sure we keep any other language versions that might have
	% been previously set.
	name <- {Adjoin
	    @name
	    LocName
	}
    end

    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    %
    % getVerbs:
    %
    % Simply returns the object's verbs list
    %
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    meth getVerbs( verbs: Verbs )
	Verbs = @verbs
    end


    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    %
    % geControltVerbs:
    %
    % Simply returns the object's controlVerbs list
    %
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    meth getControlVerbs( verbs: Verbs )
	Verbs = @controlVerbs
    end


    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    %
    % selfMatch:
    %
    % This method is called to test the extent to which the string
    % passed seems to be a match to our name or any of our aliases,
    % i.e. does the string refer to this object.
    %
    % Arguments:
    %
    % string: The string to test against our name and aliases and
    % such.
    %
    % certainty: A number from zero to one indicating how sure we
    % are that this matches us, with zero being "this is not us" and
    % one being "this is for sure us".
    %
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    meth selfMatch( string: String certainty: Certainty 
	    language: Language <= any
	) = MethHead
	DeLocName
    in
	{MozLog
	    "Starting selfMatch on MozBase: "
	    # {Value.toVirtualString MethHead 100 100}
	    debug
	    MethHead
	}

	{self
	    deLocalize( inputString: @name outputString: DeLocName
	    language: Language ) 
	}

	if String == DeLocName then
	    Certainty = 1.0
	else
	    if {EnhancedString.toLower String} ==
		{EnhancedString.toLower DeLocName}
	    then
		Certainty = 0.9
	    else
		Certainty = 0.0
	    end
	end
    end

    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    %
    % addPublicMethod:
    %
    % Appends an entry to the publicMethods attribute.  Nothing
    % special.
    % 
    % Arguments:
    %
    % method: The method atom.
    %
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    meth addPublicMethod( method: MethodLabel )
	if {IsAtom MethodLabel} then
	    publicMethods <- MethodLabel | @publicMethods
	else
	    raise
		moz_error( 'Unfinished error message 1 in MozBase.')
	    end
	end		    
    end



    
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    %
    % addControlVerb:
    %
    % Adds a verb to the controlVerbs attribute.
    %
    % Usses addVerb for all the real work.
    %
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    meth addControlVerb( language: Language verb: VerbLabel 
	    parse: ParseRecord
	)

	{self
	    addVerb(
		language: Language
		verb: VerbLabel
		parse: ParseRecord
		control: true
	    )
	}
    end



    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    %
    % addVerb:
    %
    % Adds a verb to the objects verbs record, dealing with things
    % like over-writing the same verb parse, dealing with multiple
    % parses of the same verb, and the fact that the whole verb
    % record system is very baroque.
    % 
    % Arguments:
    %
    % language: The language the verb applies in.
    %
    % verb:  The verb word itself ("help", "look", whatever).
    %
    % parse:  The parse record to add.  Note that this record will
    % over-ride any other parse record for the same verb with the
    % same label, so it's important that it be unique.
    %
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    meth addVerb( language: Language verb: VerbLabel 
	    parse: ParseRecord control: Control <= false
	) = MethHead
	VerbsLessLanguage 
	ParsesLessCurrentVerb
	VerbsLanguageLessVerb 
	Parses
	Verbs
    in
	% Check to see if we are being used to set the controlVerbs
	% variable or the regular verbs variable.
	if Control then
	    Verbs = controlVerbs
	else
	    Verbs = verbs
	end

	% Here we collect various bits of information we need from
	% the @Verbs record, subject to it actually existing.
	if {IsDet @Verbs} andthen {IsRecord @Verbs} then
	    % Get the original verbs record with everything but the
	    % language we are working on.
	    VerbsLessLanguage =
	    {Record.subtract
		@Verbs
		Language
	    }

	    if {HasFeature @Verbs Language} then 
		% Get the original @Verbs.Language, except the
		% verb we're working on.
		VerbsLanguageLessVerb =
		{Record.subtract
		    @Verbs.Language
		    VerbLabel
		}

		if {HasFeature @Verbs.Language VerbLabel} andthen
		    {HasFeature @Verbs.Language.VerbLabel parses} andthen
		    {IsList @Verbs.Language.VerbLabel.parses}
		then
		    % Get the orignal parses, less the
		    % one we're currently adding.
		    ParsesLessCurrentVerb =
		    {Filter
			@Verbs.Language.VerbLabel.parses
			% Return true if this is not the
			% label we're currently dealing
			% with; this is how replacement
			% is handled: identical parse
			% record labels.
			fun {$ A}
			    {Label A} \= {Label ParseRecord}
			end
		    }
		else
		    ParsesLessCurrentVerb = nil
		end
	    else
		VerbsLanguageLessVerb = verb()
		ParsesLessCurrentVerb = nil
	    end

	else
	    VerbsLessLanguage = allVerbs()
	    VerbsLanguageLessVerb = verb()
	    ParsesLessCurrentVerb = nil
	end

	if ParsesLessCurrentVerb == nil then
	    Parses = [ ParseRecord ]
	else
	    Parses = {Append
		ParsesLessCurrentVerb
		[ ParseRecord ]
	    }
	end

	% Here we mush all the bits of information together.
	Verbs <- {Adjoin
	    VerbsLessLanguage
	    allverbs(
		Language: 
		{Adjoin
		    VerbsLanguageLessVerb
		    verbs(
			VerbLabel: verb(
			    language: Language
			    parses: Parses
			)
		    )
		}

	    )
	}
    end



    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    %
    % enhanceStorage:
    %
    % Upgrades the storage attribute with a new capability set.
    %
    % Used for getting access to special modules.
    %
    % Note that any capability we already have wins here, so that
    % this can't be used to destroy our capability set.
    %
    % Inputs:
    %
    % storageRef: A reference to the Storage object, preferrably
    % containing at least one new capability.
    %
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    meth enhanceStorage( storageRef: Storage ... )
	% Add the new capability(ies) to our own.
	storageRef <- {MakeObjectReference
	    {Storage wrapper($)}
	    {Adjoin
		{@storageRef capabilities($)}
		{Storage capabilities($)}
	    }
	    {Storage ozName($)}
	}
    end




    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    %
    % publicSelfReference:
    %
    % Returns a reference to the current object, but with only
    % capabilities on the methods listen in publicMethods.
    %
    % Returns:
    %
    % selfRef: A reference object for the current object.
    %
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    meth publicSelfReference( selfRef: SelfRef ... )
	SelfRef = {MakeObjectReference
	    self.wrapper
	    {Record.filterInd
		{Dictionary.toRecord
		    'capabilities'
		    self.capabilityDict
		}
		proc{$ A B C }
		    C = {Member A
			@publicMethods
		    }
		end
	    }
	    self.ozName
	}
    end



    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    %
    % selfReference:
    %
    % Returns a *complete* reference to the current object.  Very
    % unsafe!
    %
    % Returns:
    %
    % selfRef: A reference object for the current object.
    %
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    meth selfReference( selfRef: SelfRef ... )
	SelfRef = {MakeObjectReference
	    self.wrapper
	    {Dictionary.toRecord 'capabilities' self.capabilityDict }
	    self.ozName
	}
    end




    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    %
    % printedList:
    %
    % Takes a list of strings and returns one big long string
    % formatted as a natlang list. In English, for example, [ "a"
    % "b" "c" ] becomes "a, b and c".
    %
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    meth printedList( stringList: StringList string: String ) = MethHead
	{MozLog
	    "Starting printedList on MozBase; list:" #
	    {Value.toVirtualString StringList 10 10} #
	    ", list length: " # {Length StringList}
	    debug
	    MethHead
	}

	String =
	{List.mapInd
	    StringList
	    proc {$ A B C}
		{MozLog
		    "In printedList on MozBase: " #
		    {Value.toVirtualString A 10 10} #
		    {Value.toVirtualString B 10 10 }
		    debug
		    MethHead
		}

		if A == 1 then
		    C = B
		else
		    if A == {Length StringList} then
			C = {Append
			    [
				listLastString
			    ]
			    B
			}
		    else
			C = {Append
			    [
				listSeperator1
			    ]
			    B
			}
		    end
		end

		{MozLog
		    "In printedList on MozBase: " #
		    {Value.toVirtualString C 10 10 }
		    debug
		    MethHead
		}

	    end
	}
    end



    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    %
    % printedObjectList:
    %
    % Takes a list of object references and returns one big long
    % string of their names with the correct articles formatted as a
    % natlang list.
    %
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    meth printedObjectList( objectList: List string: String )
	{self
	    printedList(
		stringList: 
		{Map
		    List
		    proc {$ A B}
			B = {A getArticledName( name: $ ) }
		    end
		}

		string: String
	    )
	}
    end





    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    %
    % 		Verb-Related Methods
    %
    % These are all the methods that are used to implement the various verbs
    % on the parser class.
    %
    % Standard Arguments:
    % 
    % caller:	The objectRef for the calling object.
    % player: 	The objectRef for the player object.
    % language:	The language of the verb itself, for when the player is
    % 		able to run verbs in multiple languages (i.e. help has
    % 		language en, sidju has language lb).
    % result:	The result of the verb, a record like
    %    result(
    %       status: success|failure|other  -- default success
    %       certainty: float from 0 through 1  -- default 1
    % 	    comments: <string> -- default nil, only relevant for failure
    %    )
    %  See programmer's guide for more information.
    %
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%





    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    %
    % teleportVerb:
    %
    % Used to transport the controlled object to the player's
    % location or inventory.
    %
    % Additional Arguments:
    %
    % fromString: The string indicating the from location, which is
    % either an object name to match or 'self'.
    %
    % toString:  The string indicating the location to teleport the to.
    %
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    meth teleportVerb( 
	    caller: CallerRef player: PlayerRef
	    result: Result language: VerbLang 
	    fromString: FromString
	    toString: ToString
	    force: Force <= false
	    ... 
	) = MethHead

	FullFromString = {VirtualString.toString
	    {EnhancedString.join FromString " "}
	}

	FullToString = {VirtualString.toString
	    {EnhancedString.join ToString " "}
	}

	ControlledLocation
	Certainty
    in

	{MozLog
	    "Starting teleportVerb on Control: "
	    # {Value.toVirtualString MethHead 100 100 }
	    debug
	    MethHead
	}

	% See if we're teleporting the *player*.
	% Compare the *from* string to our localized string for 'me'.
	if {EnhancedString.toLower
	    FullFromString 
	} ==
	    {EnhancedString.toLower
		{@languageStringsObjectRef
		    getLanguageString(
			key: meString
			string: $
		    )
		}.VerbLang
	    }
	then
	    PlayerLocation =
	    {PlayerRef
		getLocation( location: $ )
	    }
	in
	    % If the caller is *sure* ey wants to talk to us, we
	    % oblige.
	    if Force then
		Certainty = 1.0
	    else
		% See if we're even talking to the right object at all.
		{@controlled
		    selfMatch(
			string: FullToString
			certainty: Certainty
		    )
		}

	    end

	    % Make sure the object we control can actually
	    % accept the player, produce a useful error message
	    % if not.
	    if
		{Not
		    {HasFeature
			{@controlled capabilities( $ )}
			addToContents
		    } 
		}
	    then
		Result = result(
		    status: failure
		    certainty: Certainty
		    comments: [
			cantTeleportImmobilePre
			{@controlled
			    getArticledStarterName( name: $ )
			}
			cantTeleportImmobilePost
		    ]
		)
	    else % @controlled has contents

		if {IsObject PlayerLocation} then
		    {PlayerLocation
			give(
			    toLocation: {@controlled
				publicSelfReference(
				    selfRef: $
				)
			    }
			    objectRef: PlayerRef
			)
		    }
		else
		    {@controlled
			wantToGive(
			    oldLocation: nil
			    objectRef: {@controlled
				publicSelfReference( selfRef: $ )
			    }
			    result: _
			)
		    }
		end

		{PlayerRef
		    tell(
			string: [
			    controlTeleportSelfPre

			    {@controlled getArticledName( name: $ ) }

			    controlTeleportSelfPost
			]
		    )
		}
	    end % @controlled has no contents

	else % teleporting the object, not the player.
	    % If the caller is *sure* ey wants to talk to us, we
	    % oblige.
	    if Force then
		Certainty = 1.0
	    else
		% See if we're even talking to the right object at all.
		{@controlled
		    selfMatch(
			string: FullFromString
			certainty: Certainty
		    )
		}

	    end

	    % We're in the right place.
	    if Certainty >= 1.0 then
		% Make sure the object we control can actually be moved,
		% produce a useful error message if not.
		if
		    {Not
			{HasFeature
			    {@controlled capabilities( $ )}
			    setLocation
			} 
		    }
		then
		    Result = result(
			status: failure
			certainty: Certainty
			comments: [
			    cantTeleportImmobilePre
			    {@controlled
				getArticledStarterName( name: $ )
			    }
			    cantTeleportImmobilePost
			]
		    )
		else % @controlled is mobile

		    ControlledLocation =
		    {@controlled
			getLocation( location: $ )
		    }

		    % Compare the string to our localized string for 'me'.
		    if {EnhancedString.toLower
			FullToString 
		    } ==
			{EnhancedString.toLower
			    {@languageStringsObjectRef
				getLanguageString(
				    key: meString
				    string: $
				)
			    }.VerbLang
			}
		    then
			if {IsObject ControlledLocation} then
			    {ControlledLocation
				give(
				    toLocation: PlayerRef
				    objectRef: {@controlled
					publicSelfReference(
					    selfRef: $
					)
				    }
				)
			    }
			else
			    {PlayerRef
				wantToGive(
				    oldLocation: nil
				    objectRef: {@controlled
					publicSelfReference( selfRef: $ )
				    }
				    result: _
				)
			    }
			end

			{PlayerRef
			    tell(
				string: [
				    controlTeleportPre

				    {@controlled getArticledName( name: $ ) }

				    controlTeleportToSelf

				    controlTeleportPost
				]
			    )
			}

		    end

		    % Compare the string to our localized string for 'here'.
		    if {EnhancedString.toLower
			FullToString 
		    } ==
			{EnhancedString.toLower
			    {@languageStringsObjectRef
				getLanguageString(
				    key: hereString
				    string: $
				)
			    }.VerbLang
			}
		    then
			PlayerLocation =
			{PlayerRef
			    getLocation( location: $ )
			}

		    in
			% Find out if the thing we want to move is anywere
			% at all.
			if {IsObject ControlledLocation} then
			    % Controlled object has a location; move it to
			    % the player's location.
			    {ControlledLocation
				give(
				    toLocation: PlayerLocation
				    objectRef: {@controlled
					publicSelfReference(
					    selfRef: $
					)
				    }
				)
			    }
			else
			    % Controlled object has no location; move it by
			    % force.
			    {PlayerLocation
				wantToGive(
				    oldLocation: nil
				    objectRef: {@controlled
					publicSelfReference( selfRef: $ )
				    }
				    result: _
				)
			    }
			end

			{PlayerRef
			    tell(
				string: [
				    controlTeleportPre

				    {@controlled getArticledName( name: $ ) }

				    controlTeleportToHerePre

				    {PlayerLocation getArticledName( name: $ ) }

				    controlTeleportToHerePost

				    controlTeleportPost
				]
			    )
			}
		    end % teleporting @controlled to here
		end % controlled is mobile
	    else % certainty >= 1.0
		if {IsFree Result} then
		    % We failed to match, so we let the parser know.
		    Result = result(
			status: other
			certainty: Certainty
		    )
		end
	    end % certainty >= 1.0
	end % teleporting object or player?
    end



    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    %
    % renameVerb:
    %
    % Used by control object to rename their controlees.
    %
    % Additional Arguments:
    %
    % nameString:  The string to match ourself to.
    %
    % newNameString:  The string to change our name to.
    %
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    meth renameVerb( 
	    caller: CallerRef player: PlayerRef
	    result: Result language: VerbLang 
	    nameString: NameString
	    newNameString: NewNameString
	    force: Force <= false
	    ... 
	) = MethHead

	FullNameString = {VirtualString.toString
	    {EnhancedString.join NameString " "}
	}

	FullNewNameString = {VirtualString.toString
	    {EnhancedString.join NewNameString " "}
	}

	Certainty
    in

	{MozLog
	    "In renameVerb on MozBase, MethHead:"
	    # {Value.toVirtualString MethHead 100 100}
	    debug
	    MethHead
	}

	{MozLog
	    "In renameVerb on MozBase, name:"
	    # {Value.toVirtualString {@controlled getName( name: $ ) } 100 100}
	    debug
	    MethHead
	}

	% If the caller is *sure* ey wants to talk to us, we
	% oblige.
	if Force then
	    Certainty = 1.0
	else
	    % See if we're even talking to the right object at all.
	    {@controlled
		selfMatch(
		    string: FullNameString
		    certainty: Certainty
		)
	    }

	end

	% We're in the right place.
	if Certainty >= 1.0 then
	    {@controlled
		setName(
		    name:
		    {List.toRecord
			string
			[ VerbLang#FullNewNameString ]
		    }
		)
	    }
	    {MozLog
		"In renameVerb on MozBase, @name after:"
		# {Value.toVirtualString @name 100 100}
		debug
		MethHead
	    }

	    {PlayerRef
		tell(
		    string: 
		    [
			mozBaseRenameVerbPre
			string( any: FullNameString )
			mozBaseRenameVerbMiddle
			{@controlled getArticledName( name: $ ) }
			mozBaseRenameVerbPost
		    ]
		)
	    }
	else
	    Result = result(
		status: other
		certainty: Certainty
	    )
	end
    end





end
