/*
Tiamat - a role-playing game framework
GameData.java - contains global data for a game
    
 Copyright  (C) 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 com.huguesjohnson.PathResolver;
import com.huguesjohnson.serialization.Formatter;
import com.huguesjohnson.serialization.Storable;
import com.huguesjohnson.serialization.StorageException;
import java.io.File;
import java.util.ArrayList;

/** GameData - contains global data for a game
 * @author Hugues Johnson
 */
public class GameData implements Storable{

/* begin public properties */
    //all items that are available in the game
    private ItemCollection availableItems;
    /** Returns an ItemCollection representing all Items available in the game.
     * @return An ItemCollection representing all Items available in the game.
     */
    public ItemCollection getAvailableItems(){
        return(this.availableItems);
    }
    /** Sets the collection of all Items available in the game.
     * @param availableItems The collection of all Items available in the game.
     */
    public void setAvailableItems(ItemCollection availableItems){
        this.availableItems=availableItems;
    }
    //the script for this game
    private transient GameScript script;
    /** Returns the script for this game.
     * @return The script for this game.
     */
    public GameScript getScript(){
        return(this.script);
    }
    /** Sets the script for this game.
     * @param script The script for this game.
     */
    public void setScript(GameScript script){
        this.script=script;
    }
    /** Loads the script for this game. 
     * @param scriptPath The path to the script file.
     * @param formatter The formatter to use to deserialize the Characters.
     */
    public void setScript(String scriptPath,Formatter formatter){
        try{
            String absoluteScriptPath=PathResolver.getAbsolutePath(this.absoluteDir,scriptPath);
            this.script=(GameScript)formatter.loadFrom(absoluteScriptPath);
            this.scriptPath=new String(scriptPath);
        } catch(StorageException x){
            x.printStackTrace();
        }    
    }
    //the relative path to the script file
    private String scriptPath;
    //the characters in this game, change by setting character paths
    private transient ArrayList<Character> characters;
    /** Returns all the Charaters available in this game.
     * @return All the Charaters available in this game.
     */
    public Character[] getCharacters(){ 
        return(this.characters.toArray(new Character[0])); 
    }
    //the relative paths to saved character files
    private ArrayList<String> characterPaths;
    /** Returns a list of all relative paths to Charaters.
     * @return a list of all relative paths to Charaters.
     */
    public String[] getCharacterPaths(){ 
        return(this.characterPaths.toArray(new String[0])); 
    }
    /** Sets the Characters for this game.
     * @param characterPaths The paths to the Character files.
     * @param formatter The formatter to use to deserialize the Characters.
     */
    public void setCharacters(String[] characterPaths,Formatter formatter){
        int length=characterPaths.length;
        this.characters=new ArrayList<Character>(length);
        this.characterPaths=new ArrayList<String>(length);
        for(int index=0;index<length;index++){
            try{
                String absoluteCharacterPath=PathResolver.getAbsolutePath(this.absoluteDir,characterPaths[index]);
                this.characters.add(CharacterFactory.load(absoluteCharacterPath,formatter));
                this.characterPaths.add(characterPaths[index]);
            } catch(UnsupportedCharacterException ucx){
                ucx.printStackTrace();
            }
        }
    }
    /** Adds a Character to this game.
     * @param characterPath The path to the Character file.
     * @param formatter The formatter to use to deserialize the Characters.
     */
    public void addCharacter(String characterPath,Formatter formatter){ 
        try{
            String absoluteCharacterPath=PathResolver.getAbsolutePath(this.absoluteDir,characterPath);
            this.characters.add(CharacterFactory.load(absoluteCharacterPath,formatter));
            this.characterPaths.add(characterPath);
        } catch(UnsupportedCharacterException ucx){
            ucx.printStackTrace();   
        }
    }    
    /** Absolute path to the directory where characters are saved. */
    protected transient String absoluteDir;
    /** Sets the absolute path to the directory where characters are saved.
     * @param absoluteDir The absolute path to the directory where characters are saved.
     */
    public void setAbsoluteDir(String absoluteDir){
        if(absoluteDir.endsWith(File.separator)){
            this.absoluteDir=absoluteDir;
        } else{
            this.absoluteDir=absoluteDir+File.separator;
        }
    }
/* end public properties */
    
/* begin public methods */
    /** Returns the character with the specified name.
     * Performs a case-insensitive search of character paths that end with name+".character.xml".
     * Probably not the best way to do this
     * @param name The name of the character to search for.
     * @return The character with the specified name, null if not found.
     */
    public Character getCharacter(String name){
        String searchName=new String(name.toLowerCase()+".character.xml");
        String[] paths=this.getCharacterPaths();
        int length=paths.length;
        for(int index=0;index<length;index++){
            if(paths[index].toLowerCase().endsWith(searchName)){
                return(this.characters.get(index));
            }
        }
        return(null);
    }
    /** Returns the Item with the specified name if it exists, otherwise null. 
     * @param path The name of the Item to retreive.
     * @return The Item with the specified name if it exists, otherwise null. 
     */
    public Item getItem(String path){
        return(this.availableItems.getItem(path));
    }
    /** The onDeserialize event should be fired after an object is de-serialized.
     * This allows objects to load transient members, set their working directory, and load Storable members if needed.
     * @param formatter the formatter to use to load any storable members
     * @param absoluteDir the working directory since all paths stored in the object should be relative
     */
    public void onDeserialize(Formatter formatter,String absoluteDir){
        this.setAbsoluteDir(absoluteDir);
        //call onDeserialize for items
        if(this.availableItems==null){
            this.availableItems=new ItemCollection();
        } else{
            Item[] allItems=this.availableItems.getAll();
            int length=allItems.length;
            for(int index=0;index<length;index++){
                allItems[index].onDeserialize(formatter,absoluteDir);
            }
        }
        //load characters
        String[] characterPaths=this.getCharacterPaths();
        int length=characterPaths.length;
        this.characters=new ArrayList<Character>(length);
        this.characterPaths=new ArrayList<String>(length);
        for(int index=0;index<length;index++){
            try{
                String absoluteCharacterPath=PathResolver.getAbsolutePath(this.absoluteDir,characterPaths[index]);
                Character character=CharacterFactory.load(absoluteCharacterPath,formatter);
                this.characters.add(character);
                this.characterPaths.add(characterPaths[index]);
            } catch(UnsupportedCharacterException ucx){
                ucx.printStackTrace();
            }
        }
        //load the script
        this.setScript(this.scriptPath,formatter);
        this.script.onDeserialize(formatter,absoluteDir);
    }
/* end public methods */     
}