package hiro.yoshioka.sdh;

import hiro.yoshioka.sdh.CSVRecordDataHolder.HeaderData;
import hiro.yoshioka.util.SQLDataType;
import hiro.yoshioka.util.StringUtil;

import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.viewers.CellEditor;
import org.eclipse.jface.viewers.EditingSupport;
import org.eclipse.jface.viewers.OwnerDrawLabelProvider;
import org.eclipse.jface.viewers.TableViewerColumn;
import org.eclipse.jface.viewers.TextCellEditor;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;

public class RDHTableViewer extends CDHTableViewer implements IMenuListener {

	private static final int MAXIMUM_DATA_WIDTH = 500;

	public RDHTableViewer(Composite parent) {
		this(parent, SWT.BORDER | SWT.MULTI | SWT.FULL_SELECTION
				| SWT.HIDE_SELECTION | SWT.H_SCROLL | SWT.V_SCROLL);
	}

	public RDHTableViewer(Composite parent, int style) {
		super(parent, style);
	}

	@Override
	protected void keyReleasedAtCell(KeyEvent e) {
		if (e.character == SWT.DEL || e.character == SWT.BS) {
			deleteSelectedRows();
			e.doit = false;
		}
	}

	public void deleteSelectedRows() {
		ResultSetDataHolder rdh = getRDH();
		if (rdh == null || !rdh.hasResultSetMetaData()) {
			return;
		}
		if (rdh.getPkPositions().length == 0) {
			return;
		}
		int[] indices = getTable().getSelectionIndices();
		for (int i = 0; i < indices.length; i++) {
			getRDH().changeStatus(indices[i], HeaderType.DELETE);
		}
		if (indices.length > 0) {
			final TableItem[] items = getTable().getSelection();
			for (int j = 0; j < items.length; j++) {
				preservingSelection(new delayRefresh(items[j].getData()));
			}
		}
	}

	@Override
	public boolean canDoOperation(int operation) {
		switch (operation) {
		case COPY:
			return wasSelected();
		case COPY_WITH_HEAD:
			return wasSelected();
		case PASTE_IN_A_CELL:
			return wasSelected() && getRDH().hasResultSetMetaData();
		case PASTE:
			return wasSelected() && getRDH().hasResultSetMetaData();
		case SELECT_ALL:
			return true;
		}
		return false;
	}

	@Override
	protected Transfer getTransfer() {
		return ResultSetDataHolderTransfer.getInstance();
	}

	public void setInputAdjustDatum(ResultSetDataHolder rdh) {
		setInput(rdh, true);
	}

	public void setInputAdjustHeader(ResultSetDataHolder rdh) {
		setInput(rdh, false);
	}

	public ResultSetDataHolder getRDH() {
		return (ResultSetDataHolder) getInput();
	}

	private void setInput(final ResultSetDataHolder rdh, boolean adjustDatum) {
		if (log.isDebugEnabled()) {
			log.debug("adjustDatum[" + adjustDatum + "] count["
					+ rdh.getRowCount() + "]");
		}
		getTable().setRedraw(false);
		getTable().removeAll();

		TableColumn[] cols = getTable().getColumns();
		if (cols != null) {
			for (int i = 0; i < cols.length; i++) {
				cols[i].dispose();
			}
		}
		for (int i = 0; i < rdh.getKey().length; i++) {
			TableViewerColumn column = new TableViewerColumn(this, SWT.NONE);
			column.getColumn().setText(rdh.getKey()[i]);
			column.getColumn().setMoveable(false);
			column.getColumn().setResizable(true);
			SQLDataType dType = rdh.getSQLDataTypeOf(i);
			if (dType != null && dType.isNumerics()) {
				column.getColumn().setAlignment(SWT.RIGHT);
			}

			if (!(supportChart() || maxMultiLine > 1)) {
				column.setLabelProvider(new RDHTableLabelProvider(this, i));
			}

			if (!rdh.hasResultSetMetaData() && (!isVirtual)) {
				ColumnViewerSorter cSorter = new ColumnViewerSorter(this,
						column, i) {

					protected int doCompare(Viewer viewer, Object e1, Object e2) {
						StringRecordData[] p1 = (StringRecordData[]) e1;
						StringRecordData[] p2 = (StringRecordData[]) e2;
						String s1 = p1[colIdx].getString();
						String s2 = p2[colIdx].getString();
						if (s1.matches("\\d+([.]\\d+)?")
								&& s2.matches("\\d+([.]\\d+)?")) {
							if (s1.equals(s2)) {
								return 0;
							}
							double d1 = Double.parseDouble(s1);
							double d2 = Double.parseDouble(s2);
							if (d1 > d2) {
								return 100;
							} else {
								return -100;
							}
						}
						return s1.compareToIgnoreCase(s2);
					}

				};
			}
			boolean setEditorable = true;
			if (fICDHHyperLinkAction != null) {
				setEditorable = !fICDHHyperLinkAction.isHyperLinkColumn(i);
			}
			if (setEditorable && i > 0) {
				boolean doMulti = false;
				if (rdh.hasResultSetMetaData() && maxMultiLine > 1) {
					doMulti = rdh.meta.isTypeString(i);
				}
				column.setEditingSupport(new MyRDHEditingSupport(i, doMulti));
			}
			if (!adjustDatum) {
				column.getColumn().pack();
			}
		}
		if (supportChart() || maxMultiLine > 1) {
			this.setLabelProvider(new RDHOwnerTableLabelProvider(this,
					supportChart(), maxMultiLine));
			OwnerDrawLabelProvider.setUpOwnerDraw(this);
		}

		super.setInput(rdh);
		if (adjustDatum) {
			if (isVirtual) {
				specialPack(getTable(), rdh);
			} else {
				TableColumn[] columns = getTable().getColumns();
				for (int i = 0; i < columns.length; i++) {
					columns[i].pack();
					if (columns[i].getWidth() > MAXIMUM_DATA_WIDTH) {
						columns[i].setWidth(MAXIMUM_DATA_WIDTH);
					}
				}
				columns[0].pack();
			}
		}
		getTable().setRedraw(true);
	}

	private class MyRDHEditingSupport extends EditingSupport {
		protected int colIdx;
		private TextCellEditor editor;

		public MyRDHEditingSupport(int colIdx, boolean doMulti) {
			super(RDHTableViewer.this);
			this.colIdx = colIdx;
			if (doMulti) {
				this.editor = new TextCellEditor(getTable(), SWT.MULTI
						| SWT.V_SCROLL);
			} else {
				this.editor = new TextCellEditor(getTable(), SWT.SINGLE);
			}
		}

		protected boolean canEdit(Object element) {
			return true;
		}

		protected CellEditor getCellEditor(Object element) {
			return editor;
		}

		protected void setValue(Object element, Object value) {
			doSetValue(element, value);
			update(element, null);
		}

		protected Object getValue(Object element) {
			return ((StringRecordData[]) element)[colIdx].getString();
		}

		protected void doSetValue(Object element, Object value) {
			try {
				ResultSetDataHolder rdh = getRDH();
				if (!rdh.hasResultSetMetaData()) {
					return;
				}
				int row = getTable().getSelectionIndex();

				if (row < 0) {
					return;
				}

				if (value.equals(rdh.getRow(row)[colIdx])) {
					return;
				}
				int[] pks = rdh.getPkPositions();
				if (log.isDebugEnabled()) {
					log.debug("pks=" + pks);
				}
				if (pks == null || pks.length == 0) {
					StringRecordData sr = rdh.getStringRecordRow(row)[0];
					if (sr instanceof HeaderData) {
						HeaderData hd = (HeaderData) sr;
						if (!hd.insert()) {
							return;
						}
					}
				}
				try {
					getRDH().createBackUp(row);
					value = getRDH().getYukoString(colIdx, value.toString());
				} catch (Exception e) {
					if (log.isWarnEnabled()) {
						log.warn(StringUtil.EMPTY_STRING, e);
					}
				}
				getRDH().changeString(row, colIdx, (String) value);
				if (getRDH().reseted(row)) {
					getRDH().changeStatus(row, HeaderType.NO_EDITION);
				} else {
					getRDH().changeStatus(row, HeaderType.UPDATE);
				}
			} catch (RuntimeException e) {
				log.warn(StringUtil.EMPTY_STRING, e);
			}
		}
	}

	@Override
	protected void right_clicked() {
		try {
			Control control = getTable();
			MenuManager menuMgr = new MenuManager("#PopupMenu");
			menuMgr.setRemoveAllWhenShown(true);
			menuMgr.addMenuListener(this);
			Menu menu = menuMgr.createContextMenu(control);

			control.setMenu(menu);
		} catch (Throwable e) {
			e.printStackTrace();
		}
	}

	@Override
	public void menuAboutToShow(IMenuManager manager) {
		ResultSetDataHolder rdh = getRDH();
		if (rdh != null) {
			switch (rdh.getDatabaseType()) {
			case ORACLE:
				break;
			case DOMINO:
				break;
			case TWITTER:
				break;
			case HSQL:
				break;
			}
		}
	}

}
