/*
 * 作成日: 2005/10/18
 */
package net.sourceforge.swingx.jspread;

import java.awt.Component;
import java.awt.Point;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;

import javax.swing.SwingUtilities;
import javax.swing.event.MouseInputListener;

import net.sourceforge.swingx.Logger;
import net.sourceforge.swingx.jspread.JSpreadSheet.CurrentFocus;

/**
 * javax.swing.plaf.basic.BasicTableUI$Handlerが参考になる。
 * 
 * @author Asan
 */
public class JSpreadCellListener implements KeyListener, MouseInputListener {
	private static Logger logger = Logger.getLogger(JSpreadCellListener.class);
	final JSpread spread;
	transient JSpreadCellPane cellPane;
	
	JSpreadCellListener(JSpread spread, JSpreadCellPane cellPane) {
		this.spread = spread;
		this.cellPane = cellPane;
	}
	/** コンポーネント上でマウスボタンが押されると呼び出されます。 */ 
	public void mousePressed(MouseEvent e) {
		logger.debug("enter "+e);
		cellPane.requestFocusInWindow();
//		// もし、セルが編集中なら、編集をやめる
//		if (spread.isEditing()) {
//			boolean rc = spread.stopCellEditing();
//			if (! rc) return;	// 編集がやめれなかったら、それ以外の処理は行わない。
//		}
		JSpreadSheet sheet = spread.getSheet();
		int col = sheet.colHeader.getViewPositionAtPoint(e.getX());
		int row = sheet.rowHeader.getViewPositionAtPoint(e.getY());
        if (col != -1 && row != -1 && spread.editCellAt(row, col, e)) {
            setDispatchComponent(e);
            repostEvent(e);
        }
		if (e.getButton() == MouseEvent.BUTTON1) {
			logger.debug("A");
			if (e.isControlDown()) {
				sheet.setSelection(sheet.focusRow, sheet.focusCol, sheet.curRow, sheet.curCol, true);
			}
			else {
				sheet.setSelectionAll(false);
				sheet.setHeaderSelectionAll(JSpread.ROW, false);
				sheet.setHeaderSelectionAll(JSpread.COLUMN, false);
				sheet.cornerSelection = false;
			}
			logger.debug("B");
			if (col != -1 && row != -1) {
				CurrentFocus prev = sheet.getCurrentFocus();
				if (e.isShiftDown()) {
					sheet.curRow = row;
					sheet.curCol = col;
				}
				else {
					sheet.focusRow = sheet.curRow = row;
					sheet.focusCol = sheet.curCol = col;
				}
				CurrentFocus next = sheet.getCurrentFocus();
				logger.debug("C");
				if (! prev.equals(next)) {
					spread.fireSelectionListener(new JSpreadSelectionEvent(this, prev, next));
				}
				logger.debug("D");
			}
			e.consume();
			spread.再描画();
		}
		logger.debug("exit");
	}
    private Component dispatchComponent;
    private void setDispatchComponent(MouseEvent e) {
    	logger.debug("setDispatchComponent(e)");
        Component editorComponent = spread.getEditorComponent();
        Point p = e.getPoint();
        Point p2 = SwingUtilities.convertPoint(cellPane, p, editorComponent);
        dispatchComponent =
                SwingUtilities.getDeepestComponentAt(editorComponent,
                        p2.x, p2.y);
    }
    private boolean repostEvent(MouseEvent e) {
    	logger.debug("repostEvent(e) dispatchComponent="+dispatchComponent);
        // Check for isEditing() in case another event has
        // caused the editor to be removed. See bug #4306499.
        if (dispatchComponent == null || !spread.isEditing()) {
            return false;
        }
        MouseEvent e2 = SwingUtilities.convertMouseEvent(cellPane, e,
                dispatchComponent);
        dispatchComponent.dispatchEvent(e2);
        return true;
    }
	
    /** コンポーネント上でマウスボタンをクリック (押してから離す) したときに呼び出されます。 */
	public void mouseClicked(MouseEvent e) {
//		logger.debug(e);
//		// 左ボタンのダブルクリックで編集を開始する。
//		if (e.getButton() == MouseEvent.BUTTON1 && 
//				e.getClickCount() == spread.properties.getInt(JSpread.EDIT_START_CLICK_COUNT)) {
//			JSpreadSheet sheet = spread.getCurrentSheet();
//			// 全体が編集不可なら何もしない
//			if (! sheet.editable) return;
//			// 指定したセルのインデックスを求める。
//			int colViewIndex = sheet.colHeader.getViewPositionAtPoint(0, e.getX());
//			int rowViewIndex = sheet.rowHeader.getViewPositionAtPoint(0, e.getY());
//			if (colViewIndex == -1 || rowViewIndex == -1) return;
//			// 編集開始を試みる
//			boolean rc = spread.editCellAt(rowViewIndex, colViewIndex, e);
//			logger.debug("編集を開始したか？ rc="+rc);
//		}
	}
	/** コンポーネントにマウスが入ると呼び出されます。*/ 
	public void mouseEntered(MouseEvent e){} 
    /** コンポーネントからマウスが出ると呼び出されます。*/ 
	public void mouseExited(MouseEvent e) {} 
	/**  コンポーネント上でマウスボタンが離されると呼び出されます。*/
	public void mouseReleased(MouseEvent e) {
		logger.debug("enter "+e);
        repostEvent(e);
        dispatchComponent = null;
//        setValueIsAdjusting(false);
		logger.debug("exit");
	} 
//    private void setValueIsAdjusting(boolean flag) {
//        table.getSelectionModel().setValueIsAdjusting(flag);
//        table.getColumnModel().getSelectionModel().
//                setValueIsAdjusting(flag);
//    }
     

	/** コンポーネント上でマウスのボタンを押してドラッグすると呼び出されます。 */
	public void mouseDragged(MouseEvent e) {
		logger.debug("enter "+e);
		JSpreadSheet sheet = spread.getSheet();
		int col = sheet.colHeader.getViewPositionAtPoint(e.getX());
		int row = sheet.rowHeader.getViewPositionAtPoint(e.getY());
		if (col != -1 && row != -1) {
			CurrentFocus prev = sheet.getCurrentFocus();
			sheet.curRow = row;
			sheet.curCol = col;
			CurrentFocus next = sheet.getCurrentFocus();
			if (! prev.equals(next)) {
				spread.fireSelectionListener(new JSpreadSelectionEvent(this, prev, next));
			}
			e.consume();
			spread.再描画();
		}
		logger.debug("exit");
	}
    /** コンポーネント上でマウスのボタンを押してドラッグすると呼び出されます。*/ 
	public void mouseMoved(MouseEvent e) {
//		cellPane.setCursor(spread.properties.getCursor(JSpread.CELL_CURSOR));
	}  

    /** キーを押しているときに呼び出されます。*/ 
	public void keyPressed(KeyEvent e) {
		logger.debug(e);
		JSpreadSheet sheet = spread.getSheet();
		CurrentFocus prev = sheet.getCurrentFocus();
		switch (e.getKeyCode()) {
		case KeyEvent.VK_LEFT:
			if (sheet.curCol > 0) {
				sheet.curCol--;
				e.consume();
			}
			break;
		case KeyEvent.VK_RIGHT:
			if (sheet.curCol < sheet.colHeader.getViewCount()-1) {
				sheet.curCol++;
				e.consume();
			}
			break;
		case KeyEvent.VK_UP:
			if (sheet.curRow > 0) {
				sheet.curRow--;
				e.consume();
			}
			break;
		case KeyEvent.VK_DOWN:
			if (sheet.curRow < sheet.rowHeader.getViewCount()-1) {
				sheet.curRow++;
				e.consume();
			}
			break;
		case KeyEvent.VK_HOME:
			sheet.curCol = 0;
			if (e.isControlDown()) {
				sheet.curRow = 0;
			}
			e.consume();
			break;
		case KeyEvent.VK_END:
			sheet.curCol = sheet.colHeader.getViewCount()-1;
			if (e.isControlDown()) {
				sheet.curRow = sheet.rowHeader.getViewCount()-1;
			}
			e.consume();
			break;
		default:
			System.out.println(e);
			return;
		}
		if (! e.isShiftDown()) {
			sheet.setSelectionAll(false);
			sheet.setHeaderSelectionAll(JSpread.ROW, false);
			sheet.setHeaderSelectionAll(JSpread.COLUMN, false);
			sheet.cornerSelection = false;
			sheet.focusRow = sheet.curRow;
			sheet.focusCol = sheet.curCol;				
		}
		// 選択がかわったら
		CurrentFocus next = sheet.getCurrentFocus();
		if (! prev.equals(next)) {
			spread.fireSelectionListener(new JSpreadSelectionEvent(this, prev, next));
//			cellPane.scrollToVisible(JSpread.ROW, sheet.curRow);
//			cellPane.scrollToVisible(JSpread.COLUMN, sheet.curCol);
			spread.再描画();
		}
	}
    /** キーを押しているときに呼び出されます。*/ 
	public void keyReleased(KeyEvent e) {}
    /** キーをタイプすると呼び出されます。*/
    public void keyTyped(KeyEvent e) {}
}
