package hiro.yoshioka.sql.util;

import hiro.yoshioka.ast.sql.util.BindInfo;
import hiro.yoshioka.util.StringUtil;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.viewers.CellEditor;
import org.eclipse.jface.viewers.ComboBoxCellEditor;
import org.eclipse.jface.viewers.ICellEditorListener;
import org.eclipse.jface.viewers.ICellModifier;
import org.eclipse.jface.viewers.ILabelProviderListener;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.StructuredViewer;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TextCellEditor;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.forms.widgets.FormToolkit;
import org.eclipse.ui.forms.widgets.ScrolledForm;
import org.eclipse.ui.forms.widgets.Section;
import org.eclipse.ui.forms.widgets.TableWrapData;
import org.eclipse.ui.forms.widgets.TableWrapLayout;

public class BindDialog extends Dialog implements SelectionListener {
	MyModel[] myModel;
	protected Log fLogger = LogFactory.getLog(getClass());
	public static String[] HEADER = { "Num", "Target", "Types", "Value", "File" };
	static final int[] COL_SIZE = { 45, 150, 100, 430, 100 };
	BindInfo[] fBindInfo;

	Text fSingleText;

	public BindDialog(Shell shell, BindInfo[] binds) {
		super(shell);
		fBindInfo = binds;
	}

	private class MyLabelProvider implements ITableLabelProvider {

		@Override
		public Image getColumnImage(Object element, int columnIndex) {
			return null;
		}

		@Override
		public String getColumnText(Object element, int columnIndex) {
			try {
				MyModel model = (MyModel) element;
				switch (columnIndex) {
				case 0:
					return StringUtil.EMPTY_STRING + model.num;
				case 1:
					return model.info.getTarget();
				case 2:
					return BindInfo.TYPE_STRING[model.info.getType()];
				case 3:
					return model.info.getStringValue();
				case 4:
					if (model.info.isBinary() || model.info.isBlob()) {
						// TODO: if file exists show filepath.
						return "[Click][FileDialog]";
					}
				}
				return StringUtil.EMPTY_STRING;
			} catch (Exception e) {
				fLogger.fatal(StringUtil.EMPTY_STRING, e);
			}
			return "a"; //$NON-NLS-1$
		}

		@Override
		public void addListener(ILabelProviderListener listener) {
		}

		@Override
		public void dispose() {
		}

		@Override
		public boolean isLabelProperty(Object element, String property) {
			return false;
		}

		@Override
		public void removeListener(ILabelProviderListener listener) {
		}
	}

	public class MyModel {
		int num;
		BindInfo info;

		public MyModel(int num, BindInfo info) {
			this.info = info;
			this.num = num;
		}

	}

	private class MyCellModifier implements ICellModifier {

		private TableViewer viewer;

		public void setViewer(TableViewer viewer) {
			this.viewer = viewer;
		}

		public boolean canModify(Object element, String property) {

			MyModel model = (MyModel) element;
			if (HEADER[2].equals(property)) {
				return true;
			} else if (HEADER[3].equals(property)) {
				return model.info.isString() || model.info.isNumeric()
						|| model.info.isDate() || model.info.isTime()
						|| model.info.isTimeStamp();
			} else if (HEADER[4].equals(property)) {
				return model.info.isBlob() || model.info.isBinary();
			} else {
				return false;
			}
		}

		public Object getValue(Object element, String property) {
			MyModel model = (MyModel) element;
			if (HEADER[0].equals(property)) {
				return StringUtil.EMPTY_STRING + model.num;
			} else if (HEADER[1].equals(property)) {
				return model.info.getTarget();
			} else if (HEADER[2].equals(property)) {
				return model.info.getType();
			} else if (HEADER[3].equals(property)) {
				return StringUtil.nvl(model.info.getStringValue());
			} else if (HEADER[4].equals(property)) {
				return StringUtil.EMPTY_STRING;
			}
			return StringUtil.EMPTY_STRING;
		}

		public void modify(Object element, String property, Object value) {
			TableItem item = (TableItem) element;

			MyModel model = (MyModel) item.getData();
			if (HEADER[2].equals(property)) {
				model.info.setType(((Integer) value).intValue());
			} else if (HEADER[3].equals(property)) {
				model.info.setValue(StringUtil.nvl(value));
			} else {
				model.info.setValue(StringUtil.nvl(value));
			}
			viewer.update(item.getData(), null);
			// refreshStatement();
		}
	}

	private class MyContentProvider implements IStructuredContentProvider {

		public Object[] getElements(Object inputElement) {
			return (MyModel[]) inputElement;
		}

		public void dispose() {

		}

		public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {

		}

	}

	public class DelegatingEditor extends CellEditor {
		private int colIdx;
		private StructuredViewer viewer;

		private CellEditor delegatingTextEditor;

		private CellEditor delegatingDropDownCompEditor;

		private CellEditor activeEditor;

		private FileDialogCellEditor delegatingFileEditor;

		private class DelegatingListener implements ICellEditorListener {

			public void applyEditorValue() {
				fireApplyEditorValue();
			}

			public void cancelEditor() {
				fireCancelEditor();
			}

			public void editorValueChanged(boolean oldValidState,
					boolean newValidState) {
				fireEditorValueChanged(oldValidState, newValidState);
			}

		}

		public DelegatingEditor(int colIdx, StructuredViewer viewer,
				Composite parent) {
			super(parent);
			try {
				fLogger.info("START ");

				this.colIdx = colIdx;
				this.viewer = viewer;
				DelegatingListener l = new DelegatingListener();
				this.delegatingTextEditor = new TextCellEditor(parent);
				this.delegatingTextEditor.addListener(l);

				this.delegatingDropDownCompEditor = new ComboBoxCellEditor(
						parent, BindInfo.TYPE_STRING, SWT.READ_ONLY);
				this.delegatingDropDownCompEditor.addListener(l);

				this.delegatingFileEditor = new FileDialogCellEditor(parent);
				this.delegatingFileEditor.addListener(l);
			} catch (Exception e) {
				fLogger.fatal(StringUtil.EMPTY_STRING, e);
			}
		}

		protected Control createControl(Composite parent) {
			return null;
		}

		protected Object doGetValue() {
			fLogger.info("doGetValue ");
			return activeEditor.getValue();
		}

		protected void doSetFocus() {
			fLogger.info("doSetFocus ");
			activeEditor.setFocus();
		}

		public void activate() {
			fLogger.info("activate ");
			if (activeEditor != null) {
				activeEditor.activate();
			}
		}

		protected void doSetValue(Object value) {
			try {
				switch (colIdx) {
				case 2:
					activeEditor = delegatingDropDownCompEditor;
					break;
				case 3:
					activeEditor = delegatingTextEditor;
					break;
				case 4:
					activeEditor = delegatingFileEditor;
				}
				activeEditor.setValue(value);
			} catch (Exception e) {
				fLogger.fatal(StringUtil.EMPTY_STRING, e);
			}
		}

		public void deactivate() {
			if (activeEditor != null) {
				Control control = activeEditor.getControl();
				if (control != null && !control.isDisposed()) {
					control.setVisible(false);
				}
			}
		}

		public void dispose() {

		}

		public Control getControl() {
			return activeEditor.getControl();
		}
	}

	@Override
	protected Control createDialogArea(Composite parent) {
		getShell().setText("Bind Parameters");

		try {
			FormToolkit toolkit = new FormToolkit(parent.getDisplay());
			ScrolledForm root = toolkit.createScrolledForm(parent);
			root.setLayoutData(new GridData(GridData.FILL_BOTH));
			root.setText("Bind Parameters");

			root.getBody().setLayout(new GridLayout());

			Section section = toolkit.createSection(root.getBody(),
					Section.EXPANDED | Section.TITLE_BAR);

			section.setText("Column conditions");
			section.setLayout(new GridLayout());

			Composite c = new Composite(section, SWT.BORDER);
			c.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));

			TableWrapLayout tr = new TableWrapLayout();
			tr.numColumns = 1;
			c.setLayout(tr);

			final Table table = new Table(c, SWT.BORDER | SWT.FULL_SELECTION
					| SWT.V_SCROLL);
			final MyCellModifier modifier = new MyCellModifier();

			final TableViewer v = new TableViewer(table);
			modifier.setViewer(v);
			table.setLinesVisible(true);

			table.setHeaderVisible(true);
			CellEditor[] cellEditor = new CellEditor[HEADER.length];
			for (int i = 0; i < HEADER.length; i++) {
				TableColumn column = new TableColumn(table, SWT.NONE);
				column.setText(HEADER[i]);
				column.setWidth(COL_SIZE[i]);
				cellEditor[i] = new DelegatingEditor(i, v, v.getTable());
			}

			v.setLabelProvider(new MyLabelProvider());
			v.setContentProvider(new MyContentProvider());
			v.setCellModifier(modifier);
			v.setColumnProperties(HEADER);
			v.setCellEditors(cellEditor);

			TableWrapData layoutData = new TableWrapData();
			layoutData.heightHint = table.getItemHeight() * 10;
			layoutData.maxHeight = 500;
			layoutData.grabHorizontal = true;
			table.setLayoutData(layoutData);

			myModel = new MyModel[fBindInfo.length];
			for (int i = 0; i < fBindInfo.length; i++) {
				myModel[i] = new MyModel(i, fBindInfo[i]);

			}
			v.setInput(myModel);

			section.setClient(c);

			// ---------------------------------------
			Section section2 = toolkit.createSection(root.getBody(),
					Section.EXPANDED | Section.TITLE_BAR);
			section2.setText("Split StringSeparatedByComma to Each Bind Value"); //$NON-NLS-1$
			section2.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));

			Composite inner2 = toolkit.createComposite(section2);
			section2.setClient(inner2);
			inner2.setLayout(new GridLayout(2, false));

			Button btn = new Button(inner2, SWT.PUSH);
			fSingleText = new Text(inner2, SWT.SINGLE | SWT.BORDER);
			fSingleText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));

			btn.setText("split by comma");
			btn.addSelectionListener(new SelectionListener() {
				public void widgetSelected(SelectionEvent e) {
					String[] strs = fSingleText.getText().split(","); //$NON-NLS-1$
					for (int i = 0; i < strs.length; i++) {
						if (fBindInfo.length <= i) {
							break;
						}
						fBindInfo[i].setValue(strs[i].trim());
					}
					v.refresh();
				}

				public void widgetDefaultSelected(SelectionEvent e) {
				}

			});

			root.setSize(640, 480);
			return root;
		} catch (RuntimeException e) {
			e.printStackTrace();
		}

		return parent;
	}

	// ---------------------------------------------------------------

	@Override
	public void widgetDefaultSelected(SelectionEvent e) {
	}

	@Override
	public void widgetSelected(SelectionEvent e) {
		System.out.println(e);
	}
}