package org.geogebra.desktop.cas.view;

import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;

import javax.swing.JList;
import javax.swing.ListSelectionModel;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

import org.geogebra.common.kernel.geos.GeoCasCell;
import org.geogebra.common.util.debug.Log;
import org.geogebra.desktop.main.AppD;

/**
 * Handles mouse and key events in row headers of the CAS table
 *
 */
public class RowHeaderListener extends MouseAdapter
		implements KeyListener, ListSelectionListener, MouseMotionListener {

	private final CASTableD table;
	private final JList rowHeader;
	private int mousePressedRow;
	private boolean rightClick;
	private AppD app;

	/**
	 * @param table
	 *            CAS table
	 * @param rowHeader
	 *            row headers
	 */
	public RowHeaderListener(CASTableD table, JList rowHeader, AppD app) {
		this.table = table;
		this.rowHeader = rowHeader;
		this.app = app;
	}

	@Override
	public void mousePressed(MouseEvent e) {
		rightClick = AppD.isRightClick(e);
		table.stopEditing();
		mousePressedRow = rowHeader.locationToIndex(e.getPoint());
		table.setClickedRow(mousePressedRow);
		rowHeader.requestFocus();
	}

	@Override
	public void mouseDragged(MouseEvent e) {
		e.consume();

		// update selection
		int mouseDraggedRow = rowHeader.locationToIndex(e.getPoint());

		// make sure mouse pressed is initialized, this may not be the case
		// after closing the popup menu
		if (mousePressedRow < 0) {
			table.stopEditing();
			mousePressedRow = mouseDraggedRow;
		}
		if (AppD.isControlDown(e)) {
			rowHeader.addSelectionInterval(mousePressedRow, mouseDraggedRow);
		} else {
			rowHeader.setSelectionInterval(mousePressedRow, mouseDraggedRow);
		}
	}

	@Override
	public void mouseReleased(MouseEvent e) {
		e.consume();

		// handle marble click
		int releasedRow = table.rowAtPoint(e.getPoint());

		try {
			RowHeaderRenderer rhr = (RowHeaderRenderer) rowHeader
					.getCellRenderer().getListCellRendererComponent(rowHeader,
							(releasedRow + 1) + "", releasedRow, false, false);
			boolean marbleVisible = rhr.getComponent(1).isVisible();
			if (releasedRow == mousePressedRow && marbleVisible
					&& !rightClick) {
				int totalHeight = 0;
				for (int i = 0; i < releasedRow; i++) {
					totalHeight += table.getRowHeight(i);
				}
				// not using the renderer to get the marble top because
				// sometimes it gives wrong? values
				// see Ticket #3439, comments 8, 12
				int marbleTop = table.getRowHeight(releasedRow) / 2 + 4;
				if (e.getY() > marbleTop + totalHeight - 4
						&& e.getY() < marbleTop + totalHeight
								+ app.getScaledIconSize()) {
					GeoCasCell clickedCell = table
							.getGeoCasCell(table.rowAtPoint(e.getPoint()));
					if (table.isEditing()) {
						table.stopEditing();
					}
					clickedCell.toggleTwinGeoEuclidianVisible();
				}
			}
		} catch (IndexOutOfBoundsException ex) {
			// this can come, if one clicked on an empty header
			Log.warn("No cas cell " + releasedRow);
		}

		mousePressedRow = -1;
		// handle right click

		if (rightClick) {
			if (!rowHeader.isSelectedIndex(releasedRow)) {
				rowHeader.setSelectedIndex(releasedRow);
			}
			if (rowHeader.getSelectedIndices().length > 0) {
				RowHeaderPopupMenuD popupMenu = new RowHeaderPopupMenuD(
						rowHeader, table);
				popupMenu.show(e.getComponent(), e.getX(), e.getY());
			}
		}
	}

	@Override
	public void mouseClicked(MouseEvent e) {
		// not needed, we handle mouse events in mouseReleased
	}

	@Override
	public void mouseMoved(MouseEvent e) {
		e.consume();
	}

	@Override
	public void keyPressed(KeyEvent e) {
		boolean undoNeeded = false;

		switch (e.getKeyCode()) {
		default:
			// do nothing
			break;
		case KeyEvent.VK_DELETE:
		case KeyEvent.VK_BACK_SPACE:
			int[] selRows = rowHeader.getSelectedIndices();
			undoNeeded = table.getCASView().deleteCasCells(selRows);
			if (selRows != null && selRows.length > 0) {
				int row = selRows[0];
				rowHeader.setSelectedIndex(row);
			}
			break;
		}

		if (undoNeeded) {
			// store undo info
			table.getApplication().storeUndoInfo();
		}

	}

	@Override
	public void keyReleased(KeyEvent e) {
		// not needed, we handle key events in keyPressed
	}

	@Override
	public void keyTyped(KeyEvent e) {
		// not needed, we handle key events in keyPressed
	}

	@Override
	public void valueChanged(ListSelectionEvent e) {
		ListSelectionModel lsm = (ListSelectionModel) e.getSource();
		int minIndex = lsm.getMinSelectionIndex();
		int maxIndex = lsm.getMaxSelectionIndex();
		if (minIndex == maxIndex) {
			table.startEditingRow(minIndex);
		}
	}
}
