package net.sourceforge.phpeclipse.phpeditor;

/*
 * (c) Copyright IBM Corp. 2000, 2001.
 * All Rights Reserved.
 */

import net.sourceforge.phpdt.internal.ui.text.PHPPairMatcher;

import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.ITextViewerExtension5;
import org.eclipse.jface.text.Position;
import org.eclipse.jface.text.Region;
import org.eclipse.jface.text.source.ISourceViewer;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Point;

public final class BracketPainter implements IPainter, PaintListener {

	private PHPPairMatcher fMatcher = new PHPPairMatcher(new char[] { '{', '}',
			'(', ')', '[', ']' });

	private Position fBracketPosition = new Position(0, 0);

	private int fAnchor;

	private boolean fIsActive = false;

	private ISourceViewer fSourceViewer;

	private StyledText fTextWidget;

	private Color fColor;

	private IPositionManager fPositionManager;

	public BracketPainter(ISourceViewer sourceViewer) {
		fSourceViewer = sourceViewer;
		fTextWidget = sourceViewer.getTextWidget();
	}

	public void setHighlightColor(Color color) {
		fColor = color;
	}

	public void dispose() {
		if (fMatcher != null) {
			fMatcher.dispose();
			fMatcher = null;
		}

		fColor = null;
		fTextWidget = null;
	}

	public void deactivate(boolean redraw) {
		if (fIsActive) {
			fIsActive = false;
			fTextWidget.removePaintListener(this);
			if (fPositionManager != null)
				fPositionManager.removeManagedPosition(fBracketPosition);
			if (redraw)
				handleDrawRequest(null);
		}
	}

	public void paintControl(PaintEvent event) {
		if (fTextWidget != null)
			handleDrawRequest(event.gc);
	}

	private void handleDrawRequest(GC gc) {

		if (fBracketPosition.isDeleted)
			return;

		int offset = fBracketPosition.getOffset();
		int length = fBracketPosition.getLength();
		if (length < 1)
			return;

		if (fSourceViewer instanceof ITextViewerExtension5) {
			ITextViewerExtension5 extension = (ITextViewerExtension5) fSourceViewer;
			IRegion widgetRange = extension.modelRange2WidgetRange(new Region(
					offset, length));
			if (widgetRange == null)
				return;

			offset = widgetRange.getOffset();
			length = widgetRange.getLength();

		} else {
			IRegion region = fSourceViewer.getVisibleRegion();
			if (region.getOffset() > offset
					|| region.getOffset() + region.getLength() < offset
							+ length)
				return;
			offset -= region.getOffset();
		}

		if (PHPPairMatcher.RIGHT == fAnchor)
			draw(gc, offset, 1);
		else
			draw(gc, offset + length - 1, 1);
	}

	private void draw(GC gc, int offset, int length) {
		if (gc != null) {
			Point left = fTextWidget.getLocationAtOffset(offset);
			Point right = fTextWidget.getLocationAtOffset(offset + length);

			gc.setForeground(fColor);
			gc.drawRectangle(left.x, left.y, right.x - left.x - 1, gc
					.getFontMetrics().getHeight() - 1);

		} else {
			fTextWidget.redrawRange(offset, length, true);
		}
	}

	/*
	 * @see IPainter#paint(int)
	 */
	public void paint(int reason) {
		Point selection = fSourceViewer.getSelectedRange();
		if (selection.y > 0) {
			deactivate(true);
			return;
		}

		IRegion pair = fMatcher.match(fSourceViewer.getDocument(), selection.x);
		if (pair == null) {
			deactivate(true);
			return;
		}

		if (fIsActive) {
			// only if different
			if (pair.getOffset() != fBracketPosition.getOffset()
					|| pair.getLength() != fBracketPosition.getLength()
					|| fMatcher.getAnchor() != fAnchor) {

				// remove old highlighting
				handleDrawRequest(null);
				// update position
				fBracketPosition.isDeleted = false;
				fBracketPosition.offset = pair.getOffset();
				fBracketPosition.length = pair.getLength();
				fAnchor = fMatcher.getAnchor();
				// apply new highlighting
				handleDrawRequest(null);

			}
		} else {

			fIsActive = true;

			fBracketPosition.isDeleted = false;
			fBracketPosition.offset = pair.getOffset();
			fBracketPosition.length = pair.getLength();
			fAnchor = fMatcher.getAnchor();

			fTextWidget.addPaintListener(this);
			fPositionManager.addManagedPosition(fBracketPosition);
			handleDrawRequest(null);
		}
	}

	/*
	 * @see IPainter#setPositionManager(IPositionManager)
	 */
	public void setPositionManager(IPositionManager manager) {
		fPositionManager = manager;
	}
}