/*
 Tiamat - a role-playing game framework
 CharacterEditorFrame.java - main window for editing a Character
 
 Copyright  (C) 2004-2006 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.tools;

import java.awt.BorderLayout;
import java.awt.Dimension;
import javax.swing.BoxLayout;
import javax.swing.ButtonGroup;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.border.TitledBorder;
import javax.swing.filechooser.FileFilter;
import com.huguesjohnson.PathResolver;
import com.huguesjohnson.fileFilter.XmlFileFilter;
import com.huguesjohnson.serialization.XmlFormatter;
import com.huguesjohnson.tiamat.Attribute;
import com.huguesjohnson.tiamat.AttributeCollection;
import com.huguesjohnson.tiamat.Character;
import com.huguesjohnson.tiamat.CharacterFactory;
import com.huguesjohnson.tiamat.Item;
import com.huguesjohnson.tiamat.ItemCollection;
import com.huguesjohnson.tiamat.NonPlayerCharacter;
import com.huguesjohnson.tiamat.PlayerCharacter;
import com.huguesjohnson.tiamat.Skill;
import com.huguesjohnson.tiamat.SkillCollection;
import com.huguesjohnson.tiamat.StringTable;
import com.huguesjohnson.ui.FileBrowsePanel;
import com.huguesjohnson.ui.ImageBrowsePanel;

/**
 * CharacterEditorFrame - main window for editing a Character
 * @author Hugues Johnson
 */
public class CharacterEditorFrame extends BaseEditorFrame{
	/* Determines if a de-serialized file is compatible with this class. See <a href="http://java.sun.com/j2se/1.5.0/docs/guide/serialization/spec/class.html">Java Object Serialization Specifications</a>. */
	private static final long serialVersionUID=1207729338647204688L;

	private ProfileListPanel profilePanel;
	private AttributeListPanel attributePanel;
	private ItemListPanel itemPanel;
	private SkillListPanel skillPanel;
	private ImageBrowsePanel fullSizeImagePanel;
	private ImageBrowsePanel thumbnailImagePanel;
	private FileBrowsePanel characterFilePanel;
	private FileBrowsePanel spriteFilePanel;
	private ButtonGroup buttonGroupClass;
	private JPanel panelCharacterAndSprite;
	private JPanel panelCharacterFileSpriteFile;
	private JPanel panelClass;
	private JPanel panelFullSizeImageThumbnailImage;
	private JPanel panelProfileAttributes;
	private JPanel panelSkillsItems;
	private JRadioButton radioButtonNonPlayerCharacter;
	private JRadioButton radioButtonPlayerCharacter;

	/**
	 * Creates new form CharacterEditorFrame
	 */
	public CharacterEditorFrame(){
		super("Character");
	}

	/**
	 * Creates new form CharacterEditorFrame
	 * @param filePath the character file to load
	 */
	public CharacterEditorFrame(String filePath){
		super("Character");
		// open the character file
		this.openCharacter(filePath);
	}

	public void initComponents(){
		this.panelContent.setLayout(new BoxLayout(this.panelContent,BoxLayout.Y_AXIS));

		this.panelCharacterFileSpriteFile=new JPanel();
		this.panelCharacterFileSpriteFile.setLayout(new BoxLayout(this.panelCharacterFileSpriteFile,BoxLayout.X_AXIS));
		this.panelCharacterAndSprite=new JPanel();
		this.panelCharacterAndSprite.setLayout(new BoxLayout(this.panelCharacterAndSprite,BoxLayout.Y_AXIS));
		this.panelCharacterFileSpriteFile.add(this.panelCharacterAndSprite);

		this.panelClass=new JPanel();
		this.panelClass.setLayout(new BorderLayout());
		this.panelClass.setBorder(new TitledBorder("Class"));
		this.panelClass.setMaximumSize(new Dimension(160,2147483647));
		this.panelClass.setMinimumSize(new Dimension(160,73));
		this.panelClass.setPreferredSize(new Dimension(160,73));
		
		this.buttonGroupClass=new ButtonGroup();
		this.radioButtonNonPlayerCharacter=new JRadioButton();
		this.radioButtonNonPlayerCharacter.setSelected(true);
		this.radioButtonNonPlayerCharacter.setText("NonPlayerCharacter");
		this.radioButtonNonPlayerCharacter.setToolTipText("Set class to NonPlayerCharacter");
		this.radioButtonNonPlayerCharacter.setMaximumSize(new Dimension(85,23));
		this.radioButtonNonPlayerCharacter.setMinimumSize(new Dimension(85,23));
		this.radioButtonNonPlayerCharacter.setPreferredSize(new Dimension(85,23));
		this.buttonGroupClass.add(this.radioButtonNonPlayerCharacter);
		this.panelClass.add(this.radioButtonNonPlayerCharacter,BorderLayout.CENTER);
		
		this.radioButtonPlayerCharacter=new JRadioButton();
		this.radioButtonPlayerCharacter.setText("PlayerCharacter");
		this.radioButtonPlayerCharacter.setToolTipText("Set class to PlayerCharacter");
		this.radioButtonPlayerCharacter.setMaximumSize(new Dimension(85,23));
		this.radioButtonPlayerCharacter.setMinimumSize(new Dimension(85,23));
		this.radioButtonPlayerCharacter.setPreferredSize(new Dimension(85,23));
		this.buttonGroupClass.add(this.radioButtonPlayerCharacter);
		this.panelClass.add(this.radioButtonPlayerCharacter,BorderLayout.NORTH);

		this.panelCharacterFileSpriteFile.add(this.panelClass);
		this.panelContent.add(this.panelCharacterFileSpriteFile);

		this.panelFullSizeImageThumbnailImage=new JPanel();
		this.panelFullSizeImageThumbnailImage.setLayout(new BoxLayout(this.panelFullSizeImageThumbnailImage,BoxLayout.X_AXIS));
		this.panelContent.add(this.panelFullSizeImageThumbnailImage);

		this.panelProfileAttributes=new JPanel();
		this.panelProfileAttributes.setLayout(new BoxLayout(this.panelProfileAttributes,BoxLayout.X_AXIS));
		this.panelContent.add(this.panelProfileAttributes);

		this.panelSkillsItems=new JPanel();
		this.panelSkillsItems.setLayout(new javax.swing.BoxLayout(this.panelSkillsItems,BoxLayout.X_AXIS));

		this.panelContent.add(this.panelSkillsItems);

		FileFilter[] filters=new FileFilter[1];
		filters[0]=new XmlFileFilter();
		// add character file and sprite file panels to panelCharacterFileSpriteFile
		this.characterFilePanel=new FileBrowsePanel("Character File",filters,false);
		this.panelCharacterAndSprite.add(this.characterFilePanel);
		this.spriteFilePanel=new FileBrowsePanel("Sprite File",filters);
		this.panelCharacterAndSprite.add(this.spriteFilePanel);
		// add full size and thumbnail panels
		this.fullSizeImagePanel=new ImageBrowsePanel("Full Size Image");
		this.panelFullSizeImageThumbnailImage.add(this.fullSizeImagePanel);
		this.thumbnailImagePanel=new ImageBrowsePanel("Thumbnail Image");
		this.panelFullSizeImageThumbnailImage.add(this.thumbnailImagePanel);
		// add profile and attributes panels to panelProfileAttributes
		this.profilePanel=new ProfileListPanel();
		this.panelProfileAttributes.add(this.profilePanel);
		this.attributePanel=new AttributeListPanel();
		this.panelProfileAttributes.add(this.attributePanel);
		// add skills and items panels to panelSkillsItems
		this.skillPanel=new SkillListPanel();
		this.panelSkillsItems.add(this.skillPanel);
		this.itemPanel=new ItemListPanel(new String(""));
		this.panelSkillsItems.add(this.itemPanel);
		// pack so everything should be visible
		this.pack();
		// disable save by default
		this.disableSave();
	}

	public void onViewXml(){
		String filePath="file:///"+this.characterFilePanel.getFilePath();
		this.viewXml(filePath);
	}

	protected void onNew(){
		// reset the sprite
		this.spriteFilePanel.clear();
		// reset the thumbnail image
		this.thumbnailImagePanel.clear();
		// reset the full size image
		this.fullSizeImagePanel.clear();
		// reset the profile
		this.profilePanel.clear();
		// reset the attributes
		this.attributePanel.clear();
		// reset the items
		this.itemPanel.clear();
		// reset the skills
		this.skillPanel.clear();
		// disable save
		this.disableSave();
		//clear the character file panel
		this.characterFilePanel.clear();
	}

	private void loadCharacter(Character character){
		// clear out everything
		this.onNew();
		// set the class
		if(character instanceof PlayerCharacter){
			this.radioButtonPlayerCharacter.setSelected(true);
		} else{
			this.radioButtonNonPlayerCharacter.setSelected(true);
		}
		// set the sprite
		this.spriteFilePanel.setFilePath(character.getSpritePath());
		// set the thumbnail image
		this.thumbnailImagePanel.setImage(character.getThumbnailImagePathAbsolute());
		// set the full size image
		this.fullSizeImagePanel.setImage(character.getFullImagePathAbsolute());
		// set the profile
		this.profilePanel.clear();
		String[][] keyValuePairs=character.getProfile().getAll();
		int length=keyValuePairs[0].length;
		for(int index=0;index<length;index++){
			this.profilePanel.addProfileElement(keyValuePairs[0][index],keyValuePairs[1][index]);
		}
		// set the attributes
		this.attributePanel.clear();
		Attribute[] attributes=character.getAttributes().getAll();
		length=attributes.length;
		for(int index=0;index<length;index++){
			this.attributePanel.addAttribute(attributes[index]);
		}
		// set the items
		this.itemPanel.clear();
		Item[] items=character.getItems().getAll();
		length=items.length;
		for(int index=0;index<length;index++){
			this.itemPanel.addItem(items[index]);
		}
		// set the skills
		this.skillPanel.clear();
		Skill[] skills=character.getSkills().getAll();
		length=skills.length;
		for(int index=0;index<length;index++){
			this.skillPanel.addSkill(skills[index]);
		}
	}

	protected void onOpen(){
		boolean success=true;
		String currentFilePath=new String(this.characterFilePanel.getFilePath());
		if(this.characterFilePanel.browse()){
			String newFilePath=new String(this.characterFilePanel.getFilePath());
			success=this.openCharacter(newFilePath);
			// if the open operation failed set the file path back to the old one
			if(!success){
				this.characterFilePanel.setFilePath(currentFilePath);
			} else{
				this.addRecentFile(newFilePath);
			}
		}
	}

	protected void onRecentFile(String filePath){
		boolean success=true;
		String currentFilePath=new String(this.characterFilePanel.getFilePath());
		success=this.openCharacter(filePath);
		// if the open operation failed set the file path back to the old one
		if(!success){
			this.characterFilePanel.setFilePath(currentFilePath);
		}
	}
	
	private boolean openCharacter(String filePath){
		boolean success=true;
		String currentFilePath=new String(this.characterFilePanel.getFilePath());
		// update the character file panel if needed
		if(!currentFilePath.equals(filePath)){
			this.characterFilePanel.setFilePath(filePath);
		}
		// try loading the character
		try{
			XmlFormatter formatter=new XmlFormatter();
			Character character=CharacterFactory.load(filePath,formatter);
			// set working directories
			String absoluteDir=this.characterFilePanel.getDirectory();
			// load the character into the ui
			this.loadCharacter(character);
			this.characterFilePanel.setFilePath(filePath); //TODO load character deletes this, need to find a better fix
			// set the working directory for items after the items are loaded into the list
			this.itemPanel.setAbsoluteDir(absoluteDir);
			// enable save
			this.enableSave();
		} catch(Exception x){
			x.printStackTrace();
			success=false;
		}
		return(success);
	}

	protected void onSaveAs(){
		if(this.characterFilePanel.browse()){
			String filePath=this.characterFilePanel.getFilePath();
			if(!filePath.toLowerCase().endsWith(".character.xml")){
				this.characterFilePanel.setFilePath(filePath+".character.xml");
			}
			this.onSave();
			this.enableSave();
			this.addRecentFile(filePath);
		}
	}

	public void onSave(){
		XmlFormatter formatter=new XmlFormatter();
		Character character;
		if(this.radioButtonPlayerCharacter.isSelected()){
			character=new PlayerCharacter();
		} else{
			character=new NonPlayerCharacter();
		}
		// get the directory the file is being saved in
		String absoluteDir=this.characterFilePanel.getDirectory();
		character.setAbsoluteDir(absoluteDir);
		this.itemPanel.setAbsoluteDir(absoluteDir);
		// set the sprite
		String spritePathAbsolute=this.spriteFilePanel.getFilePath();
		if((spritePathAbsolute!=null)&&(spritePathAbsolute.length()>0)){
			String spritePathRelative=PathResolver.getRelativePath(absoluteDir,spritePathAbsolute);
			character.setSpritePath(spritePathRelative,formatter);
		}
		// full size image
		String fullImagePathAbsolute=this.fullSizeImagePanel.getImagePath();
		if((fullImagePathAbsolute!=null)&&(fullImagePathAbsolute.length()>0)){
			String fullImagePathRelative=PathResolver.getRelativePath(absoluteDir,fullImagePathAbsolute);
			character.setFullImagePath(fullImagePathRelative);
		}
		// thumbnail image
		String thumbnailImagePathAbsolute=this.thumbnailImagePanel.getImagePath();
		if((thumbnailImagePathAbsolute!=null)&&(thumbnailImagePathAbsolute.length()>0)){
			String thumbnailImagePathRelative=PathResolver.getRelativePath(absoluteDir,thumbnailImagePathAbsolute);
			character.setThumbnailImagePath(thumbnailImagePathRelative);
		}
		// set the profile
		String[][] keyValuePairs=this.profilePanel.getAllKeyValuePairs();
		if(keyValuePairs.length==2){
			int length=keyValuePairs[0].length;
			if(length==keyValuePairs[1].length){
				StringTable stringTable=new StringTable();
				for(int index=0;index<length;index++){
					stringTable.set(keyValuePairs[0][index],keyValuePairs[1][index]);
				}
				character.setProfile(stringTable);
			}
		}
		// set the attributes
		character.setAttributes(new AttributeCollection(this.attributePanel.getAllAttributes()));
		// set the skills
		character.setSkills(new SkillCollection(this.skillPanel.getAllSkills()));
		// set the items
		character.setItems(new ItemCollection(this.itemPanel.getAllItems()));
		// now try saving
		try{
			formatter.saveTo(character,this.characterFilePanel.getFilePath());
		} catch(Exception x){
			x.printStackTrace();
			JOptionPane.showMessageDialog(this,"Error saving character:"+x.getMessage(),"Error",JOptionPane.ERROR_MESSAGE);
		}
	}

	/**
	 * create a new CharacterEditorFrame
	 * @param args the command line arguments
	 */
	public static void main(String args[]){
		try{
			(new CharacterEditorFrame()).setVisible(true);
		} catch(Exception x){
			x.printStackTrace();			
		}
	}
}