/*
 * Copyright 2006 Maskat Project.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.maskat.ide.tabbedproperties;

import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.TableEditor;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.TraverseEvent;
import org.eclipse.swt.events.TraverseListener;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableItem;
import org.maskat.framework.BasicDef;
import org.maskat.ide.MaskatIDEPlugin;
import org.maskat.ide.editors.MaskatEditor;

public class TableListenerForEditor extends MouseAdapter {
	private Table targetTable;

	private ControlWrapper[] controls;

	private TableEditor[] tableEditors;

	private String[] propNames;

	private BasicDef basicDef;

	private Class childClass;

	private MaskatEditor editor;

	public TableListenerForEditor(Table targetTable, ControlWrapper[] controls,
			String[] propNames, BasicDef def, Class childClass, MaskatEditor editor) {
		this.targetTable = targetTable;
		this.controls = controls;
		tableEditors = new TableEditor[controls.length];
		for (int i = 0; i < controls.length; i++) {
			tableEditors[i] = new TableEditor(targetTable);
			tableEditors[i].horizontalAlignment = SWT.LEFT;
			tableEditors[i].grabHorizontal = true;
			tableEditors[i].minimumWidth = 50;
		}
		this.propNames = propNames;
		this.basicDef = def;
		this.childClass = childClass;
		this.editor = editor;
	}

	private TableItem lastSelected, newHeaderTableItem;

	public void mouseDown(MouseEvent e) {
		resetEditors();
		int index = targetTable.getSelectionIndex();
		if (index == -1)
			return;
		Point pt = new Point(e.x, e.y);
		newHeaderTableItem = targetTable.getItem(pt);
		TableItem oldItem = tableEditors[0].getItem();
		if (newHeaderTableItem == oldItem || newHeaderTableItem != lastSelected) {
			lastSelected = newHeaderTableItem;
			return;
		}
		targetTable.showSelection();

		for (int i = 0; i < controls.length; i++) {
			Control control = controls[i].createControl(targetTable, SWT.NONE);
			// basicDefからi番目の子要素は編集対象です
			Object targetObj = basicDef.getChildByTypeIdx(childClass, index);
			while (targetObj == null) {
				try {
					basicDef.addChild(childClass.newInstance());
				} catch (Exception e1) {
					MaskatIDEPlugin.getDefault().getLog().log(
							new Status(IStatus.ERROR, MaskatIDEPlugin.PLUGIN_ID,
									IStatus.ERROR, e1.getMessage(), e1));
					return;
				}
				targetObj = basicDef.getChildByTypeIdx(childClass, index);
			}
			controls[i].setValueWatcher(targetObj, propNames[i], editor);
			controls[i].setValue(newHeaderTableItem.getText(i));
			createControlEditor(control, tableEditors[i], i);
		}

		for (int i = 0; i < targetTable.getColumnCount(); i++) {
			Rectangle rect = newHeaderTableItem.getBounds(i);
			if (rect.contains(pt)) {
				controls[i].getControl().setFocus();
			}
		}
	}

	/**
	 * Creates the TableEditor with a Control in the given column of the table.
	 */
	void createControlEditor(Control control, TableEditor textEditor, int column) {
		control.setFont(targetTable.getFont());
		textEditor.horizontalAlignment = SWT.LEFT;
		textEditor.grabHorizontal = true;
		textEditor.setEditor(control, newHeaderTableItem, column);

		control.addTraverseListener(new TraverseListener() {
			public void keyTraversed(TraverseEvent e) {
				if (e.detail == SWT.TRAVERSE_TAB_NEXT) {
					resetEditors(true);
				}
				if (e.detail == SWT.TRAVERSE_ESCAPE) {
					outOfFocus();// disposeEditors();
				}
			}
		});
		control.addKeyListener(new KeyAdapter() {
			public void keyReleased(KeyEvent e) {
				if (e.character == '\r') {// Return
					outOfFocus();
				}
			}
		});
		control.setFocus();
	}

	void resetEditors() {
		resetEditors(false);
	}

	void resetEditors(boolean tab) {
		TableItem oldItem = tableEditors[0].getItem();
		if (oldItem != null) {
			for (int i = 0; i < controls.length; i++) {
				oldItem.setText(i, controls[i].getValue());
			}
		}
		if (!tab)
			disposeEditors();
	}

	void disposeEditors() {
		for (int i = 0; i < tableEditors.length; i++) {
			tableEditors[i].setEditor(null, null, -1);
		}
		for (int i = 0; i < controls.length; i++) {
			if (controls[i].getControl() != null)
				controls[i].getControl().dispose();
		}
	}

	void outOfFocus() {
		for (int i = 0; i < controls.length; i++) {
			Control control = controls[i].getControl();
			if (control != null && !control.isDisposed()) {
				if (control.isFocusControl()) {
					control.notifyListeners(SWT.FocusOut, null);
				}
			}
		}
		resetEditors();
	}
}
