package hiro.yoshioka.sdh;

import hiro.yoshioka.sdh.pair.DifferenceStringData;
import hiro.yoshioka.sdh.pair.FlashStringData;
import hiro.yoshioka.sdh.pair.MarkStringData;
import hiro.yoshioka.util.ColorNameEnum;
import hiro.yoshioka.util.ColorUtil;
import hiro.yoshioka.util.StringUtil;

import org.eclipse.jface.viewers.ColumnLabelProvider;
import org.eclipse.jface.viewers.ViewerCell;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.widgets.TableItem;

public class RDHTableLabelProvider extends ColumnLabelProvider {
	CDHTableViewer v;
	int colIdx;
	final boolean supportDiff;
	private Boolean isNotNull;
	int[] percentIdx;
	private OptimizedIndexSearcher searcher = new OptimizedIndexSearcher();

	public RDHTableLabelProvider(CDHTableViewer view, int colIdx) {
		this.v = view;
		this.supportDiff = v.supportDiff();
		this.colIdx = colIdx;
	}

	@Override
	public String getText(Object element) {
		StringRecordData[] datum = (StringRecordData[]) element;
		if (datum[colIdx].getPair() instanceof FlashStringData) {

		} else if (datum[colIdx].getPair() instanceof MarkStringData) {
			MarkStringData mark = (MarkStringData) datum[colIdx].getPair();
			if (colIdx > 0) {
				switch (mark.getMark()) {
				case UP:
					if (StringUtil.isEmpty(mark.getNote())) {
						return "↑ " + datum[colIdx].getString();
					}
					return datum[colIdx].getString() + " {↑ " + mark.getNote()
							+ "}";
				case DOWN:
					if (StringUtil.isEmpty(mark.getNote())) {
						return "↓ " + datum[colIdx].getString();
					}
					return datum[colIdx].getString() + " {↓ " + mark.getNote()
							+ "}";
				}
				return datum[colIdx].getString();
			}
		} else if (supportDiff
				&& datum[colIdx].getPair() instanceof DifferenceStringData) {
			DifferenceStringData d = (DifferenceStringData) datum[colIdx]
					.getPair();
			switch (d.fDifferenceKind) {
			case ADDITION:
				if (colIdx == 0) {
					return datum[colIdx].getString() + "[+]";
				}
				return datum[colIdx].getString();
			case CHANGE:
				return datum[colIdx].getString() + d;
			}
		} else if (v.isHyperLinkColumn(colIdx)
				&& colIdx != v.getTable().getSelectionIndex()) {
			String str = DefaultHyperLinkAction.getDisplayString(datum[colIdx]
					.getString());
			if (str.length() == 0) {
				return "<NULL>";
			}
			return str;
		}
		String str = datum[colIdx].getString();
		if (str.length() == 0) {
			return "<NULL>";
		}
		return str;
	}

	boolean even = true;
	Color backGroundColor, foreGroundColor;

	private boolean isNotNull() {
		if (isNotNull == null) {
			CSVRecordDataHolder cdh = this.v.getCDH();
			if (cdh != null) {
				isNotNull = cdh.isNotNullIdx(colIdx);
			}
		}
		if (isNotNull == null) {
			return false;
		}
		return isNotNull;
	}

	@Override
	public Color getForeground(Object element) {
		StringRecordData[] datum = (StringRecordData[]) element;
		if (v.isHyperLinkColumn(colIdx)
				&& colIdx != v.getTable().getSelectionIndex()
				&& !datum[colIdx].isNullValue()) {
			return v.getTable().getDisplay().getSystemColor(SWT.COLOR_BLUE);
		} else {
			if (isNotNull() && datum[colIdx].isNullValue()) {
				return v.getTable().getDisplay().getSystemColor(SWT.COLOR_RED);
			}
			if (datum[colIdx].getPair() instanceof MarkStringData) {
				MarkStringData mark = (MarkStringData) datum[colIdx].getPair();
				switch (mark.getMark()) {
				case UP:
					return v.getTable().getDisplay()
							.getSystemColor(SWT.COLOR_RED);
				case DOWN:
					return v.getTable().getDisplay()
							.getSystemColor(SWT.COLOR_BLUE);
				}
			}
		}
		return super.getForeground(element);
	}

	public Color getBackground(Object element) {
		return backGroundColor;
	}

	public void update(ViewerCell cell) {
		boolean normal = true;
		TableItem item = (TableItem) cell.getItem();
		StringRecordData[] items = (StringRecordData[]) item.getData();
		if (items.length <= colIdx) {
			return;
		}
		if (supportDiff && (items[colIdx].getPair() != null)
				&& (items[colIdx].getPair() instanceof DifferenceStringData)) {
			DifferenceStringData d = (DifferenceStringData) items[colIdx]
					.getPair();
			switch (d.fDifferenceKind) {
			case ADDITION:
				backGroundColor = ColorUtil.getColor(ColorNameEnum.ADD);
				normal = false;
				break;
			case CHANGE:
				normal = false;
				backGroundColor = ColorUtil.getColor(ColorNameEnum.CHANGE);
				break;
			case DELETION:
				normal = false;
				backGroundColor = ColorUtil.getColor(ColorNameEnum.DELETE);
				break;
			}
		}
		if (normal) {
			String str = items[colIdx].getString();
			if (str.length() == 0) {
				backGroundColor = ColorUtil.getColor(ColorNameEnum.NULL);
			} else if (str.startsWith("<") && str.endsWith(">")) {
				backGroundColor = ColorUtil.getColor(ColorNameEnum.TAG);
			} else if (searcher.isEven(item)) {
				backGroundColor = null;
			} else {
				backGroundColor = ColorUtil.getColor(ColorNameEnum.SIMA);
			}
		}

		super.update(cell);
	}

	private class OptimizedIndexSearcher {
		private int lastIndex = 0;

		public boolean isEven(TableItem item) {
			try {
				TableItem[] items = item.getParent().getItems();

				// 1. Search the next ten items
				for (int i = lastIndex; i < items.length && lastIndex + 10 > i; i++) {
					if (items[i] == item) {
						lastIndex = i;
						return lastIndex % 2 == 0;
					}
				}

				// 2. Search the previous ten items
				for (int i = lastIndex; i < items.length && lastIndex - 10 > i; i--) {
					if (items[i] == item) {
						lastIndex = i;
						return lastIndex % 2 == 0;
					}
				}

				// 3. Start from the beginning
				for (int i = 0; i < items.length; i++) {
					if (items[i] == item) {
						lastIndex = i;
						return lastIndex % 2 == 0;
					}
				}

				return false;
			} catch (Exception e) {
				System.err.println("last=" + lastIndex + "/len=");
				e.printStackTrace();
			}
			return false;
		}
	}

}