package be.aga.dominionSimulator.gui;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.HashSet;

import javax.swing.*;
import javax.swing.border.TitledBorder;
import javax.swing.text.NumberFormatter;

import be.aga.dominionSimulator.DomBuyRule;
import be.aga.dominionSimulator.DomEngine;
import be.aga.dominionSimulator.DomPlayer;
import be.aga.dominionSimulator.StartState;
import be.aga.dominionSimulator.enums.DomBotType;

public class DomBotEditor extends EscapeDialog implements ActionListener {
	/**
	 * 
	 */
	private static final long serialVersionUID = 1818817906737351312L;

  private static final int TEXT_FIELD_WIDTH = 50;

//made static for ease of use
  public static JLabel cardImageLabel;

  private JPanel myControlPanel;
  private final DomEngine myEngine;
  private final DomPlayer myChosenStrategy;
  private JPanel myPlayerPanel;
  private ArrayList<DomBuyRulePanel> myBuyRulePanels=new ArrayList<DomBuyRulePanel>();
  private JTextField myNameField;
	private JList<DomBotType> myBotTypeList;
  private JTextArea myDescriptionField;
  private JTextField myAuthorField;
  private JButton myTypeButton;
  private HashSet<DomBotType> myTypes;
  private JCheckBox myShuffleDeckBox;
  private JTextField myStartingHandField;
  private JTextField myBoardField;
  private JTextField myStartingDrawDeckField;
  private JTextField myBaneField;
  private JTextField myStartingDiscardPile;
  private JFormattedTextField myMountainPassBidField;
    private JTextField myObeliskChoice;
    private JCheckBox myShelters;

    public DomBotEditor ( final DomEngine anEngine , final DomPlayer aStrategy ) {
        myEngine=anEngine;
        myEngine.getGui().getGlassPane().setVisible(true);
        myChosenStrategy = aStrategy;
        buildGui();
        setTitle("Strategy Editor - " + myChosenStrategy);
        pack();
        setVisible( true );
        addWindowListener(new WindowAdapter() {
          public void windowClosing(WindowEvent e) {
            dispose();
          }
        });
    }

    protected void savePlayer() {
    	DomPlayer theNewPlayer = new DomPlayer(myNameField.getText());
    	theNewPlayer.setAuthor(myAuthorField.getText());
    	theNewPlayer.setDescription(myDescriptionField.getText().replaceAll("\\r\\n|\\r|\\n", "XXXX"));
    	StartState theStartState = getStartState();
    	if (theStartState==null) {
            JOptionPane.showMessageDialog(this, "An error was found in the Start State", "Error", JOptionPane.ERROR_MESSAGE);
            return;
    	}
    	if (theStartState.myOriginalDiscard.isEmpty()
    	&& theStartState.myOriginalDrawDeck.isEmpty()
    	&& theStartState.myOriginalHand.isEmpty()) {
    	  theNewPlayer.setStartState(null);
    	} else {
    	  theNewPlayer.setStartState(theStartState);
    	}
    	if (!theNewPlayer.addBoard(myBoardField.getText(), myBaneField.getText(),myMountainPassBidField.getText(),myObeliskChoice.getText(), Boolean.toString(myShelters.isSelected()))){
            JOptionPane.showMessageDialog(this, "An error was found in the Board", "Error", JOptionPane.ERROR_MESSAGE);
            return;
    	}
        for (DomBuyRulePanel theRulePanel : myBuyRulePanels) {
    	  theNewPlayer.addBuyRule(theRulePanel.getBuyRule(theNewPlayer));
    	}
    	theNewPlayer.setShelters(myShelters.isSelected());
    	theNewPlayer.setTypes(myTypes);
    	theNewPlayer.addType(DomBotType.UserCreated);
    	if (!theNewPlayer.hasType(DomBotType.ThreePlayer) && ! theNewPlayer.hasType(DomBotType.FourPlayer))
    		theNewPlayer.addType(DomBotType.TwoPlayer);
    	if (!theNewPlayer.hasType(DomBotType.Colony))
    		theNewPlayer.addType(DomBotType.Province);
    	myEngine.addUserBot(theNewPlayer);
        dispose();
    }

	private StartState getStartState() {
		StartState theStartState = new StartState();
		if (!theStartState.addDiscard(myStartingDiscardPile.getText())
		 || !theStartState.addDrawDeck(myStartingDrawDeckField.getText(), myShuffleDeckBox.isSelected()?"true":"false")
		 || !theStartState.addHand(myStartingHandField.getText()))
			return null;
		return theStartState;
	}

	private void buildGui()	{
    getContentPane().add(getControlPanel(), BorderLayout.PAGE_START);
    getContentPane().add(getPlayerPanel(), BorderLayout.CENTER);
	}

	private void fillPlayerPanel() {
	  myPlayerPanel.removeAll();
      final GridBagConstraints theCons = DomGui.getGridBagConstraints( 2 );
      JLabel theLabel = new JLabel("Important!! These will be evaluated from top to bottom for each buy!!");
      theLabel.setForeground(Color.red);
      myPlayerPanel.add(theLabel,theCons);
      JButton theBTN = new JButton("Toggle View of Buy Conditions");
      theBTN.setMnemonic('T');
      theBTN.addActionListener(this);
      theBTN.setActionCommand("toggle conditions");
      theCons.gridy++;
      theCons.fill=GridBagConstraints.NONE;
      theCons.anchor=GridBagConstraints.CENTER;
      myPlayerPanel.add(theBTN,theCons);
      theCons.anchor=GridBagConstraints.NORTHWEST;
      theCons.fill=GridBagConstraints.BOTH;

      int i=0;
      theBTN = new JButton("Add a Buy Rule");
      theBTN.setMnemonic('A');
      theBTN.addActionListener(this);
      theBTN.setActionCommand("add rule " + i);
      theCons.gridy++;
      theCons.fill=GridBagConstraints.NONE;
      myPlayerPanel.add(theBTN,theCons);
      theCons.fill=GridBagConstraints.BOTH;

      for (DomBuyRulePanel thePanel : myBuyRulePanels){
    	i++;
    	theCons.gridy++;
	    myPlayerPanel.add(thePanel, theCons);
      }

      theBTN = new JButton("Add a Buy Rule");
      theBTN.setMnemonic('B');
      theBTN.addActionListener(this);
      theBTN.setActionCommand("add rule "+i);
      theCons.gridy++;
      theCons.fill=GridBagConstraints.NONE;
      myPlayerPanel.add(theBTN,theCons);
      theCons.fill=GridBagConstraints.BOTH;

      theCons.gridy++;
      DomGui.addHeavyLabel(myPlayerPanel, theCons);

      validate();
	}

    private JScrollPane getPlayerPanel() {
  	  myPlayerPanel = new JPanel();
      myPlayerPanel.setLayout( new GridBagLayout() );
  	  myPlayerPanel.setBorder( new TitledBorder( "Buy Rules" ));
      JScrollPane scr = new JScrollPane( myPlayerPanel );
	  if (Toolkit.getDefaultToolkit().getScreenSize().height>800)
        scr.setPreferredSize( new Dimension( 750, 600 ) );
	  else
        scr.setPreferredSize( new Dimension( 750, 450 ) );
      scr.getVerticalScrollBar().setUnitIncrement(24);

      for (final DomBuyRule theRule : myChosenStrategy.getPrizeBuyRules()){
        DomBuyRulePanel theRulePanel = theRule.getGuiPanel(this);
        myBuyRulePanels.add(theRulePanel);
      }
      for (final DomBuyRule theRule : myChosenStrategy.getBuyRules()){
        DomBuyRulePanel theRulePanel = theRule.getGuiPanel(this);
        myBuyRulePanels.add(theRulePanel);
      }
      fillPlayerPanel();
      return scr;
    }

    private JPanel getControlPanel() {
        myControlPanel = new JPanel();
        myControlPanel.setLayout( new GridBagLayout() );
        myControlPanel.setBorder( new TitledBorder( "Strategy" ));
        final GridBagConstraints theCons = DomGui.getGridBagConstraints( 2 );
        //name field
        myControlPanel.add(new JLabel("Name"), theCons);
        theCons.gridx++;
        myNameField = new JTextField(myChosenStrategy.toString(),20);
        myControlPanel.add(myNameField, theCons);
        //author field
        theCons.gridx++;
        myControlPanel.add(new JLabel("written by"), theCons);
        myAuthorField = new JTextField(myChosenStrategy.getAuthor(),13);
        theCons.gridx++;
        myControlPanel.add(myAuthorField, theCons);
        theCons.gridx++;
        DomGui.addHeavyLabel(myControlPanel, theCons);
        //Save and Cancel buttons
        JButton theSaveButton = new JButton("Save");
        theSaveButton.setMnemonic('S');
        theSaveButton.addActionListener(this);
        theSaveButton.setActionCommand("Save");
        theCons.gridx++;
        myControlPanel.add(theSaveButton, theCons);
        JButton theCancelButton = new JButton("Cancel");
        theCancelButton.setMnemonic('C');
        theCancelButton.addActionListener(this);
        theCancelButton.setActionCommand("Cancel");
        theCons.gridx++;
        myControlPanel.add(theCancelButton, theCons);
        //tabbed panes
        theCons.gridy++;
        theCons.gridx=0;
        theCons.gridwidth=7;
        myControlPanel.add(getTabbedPane(), theCons);
        //Type(s) button
        theCons.gridy++;
        myControlPanel.add(getTypesButton(), theCons);

        return myControlPanel;
    }

	private JTabbedPane getTabbedPane() {
		JTabbedPane theTabbedPane = new JTabbedPane();
		theTabbedPane.add("Description", getDescriptionField());
		theTabbedPane.add("Start State", getStartStatePanel());
		theTabbedPane.add("Board", getBoardPanel());
		return theTabbedPane;
	}

	private JPanel getStartStatePanel() {
        final JPanel thePanel = new JPanel();
        thePanel.setLayout( new GridBagLayout() );
//        thePanel.setBorder( new TitledBorder( "" ));
        final GridBagConstraints theCons = DomGui.getGridBagConstraints( 2 );
        //starting hand
        thePanel.add(new JLabel("Starting Hand"),theCons);
        myStartingHandField = new JTextField(TEXT_FIELD_WIDTH);
        theCons.gridx++;
        thePanel.add(myStartingHandField,theCons);
        //starting discard
        theCons.gridx=0;
        theCons.gridy++;
        thePanel.add(new JLabel("Starting discard pile"),theCons);
        myStartingDiscardPile = new JTextField(TEXT_FIELD_WIDTH);
        theCons.gridx++;
        thePanel.add(myStartingDiscardPile,theCons);
        //starting draw deck
        theCons.gridx=0;
        theCons.gridy++;
        thePanel.add(new JLabel("Starting draw deck"),theCons);
        myStartingDrawDeckField = new JTextField(TEXT_FIELD_WIDTH);
        theCons.gridx++;
        thePanel.add(myStartingDrawDeckField,theCons);
        myShuffleDeckBox = new JCheckBox("Shuffle draw deck", null, true);
//        theCons.gridx++;
        theCons.gridx=0;
        theCons.gridy++;
        thePanel.add(myShuffleDeckBox,theCons);
        //info button
        JButton theInfoBTN = new JButton("Info");
        theInfoBTN.setMnemonic('I');
        theInfoBTN.addActionListener(this);
        theInfoBTN.setActionCommand("StartStateInfo");
        theCons.gridx++;
        theCons.fill=GridBagConstraints.NONE;
        theCons.anchor=GridBagConstraints.EAST;
        thePanel.add(theInfoBTN,theCons);

        StartState theStartState = myChosenStrategy.getStartState();
        if (theStartState!=null) {
        	myStartingDiscardPile.setText(theStartState.myOriginalDiscard);
        	myStartingDrawDeckField.setText(theStartState.myOriginalDrawDeck);
        	myStartingHandField.setText(theStartState.myOriginalHand);
        	myShuffleDeckBox.setSelected(theStartState.isShuffleDrawDeck());
        }


        return thePanel;
	}

	private JPanel getBoardPanel() {
        final JPanel thePanel = new JPanel();
        thePanel.setLayout( new GridBagLayout() );
//        thePanel.setBorder( new TitledBorder( "" ));
        final GridBagConstraints theCons = DomGui.getGridBagConstraints( 2 );
        //board cards
        thePanel.add(new JLabel("Board"),theCons);
        myBoardField = new JTextField(myChosenStrategy.getBoardString(), TEXT_FIELD_WIDTH);
        theCons.gridx++;
        thePanel.add(myBoardField,theCons);
        //bane card
        theCons.gridx=0;
        theCons.gridy++;
        theCons.fill=GridBagConstraints.NONE;
        thePanel.add(new JLabel("Bane Card"),theCons);
        myBaneField = new JTextField(myChosenStrategy.getBaneCardAsString(), 20);
        theCons.gridx++;
        thePanel.add(myBaneField,theCons);
        //Mountain Pass bid
        theCons.gridx=0;
        theCons.gridy++;
        theCons.fill=GridBagConstraints.NONE;
        thePanel.add(new JLabel("Mountain Pass bid"),theCons);
        NumberFormat format = NumberFormat.getInstance();
        NumberFormatter formatter = new NumberFormatter(format);
        formatter.setValueClass(Integer.class);
        formatter.setMinimum(0);
        formatter.setMaximum(Integer.MAX_VALUE);
//        formatter.setAllowsInvalid(false);
        formatter.setCommitsOnValidEdit(false);
        myMountainPassBidField = new JFormattedTextField(formatter);
        myMountainPassBidField.setColumns(10);
        myMountainPassBidField.setValue(myChosenStrategy.getMountainPassBid(0));
        theCons.gridx++;
        thePanel.add(myMountainPassBidField,theCons);
        //Obelisk card
        theCons.gridx=0;
        theCons.gridy++;
        theCons.fill=GridBagConstraints.NONE;
        thePanel.add(new JLabel("Obelisk choice"),theCons);
        myObeliskChoice = new JTextField(myChosenStrategy.getObeliskChoice(), 20);
        theCons.gridx++;
        thePanel.add(myObeliskChoice,theCons);
        //Shelters
        theCons.gridx=0;
        theCons.gridy++;
        theCons.fill=GridBagConstraints.NONE;
        myShelters = new JCheckBox("Shelters", myChosenStrategy.getShelters());
        thePanel.add(myShelters,theCons);
        //info button
        JButton theInfoBTN = new JButton("Info");
        theInfoBTN.setMnemonic('I');
        theInfoBTN.addActionListener(this);
        theInfoBTN.setActionCommand("BoardInfo");
        theCons.gridy++;
        theCons.fill=GridBagConstraints.NONE;
        theCons.anchor=GridBagConstraints.EAST;
        thePanel.add(theInfoBTN,theCons);
        return thePanel;
	}

	private JButton getTypesButton() {
        myTypeButton = new JButton("Type(s): "+getTypes());
        myTypeButton.setMnemonic('y');
        myTypeButton.addActionListener(this);
        myTypeButton.setActionCommand("Types");
        return myTypeButton;
	}

	private String getTypes() {
		StringBuilder theTypeString=null;
		if (myBotTypeList!=null){
			myTypes=new HashSet<DomBotType>();
			for (Object botType : myBotTypeList.getSelectedValuesList()){
				myTypes.add((DomBotType) botType);
			}
		}
		if (myTypes==null) {
			myTypes = new HashSet<DomBotType>();
			for (DomBotType botType : myChosenStrategy.getTypes()){
				myTypes.add(botType);
			}
		}
        for (DomBotType botType : myTypes){
        	if (theTypeString==null){
        		theTypeString = new StringBuilder("");
        	} else {
        		theTypeString.append(", ");
        	}
        	theTypeString.append(botType);
        }
		return theTypeString==null? "" : theTypeString.toString();
	}

	private JList<DomBotType> getTypeList() {
		myBotTypeList = new JList<DomBotType>(DomBotType.values());
      myBotTypeList.setSelectionModel(new ToggleListSelectionModel());
    	ArrayList<DomBotType> thePossibleTypes = new ArrayList<DomBotType>();
    	for (DomBotType botType : DomBotType.values()){
    		thePossibleTypes.add(botType);
    	}
    	myBotTypeList.setBorder(new TitledBorder("Choose type(s) of this strategy"));

      HashSet<DomBotType> selectedTypes = (myTypes == null ? myChosenStrategy.getTypes() : myTypes);
      int[] theSelectedIndices = new int[selectedTypes.size()];
    	int i=0;

    	for (DomBotType type : selectedTypes){
    		theSelectedIndices[i++] = thePossibleTypes.indexOf(type);
    	}
    	myBotTypeList.setSelectedIndices(theSelectedIndices);
      myBotTypeList.setBorder(new TitledBorder("Click to select types"));
    	myBotTypeList.requestFocus();
    	return myBotTypeList;
	}

	private JScrollPane getDescriptionField() {
		myDescriptionField = new JTextArea(myChosenStrategy.getDescription().replaceAll("XXXX", System.getProperty( "line.separator" )) ,5,30);
		JScrollPane thePane = new JScrollPane(myDescriptionField);
		return thePane;
	}

    @Override
	public void actionPerformed(ActionEvent aE) {
      if (aE.getActionCommand().equals( "StartStateInfo" )) {
    	  String theText= "<html><u>This tab allows defining a forced starting state (instead of starting with 7 Coppers and 3 Estates)</u>"
        		+"<br>Use the correct spelling for cards and capitals where needed (and no ending 's' for multiples)!"
        		+"<br>This is correct: <i>2 Mountebank, 2 Copper, Village</i>"
        		+"<br><br>The draw deck can either be shuffled or put into a fixed order."
        		+"<br><br>If starting hand is empty, 5 cards will be drawn."
        		+"</html>";
          JOptionPane.showMessageDialog(this, theText, "Info", JOptionPane.INFORMATION_MESSAGE);
      }

      if (aE.getActionCommand().equals( "BoardInfo" )) {
    	  String theText= "<html><u>This tab allows defining a board</u>"
        		+"<br><br>Use the correct spelling for cards and capitals where needed!"
        		+"<br>This is correct: <i>Chapel, Throne Room, Pawn, Courtyard, Vault, Caravan, Cellar, Moat, Witch and Worker's Village</i>"
        		+"<br><br>The Bane card for Young Witch, if present, must be defined separately" +
        				"</html>";
          JOptionPane.showMessageDialog(this, theText, "Info", JOptionPane.INFORMATION_MESSAGE);
      }

      if (aE.getActionCommand().equals( "Move Up" )) {
    	 JButton theButton = (JButton) aE.getSource();
    	 DomBuyRulePanel thePanel = (DomBuyRulePanel) theButton.getClientProperty("my rule box");
		 int theIndex = myBuyRulePanels.indexOf(thePanel);
		 if (theIndex>0) {
			 myBuyRulePanels.remove(theIndex);
			 myBuyRulePanels.add(theIndex-1, thePanel);
			 fillPlayerPanel();
			 return;
		 }
      }
      if (aE.getActionCommand().equals( "Move Down" )) {
     	 final JButton theButton = (JButton) aE.getSource();
     	 DomBuyRulePanel thePanel = (DomBuyRulePanel) theButton.getClientProperty("my rule box");
 		 int theIndex = myBuyRulePanels.indexOf(thePanel);
		 if (theIndex<myBuyRulePanels.size()-1) {
			 myBuyRulePanels.remove(theIndex);
			 myBuyRulePanels.add(theIndex+1, thePanel);
			 fillPlayerPanel();
			 return;
		 }
      }
      if (aE.getActionCommand().equals( "Delete" )) {
      	 JButton theButton = (JButton) aE.getSource();
      	 DomBuyRulePanel thePanel = (DomBuyRulePanel) theButton.getClientProperty("my rule box");
    	 myBuyRulePanels.remove(thePanel);
	     fillPlayerPanel();
		 return;
      }
      if (aE.getActionCommand().startsWith("add rule" )) {
    	 DomBuyRule theDummyBuyRule = new DomBuyRule("Copper", null, null);
    	 int theIndex = new Integer(aE.getActionCommand().substring(9));
    	 myBuyRulePanels.add(theIndex, theDummyBuyRule.getGuiPanel(this));
 	     fillPlayerPanel();
 		 return;
      }
      if (aE.getActionCommand().equals( "Duplicate" )) {
      	 final JButton theButton = (JButton) aE.getSource();
      	 DomBuyRulePanel thePanel = (DomBuyRulePanel) theButton.getClientProperty("my rule box");
  		 int theIndex = myBuyRulePanels.indexOf(thePanel);
    	 myBuyRulePanels.add(theIndex, thePanel.getBuyRule(myChosenStrategy).getGuiPanel(this));
 	     fillPlayerPanel();
      }
      if (aE.getActionCommand().startsWith("toggle" )) {
    	 for (DomBuyRulePanel thePanel : myBuyRulePanels) {
    	  thePanel.toggleBuyConditions();
    	 }
       }
      if (aE.getActionCommand().equals("Save" )) {
        savePlayer();
      }
      if (aE.getActionCommand().equals("Cancel" )) {
        dispose();
      }
      if (aE.getActionCommand().equals("Types" )) {
        JOptionPane.showMessageDialog(this, getTypeList());
        myTypeButton.setText("Type(s): " + getTypes());
      }
	}
    @Override
	public void dispose() {
      myEngine.getGui().getGlassPane().setVisible(false);
      super.dispose();
	}
}