package mud.core;

import java.lang.*;
import java.util.*;
import mud.event.*;

public class GameObject extends java.lang.Object
{
    /**
     *  Construct a game object. Set all the initial values.
     */
    public GameObject()
    {
        bPlayer = false;
        bPlayer = false;
        sName = "";
        goOwner = null;
        goLocation = null;
        vContents = new Vector(10);
        iMaximumCapacity = 0;
        iWeight = 0;
        iHits = 0;
        iMaximumHits = 0;
        
        // set the birthday
        lBirthday = System.currentTimeMillis();
    }


    // bPlayer attribute settings

    /**
     *  Is the game object a player?
     */
    public boolean isPlayer()
    {
        return bPlayer;
    }

    /**
     *  Set or unset the player attribute of the game object.
     */
    public void setPlayer(boolean bPlayer)
    {
        this.bPlayer = bPlayer;
    }

    /**
     *  Toggle the player attribute of the game object.
     */
    public void togglePlayer()
    {
        bPlayer = !bPlayer;
    }

    /**
     *  Is the player a wizard? (Immortal)
     */
    public boolean isWizard()
    {
        return bWizard;
    }

    /**
     *  Set or unser the wizard attribute of the game object.
     */
    public void setWizard(boolean bWizard)
    {
        this.bWizard = bWizard;
    }

    /**
     *  Toggle the wizard attribute of the game object.
     */
    public void toggleWizard()
    {
        bWizard = !bWizard;
    }


    // name and description

    /**
     *  Get the short name of the object.
     */
    public String getName()
    {
        return sName;
    }

    /**
     *  Set the short name of the object.
     */
    public void setName(String sName)
    {
        this.sName = sName;
    }

    /**
     *  Get the description of the object (long name).
     */
    public String getDescription()
    {
        return description;
    }

    /**
     *  Set the description of the object (long name).
     */
    public void setDescription(String description)
    {
        this.description = description;
    }


    // ownership

    /**
     *  Get the owning object.
     */
    public GameObject getOwner()
    {
        return goOwner;
    }

    /**
     *  Set the owning object.
     */
    public void setOwner(GameObject goOwner)
    {
        this.goOwner = goOwner;
    }


    // location management

    /**
     *  Get the location of the object.
     */
    public GameObject getLocation()
    {
        return goLocation;
    }

    /**
     *  Set the location of the object (move the object).
     */
    public void setLocation(GameObject goLocation) throws MoveRecursionException
    {
        GameObject loc, goOldLoc;

        // check for recursive containment
        loc = this.getLocation();
        while (loc != null)
        {
            if (loc == this)
            {
                throw new MoveRecursionException();
            }
            loc = loc.getLocation();
        }

        // successful move
        if (goLocation.checkCapacity(this))
        {
            // set the old location (for event generation)
            goOldLoc = this.goLocation;
            
            // remove the item from the inventory of the old location
            if (this.goLocation != null)
            {
                this.goLocation.take(this);
            }

            // change the location of the item
            this.goLocation = goLocation;

            // put the item in the inventory of the new location
            if (this.goLocation != null)
            {
                goLocation.give(this);
            }
            
            // generate the move event
            MoveEvent evMove = new MoveEvent(this, goOldLoc, this.goLocation, MUDEvent.ITEM_EVENT_MASK);
        }
    }


    // contents management

    /**
     *  Get the contents of the object.
     */
    public Vector getContents()
    {
        return vContents;
    }

    /**
     *  Give a new game object to this game object.
     */
    public void give(GameObject item)
    {
        vContents.addElement(item);
    }

    /**
     *  Take a game object from this object's contents.
     */
    public GameObject take(int itemIndex)
    {
        GameObject item = (GameObject)vContents.elementAt(itemIndex);
        vContents.removeElementAt(itemIndex);
        return item;
    }

    /**
     *  Take a specified game object from this object's contents.
     */
    public GameObject take(GameObject item)
    {
        return take(vContents.indexOf(item));
    }
    

    // weight
    
    /**
     *  Get the weight/encumberance of the game object.
     */
    public int getWeight()
    {
        return iWeight + getContentsWeight();
    }
    
    /**
     *  Set the weight/encumberance of the game object.
     */
    public void setWeight(int iWeight)
    {
        this.iWeight = iWeight;
    }

    /**
     *  Get the current carried weight inside this object.
     */
    public synchronized int getContentsWeight()
    {
        int carriedWeight = 0;
        GameObject obj;
        
        // iterate through the contents, getting each weight in turn
        for (int i = 0; i < vContents.size(); i++)
        {
            obj = (GameObject)vContents.elementAt(i);
            carriedWeight += obj.getContentsWeight() + obj.getWeight();
        }
        
        // return the contents weight
        return carriedWeight;
    }


    // capacity
     
    /**
     *  Get current available capacity.
     */
    public int getAvailableCapacity()
    {
        return getMaximumCapacity() - getWeight();
    }
    
    /**
     *  Get the maximum capacity.
     */
    public int getMaximumCapacity()
    {
        return iMaximumCapacity;
    }
    
    /**
     *  Set the maximum capacity.
     */
    public void setMaximumCapacity(int iMaximumCapacity)
    {
        this.iMaximumCapacity = iMaximumCapacity;
    }
    
    /**
     *  Check to see if the item's weight would exceed maxCapacity?
     *  @return True if this.capacity + item.weight < this.maxCapacity
     */
    public boolean checkCapacity(GameObject item)
    {
        return (getContentsWeight() + item.getWeight() < getMaximumCapacity());
    }
    

    // hits
    
    /**
     *  Get the current number of hits of the game object.
     */
    public int getHits()
    {
        return iHits;
    }
     
    /**
     *  Set the current number of hits of the game object.
     */
    public void setHits(int iHits)
    {
        this.iHits = iHits;
    }
    
    /**
     *  Modify the number of hits of the game object.
     */
    public void modifyHits(int modifier)
    {
        this.iHits += modifier;
    }

    /**
     *  Get the maximum number of hits the game object can reach by healing or repair.
     */
    public int getMaximumHits()
    {
        return iMaximumHits;
    }

    /**
     *  Set the maxiumum number of hits the game object can reach by healing or repair.
     */
    public void setMaximumHits(int iMaximumHits)
    {
        this.iMaximumHits = iMaximumHits;
    }
    

    // birthday
    
    /**
     *  Get the birthday.
     */
    public long getBirthday()
    {
        return lBirthday;
    }

    
    // sprite
    
    /**
     *  Get the sprite.
     */
    public Sprite getSprite()
    {
        return spSprite;
    }
    
    /**
     *  Set the sprite.
     */
    public void setSprite(Sprite spSprite)
    {
        this.spSprite = spSprite;
    }
    
    
    // event handling
    
    /**
     *  This is a general routine to catch and pass events to items.
     *  This method is intended to be overridden by subclasses.
     */
    public void listen(MUDEventObject evObject)
    {
        // this is not synchronized because of possible performance issues
        // this means that it will be possible for some items to miss
        // events...so be it.
        
        // grab the item list
        Enumeration enItems = vContents.elements();
        
        // temporary item
        GameObject goItem;
        
        // iterate through the item list
        while (enItems.hasMoreElements())
        {
            // grab the next item in the item list
            goItem = (GameObject)enItems.nextElement();
            
            // tell the item about the event
            goItem.listen(evObject);
        }
     
        // assist the garbage collector
        goItem = null;
        enItems = null;
    }
            
        
    
    protected boolean       bPlayer;       // is a player
    protected boolean       bWizard;       // is immortal
    protected String        sName;
    protected String        description;
    protected GameObject    goOwner;
    protected GameObject    goLocation;
    protected Vector        vContents;
    protected int           iWeight;
    protected int           iMaximumCapacity;
    protected int           iHits;
    protected int           iMaximumHits;
    protected long          lBirthday;     // in ms
    protected Sprite        spSprite;
}