package org.eclipse.nebula.widgets.nattable.renderer.swt.graphics

import java.util.HashMap
import java.util.Map
import java.util.Stack
import org.eclipse.nebula.widgets.nattable.core.geometry.PixelRectangle
import org.eclipse.nebula.widgets.nattable.core.graphics.Color
import org.eclipse.nebula.widgets.nattable.core.graphics.GraphicsContext
import org.eclipse.swt.SWT
import org.eclipse.swt.graphics.GC
import org.eclipse.swt.graphics.Rectangle
import org.eclipse.swt.widgets.Composite

import static org.eclipse.nebula.widgets.nattable.renderer.swt.graphics.GraphicsPropertiesEnum.*

/**
 * Proxy implementation of {@link IGraphicsContext} to provide the drawing
 * capabilities by {@link GC} so the NatTable can be painted using this.
 * 
 * @author Dirk Fauth
 *
 */
class SWTGraphicsContext implements GraphicsContext {
	
	val Composite composite
	/**
	 * The SWT {@link GC} which is proxied by this implementation.
	 */
	val GC gc
	val stateStack = new Stack<Map<GraphicsPropertiesEnum, Object>>
	
	Map<GraphicsPropertiesEnum, Object> originalState = newHashMap
	int xOffset
	int yOffset
	int foregroundAlpha = 255
	int backgroundAlpha = 255
	
	/**
	 * Create a new proxy instance for the specified {@link GC}.
	 * @param gc The SWT {@link GC} which is proxied by this implementation.
	 */
	new(Composite composite, GC gc) {
		if (composite == null) throw new IllegalArgumentException("composite can not be null"); //$NON-NLS-1$
		if (gc == null) throw new IllegalArgumentException("gc can not be null"); //$NON-NLS-1$
		this.composite = composite
		this.gc = gc
	}
	
	def getSWTComposite() {
		composite
	}
	
	def getXOffset() { xOffset }
	def getYOffset() { yOffset }
	
	// GraphicsContext interface
	
	override pushState() {
		stateStack.push(originalState)
		originalState = new HashMap<GraphicsPropertiesEnum, Object>
	}
	
	override popState() {
		for (property : originalState.keySet) {
			val originalValue = originalState.get(property)
			switch (property) {
				case FOREGROUND_COLOR: gc.foreground = originalValue as org.eclipse.swt.graphics.Color
				case FOREGROUND_ALPHA: foregroundAlpha = originalValue as Integer
				case BACKGROUND_COLOR: gc.background = originalValue as org.eclipse.swt.graphics.Color
				case BACKGROUND_ALPHA: backgroundAlpha = originalValue as Integer
				case CLIP_BOUNDS: gc.clipping = originalValue as Rectangle
				case X_OFFSET: xOffset = originalValue as Integer
				case Y_OFFSET: yOffset = originalValue as Integer
			}
		}
		originalState = stateStack.pop
	}
	
	override translate(int deltaX, int deltaY) {
		originalState.put(X_OFFSET, xOffset)
		originalState.put(Y_OFFSET, yOffset)
		
		xOffset = xOffset + deltaX
		yOffset = yOffset + deltaY
	}
	
	override setForegroundColor(Color foregroundColor) {
		originalState.put(FOREGROUND_COLOR, gc.foreground)
		originalState.put(FOREGROUND_ALPHA, foregroundAlpha)
		
		gc.foreground = new org.eclipse.swt.graphics.Color(
			gc.device,
			foregroundColor.red,
			foregroundColor.green,
			foregroundColor.blue
		)
		foregroundAlpha = foregroundColor.alpha
	}
	
	override setBackgroundColor(Color backgroundColor) {
		originalState.put(BACKGROUND_COLOR, gc.background)
		originalState.put(BACKGROUND_ALPHA, backgroundAlpha)
		
		gc.background = new org.eclipse.swt.graphics.Color(
			gc.device,
			backgroundColor.red,
			backgroundColor.green,
			backgroundColor.blue
		)
		backgroundAlpha = backgroundColor.alpha
	}
	
	override getClipBounds() {
		new PixelRectangle(gc.clipping.x - xOffset, gc.clipping.y - yOffset, gc.clipping.width, gc.clipping.height)
	}
	
	override setClipBounds(PixelRectangle clipBounds) {
		originalState.put(CLIP_BOUNDS, gc.clipping)
		gc.clipping = new Rectangle(xOffset + clipBounds.x, yOffset + clipBounds.y, clipBounds.width, clipBounds.height)
	}
	
	override drawLine(int x1, int y1, int x2, int y2) {
		gc.alpha = foregroundAlpha
		gc.drawLine(xOffset + x1, yOffset + y1, xOffset + x2, yOffset + y2)
	}
	
	override drawRectangle(PixelRectangle rect) {
		gc.alpha = foregroundAlpha
		gc.drawRectangle(xOffset + rect.x, yOffset + rect.y, rect.width, rect.height)
	}
	
	override fillRectangle(PixelRectangle rect) {
		gc.alpha = backgroundAlpha
		gc.fillRectangle(xOffset + rect.x, yOffset + rect.y, rect.width, rect.height)
	}
	
	override drawText(String text, int x, int y) {
		gc.alpha = foregroundAlpha
		gc.drawText(text, xOffset + x, yOffset + y, SWT::DRAW_TRANSPARENT.bitwiseOr(SWT::DRAW_DELIMITER))
		
		//TODO draw underline and strikethrough in here instead of the TextPainter itself
	}
	
	override calculateTextWidth(String text) {
		gc.textExtent(text).x
	}
	
	override getFontHeight() {
		gc.fontMetrics.height
	}
	
}