//***********************************************************
//*
//* File:           TournamentPanel.java
//* Author:         Srikant Krishna
//* Contact:        srikant@cs.columbia.edu
//* Update:         9.13.2002
//*
//* Description:    Visual Tournament setup and analysis 
//*                 class.
//*
//***********************************************************

package ui;

import java.util.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.table.TableModel;
import java.text.NumberFormat;


public final class TournamentPanel extends JPanel {

    JTabbedPane         _tabs;
    ConfigurationPanel  _configure;
    AnalysisPanel       _analysis;
    IFCTournament       _tournament;
    IFCModel            _model;
    IFCUI               _ui;
    Random              _random;

    Hashtable		_hashtable;

    static final int    _CWIDTH = 600;
    static final int    _CHEIGHT = 600;
    static final int    _CMIN_GAMES = 1;
    static final int    _CMAX_GAMES = 10000;
    static final int    _CMAX_SAMPLES = 250;
    static final int    _CMAX_GROUPS = 7;
    static final boolean _MY_TYPE_TOURNAMENT = true;

private class MyGroup
{
	int numplayers;
	Class[] clist;
	MyGroup()
	{
		numplayers = 0;
		clist = new Class[3];
	}
	public void add(Class cl)
	{
		clist[numplayers] = cl;
		numplayers++;
	}
	public Class getRandomPlayer()
	{
		int index = _random.nextInt(numplayers);
		return clist[index];
	}
}

    public TournamentPanel() throws Exception {
        super();
        setLayout(new BorderLayout());
        setBorder(BorderFactory.createCompoundBorder(BorderFactory.createRaisedBevelBorder(),
                                                     BorderFactory.createLoweredBevelBorder()));
        setPreferredSize(new Dimension(_CWIDTH, _CHEIGHT));
        setMinimumSize(new Dimension(_CWIDTH, _CHEIGHT));

        _configure = new ConfigurationPanel();
        _tabs = new JTabbedPane();
        _tabs.addTab("Configure", _configure);
        _tabs.addTab("Analysis", new JPanel());
        add(_tabs);
        _random = new Random();
    }

    public JButton[] exportTools() {
        return _configure.exportTools();
    }

    public JMenu exportMenu() {
        return null;
    }

    public void register(IFCUI __ui, IFCModel __model) throws Exception {
        _ui = __ui;
        _model = (IFCModel) __model.getClass().newInstance();
        _configure.register(_model.exportConfiguration());;
        repaint();
    }

    public JPanel exportViewPanel() throws Exception {
        return this;
    }
    
    private final class ConfigurationPanel extends JPanel implements ActionListener, ListSelectionListener {

        JScrollPane      _scrplayers;
        JScrollPane      _scrclasses;
        JList            _players;
        JList            _classes;
        JTextField       _numplayers;
        JTextField       _numgames;
        JTextField       _numrobotsfield;
        JTextField       _numroundsfield;
        JTextField       _sizefield;
        JButton          _run;
        IFCConfiguration _config;
        JRadioButton     _roundrobin;
        JRadioButton     _multisample;
        JRadioButton     _multiplayer;
        final ImageIcon  _CRUN_ICON             = new ImageIcon("Images/alum_run.gif");
        final int        _CSLOT_WIDTH           = _CWIDTH;
        final int        _CSLOT_HEIGHT          = 100;
        final int        _CTEXT_WIDTH           = _CWIDTH;
        final int        _CTEXT_HEIGHT          = 40;
        final int        _CRADIO_HEIGHT         = 20;
        final int        _CDEFAULT_NUM_GAMES    = 10;
        final int        _CDEFAULT_NUM_ROBOTS   = 3;
        final int        _CDEFAULT_SIZE         = 50;
        final int        _CDEFAULT_NUM_ROUNDS   = 3;
        final Font       _CCONFIG_FONT          = new Font("Courier", Font.BOLD, 16);
        final Font       _CLIST_FONT            = new Font("Courier", Font.BOLD, 10);
        final String     _CSPACER               = "  ";
        
        public ConfigurationPanel() throws Exception {
            super();
            setLayout(new GridLayout(2, 2));
            setBorder(BorderFactory.createCompoundBorder(BorderFactory.createRaisedBevelBorder(),
                                                     BorderFactory.createLoweredBevelBorder()));
            setPreferredSize(new Dimension(_CWIDTH, _CHEIGHT));
            setMinimumSize(new Dimension(_CWIDTH, _CHEIGHT));

            _run = new JButton(_CRUN_ICON);
            _run.addActionListener(this);
        }

        public void register(IFCConfiguration __config) throws Exception {
            SlotPanel slot;
            JPanel box;
            JLabel label;
            ButtonGroup bg;

            removeAll();
            _config = __config;
            slot = new SlotPanel(_CSLOT_WIDTH, _CSLOT_HEIGHT);
            slot.setVertical();
            _classes = new JList(_config.classList());
            _classes.setFont(_CLIST_FONT);
            _classes.addListSelectionListener(this);
            _scrclasses = new JScrollPane(_classes);
            label = new JLabel("Available Players");
            label.setFont(_CCONFIG_FONT);
            slot.add(label, _scrclasses);
            add(slot);

            slot = new SlotPanel(_CSLOT_WIDTH, _CSLOT_HEIGHT);
            slot.setVertical();
            _players = new JList(_config.playerList());
            _players.setFont(_CLIST_FONT);
            _players.addListSelectionListener(this);
            _scrplayers = new JScrollPane(_players);
            label = new JLabel("Contestants");
            label.setFont(_CCONFIG_FONT);
            slot.add(label, _scrplayers);
            add(slot);;

            box = new JPanel();
            box.setLayout(new BoxLayout(box, BoxLayout.Y_AXIS));
            slot = new SlotPanel(_CTEXT_WIDTH, _CTEXT_HEIGHT);
            box.add(slot);

            slot = new SlotPanel(_CTEXT_WIDTH, _CTEXT_HEIGHT);
            _numplayers = new JTextField(Integer.toString(_config.numPlayers()));
            _numplayers.setFont(_CCONFIG_FONT);
            label = new JLabel("NumPlayers:  ");
            label.setFont(_CCONFIG_FONT);
            slot.add(label, _numplayers);
            box.add(slot);

            slot = new SlotPanel(_CTEXT_WIDTH, _CTEXT_HEIGHT);
            _numgames = new JTextField(Integer.toString(_CDEFAULT_NUM_GAMES));
            _numgames.setFont(_CCONFIG_FONT);
            label = new JLabel("NumGames:    ");
            label.setFont(_CCONFIG_FONT);
            slot.add(label, _numgames);
            box.add(slot);
            add(box);
            
            slot = new SlotPanel(_CTEXT_WIDTH, _CTEXT_HEIGHT);
            _numrobotsfield = new JTextField(Integer.toString(_CDEFAULT_NUM_ROBOTS));
            _numrobotsfield.setFont(_CCONFIG_FONT);
            label = new JLabel("NumRobots:   ");
            label.setFont(_CCONFIG_FONT);
            slot.add(label, _numrobotsfield);
            box.add(slot);
            add(box);

            slot = new SlotPanel(_CTEXT_WIDTH, _CTEXT_HEIGHT);
            _sizefield = new JTextField(Integer.toString(_CDEFAULT_SIZE));
            _sizefield.setFont(_CCONFIG_FONT);
            label = new JLabel("Size:        ");
            label.setFont(_CCONFIG_FONT);
            slot.add(label, _sizefield);
            box.add(slot);
            add(box);
            
            slot = new SlotPanel(_CTEXT_WIDTH, _CTEXT_HEIGHT);
            _numroundsfield = new JTextField(Integer.toString(_CDEFAULT_NUM_ROUNDS));
            _numroundsfield.setFont(_CCONFIG_FONT);
            label = new JLabel("NumRounds:   ");
            label.setFont(_CCONFIG_FONT);
            slot.add(label, _numroundsfield);
            box.add(slot);
            add(box);
            
            box = new JPanel();
            box.setLayout(new BoxLayout(box, BoxLayout.Y_AXIS));
            slot = new SlotPanel(_CTEXT_WIDTH, _CTEXT_HEIGHT);
            box.add(slot);
            slot = new SlotPanel(_CTEXT_WIDTH, _CTEXT_HEIGHT);
            label = new JLabel("Tournament Type");
            label.setFont(_CCONFIG_FONT);
            slot.add(new JLabel(_CSPACER), label);
            box.add(slot);
            slot = new SlotPanel(_CTEXT_WIDTH, _CRADIO_HEIGHT);
            _roundrobin = new JRadioButton("Round Robin");
            _roundrobin.setFont(_CLIST_FONT);
            _roundrobin.addActionListener(this);
            _roundrobin.setSelected(true);
            slot.add(new JLabel(_CSPACER), _roundrobin);
            box.add(slot);
            slot = new SlotPanel(_CTEXT_WIDTH, _CRADIO_HEIGHT);
            _multiplayer = new JRadioButton("Multiplayer");
            _multiplayer.setFont(_CLIST_FONT);
            _multiplayer.addActionListener(this);
            slot.add(new JLabel(_CSPACER), _multiplayer);
            box.add(slot);
            slot = new SlotPanel(_CTEXT_WIDTH, _CRADIO_HEIGHT);
            _multisample = new JRadioButton("Multisample");
            _multisample.setFont(_CLIST_FONT);
            _multisample.addActionListener(this);
            slot.add(new JLabel(_CSPACER), _multisample);
            box.add(slot);
            bg = new ButtonGroup();
            bg.add(_roundrobin);
            bg.add(_multiplayer);
            bg.add(_multisample);
            add(box);
        }

        public void valueChanged(ListSelectionEvent __event) {
            try {
                Object source = __event.getSource();
                ListModel listmodel;
                Vector contents;
                Class selection;
                int val;
                int _MAX;
                
                if (source == _classes) {
                    listmodel = _classes.getModel();
                    selection = (Class) listmodel.getElementAt(_classes.getSelectedIndex());

                    contents = new Vector();
                    listmodel = _players.getModel();
                    _MAX = listmodel.getSize();
                    for (int i=0; i < _MAX; i++) {
                        contents.add(listmodel.getElementAt(i));
                    }
                    if (!contents.contains(selection)) {
                        contents.add(selection);
                        _players.setListData(contents);
                        _numplayers.setText(Integer.toString(contents.size()));
                        repaint();
                    }
                }

                if (source == _players) {
                    val = _players.getSelectedIndex();
                    contents = new Vector();
                    listmodel = _players.getModel();
                    _MAX = listmodel.getSize();
                    for (int i=0; i < _MAX; i++) {
                        if (i != val) {
                            contents.add(listmodel.getElementAt(i));
                        }
                    }
                    _players.setListData(contents);
                    _numplayers.setText(Integer.toString(contents.size()));
                    repaint();
                }

            } catch (Exception EXC) {
                System.out.println(EXC.getMessage());
                EXC.printStackTrace();
            }
        }

        public void actionPerformed(ActionEvent __event) {
            try {
                Object source = __event.getSource();
                IFCGameRecord[] games=null;
                IFCTournamentResults[] results;
                IFCTournament tournament;
                ListModel listmodel;
                ParseValue pv;
                ArrayList alist;
                Class[] clist;
                Class[] plist;
                int _MAXI;
                int _MAXJ;
                int _MAXK;
                int _MAXS;
                int rounds;
                int robots;
                int size;

		MyGroup[] mygroups;
		mygroups = new MyGroup[_CMAX_GROUPS];
		for(int i=0;i < _CMAX_GROUPS;i++)
			mygroups[i] = new MyGroup();
		_hashtable = new Hashtable();
		_hashtable.put("class Rectangles.Group1Player1", new Integer(0));
		_hashtable.put("class Rectangles.Group2PlayerF", new Integer(1));
		_hashtable.put("class Rectangles.Group3Player6", new Integer(2));
		_hashtable.put("class Rectangles.Group5Player1", new Integer(3));
		_hashtable.put("class Rectangles.Group6Player2f", new Integer(4));
		_hashtable.put("class Rectangles.Group7Player8", new Integer(5));
		_hashtable.put("class Rectangles.Group8Player0", new Integer(6));

                if (source == _run) {
                    if (_roundrobin.isSelected()) {
                        listmodel = _players.getModel();
                        _MAXI = listmodel.getSize();
                        if (_MAXI < 2) {
                            throw new Exception("Error:  Invalid Number of Players Specified");
                        }

                        clist = new Class[_MAXI];
                        for (int i=0; i < _MAXI; i++) {
                            clist[i] = (Class) listmodel.getElementAt(i);
				int val = ((Integer) _hashtable.get(clist[i].toString())).intValue();
				System.out.println("val= "+val+", pt= "+mygroups[val]);
				mygroups[val].add(clist[i]);
                        }
                        Arrays.sort(clist, new Util.ClassSorter());

                        pv = ParseValue.parseIntegerValue(_numgames.getText(), _CMIN_GAMES, _CMAX_GAMES);
                        if (!pv.isValid()) {
                            throw new Exception("Error:  Number of Games Out of Range");
                        }
                        _MAXK = ((Integer) pv.value()).intValue();

                        pv = ParseValue.parseIntegerValue(_numrobotsfield.getText(), _config.numRobotsMin(), _config.numRobotsMax());
                        if (!pv.isValid()) {
                            throw new Exception("Error:  Number of Robots Out of Range");
                        }
                        robots = ((Integer) pv.value()).intValue();

                        pv = ParseValue.parseIntegerValue(_sizefield.getText(), _config.sizeMin(), _config.sizeMax());
                        if (!pv.isValid()) {
                            throw new Exception("Error:  Specified Size Out of Range");
                        }
                        size = ((Integer) pv.value()).intValue();

                        pv = ParseValue.parseIntegerValue(_numroundsfield.getText(), _config.numRoundsMin(), _config.numRoundsMax());
                        if (!pv.isValid()) {
                            throw new Exception("Error:  Number of Rounds Out of Range");
                        }
                        rounds = ((Integer) pv.value()).intValue();

                        _MAXJ = _MAXI;
		if(!_MY_TYPE_TOURNAMENT)
		{
                        games = new GameRecord[(int) (_MAXI*_MAXJ*_MAXK - _MAXI*_MAXK)/2];
                        for (int i=0, pos=0; i < _MAXI; i++) {
                            for (int j=i+1; j < _MAXJ; j++) {
                                for (int k=0; k < _MAXK; k++, pos++) {
                                    plist = new Class[2];
                                    plist[0] = clist[i];
                                    plist[1] = clist[j];
                                    games[pos] = new GameRecord();
                                    games[pos].setPlayers(plist);
                                    games[pos].setNumRobots(robots);
                                    games[pos].setSize(size);
                                    games[pos].setNumRounds(rounds);
                                    if (k == _MAXK - 1) {
                                        games[pos].setBatchComplete(true);
                                    }
                                }
                            }
                        }
		}
		else
		{
			// My type of Tournament
			int skip = (_CMAX_GROUPS*(_CMAX_GROUPS - 1))/2;
			int totalgames = _MAXK * skip;
			games = new GameRecord[totalgames];
                        for (int i=0, pos=0; i < _CMAX_GROUPS; i++) {
                            for (int j=i+1; j < _CMAX_GROUPS; j++) {
                                for (int k=0; k < _MAXK; k++) {
                                    plist = new Class[2];
                                    plist[0] = mygroups[i].getRandomPlayer();
                                    plist[1] = mygroups[j].getRandomPlayer();
                                    games[pos + k*skip] = new GameRecord();
                                    games[pos + k*skip].setPlayers(plist);
                                    games[pos + k*skip].setNumRobots(robots);
                                    games[pos + k*skip].setSize(size);
                                    games[pos + k*skip].setNumRounds(rounds);
                                }
				pos++;
                            }
                        }
		}
                    }
                    else
                    if (_multiplayer.isSelected()) {
                        listmodel = _players.getModel();
                        _MAXI = listmodel.getSize();
                        if (_MAXI < 2) {
                            throw new Exception("Error:  Invalid Number of Players Specified");
                        }
                        clist = new Class[_MAXI];
                        for (int i=0; i < _MAXI; i++) {
                            clist[i] = (Class) listmodel.getElementAt(i);
                        }

                        pv = ParseValue.parseIntegerValue(_numgames.getText(), _CMIN_GAMES, _CMAX_GAMES);
                        if (!pv.isValid()) {
                            throw new Exception("Error:  Number of Games Out of Range");
                        }
                        _MAXJ = ((Integer) pv.value()).intValue();
                        
                        pv = ParseValue.parseIntegerValue(_numrobotsfield.getText(), _config.numRobotsMin(), _config.numRobotsMax());
                        if (!pv.isValid()) {
                            throw new Exception("Error:  Number of Robots Out of Range");
                        }
                        robots = ((Integer) pv.value()).intValue();
                        
                        pv = ParseValue.parseIntegerValue(_sizefield.getText(), _config.sizeMin(), _config.sizeMax());
                        if (!pv.isValid()) {
                            throw new Exception("Error:  Number of Size Out of Range");
                        }
                        size = ((Integer) pv.value()).intValue();
                        
                        pv = ParseValue.parseIntegerValue(_numroundsfield.getText(), _config.numRoundsMin(), _config.numRoundsMax());
                        if (!pv.isValid()) {
                            throw new Exception("Error:  Number of Rounds Out of Range");
                        }
                        rounds = ((Integer) pv.value()).intValue();

                        games = new GameRecord[_MAXJ];
                        for (int j=0; j < _MAXJ; j++) {
                            plist = new Class[_MAXI];
                            System.arraycopy(clist, 0, plist, 0, _MAXI);
                            games[j] = new GameRecord();
                            games[j].setPlayers(plist);
                            games[j].setNumRobots(robots);
                            games[j].setSize(size);
                            games[j].setNumRounds(rounds);
                            if (j == _MAXJ - 1) {
                                games[j].setBatchComplete(true);
                            }
                        }
                    }
                    else
                    if (_multisample.isSelected()) {
                    
                        listmodel = _players.getModel();
                        _MAXI = listmodel.getSize();
                        if (_MAXI < 2) {
                            throw new Exception("Error:  Invalid Number of Players Specified");
                        }
                        clist = new Class[_MAXI];
                        for (int i=0; i < _MAXI; i++) {
                            clist[i] = (Class) listmodel.getElementAt(i);
				int val = ((Integer) _hashtable.get(clist[i].toString())).intValue();
				mygroups[val].add(clist[i]);
                        }

                        pv = ParseValue.parseIntegerValue(_numplayers.getText(), _config.numPlayersMin(), _config.numPlayersMax());
                        if (!pv.isValid()) {
                            throw new Exception("Error:  Number of Players Out of Range");
                        }
                        _MAXJ = ((Integer) pv.value()).intValue();
                        if (_MAXI < _MAXJ) {
                            throw new Exception("Error:  Number of Players per Game Is Larger Than Contestant List Size");
                        }

                        pv = ParseValue.parseIntegerValue(_numgames.getText(), _CMIN_GAMES, _CMAX_GAMES);
                        if (!pv.isValid()) {
                            throw new Exception("Error:  Number of Games Out of Range");
                        }
                        _MAXK = ((Integer) pv.value()).intValue();

                        pv = ParseValue.parseIntegerValue(_numrobotsfield.getText(), _config.numRobotsMin(), _config.numRobotsMax());
                        if (!pv.isValid()) {
                            throw new Exception("Error:  Number of Robots Out of Range");
                        }
                        robots = ((Integer) pv.value()).intValue();
                        
                        pv = ParseValue.parseIntegerValue(_sizefield.getText(), _config.sizeMin(), _config.sizeMax());
                        if (!pv.isValid()) {
                            throw new Exception("Error:  Number of Size Out of Range");
                        }
                        size = ((Integer) pv.value()).intValue();
                        
                        pv = ParseValue.parseIntegerValue(_numroundsfield.getText(), _config.numRoundsMin(), _config.numRoundsMax());
                        if (!pv.isValid()) {
                            throw new Exception("Error:  Number of Rounds Out of Range");
                        }
                        rounds = ((Integer) pv.value()).intValue();

		if(!_MY_TYPE_TOURNAMENT)
		{
                        _MAXS = (int) choose(_MAXI, _MAXJ);
                        _MAXS = (_MAXS > _CMAX_SAMPLES) ? _CMAX_SAMPLES : _MAXS;
                        plist = new Class[_MAXJ];
                        alist = new ArrayList();
                        games = new GameRecord[_MAXS * _MAXK];
                        for (int s=0, pos=0; s < _MAXS; s++) {
                            alist.clear();
                            for (int i=0; i < _MAXI; i++) {
                                alist.add(clist[i]);
                            }
                            for (int j=0; j < _MAXJ; j++) {
                                plist[j]  = (Class) alist.remove(_random.nextInt(alist.size()));
                            }
                            for (int k=0; k < _MAXK; k++, pos++) {
                                games[pos] = new GameRecord();
                                games[pos].setPlayers(plist);
                                games[pos].setNumRobots(robots);
                                games[pos].setSize(size);
                                games[pos].setNumRounds(rounds);
                                if (k == _MAXK - 1) {
                                    games[pos].setBatchComplete(true);
                                }
                            }
                        }
		}
		else
		{
                        _MAXS = (int) choose(_CMAX_GROUPS, _MAXJ);
                        _MAXS = (_MAXS > _CMAX_SAMPLES) ? _CMAX_SAMPLES : _MAXS;
                        plist = new Class[_MAXJ];
                        alist = new ArrayList();
                        games = new GameRecord[_MAXS * _MAXK];
			int skip = _MAXS;
                        for (int s=0, pos=0; s < _MAXS; s++) {
                            for (int k=0; k < _MAXK; k++) {
                            	alist.clear();
                            	for (int i=0; i < _CMAX_GROUPS; i++) {
                            	    alist.add(new Integer(i));
                            	}
                            	for (int j=0; j < _MAXJ; j++) {
                            	    int groupindex = ((Integer) alist.remove(_random.nextInt(alist.size()))).intValue();
                                	plist[j] = mygroups[groupindex].getRandomPlayer();
                            	}
                                games[pos + k*skip] = new GameRecord();
                                games[pos + k*skip].setPlayers(plist);
                                games[pos + k*skip].setNumRobots(robots);
                                games[pos + k*skip].setSize(size);
                                games[pos + k*skip].setNumRounds(rounds);
                            }
			pos++;
                        }
		} // End my if
                    }
                    tournament = new Tournament();
                    tournament.setGames(games);
                    _model.run(tournament);
                    _tabs.remove(1);
                    results = new IFCTournamentResults[2];
                    results[0] = new TournamentResults(games);
                    results[1] = new PlayerSpecificResults(games);
			results[0].Print();
			results[1].Print();
                    _analysis = new AnalysisPanel(results);
                    _tabs.addTab("Analysis", _analysis);
                    _tabs.setSelectedComponent(_analysis);
                    _ui.maximizeViewSize();
                    repaint();
                }
            } catch (Exception EXC) {
                System.out.println(EXC.getMessage());
                EXC.printStackTrace();
            }
        }

        public JButton[] exportTools() {
            JButton[] RET = new JButton[1];
            RET[0] = _run;
            return RET;
        }
        
        double choose(int __c, int __n) {
            return  (factorial(__c) / (factorial(__n) * factorial(__c - __n)));
        }
        
        double factorial(int __n) {
            double RET=1;

            for (int i=2; i <= __n; i++) {
                RET *= i;
            }
            return RET;
        }
    }

    private final class AnalysisPanel extends JPanel {

        JTabbedPane             _tabs;
        IFCTournamentResults[]  _results;
        final Font              _CHEADER_FONT = new Font("Courier", Font.BOLD, 14);
        final Font              _CCELL_FONT = new Font("Courier", Font.BOLD, 12);

        public AnalysisPanel(IFCTournamentResults[] __results) throws Exception {
            super();
            
            JTable table;
            JScrollPane scr;
            int _MAX;

            setLayout(new BorderLayout());
            setBorder(BorderFactory.createCompoundBorder(BorderFactory.createRaisedBevelBorder(),
                                                     BorderFactory.createLoweredBevelBorder()));
            setPreferredSize(new Dimension(_CWIDTH, _CHEIGHT));
            setMinimumSize(new Dimension(_CWIDTH, _CHEIGHT));

            _tabs = new JTabbedPane();
            _results = __results;
            _MAX = _results.length;
            for (int i=0; i < _MAX; i++) {
                table = new JTable();
                table.setFont(_CCELL_FONT);
                table.getTableHeader().setFont(_CHEADER_FONT);
                table.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS);
                table.setModel(_results[i]);
                table.getColumnModel().addColumnModelListener(_results[i]);
                scr = new JScrollPane(table);
                _tabs.add(_results[i].name(), scr);
            }
            add(_tabs);
        }
    }
}



