/*
Tiamat - a role-playing game framework
EventListPanel.java - A panel used to edit a list of events
    
 Copyright  (C) 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.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.BoxLayout;
import javax.swing.DefaultListModel;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JToolBar;
import javax.swing.border.TitledBorder;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

import com.huguesjohnson.tiamat.Event;
import com.huguesjohnson.tiamat.StringTable;

/** EventListPanel - A panel used to edit a list of events
 * @author Hugues Johnson
 */
public class EventListPanel extends JPanel{
	/* 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=983394054830620844L;
	
	//used to store items in the list
	private class ListEntry{
		public Event event;
		public ListEntry(){ /* used for cloneEntry() */ }
		public ListEntry(Event event){
			this.event=event;
		}
		public String toString(){ return(this.event.getAction()); }
		public ListEntry cloneEntry(){
			ListEntry clone=new ListEntry();
			StringTable cloneTable=new StringTable();
			String[][] stringTable=this.event.getParameters().getAll();
			if(stringTable!=null){
				if(stringTable.length==2){
					int length=stringTable[0].length;
					for(int index=0;index<length;index++){
						cloneTable.set(stringTable[0][index],stringTable[1][index]);
					}
				}
			}
			clone.event=new Event(this.event.getAction(),this.event.getParameters());
			return(clone);
		}
	}
	
	private EventPanel eventPanel;
	private JButton addButton;
	private JButton removeButton;
	private JButton upButton;
	private JButton downButton;
	private JList eventList;
	private int currentEventIndex;
	
	public EventListPanel(){
		this.initComponents();
		this.currentEventIndex=-1;
	}

	public EventListPanel(Event[] eventList){
		this.initComponents();
		this.currentEventIndex=-1;
		this.setEventList(eventList);
	}
	
	private void initComponents(){
		//set the layout
		this.setLayout(new BoxLayout(this,BoxLayout.Y_AXIS));
			
		//create the navigation panel
		JPanel navigationPanel=new JPanel();
		navigationPanel.setLayout(new BoxLayout(navigationPanel,BoxLayout.Y_AXIS));
		navigationPanel.setBorder(new TitledBorder("Events"));
		this.eventList=new JList();
		this.eventList.setMinimumSize(new Dimension(120,240));
		this.eventList.setPreferredSize(new Dimension(120,240));
		this.eventList.addListSelectionListener(new ListSelectionListener(){
			public void valueChanged(ListSelectionEvent e){
				onListSelectionChanged(e);
			}
       	});	
		this.eventList.setModel(new DefaultListModel());
		JScrollPane scrollPane=new JScrollPane(this.eventList);
		navigationPanel.add(scrollPane);
		JPanel buttonPanel=new JPanel();
		buttonPanel.setLayout(new BoxLayout(buttonPanel,BoxLayout.X_AXIS));
		JToolBar toolBar=new JToolBar();
        toolBar.setFloatable(false);
        toolBar.setRollover(true);
        this.addButton=new JButton();
        this.addButton.setIcon(new ImageIcon(this.getClass().getResource("/com/huguesjohnson/tiamat/tools/images/plus.gif")));
        this.addButton.setToolTipText("Add new Event");
        this.addButton.setEnabled(true);
        this.addButton.addActionListener(new ActionListener(){
            public void actionPerformed(ActionEvent actionEvent){
                onAdd();
            }
       	});
		toolBar.add(this.addButton);
		this.removeButton=new JButton();
		this.removeButton.setIcon(new ImageIcon(this.getClass().getResource("/com/huguesjohnson/tiamat/tools/images/minus.gif")));
		this.removeButton.setToolTipText("Delete selected Event");
        this.removeButton.setEnabled(false);
		this.removeButton.addActionListener(new ActionListener(){
            public void actionPerformed(ActionEvent actionEvent){
            	onRemove();
            }
		});
		toolBar.add(this.removeButton);
		toolBar.addSeparator();
		this.upButton=new JButton();
		this.upButton.setIcon(new ImageIcon(this.getClass().getResource("/com/huguesjohnson/tiamat/tools/images/up.gif")));
		this.upButton.setToolTipText("Move selected Event up");
		this.upButton.setEnabled(false);
		this.upButton.addActionListener(new ActionListener(){
            public void actionPerformed(ActionEvent actionEvent){
                onUp();
            }
        });
		toolBar.add(this.upButton);
		this.downButton=new JButton();
		this.downButton.setIcon(new ImageIcon(this.getClass().getResource("/com/huguesjohnson/tiamat/tools/images/down.gif")));
		this.downButton.setToolTipText("Move selected Event down");
		this.downButton.setEnabled(false);
		this.downButton.addActionListener(new ActionListener(){
            public void actionPerformed(ActionEvent actionEvent){
            	onDown();
            }
        });
		toolBar.add(this.downButton);
		buttonPanel.add(toolBar);
		navigationPanel.add(buttonPanel);
			
		//create the current event panel
		this.eventPanel=new EventPanel();
		
		//now add a split pane to how the navigation and current frame panel
		JPanel panel=new JPanel();
		panel.setLayout(new BoxLayout(panel,BoxLayout.X_AXIS));
		JSplitPane splitPane=new JSplitPane(JSplitPane.HORIZONTAL_SPLIT,navigationPanel,this.eventPanel);
		splitPane.setDividerLocation(150);
		panel.add(splitPane);
		this.add(panel);
	}

	public void onListSelectionChanged(ListSelectionEvent e){
		if(e.getValueIsAdjusting()==false){
			int selectedIndex=this.eventList.getSelectedIndex();
			if((selectedIndex==this.currentEventIndex)){ return; }
			DefaultListModel listModel=(DefaultListModel)this.eventList.getModel();
			//save the previous frame
			if(this.currentEventIndex>=0){
				this.saveSelectedEvent();
			}
			//load the new one
			if(selectedIndex>=0){
				Event currentEvent=((ListEntry)listModel.get(selectedIndex)).event;
				this.eventPanel.setEvent(currentEvent);
			}
			//check which buttons should be enabled
			if(listModel.size()>1){ 
				this.removeButton.setEnabled(true); 
			} else{
				this.removeButton.setEnabled(false); 
			}
			this.upButton.setEnabled(selectedIndex>0);
			this.downButton.setEnabled(selectedIndex<(listModel.size()-1));
			//set the current frame index
			this.currentEventIndex=selectedIndex;
		}
	}
	
	public void onAdd(){ 
		DefaultListModel listModel=(DefaultListModel)this.eventList.getModel();
		ListEntry entry=new ListEntry(new Event("New Event"));
		listModel.addElement(entry);
		this.eventList.setSelectedIndex(listModel.getSize()-1);
	}
	
	public void onRemove(){
		this.currentEventIndex=-1; //this will be updated when the selection change event fires after the remove
		//remove the selected item
		int removeIndex=this.eventList.getSelectedIndex();
		DefaultListModel listModel=(DefaultListModel)this.eventList.getModel();
		listModel.remove(removeIndex);
		if(removeIndex>=listModel.getSize()){ removeIndex--; }
		this.eventList.setSelectedIndex(removeIndex);
	}
	
	public void onUp(){
		//save the current event
		this.saveSelectedEvent();
		//get the frames that need to be swapped
		int selectedIndex=this.eventList.getSelectedIndex();
		DefaultListModel listModel=(DefaultListModel)this.eventList.getModel();
		ListEntry selectedEntry=((ListEntry)listModel.getElementAt(selectedIndex)).cloneEntry();
		ListEntry swapEntry=((ListEntry)listModel.getElementAt(selectedIndex-1)).cloneEntry();
		//swap the frames
		listModel.setElementAt(swapEntry,selectedIndex);
		listModel.setElementAt(selectedEntry,selectedIndex-1);
		//follow the frame that was moved up
		this.currentEventIndex=-1;
		this.eventList.setSelectedIndex(selectedIndex-1);
	}

	public void onDown(){
		//save the current frame
		this.saveSelectedEvent();
		//get the frames that need to be swapped
		int selectedIndex=this.eventList.getSelectedIndex();
		DefaultListModel listModel=(DefaultListModel)this.eventList.getModel();
		ListEntry selectedEntry=((ListEntry)listModel.getElementAt(selectedIndex)).cloneEntry();
		ListEntry swapEntry=((ListEntry)listModel.getElementAt(selectedIndex+1)).cloneEntry();
		//swap the frames
		listModel.setElementAt(swapEntry,selectedIndex);
		listModel.setElementAt(selectedEntry,selectedIndex+1);
		//follow the frame that was moved up
		this.currentEventIndex=-1;
		this.eventList.setSelectedIndex(selectedIndex+1);
	}
		
	public void saveSelectedEvent(){
		DefaultListModel listModel=(DefaultListModel)this.eventList.getModel();
		listModel.setElementAt(new ListEntry(this.eventPanel.getEvent()),this.currentEventIndex);
	}	
	
	public Event[] getEventList(){
		DefaultListModel listModel=(DefaultListModel)this.eventList.getModel();
		int length=listModel.size();
		if(length<=0){ return(new Event[0]); }
		Event[] eventList=new Event[length];
		for(int index=0;index<length;index++){
			eventList[index]=((ListEntry)listModel.getElementAt(index)).event;
		}
		return(eventList);
	}
	
	public void setEventList(Event[] eventList){
		DefaultListModel listModel=new DefaultListModel();
		int length=eventList.length;
		for(int index=0;index<length;index++){
			listModel.addElement(new ListEntry(eventList[index]));
		}
		this.eventList.setModel(listModel);
	}
	
}