/*
 * This file is part of the DistSim distributed simulation framework (client)
 * Copyright (C) 2007 Ulf Hermann
 *
 * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */
package brn.distsim.client.tableModels;

import java.awt.event.ActionEvent;
import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import brn.distsim.client.DBConnector;
import brn.distsim.client.data.Group;
import brn.distsim.client.data.Host;
import brn.distsim.client.data.Simulation;
import brn.distsim.client.data.Study;
import brn.distsim.client.ui.ClientFrame;
import brn.distsim.client.ui.MonitorPanel;
import brn.distsim.wrapper.RemoteSimulation;


public class MonitorTableModel extends BaseTableModel {

	private static final long serialVersionUID = 1590952144614933447L;

	private Map<Integer, String> hosts;

	private Study study;

	private List<Simulation> simulations;

	public MonitorTableModel(ClientFrame parent, Study study) {
		super(parent, parent.getMonitorPanel().getContent());
		this.study = study;
		try {
			simulations = new ArrayList<Simulation>();
			MonitorPanel panel = frame.getMonitorPanel();
			subject.setModel(this);
			if (study != null) {
				panel.setStudy(study.getName(), study.getVersion());
				readData();
			}
			reconnectButton(panel.getCancelButton());
			reconnectButton(panel.getStopButton());
			reconnectButton(panel.getRestartButton());
			reconnectButton(panel.getRefreshButton());
			reconnectButton(panel.getDeleteButton());
			reconnectButton(panel.getSelectButton());
		} catch (SQLException e) {
			error(e);
		}
	}

	private void readData() throws SQLException {
		simulations.clear();
		study.loadFromDb();
		Connection results = DBConnector.getResults();
		hosts = Host.getHosts(DBConnector.getDefinitions());
		for (Group g : study) {
			g.loadFromDb();
			for (Simulation s : g) {
				s.loadProgress(results);
				simulations.add(s);
			}
		}
		fireTableStructureChanged();
	}

	public void actionPerformed(ActionEvent e) {
		try {
			String command = e.getActionCommand();
			if (command.equals("cancel")) {
				cancelSimulation();
				readData();
			} else if (command.equals("stop")) {
				stopSimulator();
				readData();
			} else if (command.equals("restart")) {
				restartSimulation();
				readData();
			} else if (command.equals("rollback")) {
				readData();
			} else if (command.equals("delete")) {
				deleteResults();
				readData();
			} else if (command.equals("select")) {
				new ResultsModel(frame, simulations.get(
						subject.getSelectedRow()).getResults(
						DBConnector.getResults()));
				switchTabs();
			}
		} catch (SQLException ex) {
			error(ex);
		}
	}

	private void restartSimulation() {
		try {
			deleteResults();
			Simulation sim = simulations.get(subject.getSelectedRow());
			sim.unassign();
		} catch (SQLException e) {
			error(e);
		}
	}

	private void deleteResults() {
		try {
			Simulation sim = simulations.get(subject.getSelectedRow());
			if (sim.getProgress().getState().equals("RUNNING"))
				stopSimulator();
			sim.getResults(DBConnector.getResults()).deleteAll();
		} catch (SQLException e) {
			error(e);
		}
	}

	private void stopSimulator() {
		try {
			RemoteSimulation sim = getRemote();
			if (sim != null)
				sim.stop();
		} catch (RemoteException e) {
			AddRemoveTableModel.error(e);
		}
	}

	private RemoteSimulation getRemote() throws RemoteException {
		try {
			int hostId = simulations.get(subject.getSelectedRow()).getHost();
			String hostName = hosts.get(hostId);
			return (RemoteSimulation) Naming.lookup("rmi://" + hostName
					+ "/host" + hostId);
		} catch (MalformedURLException e) {
			AddRemoveTableModel.error(e);
		} catch (NotBoundException e) {
			AddRemoveTableModel.error(e);
		}
		return null;
	}

	private void cancelSimulation() {
		try {
			RemoteSimulation sim = getRemote();
			if (sim != null)
				sim.cancel();
		} catch (RemoteException e) {
			AddRemoveTableModel.error(e);
		}
	}

	public int getColumnCount() {
		return 8;
	}

	public int getRowCount() {
		return simulations.size();
	}

	public String getColumnName(int columnIndex) {
		switch (columnIndex) {
		case 0:
			return "group id";
		case 1:
			return "simulation id";
		case 2:
			return "host name";
		case 3:
			return "defined at";
		case 4:
			return "started at";
		case 5:
			return "expected end";
		case 6:
			return "progress";
		case 7:
			return "state";
		default:
			return null;
		}
	}

	public Class<?> getColumnClass(int columnIndex) {
		switch (columnIndex) {
		case 0:
			return Integer.class;
		case 1:
			return Integer.class;
		case 2:
			return String.class;
		case 3:
			return Timestamp.class;
		case 4:
			return Timestamp.class;
		case 5:
			return Timestamp.class;
		case 6:
			return Float.class;
		case 7:
			return String.class;
		default:
			return null;
		}
	}

	public Object getValueAt(int rowIndex, int columnIndex) {
		Simulation s = simulations.get(rowIndex);
		switch (columnIndex) {
		case 0:
			return s.getGroupId();
		case 1:
			return s.getId();
		case 2:
			return hosts.get(s.getHost());
		case 3:
			return s.getDefined();
		case 4:
			return s.getProgress().getStarted();
		case 5:
			return s.getProgress().getExpectedEnd();
		case 6:
			return new Float(s.getProgress().getPercentageDone() / 100.0);
		case 7:
			return s.getProgress().getState();
		default:
			return null;
		}
	}

}
