package Cluedo.GUI2;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.Hashtable;
import java.util.StringTokenizer;
import java.util.Vector;

import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.ListModel;
import javax.swing.ListSelectionModel;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

import Cluedo.API.CluedoConfig;
import Cluedo.API.Constants;
import Cluedo.API.LanguagePack;
import Cluedo.API.Resources;
import Cluedo.API.StringFuncs;

public class WeaponSelect extends JPanel implements ActionListener {
    CluedoConfig gameConfig;
    
    DefaultListModel predefinedModel;
    
    DefaultListModel playListModel;
    
    JList predefinedList = null;
    
    JList playList = null;
    
    JLabel instructionsLabel = new JLabel("Choose the Weapons for this game");
    
    String[] cardSets;
    
    String currentCardSet = "";
    
    static String cardType = "Weapon";
    static String fileExtension = ".weapon";
    static String cardFolder = "./Resources/Cards/Weapons/";
    static int minCards = 6;
    
    Hashtable buttons = new Hashtable();
    
    private static final String DEFAULT_GROUP = "weapon_selection";
    
    
    /**
     * Finds all files ending in .weapons and populates list with that data.
     *
     */
    public void updatePredefinedList() {
        FilenameFilter filter = new FilenameFilter() {
            public boolean accept(File dir, String name) {
                if (name.endsWith(fileExtension))
                    return true;
                return false;
            }
        };
        
        try {
            // Get list of cardSets
            cardSets = new File(cardFolder).list(filter);
            
            for (int i = 0; i < cardSets.length; i++) {
                cardSets[i] = cardSets[i].substring(0, cardSets[i].lastIndexOf("."));
            }
            
            // Can't find any cardSets
        } catch (NullPointerException e) {
            cardSets = new String[] {};
        }
        
        predefinedList.setListData(cardSets);
        
    }
    
    
    /**
     * Loads and displays cards from the current card set.
     *
     * @param cardSet
     */
    public void updatePlayList(String cardSet) {
        Vector memberCards = loadCardSet(cardSet, cardType);
        playListModel.removeAllElements();
        
        for (int i = 0; i < memberCards.size(); i++) {
            playListModel.addElement(memberCards.elementAt(i));
        }
    }
    
    /**
     * When the user clicks on a card list it will be loaded
     * 
     */
    ListSelectionListener predefinedListener = new ListSelectionListener() {
        public void valueChanged(ListSelectionEvent e) {
            if (e.getValueIsAdjusting() == false) {
                playListModel.removeAllElements();
                
                if(predefinedList.getSelectedValue() != null) {
                    currentCardSet = (String) predefinedList.getSelectedValue().toString();
                    enableButtons();
                }
                else
                    return;
                
                try {
                    updatePlayList(currentCardSet);
                } catch (Exception exp) {
                }
            }
            
        }
    };
    
    /**
     * 
     * All button events are handled here for updating cards and lists.
     * 
     */
    public void actionPerformed(ActionEvent e) {
        
        if (e.getActionCommand().equals("new_card")) {

            if(playListModel.getSize() >= 6) {
                String card_number_problem = lookup("card_number_problem");
                

                JOptionPane.showMessageDialog(null, card_number_problem, "Sorry..", JOptionPane.ERROR_MESSAGE);
                return;
            }
            
            Vector currentWeapons = new Vector();
            
            for (int i = 0; i < playListModel.size(); i++)
                currentWeapons.add(playListModel.getElementAt(i));
            
            String name = JOptionPane.showInputDialog(null, lookup("name_prompt"));
            String error = ""; 
            String cant_add_player_error = lookup("cant_add_player_error");

            if(name.length() > 12) { 
                String name_too_long_error =  lookup("name_too_long_error"); 
                
                error += name_too_long_error; 
                
            } 
      
			if(StringFuncs.validAlphaNumeric(name)==false) { 
                String name_not_valid_error = lookup("name_not_valid_error"); 
                if(error.equals("")) 
                    error =name_not_valid_error; 
                else 
                    error+=  name_not_valid_error; 
                
            } 
            if(!error.equals("")) { 
                JOptionPane.showMessageDialog(null, error, cant_add_player_error, JOptionPane.INFORMATION_MESSAGE); 
                return; 
            }
            //checking to see if weapon name is not duplicate
            if (playListModel.contains(name)) {
                String card_contained_message = addArguments(lookup("card_contained_message"), new String[]{name});

                JOptionPane.showMessageDialog(null, card_contained_message);
            } else if (!name.equals("")) {
                // add weapon to model
                playListModel.addElement(name);
            }
        } else if (e.getActionCommand().equals("remove_card")) {
            if (playList.getSelectedValue() != null) {
                playListModel.removeElement(playList.getSelectedValue());
                playList.repaint();
            }
        } else if (e.getActionCommand().equals("edit_card")) {
            if (playList.getSelectedValue() != null) {
                String selected = (String) playList.getSelectedValue();
                
                String edit_card_message = addArguments(lookup("edit_card_message"), new String []{selected});
                
                String name = JOptionPane.showInputDialog(null, edit_card_message);

                if (playListModel.contains(name) && !selected.equals(name)) {
                    
                    String card_contained_message = addArguments(lookup("card_contained_message"), new String[]{name});
                    JOptionPane.showMessageDialog(null, card_contained_message);

                } else if(name != null && !name.equals("")){
                    playListModel.removeElement(playList.getSelectedValue());
                    playListModel.addElement(name);
                    
                    playList.repaint();
                }
            }
            
        } else if (e.getActionCommand().equals("clear_list")) {
            playListModel.removeAllElements();
        } else if (e.getActionCommand().equals("delete_list")) {

            if(!currentCardSet.equals("")) {

                String delete_confirm_message = addArguments(lookup("delete_confirm_message"), new String[]{currentCardSet});

                int yesNo = JOptionPane.showConfirmDialog(null, delete_confirm_message, "Ut-oh!", JOptionPane.YES_NO_OPTION);
                
                if(yesNo == JOptionPane.YES_OPTION) {
                    removeCardSet(currentCardSet);
                    playListModel.removeAllElements();
                    
                    currentCardSet = "";
                    updatePredefinedList();
                    
                    predefinedList.repaint();
                    disableButtons();
                }
               
            }
        } else if (e.getActionCommand().equals("new_list")) {
            String new_list_name = lookup("new_list_name");
            
            String name = JOptionPane.showInputDialog(null, new_list_name);

            if (!predefinedModel.contains(name) && !name.equals("")) {
                playListModel.removeAllElements();
                writeToDisk(name, new DefaultListModel());
                currentCardSet = name;
                updatePredefinedList();

                // Find the index of the new set to show it highlighted
                int index = getIndexOf(predefinedList.getModel(), name);

                predefinedList.setSelectedIndex(index);
                predefinedList.repaint();
                
            }
            
        } else if (e.getActionCommand().equals("use_card_set")) {
            if (!playListModel.isEmpty() && playListModel.size() == minCards) {
                gameConfig.setCards(PlayerSelect.updateCardSet(
                        loadCardSet(currentCardSet, cardType), gameConfig.getCards(),
                        cardType));
                String card_set_confirm = addArguments(lookup("card_set_confirm"), new String[]{currentCardSet});
                
                JOptionPane.showMessageDialog(this, card_set_confirm);
            } else {
                String card_set_bad_size = lookup("card_set_bad_size");
                JOptionPane.showMessageDialog(this, card_set_bad_size);
            }            

        }
        
        else if (e.getActionCommand().equals("save_list")) {
            if(!currentCardSet.equals("")) {
                writeToDisk(currentCardSet, playListModel);
            }
        }
    }

    
    /**
     * Disables all buttons which shouldn't be pressed while no list is selected
     */
    private void disableButtons() {
        String disableButtons[] = {"edit_card","new_card", "remove_card", "save_list", "delete_list",  "clear_list"};

        for(int i=0;i<disableButtons.length;i++){
            getButton(disableButtons[i]).setEnabled(false);
        }

    }

    /**
     * Enables buttons, see disableButtons
     */
    private void enableButtons() {
        String enableButtons[] = {"edit_card","new_card", "remove_card", "save_list", "delete_list",  "clear_list"};

        for(int i=0;i<enableButtons.length;i++){
            getButton(enableButtons[i]).setEnabled(true);
        }

    }

    /**
     * @param cardSet
     */
    private boolean removeCardSet(String cardSet) {
        return new File(cardFolder + cardSet + fileExtension).delete();
    }


    /**
     * Returns the index of an item in a data list model.
     * 
     * @param model
     * @param name
     * @return
     */
    private static int getIndexOf(ListModel model, String name) {
        int index = -1;
        
        for(int i=0; i < model.getSize(); i++) {
            System.out.println(((String)model.getElementAt(i)));
            if(((String)model.getElementAt(i)).toLowerCase().equals(name.toLowerCase())) {
                index = i;
                break;
            }
        }
        
        return index;
    }

    private static void writeToDisk(String listName, DefaultListModel data) {
        StringBuffer payload = new StringBuffer();
        
        for (int i = 0; i < data.size(); i++)
            payload.append(data.elementAt(i) + "," + cardType + "" + "\n");
        try {
            Resources.dumpTextFile(cardFolder + listName + fileExtension,
                    payload.toString());
        } catch (IOException err) {
            System.out.println("[Simple:localSaveGame] can't write save game.");
        }
        
    }
    
    /**
     * 
     * 
     * 
     * 
     * Layout code
     * 
     * 
     *  
     * 
     */
    
    private JButton createSelectButton(String caption) {
        JButton ret = new JButton(caption);
        Dimension dims = new Dimension(50, 20);
        
        ret.setMaximumSize(dims);
        ret.setPreferredSize(dims);
        ret.addActionListener(this);
        
        return ret;
    }
    
    public JPanel buildWeaponsPanel() {
        JPanel content = new JPanel();
        
        content.setLayout(new BorderLayout());
        
        predefinedModel = new DefaultListModel();
        
        playListModel = new DefaultListModel();
        
        this.repaint();
        
        Box pageLayout = Box.createVerticalBox();
        Box header = Box.createVerticalBox();
        
        Box cardDisplay = Box.createHorizontalBox();
        Box controlsFlow = Box.createVerticalBox();
        Box pageButtons = Box.createVerticalBox();
        
        header.add(instructionsLabel);
        header.add(Box.createVerticalStrut(50));
        
        predefinedList = new JList(predefinedModel);
        predefinedList.setFont(new Font("Arial", Font.BOLD, 20));
        playList = new JList(playListModel);
        playList.setFont(new Font("Arial", Font.BOLD, 15));
        updatePredefinedList();
        
        JPanel intermediate = new JPanel();
        
        Dimension listDims = new Dimension(150, 210);
        
        predefinedList.addListSelectionListener(predefinedListener);
        predefinedList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        
        JScrollPane j1 = new JScrollPane(predefinedList);
        
        j1.setPreferredSize(listDims);
        j1.setMaximumSize(listDims);
        j1.setMinimumSize(listDims);
        j1
        .setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
        
        JScrollPane j2 = new JScrollPane(playList);
        j2.setPreferredSize(listDims);
        j2.setMaximumSize(listDims);
        j2.setMinimumSize(listDims);
        j2.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
        
        JButton customButton = null;
        
        JPanel fileBox = new JPanel();
        fileBox.setLayout(new BorderLayout());
        
        fileBox.add(new JLabel("Saved weapons: "), BorderLayout.NORTH);
        
        fileBox.add(j1, BorderLayout.CENTER);
        customButton = new JButton(lookup("apply_button"));
        customButton.setActionCommand("use_card_set");
        buttons.put("use_card_set" , customButton);
        customButton.addActionListener(this);
        customButton.setMaximumSize(new Dimension(200, 30));
        customButton.setMinimumSize(new Dimension(200, 30));
        
        Box button = Box.createVerticalBox();
        button.add(Box.createVerticalStrut(10));
        button.add(Box.createHorizontalStrut(30));
        button.add(customButton);
        button.add(Box.createVerticalStrut(10));
        
        fileBox.add(button, BorderLayout.SOUTH);
        
        Box weaponsBox = Box.createHorizontalBox();
        
        weaponsBox.add(j2);
        
        pageButtons.add(Box.createVerticalStrut(5));
        
        customButton = new JButton(lookup("new_list_button"));
        customButton.setActionCommand("new_list");
        buttons.put("new_list" , customButton);
        customButton.addActionListener(this);
        customButton.setMaximumSize(new Dimension(100, 30));
        customButton.setMinimumSize(new Dimension(100, 30));
        pageButtons.add(customButton);
        pageButtons.add(Box.createVerticalStrut(10));
        
        
        customButton = new JButton(lookup("clear_list_button"));
        customButton.setActionCommand("clear_list");
        buttons.put("clear_list" , customButton);
        customButton.addActionListener(this);
        customButton.setMaximumSize(new Dimension(100, 30));
        customButton.setMinimumSize(new Dimension(100, 30));
        pageButtons.add(customButton);
        pageButtons.add(Box.createVerticalStrut(10));
        
        customButton = new JButton(lookup("delete_list_button"));
        customButton.setActionCommand("delete_list");
        buttons.put("delete_list" , customButton);
        customButton.addActionListener(this);
        customButton.setMaximumSize(new Dimension(100, 30));
        customButton.setMinimumSize(new Dimension(100, 30));
        pageButtons.add(customButton);
        pageButtons.add(Box.createVerticalStrut(10));
        
        customButton = new JButton(lookup("save_listButton"));
        customButton.setActionCommand("save_list");
        buttons.put("save_list" , customButton);
        customButton.addActionListener(this);
        
        customButton.setMaximumSize(new Dimension(100, 30));
        customButton.setMinimumSize(new Dimension(100, 30));
        pageButtons.add(customButton);
        pageButtons.add(Box.createVerticalStrut(10));

        customButton = new JButton(lookup("new_weapon_button"));
        customButton.setActionCommand("new_card");
        buttons.put("new_card" , customButton);
        customButton.addActionListener(this);
        customButton.setMaximumSize(new Dimension(100, 30));
        customButton.setMinimumSize(new Dimension(100, 30));
        pageButtons.add(customButton);
        pageButtons.add(Box.createVerticalStrut(10));
        
        customButton = new JButton(lookup("edit_weapon_card_button"));
        customButton.setActionCommand("edit_card");
        buttons.put("edit_card" , customButton);
        customButton.addActionListener(this);
        customButton.setMaximumSize(new Dimension(100, 30));
        customButton.setMinimumSize(new Dimension(100, 30));
        pageButtons.add(customButton);
        pageButtons.add(Box.createVerticalStrut(10));
        
        customButton = new JButton(lookup("remove_button"));
        customButton.setActionCommand("remove_card");
        buttons.put("remove_card" , customButton);
        customButton.addActionListener(this);
        customButton.setMaximumSize(new Dimension(100, 30));
        customButton.setMinimumSize(new Dimension(100, 30));
        pageButtons.add(customButton);
        pageButtons.add(Box.createVerticalStrut(5));
        
        pageButtons.setBorder(BorderFactory.createEtchedBorder());
        
        weaponsBox.add(Box.createHorizontalStrut(20));
        weaponsBox.add(pageButtons);
        
        Box overall = Box.createHorizontalBox();
        overall.add(fileBox);
        overall.add(Box.createHorizontalStrut(50));
        overall.add(weaponsBox);
        
        content.add(header, BorderLayout.NORTH);
        content.add(overall, BorderLayout.SOUTH);
        
        return content;
        
    }
    
    public WeaponSelect(CluedoConfig gameConfig) {
        this.gameConfig = gameConfig;
        add(buildWeaponsPanel());
        
        
        disableButtons();
    }
    
    /**
     * Gets a button from the hashtable
     * 
     * @param command
     * @return a button or null
     */
    private JButton getButton(String command) {
        return (JButton)buttons.get(command);
    }
    
    
    /**
     * Reads a card set from file into a vector with a filter applied
     * 
     * @param cardset name
     * @param filter the type of cards to load
     * @return vector of cards read from file or an empty vector
     */
    public static Vector loadCardSet(String cardSet, String filter) {
        Vector list = new Vector();
        String fileName = cardFolder + cardSet + fileExtension;
        
        try {
            StringTokenizer lines = new StringTokenizer(Cluedo.API.Resources
                    .catTextFileExt(fileName, null), "\n");
            
            StringTokenizer parts = null;
            
            String cardName = "";
            String cardType = "";
            
            while (lines.hasMoreTokens() == true) {
                // Get ID and type
                String line = lines.nextToken();
                if (!(line.charAt(0) == '#')) {
                    
                    parts = new StringTokenizer(line, ",");
                    
                    cardName = parts.nextToken();
                    cardType = parts.nextToken();
                   
                    if (cardType.equals(filter) || filter.equals("")) {
                        list.add(cardName);
                    }
                }
            }
        } catch (Exception IO) {
            System.out.println("[WeaponSelect] Can't load set " + cardSet);
            list = new Vector();
        }
        
        return list;
    }
    
    
    
    
    private static String lookup(String function) {
      	return LanguagePack.getString(function, DEFAULT_GROUP);
      }

    
    	/**
    	 * Adds relevant arguments to string from String array 
    	 * 
    	 * @param string
    	 * @param names2
    	 * @return
    	 */
    	private static String addArguments(String string, String[] names2) {
    		for(int i=0;i<names2.length;i++)
    			string = string.replaceAll("%"+(i+1), names2[i]);
    		if(string.indexOf("@@") > -1) {
    			string = addBreaks(string);
    		}
    		return string;
    	}
    	
    	
    	/**
    	 * @param string
    	 * @return
    	 */
    	private static String addBreaks(String string) {
    		string = string.replaceAll("@@", "<br>");
    		string = Constants.HTML_ON + string + Constants.HTML_OFF;
    		return string;
    	}
      
}