/*
Tiamat - a role-playing game framework
ItemCollection.java - used to store a collection of items
 
 Copyright  (C) 2004-2005 Hugues Johnson
 
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
 
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
the GNU General Public License for more details.
 
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

package com.huguesjohnson.tiamat;

import java.lang.String;
import java.lang.StringBuffer;
import java.util.ArrayList;
import com.huguesjohnson.tiamat.Item;
import com.huguesjohnson.tiamat.NamedObjectTreeNode;
import com.huguesjohnson.tiamat.Target;
import com.huguesjohnson.tiamat.TreeNode;

/** ItemCollection - used to store a collection of items
 * @author Hugues Johnson
 */
public class ItemCollection{
    
/* begin private members */
    private NamedObjectTreeNode rootNode;
/* end private members */

/* begin private constants */
    private final static String ROOT_NAME="ITEMS";
    private final static String ROOT_DESCRIPTION="Root node for ItemCollection";
/* end private constants */

/* begin constructors */
    /** 
     * Default constructor, uses default pathDelimiter.
     */
   public ItemCollection(){
        this.rootNode=new NamedObjectTreeNode(new Item(ItemCollection.ROOT_NAME,ItemCollection.ROOT_DESCRIPTION));
    }
   /** 
    * Create a new ItemCollection with a custom path delimiter.
    * @param pathDelimiter The new path delimiter to use.
    */
    public ItemCollection(String pathDelimiter){
        this.rootNode=new NamedObjectTreeNode(new Item(ItemCollection.ROOT_NAME,ItemCollection.ROOT_DESCRIPTION),pathDelimiter);
   }
    /** 
     * Create a new ItemCollection based off an array of Items with a the default path delimiter.
     * @param items The initial set of items to add to the collection.
     */
    public ItemCollection(Item[] items){
        this.rootNode=new NamedObjectTreeNode(new Item(ItemCollection.ROOT_NAME,ItemCollection.ROOT_DESCRIPTION));
        int length=items.length;
        for(int index=0;index<length;index++){
            NamedObjectTreeNode node=new NamedObjectTreeNode(items[index],this.rootNode);
        }
    }
    /** 
     * Create a new ItemCollection based off an array of Items with a the default path delimiter.
     * @param items The initial set of Items to add to the collection.
     * @param pathDelimiter The new path delimiter to use.
     */
    public ItemCollection(Item[] items,String pathDelimiter){
        this.rootNode=new NamedObjectTreeNode(new Item(ItemCollection.ROOT_NAME,ItemCollection.ROOT_DESCRIPTION),pathDelimiter);
        int length=items.length;
        for(int index=0;index<length;index++){
            NamedObjectTreeNode node=new NamedObjectTreeNode(items[index],this.rootNode);
        }
    }

/* end constructors */

/* begin public methods */
    /** 
     * Removes the Item with the specified path.
     * @param path The path of the Item to remove.
     * @return The success of the operation.
     */
    public boolean removeItem(String path){
        return(this.rootNode.removeChildNode(path,true));
    }
    /**
     * Returns the Item with the specified path if it exists, otherwise null.
     * @param path The path of the Item to retreive. 
     * @return The Item with the specified path if it exists, otherwise null.
     */
    public Item getItem(String path){
        Object object=this.rootNode.getChildNode(path,true);
        if(object==null){
            return(null);
        } else if(object instanceof NamedObjectTreeNode){
            Object namedObject=((NamedObjectTreeNode)object).getObject();
            if(namedObject==null){
                return(null);
            } else if(namedObject instanceof Item){
                return((Item)namedObject);
            } else{ //found something that's not an Item, shouldn't happen
                return(null);
            }
        } else{
            return(null);
        }    
    }
    /**
     * Sets the Item with the specified path, adds it if it doesn't exist.
     * @param path The path of the Item to set.
     * @param item The Item to set. 
     */
    public void setItem(String path,Item item){
        TreeNode node=this.rootNode.getChildNode(path+item.getName(),true);
        if(node==null){
            NamedObjectTreeNode newNode=new NamedObjectTreeNode(item,this.rootNode.getPathDelimiter());
            this.rootNode.insertChildNode(path,newNode);
        } else{
            node.setObject(item);
        }    
    } 
    /** 
     * Returns the total number of Items in the collection. 
     * @return The total number of Items in the collection.
     */
    public int getCount(){ 
        return(this.rootNode.getChildLeafCount(true));
    }
    /** Returns the total number of Items starting from the specified path. 
     * @param path The starting path to count from.
     * @return The total number of Items starting from the specified path. 
     */
    public int getCount(String path){
        TreeNode node=this.rootNode.getChildNode(path,true);
        if(node==null){
            return(-1);
        } 	
        return(node.getChildLeafCount(true));
    }
    /** 
     * Returns a collection of all equipped Items that have a target with a name equal to targetPath. 
     * @param targetPath The target name to look for.
     * @return A collection of all equipped Items that have a target with a name equal to targetPath.
     */
    public ItemCollection getModifiersFor(String targetPath){ 
        ArrayList<Item> returnList=new ArrayList<Item>();
        TreeNode[] nodes=this.rootNode.getChildLeaves(true);
        int length=nodes.length;
        for(int index=0;index<length;index++){
            if(nodes[index] instanceof NamedObjectTreeNode){
                Object namedObject=((NamedObjectTreeNode)nodes[index]).getObject();
                if(namedObject!=null){
                    if(namedObject instanceof Item){
                        if(((Item)namedObject).getEquipped()==true){
                            Target[] targets=((Item)namedObject).getTargets();
                            int targetsLength=targets.length;
                            int targetIndex=0;
                            int foundIndex=-1;
                            while((targetIndex<targetsLength)&&(foundIndex<0)){
                                if(targets[targetIndex].getTargetPath().equals(targetPath)){
                                    foundIndex=targetIndex;
                                } else{
                                    targetIndex++;
                                }
                            }
                            if(foundIndex>=0){
                                returnList.add((Item)namedObject);
                            }
                        }
                    }
                }
            }
        }
        if(returnList.size()<1){
            return(new ItemCollection());
        }
        return(new ItemCollection(returnList.toArray(new Item[0])));
    }
    /** 
     * This method is used to get all the modifiers for a target and return the sum of their values.
     * @param targetPath The target name to look for.
     * @return The sum of modifiers for a target.
     */
    public int getNetModification(String targetPath){
        int netModification=0;
        Item[] items=this.getModifiersFor(targetPath).getAll();
        if(items!=null){
            int length=0;
            for(int index=0;index<length;index++){
                Target[] targets=items[index].getTargets();
                int targetsLength=targets.length;
                int targetIndex=0;
                int foundIndex=-1;
                while((targetIndex<targetsLength)&&(foundIndex<0)){
                    if(targets[targetIndex].getTargetPath().equals(targetPath)){
                        foundIndex=targetIndex;
                    } else{
                        targetIndex++;
                    }
                }
                if(foundIndex>=0){ //*should* always be found
                    netModification+=targets[foundIndex].getValue();
                }
            }
        }
        return(netModification);
    }
    /** 
     * Returns all Items in the collection.
     * @return All Items in the collection. 
     */
    public Item[] getAll(){
        TreeNode[] nodes=this.rootNode.getChildLeaves(true);
        int length=nodes.length;
        ArrayList<Item> itemList=new ArrayList<Item>(length);
        for(int index=0;index<length;index++){
            Object object=nodes[index].getObject();
            if(object!=null){
                if(object instanceof Item){
                    itemList.add((Item)object);
                }
            }
        }
        return(itemList.toArray(new Item[0]));
    }    
    /** 
     * Returns a string representation of the object.
     * @return A string representation of the object.
     */
    public String toString(){
        StringBuffer tostring=new StringBuffer(this.getClass().getName());
        //tostring.append("\n  member="+this.member);
        return(tostring.toString());
    }
/* end public methods */
}