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.ITextViewerExtension3;
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 ITextViewerExtension3) {
			ITextViewerExtension3 extension= (ITextViewerExtension3) 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;
	}
}