/* -*- tab-width: 4 -*-
 *
 * Electric(tm) VLSI Design System
 *
 * File: Project.java
 * Project management tool: cell history dialog
 * Written by: Steven M. Rubin
 *
 * Copyright (c) 2006, Static Free Software. All rights reserved.
 *
 * Electric(tm) 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 3 of the License, or
 * (at your option) any later version.
 *
 * Electric(tm) 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, see <http://www.gnu.org/licenses/>.
 */
package com.sun.electric.tool.project;

import com.sun.electric.database.EditingPreferences;
import com.sun.electric.database.hierarchy.Cell;
import com.sun.electric.database.hierarchy.Library;
import com.sun.electric.database.hierarchy.View;
import com.sun.electric.database.variable.UserInterface;
import com.sun.electric.tool.Job;
import com.sun.electric.tool.JobException;
import com.sun.electric.tool.user.dialogs.EDialog;
import com.sun.electric.tool.user.ui.WindowFrame;
import com.sun.electric.util.TextUtils;

import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

import javax.swing.JButton;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableColumn;
import javax.swing.table.TableModel;

/**
 * Class to display a cell history dialog.
 */
public class HistoryDialog extends EDialog
{
	private ProjectDB pdb;
	private Cell cell;
	private TableModel dataModel;
	private JTable table;

	/**
	 * Method to examine the history of the currently edited cell.
	 */
	public static void examineThisHistory()
	{
		UserInterface ui = Job.getUserInterface();
		Cell cell = ui.needCurrentCell();
		if (cell == null) return;
		if (Project.ensureRepository()) return;
		examineHistory(cell);
	}

	/**
	 * Method to examine the history of a cell.
	 * @param cell the Cell to examine.
	 */
	public static void examineHistory(Cell cell)
	{
		Project.pmActive = true;
		new HistoryDialog(cell);
	}

	HistoryDialog(Cell cell)
	{
		super(null, true);
		this.pdb = Project.projectDB;
		this.cell = cell;
		initComponents();
		setVisible(true);
	}

	protected void escapePressed() { doButton(false); }

	private void doButton(boolean retrieve)
	{
		if (retrieve)
		{
			int index = table.getSelectedRow();
			int version = TextUtils.atoi((String)dataModel.getValueAt(index, 0));
			Library lib = cell.getLibrary();
			ProjectLibrary pl = pdb.findProjectLibrary(lib);

			String cellName = cell.getName() + ";" + version;
			if (cell.getView() != View.UNKNOWN) cellName += cell.getView().getAbbreviationExtension();
			Cell exists = cell.getLibrary().findNodeProto(cellName);
			if (exists != null)
			{
				Job.getUserInterface().showErrorMessage("Version " + version + " of cell " + cell.getName() +
					" is already in your library", "Version Retrieval Error");
				return;
			}

			ProjectCell foundPC = pl.findProjectCellByNameViewVersion(cell.getName(), cell.getView(), version);
			if (foundPC == null)
			{
				Job.getUserInterface().showErrorMessage("Can't find that version in the repository!", "Version Retrieval Error");
				return;
			}
			new GetOldVersionJob(pdb, cell, version);
		} else
		{
			dispose();
		}
	}

	private void initComponents()
	{
		getContentPane().setLayout(new GridBagLayout());

		setTitle("Examine the History of " + cell);
		setName("");
		addWindowListener(new WindowAdapter()
		{
			public void windowClosing(WindowEvent evt) { doButton(false); }
		});

		// gather versions found in the project file
		ProjectLibrary pl = pdb.findProjectLibrary(cell.getLibrary());
		List<ProjectCell> versions = new ArrayList<ProjectCell>();
		for(Iterator<ProjectCell> it = pl.getProjectCells(); it.hasNext(); )
		{
			ProjectCell pc = it.next();
			if (pc.getCellName().equals(cell.getName()) && pc.getView() == cell.getView())
			{
				pc.setCheckInDate("Not In Repository Yet");
				versions.add(pc);
			}
		}

		// consider the files in the repository, too
		String dirName = pl.getProjectDirectory() + File.separator + cell.getName();
		File dir = new File(dirName);
		File [] filesInDir = dir.listFiles();
		for(int i=0; i<filesInDir.length; i++)
		{
			File subFile = filesInDir[i];
			Date modDate = new Date(subFile.lastModified());
			int version = TextUtils.atoi(subFile.getName());
			boolean found = false;
			for(ProjectCell pc : versions)
			{
				if (pc.getVersion() == version)
				{
					pc.setCheckInDate(TextUtils.formatDate(modDate));
					found = true;
					break;
				}
			}
			if (!found)
			{
				ProjectCell pc = new ProjectCell(null, pl);
				pc.setCheckInDate(TextUtils.formatDate(modDate));
				pc.setCellName(cell.getName());
				pc.setVersion(version);
				versions.add(pc);
			}
		}

		// sort the list by versions
		Collections.sort(versions, new ProjectCellByVersion());

		// make table
		int numVersions = versions.size();
		Object [][] data = new Object[numVersions][4];
		int index = 0;
		for(ProjectCell pc : versions)
		{
			data[index][0] = Integer.toString(pc.getVersion());
			data[index][1] = pc.getCheckInDate();
			data[index][2] = pc.getLastOwner();
			if (pc.getOwner().length() > 0) data[index][2] = pc.getOwner();
			data[index][3] = (pc.getComment() != null) ? pc.getComment() : "";
			index++;
		}

		dataModel = new HistoryTableModel(data);
		table = new JTable(dataModel);
//		table.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS);
		TableColumn versCol = table.getColumnModel().getColumn(0);
		TableColumn dateCol = table.getColumnModel().getColumn(1);
		TableColumn userCol = table.getColumnModel().getColumn(2);
		TableColumn commentCol = table.getColumnModel().getColumn(3);
		versCol.setPreferredWidth(10);
		dateCol.setPreferredWidth(30);
		userCol.setPreferredWidth(20);
		commentCol.setPreferredWidth(40);
		JScrollPane tableScrollPane = new JScrollPane(table);
		GridBagConstraints gbc = new GridBagConstraints();
		gbc.gridx = 0;   gbc.gridy = 0;
		gbc.gridwidth = 2;
		gbc.weightx = gbc.weighty = 1;
		gbc.fill = GridBagConstraints.BOTH;
		gbc.insets = new Insets(4, 4, 4, 4);
		getContentPane().add(tableScrollPane, gbc);

		// OK and Cancel
		JButton ok = new JButton("Retrieve");
		gbc = new GridBagConstraints();
		gbc.gridx = 1;   gbc.gridy = 1;
		gbc.anchor = GridBagConstraints.CENTER;
		gbc.insets = new Insets(4, 4, 4, 4);
		getContentPane().add(ok, gbc);
		ok.addActionListener(new ActionListener()
		{
			public void actionPerformed(ActionEvent evt) { doButton(true); }
		});

		JButton cancel = new JButton("Done");
		getRootPane().setDefaultButton(cancel);
		gbc = new GridBagConstraints();
		gbc.gridx = 0;   gbc.gridy = 1;
		gbc.anchor = GridBagConstraints.CENTER;
		gbc.insets = new Insets(4, 4, 4, 4);
		getContentPane().add(cancel, gbc);
		cancel.addActionListener(new ActionListener()
		{
			public void actionPerformed(ActionEvent evt) { doButton(false); }
		});

		pack();
	}

	class HistoryTableModel extends AbstractTableModel
	{
	    private String[] columnNames;
	    private Object[][] data;

	    HistoryTableModel(Object [][] data)
	    {
	    	this.data = data;
	    	columnNames = new String[] {"Version", "Date", "Who", "Comments"};
        }

        public int getColumnCount() { return columnNames.length; }

        public int getRowCount() { return data.length; }

        public String getColumnName(int col) { return columnNames[col]; }

        public Object getValueAt(int row, int col) { return data[row][col]; }

        public Class<?> getColumnClass(int c) { return getValueAt(0, c).getClass(); }
	}

	/**
	 * This class gets old versions of cells from the Project Management repository.
	 */
	private static class GetOldVersionJob extends Job
	{
		private ProjectDB pdb;
		private Cell cell;
		private int version;

		private GetOldVersionJob(ProjectDB pdb, Cell cell, int version)
		{
			super("Update " + cell, Project.getProjectTool(), Job.Type.CHANGE, null, null, Job.Priority.USER);
			this.pdb = pdb;
			this.cell = cell;
			this.version = version;
			startJob();
		}

        @Override
		public boolean doIt() throws JobException
		{
            EditingPreferences ep = getEditingPreferences();
			// prevent tools (including this one) from seeing the change
			Project.setChangeStatus(true);

			Library lib = cell.getLibrary();
			ProjectLibrary pl = pdb.findProjectLibrary(lib);
			ProjectCell foundPC = pl.findProjectCellByNameViewVersion(cell.getName(), cell.getView(), version);
			Project.getCellFromRepository(pdb, foundPC, lib, false, false, ep);		// CHANGES DATABASE
			if (foundPC.getCell() == null)
			{
				Project.setChangeStatus(false);
				throw new JobException("Error retrieving old version of cell");
			}
			Project.markLocked(foundPC.getCell(), false, ep);		// CHANGES DATABASE

			// allow changes
			Project.setChangeStatus(false);

			System.out.println("Cell " + foundPC.getCell().describe(true) + " is now in this library");
			fieldVariableChanged("pdb");
			return true;
		}

		public void terminateOK()
		{
	    	// take the new version of the project database from the server
	    	Project.projectDB = pdb;

	    	// update explorer tree
			WindowFrame.wantToRedoLibraryTree();
		}
	}
	
	/**
	 * Class to sort project cells by reverse version number.
	 */
	private static class ProjectCellByVersion implements Comparator<ProjectCell>
	{
	    public int compare(ProjectCell pc1, ProjectCell pc2)
	    {
	    	return pc2.getVersion() - pc1.getVersion();
	    }
	}

}
