package com.hero.ui.widgets;

// Import the GUI classes
import java.awt.*;
import java.awt.event.*;
import java.io.File;

import javax.swing.*;

import com.hero.HeroDesigner;
import com.hero.Prefab;
import com.hero.objects.GenericObject;
import com.hero.ui.SelectionList;

// Import the Java classes
import java.util.*;

/**
 * An OutlookBar provides a component that is similar to a JTabbedPane, but
 * instead of maintaining tabs, it uses Outlook-style bars to control the
 * visible component
 */
public class PrefabOutlookBar extends JPanel implements ActionListener {

	public static final int SKILLLIST = 1;
	public static final int TALENTLIST = 2;
	public static final int PERKLIST = 3;
	public static final int MANEUVERLIST = 4;
	public static final int POWERLIST = 5;
	public static final int DISADLIST = 6;
	public static final int EQUIPMENTLIST = 7;

	private int listType;
	/**
	 * The top panel: contains the buttons displayed on the top of the
	 * OutlookBar
	 */
	private JPanel topPanel = new JPanel(new GridLayout(1, 1));

	/**
	 * The bottom panel: contains the buttons displayed on the bottom of the
	 * OutlookBar
	 */
	private JPanel bottomPanel = new JPanel(new GridLayout(1, 1));

	/**
	 * A LinkedHashMap of bars: we use a linked hash map to preserve the order
	 * of the bars
	 */
	private Map bars = new LinkedHashMap();

	/**
	 * The currently visible bar (zero-based index)
	 */
	private int visibleBar = 0;

	private SelectionList visibleComponent = new SelectionList(
			new ArrayList<GenericObject>(), true);

	/**
	 * Creates a new JOutlookBar; after which you should make repeated calls to
	 * addBar() for each bar
	 */
	public PrefabOutlookBar(int type) {
		this.listType = type;
		this.setLayout(new BorderLayout());
		this.add(topPanel, BorderLayout.NORTH);
		this.add(visibleComponent, BorderLayout.CENTER);
		this.add(bottomPanel, BorderLayout.SOUTH);
	}

	/**
	 * Adds the specified component to the OutlookBar and sets the bar's name
	 * 
	 * @param name
	 *            The name of the outlook bar
	 * @param file
	 *            The prefab File reference
	 */
	public void addBar(String name, File file) {
		BarInfo barInfo = new BarInfo(name, file);
		barInfo.getButton().addActionListener(this);
		this.bars.put(name, barInfo);
		render();
	}

	/**
	 * Adds the specified component to the OutlookBar and sets the bar's name
	 * 
	 * @param name
	 *            The name of the outlook bar
	 * @param icon
	 *            An icon to display in the outlook bar
	 * @param file
	 *            The prefab file reference to add to the bar
	 */
	public void addBar(String name, Icon icon, File file) {
		BarInfo barInfo = new BarInfo(name, icon, file);
		barInfo.getButton().addActionListener(this);
		this.bars.put(name, barInfo);
		render();
	}

	/**
	 * Removes the specified bar from the JOutlookBar
	 * 
	 * @param name
	 *            The name of the bar to remove
	 */
	public void removeBar(String name) {
		this.bars.remove(name);
		render();
	}

	/**
	 * Returns the index of the currently visible bar (zero-based)
	 * 
	 * @return The index of the currently visible bar
	 */
	public int getVisibleBar() {
		return this.visibleBar;
	}

	/**
	 * Programmatically sets the currently visible bar; the visible bar index
	 * must be in the range of 0 to size() - 1
	 * 
	 * @param visibleBar
	 *            The zero-based index of the component to make visible
	 */
	public void setVisibleBar(int visibleBar) {
		if (visibleBar > 0 && visibleBar < this.bars.size() - 1) {
			this.visibleBar = visibleBar;
			render();
		}
	}

	/**
	 * Causes the outlook bar component to rebuild itself; this means that it
	 * rebuilds the top and bottom panels of bars as well as making the
	 * currently selected bar's panel visible
	 */
	public void render() {
		// Compute how many bars we are going to have where
		int totalBars = this.bars.size();
		int topBars = this.visibleBar + 1;
		int bottomBars = totalBars - topBars;

		// Get an iterator to walk through out bars with
		Iterator itr = this.bars.keySet().iterator();

		// Render the top bars: remove all components, reset the GridLayout to
		// hold to correct number of bars, add the bars, and "validate" it to
		// cause it to re-layout its components
		this.topPanel.removeAll();
		GridLayout topLayout = (GridLayout) this.topPanel.getLayout();
		topLayout.setRows(topBars);
		BarInfo barInfo = null;
		for (int i = 0; i < topBars; i++) {
			String barName = (String) itr.next();
			barInfo = (BarInfo) this.bars.get(barName);
			this.topPanel.add(barInfo.getButton());
		}
		this.topPanel.validate();

		// Render the bottom bars: remove all components, reset the GridLayout
		// to
		// hold to correct number of bars, add the bars, and "validate" it to
		// cause it to re-layout its components
		this.bottomPanel.removeAll();
		GridLayout bottomLayout = (GridLayout) this.bottomPanel.getLayout();
		bottomLayout.setRows(bottomBars);
		for (int i = 0; i < bottomBars; i++) {
			String barName = (String) itr.next();
			barInfo = (BarInfo) this.bars.get(barName);
			this.bottomPanel.add(barInfo.getButton());
		}
		this.bottomPanel.validate();

		// Validate all of our components: cause this container to re-layout its
		// subcomponents
		this.validate();
	}

	/**
	 * Invoked when one of our bars is selected
	 */
	public void actionPerformed(ActionEvent e) {
		int currentBar = 0;
		for (Iterator i = this.bars.keySet().iterator(); i.hasNext();) {
			String barName = (String) i.next();
			BarInfo barInfo = (BarInfo) this.bars.get(barName);
			if (barInfo.getButton() == e.getSource()) {
				// Found the selected button
				this.visibleBar = currentBar;
				visibleComponent.setAvailableList(barInfo.getPrefab());
				render();
			} else {
				barInfo.clearList();
			}
			currentBar++;
		}
	}

	/**
	 * Debug test...
	 */
	public static void main( String[] args )
  {
	  try {
	  HeroDesigner hd = HeroDesigner.getInstance();
	  hd.openHero(new File("C:\\Documents and Settings\\Dan Simon\\My Documents\\HDv3\\Acid Powers.hdp"), false);
    JFrame frame = new JFrame( "JOutlookBar Test" );
    PrefabOutlookBar outlookBar = new PrefabOutlookBar(5);

    outlookBar.addBar( "Acid Powers", new File("C:\\Documents and Settings\\Dan Simon\\My Documents\\HDv3\\Prefabs\\Acid Powers.hdp"));
    outlookBar.addBar( "Air and Wind Powers", new File("C:\\Documents and Settings\\Dan Simon\\My Documents\\HDv3\\Prefabs\\Air and Wind Powers.hdp"));
    outlookBar.addBar( "Animal Powers (Aquatic Powers)", new File("C:\\Documents and Settings\\Dan Simon\\My Documents\\HDv3\\Prefabs\\Animal Powers (Aquatic Powers).hdp"));
    outlookBar.addBar( "Animal Powers (Avian Powers)", new File("C:\\Documents and Settings\\Dan Simon\\My Documents\\HDv3\\Prefabs\\Animal Powers (Avian Powers).hdp"));
    outlookBar.addBar( "Animal Powers (General)", new File("C:\\Documents and Settings\\Dan Simon\\My Documents\\HDv3\\Prefabs\\Animal Powers (General).hdp"));
    outlookBar.addBar( "Body Control Powers", new File("C:\\Documents and Settings\\Dan Simon\\My Documents\\HDv3\\Prefabs\\Body Control Powers.hdp"));

    outlookBar.setVisibleBar( 2 );
    frame.getContentPane().add( outlookBar );

    frame.setSize( 800, 600 );
    Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
    frame.setLocation( d.width / 2 - 400, d.height / 2 - 300 );
    frame.setVisible( true );
    frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
	  } catch(Exception exp) {
		  exp.printStackTrace();
	  }
  }

	/**
	 * Internal class that maintains information about individual Outlook bars;
	 * specifically it maintains the following information:
	 * 
	 * name The name of the bar button The associated JButton for the bar
	 * component The component maintained in the Outlook bar
	 */
	class BarInfo {
		/**
		 * The name of this bar
		 */
		private String name;

		/**
		 * The JButton that implements the Outlook bar itself
		 */
		private JButton button;

		/**
		 * The component that is the body of the Outlook bar
		 */
		private ArrayList<GenericObject> availableList;

		private File file;

		/**
		 * Creates a new BarInfo
		 * 
		 * @param name
		 *            The name of the bar
		 * @param file
		 *            The file reference to the prefab
		 */
		public BarInfo(String name, File file) {
			this.name = name;
			this.file = file;
			this.button = new JButton(name);
		}

		/**
		 * Creates a new BarInfo
		 * 
		 * @param name
		 *            The name of the bar
		 * @param icon
		 *            JButton icon
		 * @param file
		 *            The file reference to the prefab
		 */
		public BarInfo(String name, Icon icon, File file) {
			this.name = name;
			this.file = file;
			this.button = new JButton(name, icon);
		}

		/**
		 * Returns the name of the bar
		 * 
		 * @return The name of the bar
		 */
		public String getName() {
			return this.name;
		}

		/**
		 * Sets the name of the bar
		 * 
		 * @param The
		 *            name of the bar
		 */
		public void setName(String name) {
			this.name = name;
		}

		/**
		 * Returns the outlook bar JButton implementation
		 * 
		 * @return The Outlook Bar JButton implementation
		 */
		public JButton getButton() {
			return this.button;
		}

		public void clearList() {
			availableList = null;
		}

		public ArrayList<GenericObject> getPrefab() {
			if (availableList != null)
				return availableList;
			System.out.println("Loading prefab...");
			Prefab prefab = new Prefab(file);
			System.out.println(prefab.getPowers().size());
			switch (listType) {
			case SKILLLIST:
				availableList = prefab.getSkills();
				break;
			case TALENTLIST:
				availableList = prefab.getTalents();
				break;
			case PERKLIST:
				availableList = prefab.getPerks();
				break;
			case MANEUVERLIST:
				availableList = prefab.getManeuvers();
				break;
			case POWERLIST:
				availableList = prefab.getPowers();
				break;
			case EQUIPMENTLIST:
				availableList = prefab.getEquipment();
				break;
			case DISADLIST:
				availableList = prefab.getDisads();
				break;
			}
			System.out.println("List size = "+availableList.size());
			return availableList;
		}
	}
}