/*
 *  Initiative - A role playing utility to track turns
 *  Copyright (C) 2002 Devon D Jones
 *
 *  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., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 *  The author of this program grants you the ability to use this code
 *  in conjunction with code that is covered under the Open Gaming License
 *
 * Initiative.java
 *
 * Created on September 18, 2002, 4:36 PM
 */

package org.evilsoft.gaming.Init;

import org.jdom.*;
import org.jdom.input.*;
import org.jdom.output.*;
import java.util.prefs.*;
import java.util.*;
import java.io.*;
import javax.swing.JOptionPane;
import org.evilsoft.gaming.System.SystemInitiative;
import org.evilsoft.gaming.System.SystemAttribute;
import org.evilsoft.gaming.System.SystemHP;

/**
 *
 * @author  Devon Jones
 */
public class Initiative extends javax.swing.JPanel {

    /** Creates new form Initiative */
    public Initiative() {
        initComponents();
        initDynamicComponents();
        initPrefs();
        initTable();
        initLast();
        addTableListener();
        jSplitPane1.setOneTouchExpandable(true);
    }

    public Initiative(java.awt.Frame main) {
        mainFrame = main;
        initComponents();
        initDynamicComponents();
        initPrefs();
        initTable();
        initLast();
        addTableListener();
        jSplitPane1.setOneTouchExpandable(true);
    }
    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    private void initComponents() {//GEN-BEGIN:initComponents
        tablePopup = new javax.swing.JPopupMenu();
        tablePopupCBNumber = new javax.swing.JCheckBoxMenuItem();
        tablePopupCBName = new javax.swing.JCheckBoxMenuItem();
        tablePopupCBPlayer = new javax.swing.JCheckBoxMenuItem();
        tablePopupCBStatus = new javax.swing.JCheckBoxMenuItem();
        tablePopupCBPlus = new javax.swing.JCheckBoxMenuItem();
        tablePopupCBInitiative = new javax.swing.JCheckBoxMenuItem();
        tablePopupCBDuration = new javax.swing.JCheckBoxMenuItem();
        tablePopupCBHP = new javax.swing.JCheckBoxMenuItem();
        tablePopupCBHPMax = new javax.swing.JCheckBoxMenuItem();
        jToolBar1 = new javax.swing.JToolBar();
        jPanel10 = new javax.swing.JPanel();
        bRoll = new javax.swing.JButton();
        bAddCombatant = new javax.swing.JButton();
        bNextInit = new javax.swing.JButton();
        bRefocus = new javax.swing.JButton();
        bCombatantReRoll = new javax.swing.JButton();
        bDelete = new javax.swing.JButton();
        jPanel2 = new javax.swing.JPanel();
        lCounter = new javax.swing.JLabel();
        jSplitPane1 = new javax.swing.JSplitPane();
        jScrollPane1 = new javax.swing.JScrollPane();
        combatantTable = new javax.swing.JTable();
        jScrollPane2 = new javax.swing.JScrollPane();
        tpaneInfo = new javax.swing.JTabbedPane();
        tpCombatInfo = new javax.swing.JTextArea();
        jToolBar2 = new javax.swing.JToolBar();

        tablePopupCBNumber.setText("#");
        tablePopupCBNumber.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                TablePopupActionPerformed(evt);
            }
        });

        tablePopup.add(tablePopupCBNumber);
        tablePopupCBName.setText("Name");
        tablePopupCBName.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                TablePopupActionPerformed(evt);
            }
        });

        tablePopup.add(tablePopupCBName);
        tablePopupCBPlayer.setText("Player");
        tablePopupCBPlayer.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                TablePopupActionPerformed(evt);
            }
        });

        tablePopup.add(tablePopupCBPlayer);
        tablePopupCBStatus.setText("Status");
        tablePopupCBStatus.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                TablePopupActionPerformed(evt);
            }
        });

        tablePopup.add(tablePopupCBStatus);
        tablePopupCBPlus.setText("Plus");
        tablePopupCBPlus.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                TablePopupActionPerformed(evt);
            }
        });

        tablePopup.add(tablePopupCBPlus);
        tablePopupCBInitiative.setText("Initiative");
        tablePopupCBInitiative.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                TablePopupActionPerformed(evt);
            }
        });

        tablePopup.add(tablePopupCBInitiative);
        tablePopupCBDuration.setText("Duration");
        tablePopupCBDuration.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                TablePopupActionPerformed(evt);
            }
        });

        tablePopup.add(tablePopupCBDuration);
        tablePopupCBHP.setText("HP");
        tablePopupCBHP.setEnabled(false);
        tablePopupCBHP.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                TablePopupActionPerformed(evt);
            }
        });

        tablePopup.add(tablePopupCBHP);
        tablePopupCBHPMax.setText("HP Max");
        tablePopupCBHPMax.setEnabled(false);
        tablePopupCBHPMax.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                TablePopupActionPerformed(evt);
            }
        });

        tablePopup.add(tablePopupCBHPMax);

        setLayout(new java.awt.BorderLayout());

        setPreferredSize(new java.awt.Dimension(700, 600));
        jPanel10.setLayout(new javax.swing.BoxLayout(jPanel10, javax.swing.BoxLayout.X_AXIS));

        bRoll.setText("Roll");
        bRoll.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                bRollActionPerformed(evt);
            }
        });

        jPanel10.add(bRoll);

        bAddCombatant.setText("Add Combatant");
        bAddCombatant.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                bAddCombatantActionPerformed(evt);
            }
        });

        jPanel10.add(bAddCombatant);

        bNextInit.setText("Next Initiative");
        bNextInit.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                bNextInitActionPerformed(evt);
            }
        });

        jPanel10.add(bNextInit);

        bRefocus.setText("Refocus");
        bRefocus.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                bRefocusActionPerformed(evt);
            }
        });

        jPanel10.add(bRefocus);

        bCombatantReRoll.setText("Reroll");
        bCombatantReRoll.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                bCombatantReRollActionPerformed(evt);
            }
        });

        jPanel10.add(bCombatantReRoll);

        bDelete.setText("Delete");
        bDelete.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                bDeleteActionPerformed(evt);
            }
        });

        jPanel10.add(bDelete);

        jToolBar1.add(jPanel10);

        jToolBar1.add(jPanel2);

        lCounter.setFont(new java.awt.Font("Dialog", 0, 18));
        jToolBar1.add(lCounter);

        add(jToolBar1, java.awt.BorderLayout.NORTH);

        jSplitPane1.setDividerLocation(400);
        jSplitPane1.setOneTouchExpandable(true);
        jSplitPane1.setPreferredSize(new java.awt.Dimension(800, 405));
        combatantTable.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mousePressed(java.awt.event.MouseEvent evt) {
                combatantTableMousePressed(evt);
            }
            public void mouseReleased(java.awt.event.MouseEvent evt) {
                combatantTableMouseReleased(evt);
            }
        });

        combatantTable.addPropertyChangeListener(new java.beans.PropertyChangeListener() {
            public void propertyChange(java.beans.PropertyChangeEvent evt) {
                combatantTablePropertyChange(evt);
            }
        });

        jScrollPane1.setViewportView(combatantTable);

        jSplitPane1.setLeftComponent(jScrollPane1);

        tpaneInfo.addTab("Combat", null, tpCombatInfo, "");

        jScrollPane2.setViewportView(tpaneInfo);

        jSplitPane1.setRightComponent(jScrollPane2);

        add(jSplitPane1, java.awt.BorderLayout.CENTER);

        add(jToolBar2, java.awt.BorderLayout.SOUTH);

    }//GEN-END:initComponents

    private void combatantTablePropertyChange(java.beans.PropertyChangeEvent evt) {//GEN-FIRST:event_combatantTablePropertyChange
        editTableRow();
        refreshTable();
    }//GEN-LAST:event_combatantTablePropertyChange

    private void combatantTableMouseReleased(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_combatantTableMouseReleased
        if (evt.isPopupTrigger()) {
            initTablePopup();
            tablePopup.show(evt.getComponent(), evt.getX(), evt.getY());
        }
    }//GEN-LAST:event_combatantTableMouseReleased

    private void bDeleteActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bDeleteActionPerformed
        deleteCombatant();
        focusNextInit();
    }//GEN-LAST:event_bDeleteActionPerformed

    private void bCombatantReRollActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bCombatantReRollActionPerformed
        rerollCombatant();
        focusNextInit();
    }//GEN-LAST:event_bCombatantReRollActionPerformed

    private void bRefocusActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bRefocusActionPerformed
        refocusCombatant();
        focusNextInit();
    }//GEN-LAST:event_bRefocusActionPerformed

    private void bNextInitActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bNextInitActionPerformed
        nextInit();
    }//GEN-LAST:event_bNextInitActionPerformed

    private void bAddCombatantActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bAddCombatantActionPerformed
        addCombatant();
    }//GEN-LAST:event_bAddCombatantActionPerformed

    private void bRollActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bRollActionPerformed
        roll();
        focusNextInit();
    }//GEN-LAST:event_bRollActionPerformed

    private void combatantTableMousePressed(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_combatantTableMousePressed
        if (evt.isPopupTrigger()) {
            initTablePopup();
            tablePopup.show(evt.getComponent(), evt.getX(), evt.getY());
        }
    }//GEN-LAST:event_combatantTableMousePressed

    private void TablePopupActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_TablePopupActionPerformed
        checkAndFixColumns(tablePopupCBName.getState(), "Name");
        checkAndFixColumns(tablePopupCBPlayer.getState(), "Player");
        checkAndFixColumns(tablePopupCBStatus.getState(), "Status");
        checkAndFixColumns(tablePopupCBPlus.getState(), "+");
        checkAndFixColumns(tablePopupCBInitiative.getState(), "Init");
        checkAndFixColumns(tablePopupCBDuration.getState(), "Dur");
        checkAndFixColumns(tablePopupCBHP.getState(), "HP");
        checkAndFixColumns(tablePopupCBHPMax.getState(), "HP Max");
        checkAndFixColumns(tablePopupCBNumber.getState(), "#");
        refreshTable();
    }//GEN-LAST:event_TablePopupActionPerformed

    private void bCastActionPerformed(java.awt.event.ActionEvent evt) {
        castSpell();
        focusNextInit();
    }

    private void bKillActionPerformed(java.awt.event.ActionEvent evt) {
        killCombatant();
        focusNextInit();
    }

    private void showDeadActionPerformed(java.awt.event.ActionEvent evt) {
        refreshTable();
        focusNextInit();
    }

    private void bDamageActionPerformed(java.awt.event.ActionEvent evt) {
        damageCombatant();
        focusNextInit();
    }

    private void bHealActionPerformed(java.awt.event.ActionEvent evt) {
        healCombatant();
        focusNextInit();
    }

    private void bStabilizeActionPerformed(java.awt.event.ActionEvent evt) {
        stabilizeCombatant();
        refreshTable();
        focusNextInit();
    }

    private void bRaiseActionPerformed(java.awt.event.ActionEvent evt) {
        raiseCombatant();
        refreshTable();
        focusNextInit();
    }

    //Initialization Function
    private void initDynamicComponents() {
        bCast.setText("Cast Spell");
        bCast.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                bCastActionPerformed(evt);
            }
        });

        bKill.setText("Kill");
        bKill.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                bKillActionPerformed(evt);
            }
        });

        bDamage.setText("Damage");
        bDamage.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                bDamageActionPerformed(evt);
            }
        });

        bHeal.setText("Heal");
        bHeal.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                bHealActionPerformed(evt);
            }
        });

        bStabilize.setText("Stabilize");
        bStabilize.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                bStabilizeActionPerformed(evt);
            }
        });

        bRaise.setText("Raise");
        bRaise.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                bRaiseActionPerformed(evt);
            }
        });

        showDead.setSelected(true);
        showDead.setText("Show Dead");
        showDead.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                showDeadActionPerformed(evt);
            }
        });
    }

    private void initTablePopup() {
        javax.swing.table.TableColumnModel colModel = combatantTable.getColumnModel();
        int numCols =  colModel.getColumnCount();
        tablePopupCBName.setSelected(false);
        tablePopupCBPlayer.setSelected(false);
        tablePopupCBStatus.setSelected(false);
        tablePopupCBPlus.setSelected(false);
        tablePopupCBInitiative.setSelected(false);
        tablePopupCBDuration.setSelected(false);
        tablePopupCBHP.setSelected(false);
        tablePopupCBHPMax.setSelected(false);
        tablePopupCBNumber.setSelected(false);
        for(int i = 0; i < numCols; i++) {
            javax.swing.table.TableColumn col = colModel.getColumn(i);
            String name = col.getIdentifier().toString();
            if(name.equals("Name")) {
                tablePopupCBName.setSelected(true);
            }
            else if(name.equals("Player")) {
                tablePopupCBPlayer.setSelected(true);
            }
            else if(name.equals("Status")) {
                tablePopupCBStatus.setSelected(true);
            }
            else if(name.equals("+")) {
                tablePopupCBPlus.setSelected(true);
            }
            else if(name.equals("Init")) {
                tablePopupCBInitiative.setSelected(true);
            }
            else if(name.equals("Dur")) {
                tablePopupCBDuration.setSelected(true);
            }
            else if(name.equals("HP")) {
                tablePopupCBHP.setSelected(true);
            }
            else if(name.equals("HP Max")) {
                tablePopupCBHPMax.setSelected(true);
            }
            else if(name.equals("#")) {
                tablePopupCBNumber.setSelected(true);
            }
        }
        if(initPrefs.getBoolean("doSpells", true) || initPrefs.getBoolean("doDeath", true) || initPrefs.getBoolean("doHP", true)) {
            tablePopupCBDuration.setEnabled(true);
        }
        else {
            tablePopupCBDuration.setEnabled(false);
        }
        if(initPrefs.getBoolean("doHP", true)) {
            tablePopupCBHP.setEnabled(true);
            tablePopupCBHPMax.setEnabled(true);
        }
        else {
            tablePopupCBHP.setEnabled(false);
            tablePopupCBHPMax.setEnabled(false);
        }
        if(initPrefs.getBoolean("doNumber", true)) {
            tablePopupCBNumber.setEnabled(true);
        }
    }

    private void initTable() {
        initTableColumns();
        javax.swing.table.JTableHeader header = combatantTable.getTableHeader();
        header.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mousePressed(java.awt.event.MouseEvent evt) {
                combatantTableMousePressed(evt);
            }
            public void mouseReleased(java.awt.event.MouseEvent evt) {
                combatantTableMouseReleased(evt);
            }
        });
        columnVector = getColumnOrder();
    }

    private void initTableColumns() {
        javax.swing.table.DefaultTableModel tabModel = (javax.swing.table.DefaultTableModel)combatantTable.getModel();
        tabModel.setColumnCount(0);
        int colNo = initPrefs.getInt("Number of Columns", 0);
        int[] widths = new int[colNo];
        for(int i = 0; i < colNo; i++) {
            String name = initPrefs.get("ColumnName " + i, "");
            int width = initPrefs.getInt("ColumnWidth " + i, 100);
            addColumn(name, width);
            widths[i] = width;
        }
        setColumnWidths(widths);
    }

    public void initPrefs() {
        boolean prefsSet = initPrefs.getBoolean("arePrefsSet", false);
        if(!prefsSet) {
            initPrefs.putBoolean("arePrefsSet", true);
        }
        double version = initPrefs.getDouble("Version", 0);
        if(version < 0.6 || !prefsSet) {
            initPrefs.putDouble("Version", 0.6);
            initPrefs.putBoolean("doSpells", true);
            initPrefs.putBoolean("doDeath", true);
        }
        if(version < 0.8 || !prefsSet) {
            initPrefs.putDouble("Version", 0.8);
        }
        if(version < 0.9 || !prefsSet) {
            initPrefs.putDouble("Version", 0.9);
            initPrefs.putBoolean("doHP", true);
            initPrefs.putInt("Number of Columns", 9);
            initPrefs.put("ColumnName 0", "#");
            initPrefs.putInt("ColumnWidth 0", 25);
            initPrefs.put("ColumnName 1", "Name");
            initPrefs.putInt("ColumnWidth 1", 100);
            initPrefs.put("ColumnName 2", "Player");
            initPrefs.putInt("ColumnWidth 2", 100);
            initPrefs.put("ColumnName 3", "Status");
            initPrefs.putInt("ColumnWidth 3", 75);
            initPrefs.put("ColumnName 4", "+");
            initPrefs.putInt("ColumnWidth 4", 25);
            initPrefs.put("ColumnName 5", "Init");
            initPrefs.putInt("ColumnWidth 5", 25);
            initPrefs.put("ColumnName 6", "Dur");
            initPrefs.putInt("ColumnWidth 6", 25);
            initPrefs.put("ColumnName 7", "HP");
            initPrefs.putInt("ColumnWidth 7", 25);
            initPrefs.put("ColumnName 8", "HP Max");
            initPrefs.putInt("ColumnWidth 8", 50);
            initPrefs.putInt("doMaxHP", 100);
            initPrefs.putInt("doMaxNum", 20);
            initPrefs.putInt("doNum", 20);
            initPrefs.putInt("DividerLocation", 450);
        }
        initPrefs.putDouble("SubVersion", 0);
    }

    public void initLast() {
        int iDividerLocation = initPrefs.getInt("DividerLocation", 400);
        jSplitPane1.setDividerLocation(iDividerLocation);

        //Spell Tracking On
        if(initPrefs.getBoolean("doSpells", true)) {
            jToolBar2.add(bCast);
        }

        //HP Tracking On
        if(initPrefs.getBoolean("doHP", true)) {
            jToolBar2.add(bDamage);
            jToolBar2.add(bHeal);
            jToolBar2.add(bStabilize);
        }

        //Death Tracking On
        if(initPrefs.getBoolean("doDeath", true)) {
            jToolBar2.add(bKill);
            jToolBar2.add(bRaise);
            jToolBar2.add(showDead);
        }

        boolean bShowDead = initPrefs.getBoolean("ShowDead", true);
        showDead.setSelected(bShowDead);
    }

    private void addTableListener() {
        javax.swing.table.TableColumnModel colModel = combatantTable.getColumnModel();
        colModel.addColumnModelListener(new javax.swing.event.TableColumnModelListener() {
            public void columnAdded(javax.swing.event.TableColumnModelEvent evt) {
                colModAdded(evt);
            }
            public void columnMarginChanged(javax.swing.event.ChangeEvent evt) {
                colModMarginChanged(evt);
            }
            public void columnMoved(javax.swing.event.TableColumnModelEvent evt) {
                colModMoved(evt);
            }
            public void columnRemoved(javax.swing.event.TableColumnModelEvent evt) {
                colModRemoved(evt);
            }
            public void columnSelectionChanged(javax.swing.event.ListSelectionEvent evt) {
                colModSelectionChanged(evt);
            }
        });
    }

    private void colModAdded(javax.swing.event.TableColumnModelEvent evt) {
    }

    private void colModMarginChanged(javax.swing.event.ChangeEvent evt) {
        trackTable();
    }

    private void colModMoved(javax.swing.event.TableColumnModelEvent evt) {
        trackTable();
    }

    private void colModRemoved(javax.swing.event.TableColumnModelEvent evt) {
    }

    private void colModSelectionChanged(javax.swing.event.ListSelectionEvent evt) {
    }

    public void editTableRow() {
        int row = combatantTable.getEditingRow();
        int column = combatantTable.getEditingColumn();
        if(row > -1 && column > -1) {
            editTable(row, column);
        }
    }

    public void editTable(int row, int column) {
        InitHolder iH = (InitHolder)initVector.elementAt(row);
        Object data = combatantTable.getValueAt(row, column);
        iH.editRow(columnVector, column, data);
        initVector.sort();
        refreshTable();
    }

    public void roll() {
        round = 0;
        initVector.check();
        int maxInit = initVector.getMaxInit();
        setCurrentInit(maxInit);
        writeToCombatTab("Combat Number " + currentCombat + ": ");
        writeToCombatTab("Round 1");
        currentCombat++;
        round = 1;
    }

    public void setCurrentInit(int init) {
        currentInit = init;
        if(currentInit > 0) {
            lCounter.setText("" + init);
        }
        else {
            lCounter.setText("");
        }
        refreshTable();
    }

    public void saveToFile() {
        String sFile = initPrefs.get("LastFile", "");
        File defaultFile = new File(sFile);
        javax.swing.JFileChooser fLoad = new javax.swing.JFileChooser();
        fLoad.setCurrentDirectory(defaultFile);
        fLoad.addChoosableFileFilter(new InitFileFilter());
        int returnVal = fLoad.showSaveDialog(this);
        try {
            if(returnVal == javax.swing.JFileChooser.APPROVE_OPTION) {
                String fileName = fLoad.getSelectedFile().getName();
                String ext = "";
                if(fileName.indexOf(".init") < 0) {
                    ext = ".init";
                }
                File xml = new File(fileName + ext);
                if(xml.exists()) {
                    int choice = JOptionPane.showConfirmDialog(this, "File Exists, Overwrite?", "File Exists", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);
                    if(choice == JOptionPane.YES_OPTION) {
                        initPrefs.put("LastFile", xml.toString());
                        saveToDocument(xml);
                    }
                }
                else {
                    initPrefs.put("LastFile", xml.toString());
                    saveToDocument(xml);
                }
            }
        }
        catch(Exception e) {
            JOptionPane.showMessageDialog(this, "Error Writing File");
            System.out.println("Error Writing File");
            e.printStackTrace();
        }
    }

    public void saveToDocument(File xml) throws Exception {
        Element party = new Element("Party");
        party.setAttribute("filever", "1.0");
        party.setAttribute("filetype", "initsave");
        for(int i = 0; i < initVector.size(); i++) {
            InitHolder iH = (InitHolder)initVector.elementAt(i);
            String type = iH.getHolderType();
            if(type.equals("XMLCombatant")) {
                XMLCombatant c = (XMLCombatant)iH;
                party.addContent(c.getSaveElement());
            }
        }
        Document saveDocument = new Document(party);
        InitOutputter xmlOut = new InitOutputter();
        xmlOut.setEncoding("US-ASCII");
        FileWriter fr = new FileWriter(xml);
        xmlOut.output(saveDocument, fr);
        fr.flush();
        fr.close();
    }

    public void loadFromFile() {
        String sFile = initPrefs.get("LastFile", "");
        File defaultFile = new File(sFile);

        javax.swing.JFileChooser fLoad = new javax.swing.JFileChooser();
        fLoad.setCurrentDirectory(defaultFile);
        fLoad.addChoosableFileFilter(new InitFileFilter());
        int returnVal = fLoad.showOpenDialog(this);
        try {
            if(returnVal == javax.swing.JFileChooser.APPROVE_OPTION) {
                File xml = fLoad.getSelectedFile();
                initPrefs.put("LastFile", xml.toString());
                SAXBuilder builder = new SAXBuilder();
                Document character = builder.build(xml);
                loadFromDocument(character);
            }
        }
        catch(Exception e) {
            System.out.println("XML ERROR");
            e.printStackTrace();
        }
    }

    public void loadFromDocument(Document character) {
        if(character.getRootElement().getName().equals("Party")) {
            Element party = character.getRootElement();
            List children = party.getChildren("Character");
            ListIterator elementIterator = children.listIterator();
            while(elementIterator.hasNext()) {
                Element eCharacter = (Element)elementIterator.next();
                XMLCombatant combatant = new XMLCombatant(eCharacter);
                initVector.add(combatant);
            }
        }
        else if(character.getRootElement().getName().equals("Character")) {
            Element eCharacter = character.getRootElement();
            XMLCombatant combatant = new XMLCombatant(eCharacter);
            initVector.add(combatant);
        }
    }

    public void nextInit() {
        int oldInit = currentInit;
        setCurrentInit(currentInit - 1);

        for(int i = 0; i < initVector.size(); i++) {
            InitHolder iH = (InitHolder)initVector.elementAt(i);
            String type = iH.getHolderType();
            if(type.equals("Spell")) {
                Spell s = (Spell)iH;
                int sInit = s.getInitiative().getCurrentInitiative();
                if(oldInit == sInit) {
                    int duration = s.decDuration();
                    if(duration < 0) {
                        writeToCombatTabWithRound(s.getPlayer() + "'s " + s.getName() + " ended");
                        initVector.remove(i);
                    }
                }
            }
            else if(type.equals("XMLCombatant")) {
                XMLCombatant xmlcbt = (XMLCombatant)iH;
                int cInit = xmlcbt.getInitiative().getCurrentInitiative();
                if(oldInit == cInit) {
                    String oldStatus = xmlcbt.getStatus();
                    xmlcbt.bleed();
                    String newStatus = xmlcbt.getStatus();
                    if(!oldStatus.equals(newStatus) && newStatus.equals("Dead")) {
                        writeToCombatTabWithRound(xmlcbt.getName() + " (" + xmlcbt.getPlayer() + ") Killed");
                    }
                }
            }
        }

        if(currentInit <= 0) {
            int maxInit = initVector.getMaxInit();
            setCurrentInit(maxInit);
            round++;
            writeToCombatTab("Round " + round);
        }
        else if (!initVector.initValid(currentInit)) {
            nextInit();
        }
        refreshTable();
    }

    public void refreshTable() {
        combatantTable.clearSelection();
//        initTableColumns();
        javax.swing.table.DefaultTableModel model = (javax.swing.table.DefaultTableModel)combatantTable.getModel();
        model.setNumRows(0);
        int startSelect = -1;
        int rowNum = 0;
        for(int i = 0; i < initVector.size(); i++) {
        InitHolder c = (InitHolder)initVector.elementAt(i);
            if(!c.getStatus().equals("Dead") || showDead.isSelected()) {
                Vector rowVector = initVector.getRowVector(i, columnVector);
                model.addRow(rowVector);
                int cInit = c.getInitiative().getCurrentInitiative();
                if(cInit == currentInit) {
                    if(startSelect == -1) {
                        startSelect = rowNum;
                    }
                    combatantTable.setRowSelectionInterval(startSelect, rowNum);
                }
                rowNum++;
            }
        }
    }

    public void rerollCombatant () {
        int j = -1;
        for(int i = 0; i < combatantTable.getRowCount(); i++) {
            j++;
            InitHolder iH = (InitHolder)initVector.elementAt(j);
            if(iH.getStatus().equals("Dead") && !showDead.isSelected()) {
                i--;
                continue;
            }
            if(combatantTable.isRowSelected(i)) {
                String type = iH.getHolderType();
                if(type.equals("XMLCombatant")) {
                  XMLCombatant c = (XMLCombatant)iH;
                  c.init.check();
                }
                writeToCombatTabWithRound(iH.getName() + " (" + iH.getPlayer() + ") Rerolled");
            }
        }
        initVector.sort();
        refreshTable();
    }

    public void refocusCombatant() {
        int j = -1;
        for(int i = 0; i < combatantTable.getRowCount(); i++) {
            j++;
            InitHolder iH = (InitHolder)initVector.elementAt(j);
            if(iH.getStatus().equals("Dead") && !showDead.isSelected()) {
                i--;
                continue;
            }
            if(combatantTable.isRowSelected(i)) {
                String type = iH.getHolderType();
                if(type.equals("XMLCombatant")) {
                  XMLCombatant c = (XMLCombatant)iH;
                  c.init.refocus();
                }
                writeToCombatTabWithRound(iH.getName() + " (" + iH.getPlayer() + ") Refocused");
            }
        }
        initVector.sort();
        refreshTable();
    }

    public void deleteCombatant() {
        int j = initVector.size();
        for(int i = combatantTable.getRowCount() - 1; i >= 0; i--) {
            j--;
            InitHolder iH = (InitHolder)initVector.elementAt(j);
            if(iH.getStatus().equals("Dead") && !showDead.isSelected()) {
                i--;
                continue;
            }
            if(combatantTable.isRowSelected(i)) {
                initVector.remove(j);
            }
        }
        initVector.sort();
        refreshTable();
    }

    public void killCombatant() {
        int j = initVector.size();
        for(int i = combatantTable.getRowCount() - 1; i >= 0; i--) {
            j--;
            InitHolder iH = (InitHolder)initVector.elementAt(j);
            if(iH.getStatus().equals("Dead") && !showDead.isSelected()) {
                i--;
                continue;
            }
            if(combatantTable.isRowSelected(i)) {
                String type = iH.getHolderType();
                if(type.equals("XMLCombatant")) {
                    XMLCombatant xmlcbt = (XMLCombatant)iH;
                    writeToCombatTabWithRound(iH.getName() + " (" + iH.getPlayer() + ") Killed");
                    xmlcbt.kill();
                }
            }
        }
        initVector.sort();
        refreshTable();
    }

    public void stabilizeCombatant() {
        int j = initVector.size();
        for(int i = combatantTable.getRowCount() - 1; i >= 0; i--) {
            j--;
            InitHolder iH = (InitHolder)initVector.elementAt(j);
            if(iH.getStatus().equals("Dead") && !showDead.isSelected()) {
                i--;
                continue;
            }
            if(combatantTable.isRowSelected(i) && iH.getStatus().equals("Bleeding")) {
                String type = iH.getHolderType();
                if(type.equals("XMLCombatant")) {
                    XMLCombatant xmlcbt = (XMLCombatant)iH;
                    writeToCombatTabWithRound(iH.getName() + " (" + iH.getPlayer() + ") Stabilized");
                    xmlcbt.stabilize();
                }
            }
        }
        initVector.sort();
        refreshTable();
    }

    public void raiseCombatant() {
        int j = initVector.size();
        for(int i = combatantTable.getRowCount() - 1; i >= 0; i--) {
            j--;
            InitHolder iH = (InitHolder)initVector.elementAt(j);
            if(iH.getStatus().equals("Dead") && !showDead.isSelected()) {
                i--;
                continue;
            }
            if(combatantTable.isRowSelected(i)) {
                String type = iH.getHolderType();
                if(type.equals("XMLCombatant")) {
                    XMLCombatant xmlcbt = (XMLCombatant)iH;
                    writeToCombatTabWithRound(iH.getName() + " (" + iH.getPlayer() + ") Raised");
                    xmlcbt.raise();
                }
            }
        }
        initVector.sort();
        refreshTable();
    }

    public void addCombatant() {
        if(mainFrame != null) {
            AddCombatant dialog = new AddCombatant(mainFrame, true, this);
            dialog.setVisible(true);
        }
        else {
            AddCombatant dialog = new AddCombatant(this);
            dialog.setVisible(true);
        }
        refreshTable();
    }

    public void damageCombatant() {
        if(mainFrame != null) {
            AffectHitPoints dialog = new AffectHitPoints(mainFrame, true, true, this);
            dialog.setVisible(true);
        }
        else {
            AffectHitPoints dialog = new AffectHitPoints(true, this);
            dialog.setVisible(true);
        }
    }

    public void doHeal(int heal) {
        int j = initVector.size();
        for(int i = combatantTable.getRowCount() - 1; i >= 0; i--) {
            j--;
            InitHolder iH = (InitHolder)initVector.elementAt(j);
            if(iH.getStatus().equals("Dead") && !showDead.isSelected()) {
                i--;
                continue;
            }
            if(combatantTable.isRowSelected(i)) {
                String type = iH.getHolderType();
                if(type.equals("XMLCombatant")) {
                    XMLCombatant xmlcbt = (XMLCombatant)iH;
                    xmlcbt.heal(heal);
                }
            }
        }
        initVector.sort();
        refreshTable();
    }

    public void healCombatant() {
        if(mainFrame != null) {
            AffectHitPoints dialog = new AffectHitPoints(mainFrame, true, false, this);
            dialog.setVisible(true);
        }
        else {
            AffectHitPoints dialog = new AffectHitPoints(false, this);
            dialog.setVisible(true);
        }
    }

    public void doDamage(int damage) {
        int j = initVector.size();
        for(int i = combatantTable.getRowCount() - 1; i >= 0; i--) {
            j--;
            InitHolder iH = (InitHolder)initVector.elementAt(j);
            if(iH.getStatus().equals("Dead") && !showDead.isSelected()) {
                i--;
                continue;
            }
            if(combatantTable.isRowSelected(i)) {
                String type = iH.getHolderType();
                if(type.equals("XMLCombatant")) {
                    XMLCombatant xmlcbt = (XMLCombatant)iH;
                    String oldStatus = xmlcbt.getStatus();
                    xmlcbt.damage(damage);
                    String newStatus = xmlcbt.getStatus();
                    if(!oldStatus.equals(newStatus) && newStatus.equals("Dead")) {
                        writeToCombatTabWithRound(xmlcbt.getName() + " (" + xmlcbt.getPlayer() + ") Killed");
                    }
                }
            }
        }
        initVector.sort();
        refreshTable();
    }

    public void showPreferences() {
        if(mainFrame != null) {
            PreferencesDialog dialog = new PreferencesDialog(mainFrame, true, this);
            dialog.setVisible(true);
        }
        else {
            PreferencesDialog dialog = new PreferencesDialog(this);
            dialog.setVisible(true);
        }
        refreshTable();
    }

    public void castSpell() {
        int j = initVector.size();
        for(int i = combatantTable.getRowCount() - 1; i >= 0; i--) {
            j--;
            InitHolder iH = (InitHolder)initVector.elementAt(j);
            if(iH.getStatus().equals("Dead") && !showDead.isSelected()) {
                i--;
                continue;
            }
            if(combatantTable.isRowSelected(i)) {
                if(mainFrame == null) {
                  CastSpell dialog = new CastSpell(this, iH.getPlayer(), iH.getInitiative().getCurrentInitiative());
                  dialog.setVisible(true);
                }
                else {
                  CastSpell dialog = new CastSpell(mainFrame, true, this, iH.getPlayer(), iH.getInitiative().getCurrentInitiative());
                  dialog.setVisible(true);
                }
                refreshTable();
                return;
            }
        }
        if(mainFrame == null) {
          CastSpell dialog = new CastSpell(this);
          dialog.setVisible(true);
        }
        else {
          CastSpell dialog = new CastSpell(mainFrame, true, this);
          dialog.setVisible(true);
        }
        refreshTable();
    }

    public void focusNextInit() {
        bNextInit.grabFocus();
    }

    public void focusRoll() {
        bRoll.grabFocus();
    }

    private void trackTable() {
        javax.swing.table.TableColumnModel colModel = combatantTable.getColumnModel();
        int numCols = colModel.getColumnCount();
        initPrefs.putInt("Number of Columns", numCols);
        for(int i = 0; i < numCols; i++) {
            javax.swing.table.TableColumn col = colModel.getColumn(i);
            String name = col.getIdentifier().toString();
            initPrefs.put("ColumnName " + i, name);
            initPrefs.putInt("ColumnWidth " + i, col.getWidth());
        }
    }

    public void writeToCombatTab(String message) {
        tpCombatInfo.setText(tpCombatInfo.getText() + "\n" + message);
    }

    public void writeToCombatTabWithRound(String message) {
        writeToCombatTab(" (Round: " + round + ", Init: " + currentInit + "): " + message);
    }

    public void applyPrefs() {
        try {
            initPrefs.sync();
        }
        catch(BackingStoreException e) {
        }

        //Spell Prefs
        if(initPrefs.getBoolean("doSpells", true) && !jToolBar2.isAncestorOf(bCast)) {
            jToolBar2.add(bCast);
        }
        if(!initPrefs.getBoolean("doSpells", true) && jToolBar2.isAncestorOf(bCast)) {
            jToolBar2.remove(bCast);
        }
        checkAndFixColumns(initPrefs.getBoolean("doSpells", true), "Dur");

        //Mixed Prefs
        checkAndFixColumns(initPrefs.getBoolean("doSpells", true) || initPrefs.getBoolean("doDeath", true), "Status");

        //Spell Prefs
        if(initPrefs.getBoolean("doHP", true) && !jToolBar2.isAncestorOf(bCast)) {
            jToolBar2.add(bDamage);
            jToolBar2.add(bHeal);
            jToolBar2.add(bStabilize);
        }
        if(!initPrefs.getBoolean("doHP", true) && jToolBar2.isAncestorOf(bCast)) {
            jToolBar2.remove(bDamage);
            jToolBar2.remove(bHeal);
            jToolBar2.remove(bStabilize);
        }
        checkAndFixColumns(initPrefs.getBoolean("doHP", true), "HP");
        checkAndFixColumns(initPrefs.getBoolean("doHP", true), "HP Max");
        checkAndFixColumns(initPrefs.getBoolean("doNumber", true), "#");

        //Death Prefs
        if(initPrefs.getBoolean("doDeath", true) && !jToolBar2.isAncestorOf(bKill)) {
            jToolBar2.add(bKill);
            jToolBar2.add(showDead);
        }
        if(!initPrefs.getBoolean("doDeath", true) && jToolBar2.isAncestorOf(bKill)) {
            jToolBar2.remove(bKill);
            jToolBar2.remove(showDead);
        }

        initTable();
        refreshTable();
        this.repaint();
    }

    private void addColumn(String name, int width) {
        javax.swing.table.DefaultTableModel tabModel = (javax.swing.table.DefaultTableModel)combatantTable.getModel();
        javax.swing.table.TableColumnModel colModel = combatantTable.getColumnModel();
        tabModel.addColumn(name);
        javax.swing.table.TableColumn column = colModel.getColumn(colModel.getColumnCount() - 1);
        column.setPreferredWidth(width);
        column.setWidth(width);
        column.setIdentifier(name);
        columnVector = getColumnOrder();
    }

    private void removeColumn(String name) {
        javax.swing.table.DefaultTableModel tabModel = (javax.swing.table.DefaultTableModel)combatantTable.getModel();
        javax.swing.table.TableColumnModel colModel = combatantTable.getColumnModel();
        for(int i = 0; i < colModel.getColumnCount(); i++) {
            javax.swing.table.TableColumn col = colModel.getColumn(i);
            if(col.getHeaderValue().toString().equals(name)) {
                colModel.removeColumn(col);
            }
        }
        trackTable();
        initTable();
        columnVector = getColumnOrder();
    }

    private void setColumnWidths(int[] widths) {
        javax.swing.table.DefaultTableModel tabModel = (javax.swing.table.DefaultTableModel)combatantTable.getModel();
        javax.swing.table.TableColumnModel colModel = combatantTable.getColumnModel();
        for(int i = 0; i < widths.length; i++) {
            javax.swing.table.TableColumn col = colModel.getColumn(i);
            col.setPreferredWidth(widths[i]);
        }
    }

    private void checkAndFixColumns(boolean shouldExist, String colName) {
        if(shouldExist && !getColumnOrder().contains(colName)) {
            addColumn(colName, 100);
            trackTable();
        }
        else if(!shouldExist && getColumnOrder().contains(colName)) {
            removeColumn(colName);
        }
    }

    public void setExitPrefs() {
        initPrefs.putBoolean("ShowDead", showDead.isSelected());
        initPrefs.putInt("DividerLocation", jSplitPane1.getDividerLocation());
    }

    private Vector getColumnOrder() {
        javax.swing.table.TableColumnModel colModel = combatantTable.getColumnModel();
        Vector colOrder = new Vector();
        for(int i = 0; i < colModel.getColumnCount(); i++) {
            colOrder.add(colModel.getColumn(i).getHeaderValue());
        }
        return colOrder;
    }

    public int getSelectedCount() {
        int selectedCount = 0;
        int j = initVector.size();
        for(int i = combatantTable.getRowCount() - 1; i >= 0; i--) {
            j--;
            InitHolder iH = (InitHolder)initVector.elementAt(j);
            if(iH.getStatus().equals("Dead") && !showDead.isSelected()) {
                i--;
                continue;
            }
            if(combatantTable.isRowSelected(i)) {
                selectedCount++;
            }
        }
        return selectedCount;
    }

    public void copy() {
        int j = initVector.size();
        for(int i = combatantTable.getRowCount() - 1; i >= 0; i--) {
            j--;
            InitHolder iH = (InitHolder)initVector.elementAt(j);
            if(iH.getStatus().equals("Dead") && !showDead.isSelected()) {
                i--;
                continue;
            }
            if(combatantTable.isRowSelected(i)) {
                String type = iH.getHolderType();
                if(type.equals("XMLCombatant")) {
                    copyCombatant = (XMLCombatant)iH;
                }
            }
        }
    }

    public void pasteNew() {
        SystemInitiative init = copyCombatant.getInitiative();
        SystemHP hitPoints = copyCombatant.getHP();
        String name = copyCombatant.getName();
        int i = 1;
        while(!initVector.isUniqueName(name)) {
            name = copyCombatant.getName().replaceAll(" \\(\\d.*\\)", "")  + " (" + i + ")";
            i++;
        }
        XMLCombatant newCbt = new XMLCombatant(name, copyCombatant.getPlayer(), init.getAttribute().getValue(), hitPoints.getAttribute().getValue(), hitPoints.getMax(), hitPoints.getCurrent(), init.getBonus());
        initVector.add(newCbt);
        refreshTable();
    }

    public boolean isPastable() {
        if(copyCombatant == null) {
            return false;
        }
        return true;
    }

    public boolean isXMLCombatantSelected() {
        int j = initVector.size();
        for(int i = combatantTable.getRowCount() - 1; i >= 0; i--) {
            j--;
            InitHolder iH = (InitHolder)initVector.elementAt(j);
            if(iH.getStatus().equals("Dead") && !showDead.isSelected()) {
                i--;
                continue;
            }
            if(combatantTable.isRowSelected(i)) {
                String type = iH.getHolderType();
                if(type.equals("XMLCombatant")) {
                    return true;
                }
                else {
                    return false;
                }
            }
        }
        return false;
    }


    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JCheckBoxMenuItem tablePopupCBStatus;
    private javax.swing.JCheckBoxMenuItem tablePopupCBName;
    private javax.swing.JToolBar jToolBar2;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JCheckBoxMenuItem tablePopupCBNumber;
    private javax.swing.JCheckBoxMenuItem tablePopupCBPlayer;
    private javax.swing.JButton bCombatantReRoll;
    private javax.swing.JButton bAddCombatant;
    private javax.swing.JPanel jPanel10;
    private javax.swing.JSplitPane jSplitPane1;
    private javax.swing.JCheckBoxMenuItem tablePopupCBInitiative;
    private javax.swing.JPanel jPanel2;
    private javax.swing.JButton bDelete;
    private javax.swing.JScrollPane jScrollPane2;
    private javax.swing.JTable combatantTable;
    private javax.swing.JButton bRoll;
    private javax.swing.JCheckBoxMenuItem tablePopupCBHPMax;
    private javax.swing.JTextArea tpCombatInfo;
    private javax.swing.JToolBar jToolBar1;
    private javax.swing.JCheckBoxMenuItem tablePopupCBPlus;
    private javax.swing.JButton bNextInit;
    private javax.swing.JTabbedPane tpaneInfo;
    private javax.swing.JPopupMenu tablePopup;
    private javax.swing.JLabel lCounter;
    private javax.swing.JButton bRefocus;
    private javax.swing.JCheckBoxMenuItem tablePopupCBHP;
    private javax.swing.JCheckBoxMenuItem tablePopupCBDuration;
    // End of variables declaration//GEN-END:variables
    //Dynamic Components
    private javax.swing.JButton bCast = new javax.swing.JButton();
    private javax.swing.JButton bKill = new javax.swing.JButton();
    private javax.swing.JButton bDamage = new javax.swing.JButton();
    private javax.swing.JButton bHeal = new javax.swing.JButton();
    private javax.swing.JButton bStabilize = new javax.swing.JButton();
    private javax.swing.JButton bRaise = new javax.swing.JButton();
    private javax.swing.JCheckBox showDead = new javax.swing.JCheckBox();
    private java.awt.Frame mainFrame;

    //Other Variables
    public InitHolderVector initVector = new InitHolderVector();
    public Vector columnVector = new Vector();
    private int currentInit = -1;
    private int currentCombat = 1;
    private int round = 0;
    private Preferences initPrefs = Preferences.userNodeForPackage(Initiative.class);
    private XMLCombatant copyCombatant;
}
