/*
 * $Id: MultiRoll.java 7738 2011-08-03 18:38:35Z uckelman $
 *
 * Copyright (c) 2000-2003 by Brent Easton
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License (LGPL) as published by the Free Software Foundation.
 *
 * This library 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
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, copies are available
 * at http://www.opensource.org.
 */
package VASSAL.build.module;


import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.ArrayList;

import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JTextField;
import javax.swing.border.Border;
import javax.swing.border.EtchedBorder;

import VASSAL.build.GameModule;
import VASSAL.build.module.dice.RollSet;
import VASSAL.preferences.Prefs;

/**
 * @author Brent Easton
 *
 * Dialog for defining a {@link DieManager.RollSet}
 * For use with internet dice rollers
 */
public class MultiRoll extends JDialog implements ActionListener {
  private static final long serialVersionUID = 1L;

  private JButton rollButton = new JButton("Roll");
  private JButton canButton = new JButton("Cancel");
  private JButton emailButton = new JButton("Change Email Address");

  private JDialog me;
  private JPanel serverPanel;
  private JLabel serverLabel;
  private JPanel emailPanel;
  private JLabel emailLabel;
  private JPanel descPanel;
  private JTextField descText;
  private JPanel topPanel;
  private JPanel buttonPanel;
  private JPanel detailPanel;
  protected int lastSelectedRow, lastSelectedCol;
  private String description = "";

  protected RollRow[] rollRows;

  public static final int COL_IDX = 0;
  public static final int COL_ROLL = 1;
  public static final int COL_DESC = 2;
  public static final int COL_NDICE = 3;
  public static final int COL_NSIDES = 4;
  public static final int COL_ADD = 5;
  public static final int COL_TOTAL = 6;
  public static final int NUMCOLS = 7;

  public static final int MAX_ROLLS = 10;
  public static final int ROW_HEIGHT = 20;

  public static final int COL1_WIDTH = 31;
  public static final int COL2_WIDTH = 30;
  public static final int COL3_WIDTH = 137;
  public static final int COL4_WIDTH = 50;
  public static final int COL5_WIDTH = 50;
  public static final int COL6_WIDTH = 25;
  public static final int COL7_WIDTH = 35;

  protected DieManager dieManager;
  protected DieRoll[] rolls = new DieRoll[MAX_ROLLS];
  protected boolean[] useDie = new boolean[MAX_ROLLS];
  protected String verification = "";
  protected boolean rollCancelled = false;
  protected boolean singleRoll;

  protected MultiRoll() {

    addWindowListener(new WindowAdapter() {
      public void windowClosing(WindowEvent e) {
        rollCancelled = true;
        setVisible(false);
      }
    });
  }

  public MultiRoll(DieManager d, int dfltNDice, int dfltNSides) {
    this();
    dieManager = d;
    for (int i = 0; i < MAX_ROLLS; i++) {
      rolls[i] = new DieRoll("", dfltNDice, dfltNSides);
    }
    initConfig(dfltNDice, dfltNSides);
    clearDie();
  }

  private void clearDie() {
    for (int i = 0; i < MAX_ROLLS; i++) {
      useDie[i] = false;
    }
  }

  public boolean wasCancelled() {
    return rollCancelled;
  }

  public void setDescription(String s) {
    description = s;
    descText.setText(s);
  }

  public String getDescription() {
    return description;
  }

  public RollSet getRollSet() {
    ArrayList<DieRoll> l = new ArrayList<DieRoll>();
    for (int i = 0; i < MAX_ROLLS; ++i) {
      if (useDie[i]) {
        l.add(rolls[i]);
      }
    }
    DieRoll[] rolls = l.toArray(new DieRoll[l.size()]);
    return new RollSet(getDescription(), rolls);
  }

  /*
   * Reset the status display before making visible in case preferences
   * have been changed.
   */
  public void setVisible(boolean b) {
    setServerHeader();
    setEmailHeader();
    super.setVisible(b);
  }

  // Multi-roll Configuration code
  private void initConfig(int nd, int ns) {

    setModal(true);

    setTitle("Multi Roller");
    setSize(380, 206);
    setBackground(Color.gray);

    // Create a panel to hold all other components
    topPanel = new JPanel();
    topPanel.setLayout(new BoxLayout(topPanel, BoxLayout.PAGE_AXIS));

    // Build the Server/Email header
    serverPanel = new JPanel();
    serverLabel = new JLabel();
    setServerHeader();
    serverPanel.add(serverLabel);
    topPanel.add(serverPanel);

    emailPanel = new JPanel();
    emailLabel = new JLabel();
    setEmailHeader();
    emailPanel.add(emailLabel);
    topPanel.add(emailPanel);

    // And the body
    descPanel = new JPanel();
    JLabel descLabel = new JLabel("Roll Description");
    descText = new JTextField(20);
    descText.setText(GameModule.getGameModule().getChatter().getInputField().getText());
    descText.addKeyListener(new java.awt.event.KeyAdapter() {
      public void keyReleased(java.awt.event.KeyEvent e) {
        description = descText.getText();
      }
    });
    descPanel.add(descLabel);
    descPanel.add(descText);
    topPanel.add(descPanel);

    detailPanel = new JPanel();
    detailPanel.setLayout(new BoxLayout(detailPanel, BoxLayout.PAGE_AXIS));
    detailPanel.setBorder(BorderFactory.createLineBorder(Color.black));

    detailPanel.add(new HeaderRow());

    rollRows = new RollRow[MAX_ROLLS];
    for (int i = 0; i < MAX_ROLLS; i++) {
      rollRows[i] = new RollRow(i, nd, ns);
      detailPanel.add(rollRows[i]);
    }

    topPanel.add(detailPanel);

    // Add Some buttons
    buttonPanel = new JPanel();
    rollButton.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(java.awt.event.ActionEvent e) {
        rollCancelled = false;
        int dieCount = 0;
        for (int i = 0; i < MAX_ROLLS; i++) {
          dieCount += useDie[i] ? 1 : 0;
        }
        if (dieCount == 0) {
          JOptionPane.showMessageDialog(me, "No dice selected for Roll.", "Roll Cancelled", JOptionPane.ERROR_MESSAGE);
          return;
        }
        setVisible(false);
      }
    });
    canButton.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(java.awt.event.ActionEvent e) {
        rollCancelled = true;
        setVisible(false);
      }
    });

    emailButton.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(java.awt.event.ActionEvent e) {
        updateEmailAddress();
      }
    });

    buttonPanel.add(rollButton);
    buttonPanel.add(canButton);
    buttonPanel.add(emailButton);

    add(topPanel, BorderLayout.PAGE_START);
    add(buttonPanel, BorderLayout.PAGE_END);

    pack();
  }

  protected void setServerHeader() {
    serverLabel.setText("Server: " + dieManager.getServer().getName());
  }

  private static final String EMAIL_OFF = "Off";

  protected void setEmailHeader() {

    String label;
    Prefs prefs = GameModule.getGameModule().getPrefs();

    if (((Boolean) prefs.getValue(DieManager.USE_EMAIL)).booleanValue()) {
      label = (String) prefs.getValue(DieManager.SECONDARY_EMAIL);
    }
    else {
      label = EMAIL_OFF;
    }
    emailLabel.setText("Email: " + label);
  }

  protected void updateEmailAddress() {

    Prefs prefs = GameModule.getGameModule().getPrefs();
    String[] aBook = (String[]) prefs.getValue(DieManager.ADDRESS_BOOK);

    JPopupMenu popup = new JPopupMenu();

    JMenuItem menuItem = new JMenuItem(EMAIL_OFF);
    menuItem.addActionListener(this);
    popup.add(menuItem);

    for (int i = 0; i < aBook.length; i++) {
      menuItem = new JMenuItem(aBook[i]);
      menuItem.addActionListener(this);
      popup.add(menuItem);
    }

    popup.show(emailButton, emailButton.getX(), emailButton.getY());
  }

  public void actionPerformed(ActionEvent e) {
    String address = e.getActionCommand();
    Prefs prefs = GameModule.getGameModule().getPrefs();
    if (address.equals(EMAIL_OFF)) {
      prefs.setValue(DieManager.USE_EMAIL, Boolean.FALSE);
    }
    else {
      prefs.setValue(DieManager.SECONDARY_EMAIL, address);
      prefs.setValue(DieManager.USE_EMAIL, Boolean.TRUE);
    }
    setEmailHeader();
  }

  protected static class HeaderRow extends JPanel {
    private static final long serialVersionUID = 1L;

    public HeaderRow() {

      Border raisedbevel = BorderFactory.createRaisedBevelBorder();
      Border myBorder = raisedbevel;

      //setLayout(new BoxLayout(this, BoxLayout.LINE_AXIS));
      //setBorder(blackline);

      JLabel col1 = new JLabel("Roll");
      col1.setPreferredSize(new Dimension(COL1_WIDTH, ROW_HEIGHT));
      col1.setHorizontalAlignment(JTextField.CENTER);
      col1.setBorder(myBorder);

//      JLabel col2 = new JLabel("Roll");
//      col2.setPreferredSize(new Dimension(COL2_WIDTH, ROW_HEIGHT));
//      col2.setHorizontalAlignment(JTextField.CENTER);
//            col2.setBorder(myBorder);

      JLabel col3 = new JLabel("Details");
      col3.setPreferredSize(new Dimension(COL3_WIDTH, ROW_HEIGHT));
      col3.setBorder(myBorder);

      JLabel col4 = new JLabel("nDice");
      col4.setBorder(myBorder);
      col4.setHorizontalAlignment(JTextField.CENTER);
      col4.setPreferredSize(new Dimension(COL4_WIDTH, ROW_HEIGHT));

      JLabel col5 = new JLabel("nSides");
      col5.setBorder(myBorder);
      col5.setHorizontalAlignment(JTextField.CENTER);
      col5.setPreferredSize(new Dimension(COL5_WIDTH, ROW_HEIGHT));

      JLabel col6 = new JLabel("add");
      col6.setBorder(myBorder);
      col6.setPreferredSize(new Dimension(COL6_WIDTH, ROW_HEIGHT));

      JLabel col7 = new JLabel("Total");
      col7.setBorder(myBorder);
      col7.setPreferredSize(new Dimension(COL7_WIDTH, ROW_HEIGHT));

      add(col1);
      //add(col2);
      add(col3);
      add(col4);
      add(col5);
      add(col6);
      add(col7);
    }
  }

  class RollRow extends JPanel {
    private static final long serialVersionUID = 1L;

    int myRow;
    boolean selected;
    String description;
    int nDice, nSides, plus;
    boolean reportTotal;
    Dimension rowDim = new Dimension(40, ROW_HEIGHT);

    StateButton col1;
    JCheckBox col2, col7;
    JComboBox col4, col5;
    JTextField col3, col6;

    Border blackline = BorderFactory.createLineBorder(Color.black);
    Border raisedetched = BorderFactory.createEtchedBorder(EtchedBorder.RAISED);
    Border loweredetched = BorderFactory.createEtchedBorder(EtchedBorder.LOWERED);
    Border raisedbevel = BorderFactory.createRaisedBevelBorder();
    Border loweredbevel = BorderFactory.createLoweredBevelBorder();
    Border myBorder = raisedbevel;

    public void setEnabled(boolean enabled) {
      col3.setEnabled(enabled);
      col4.setEnabled(enabled);
      col5.setEnabled(enabled);
      col6.setEnabled(enabled);
      col7.setEnabled(enabled);
    }

    public RollRow(int row, int nd, int ns) {

      myRow = row;

      //setLayout(new BoxLayout(this, BoxLayout.LINE_AXIS));

      col1 = new StateButton((row + 1) + "");
      col1.setPreferredSize(new Dimension(COL1_WIDTH, ROW_HEIGHT));
      col1.setState(useDie[myRow]);
      col1.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
          col1.switchState();
          useDie[myRow] = col1.getState();
          setEnabled(col1.getState());
        }
      });

      // Roll Description
      col3 = new JTextField(12);
      col3.setBorder(myBorder);
      col3.setPreferredSize(new Dimension(COL3_WIDTH, ROW_HEIGHT));
      col3.setText(rolls[myRow].getDescription() + "");
      col3.addKeyListener(new java.awt.event.KeyAdapter() {
        public void keyReleased(java.awt.event.KeyEvent e) {
          rolls[myRow].setDescription(col3.getText());
        }
      });
      col3.addMouseListener(new MouseAdapter() {
        public void mousePressed(MouseEvent e) {
          if (!col3.hasFocus()) {
            col3.selectAll();
          }
        }
      });
      col3.setEnabled(false);

      // Number of Dice
      int allowableDice[] = dieManager.getServer().getnDiceList();
      String diceData[] = new String[allowableDice.length];
      int defaultNDIdx = 0;
      for (int i = 0; i < diceData.length; i++) {
        diceData[i] = allowableDice[i] + "";
        if (nd == allowableDice[i])
          defaultNDIdx = i;
      }
      col4 = new JComboBox(diceData);
      col4.setSelectedIndex(defaultNDIdx);
      col4.setPreferredSize(new Dimension(COL4_WIDTH, ROW_HEIGHT));
      col4.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
          JComboBox cb = (JComboBox) e.getSource();
          rolls[myRow].setNumDice(Integer.valueOf((String) cb.getSelectedItem()).intValue());
        }
      });
      col4.setEnabled(false);

      // Number of Sides
      int[] allowableSides = dieManager.getServer().getnSideList();
      String sideData[] = new String[allowableSides.length];
      int defaultNSIdx = 0;
      for (int i = 0; i < sideData.length; i++) {
        sideData[i] = allowableSides[i] + "";
        if (ns == allowableSides[i])
          defaultNSIdx = i;
      }
      col5 = new JComboBox(sideData);
      col5.setSelectedIndex(defaultNSIdx);
      col5.setPreferredSize(new Dimension(COL5_WIDTH, ROW_HEIGHT));
      col5.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
          JComboBox cb = (JComboBox) e.getSource();
          rolls[myRow].setNumSides(Integer.valueOf((String) cb.getSelectedItem()).intValue());
        }
      });
      col5.setEnabled(false);

      // Add to Total
      col6 = new JTextField(2);
      col6.setBorder(myBorder);
      col6.setPreferredSize(new Dimension(COL6_WIDTH, ROW_HEIGHT));
      col6.setText(rolls[myRow].getPlus() + "");
      col6.addKeyListener(new java.awt.event.KeyAdapter() {
        public void keyReleased(java.awt.event.KeyEvent e) {
          try {
            rolls[myRow].setPlus(Integer.valueOf(col3.getText()).intValue());
          }
          catch (NumberFormatException ev) {
            // TODO use IntConfigurer for col3
            rolls[myRow].setPlus(0);
          }
        }
      });
      col6.setEnabled(false);

      // Report Total Only
      col7 = new JCheckBox();
      col7.setBorder(myBorder);
      col7.setPreferredSize(new Dimension(COL7_WIDTH, ROW_HEIGHT));
      col7.setHorizontalAlignment(JCheckBox.CENTER);
      col7.setSelected(rolls[myRow].isReportTotal());
      col7.addItemListener(new ItemListener() {
        public void itemStateChanged(ItemEvent e) {
          rolls[myRow].setReportTotal((e.getStateChange() == ItemEvent.SELECTED));
        }
      });
      col7.setEnabled(false);

      add(col1);
      add(col3);
      add(col4);
      add(col5);
      add(col6);
      add(col7);

    }
  }

  /*
   * An on/off button that changes state to show it's status
   */
  protected static class StateButton extends JButton {
    private static final long serialVersionUID = 1L;

    boolean state = false;

    StateButton(String s, boolean b) {
      super(s);
      setHorizontalAlignment(JButton.CENTER);
      setState(b);

    }

    StateButton(String s) {
      this(s, false);
    }

    public void setState(boolean b) {
      state = b;
      if (state) {
        setBorder(BorderFactory.createLoweredBevelBorder());
      }
      else {
        setBorder(BorderFactory.createRaisedBevelBorder());
      }
    }

    public boolean getState() {
      return state;
    }

    public void switchState() {
      setState(!state);
    }
  }


}