package de.fhpotsdam.unfolding.mapdisplay;

import processing.core.PApplet;
import processing.core.PConstants;
import processing.core.PGraphics;
import de.fhpotsdam.unfolding.mapdisplay.shaders.MapDisplayShader;
import de.fhpotsdam.unfolding.mapdisplay.shaders.MaskedMapDisplayShader;
import de.fhpotsdam.unfolding.marker.Marker;
import de.fhpotsdam.unfolding.marker.MarkerManager;
import de.fhpotsdam.unfolding.providers.AbstractMapProvider;

@SuppressWarnings("rawtypes")
public class OpenGLMapDisplay extends P2DMapDisplay implements PConstants {
  protected String renderer;
	// Inner map (and inner marker) will be drawn on this.
	protected PGraphics offscreenPG;
	// Outer marker will be drawn on this
	protected PGraphics offscreenCutoffPG;

	protected float opacity = 255;

	protected MapDisplayShader mapDisplayShader = null;

	public OpenGLMapDisplay(PApplet papplet, AbstractMapProvider provider,
	    String renderer, float offsetX, float offsetY, float width, float height) {
		super(papplet, provider, offsetX, offsetY, width, height);
 
		if (renderer == null || renderer.equals("")) {
	    try {
	      Class P2DClass = Class.forName(P2D);
	      Class P3DClass = Class.forName(P3D);
	      if (P2DClass.isInstance(papplet.g)){
	        this.renderer = P2D;
	      } else if (P3DClass.isInstance(papplet.g)){
	        this.renderer = P3D;
	      } else {
	        this.renderer = OPENGL;
	      }
	    } catch (ClassNotFoundException e) {
	      this.renderer = OPENGL;
	    }		  
		} else {
		  this.renderer = renderer;
		}
		
		offscreenPG = papplet.createGraphics((int) width, (int) height, this.renderer);
		offscreenPG.smooth(papplet.g.quality);
		offscreenCutoffPG = papplet.createGraphics((int) width, (int) height, this.renderer);
		offscreenCutoffPG.smooth(papplet.g.quality);
		
	}

	public void setMapDisplayShader(MapDisplayShader shader) {
		this.mapDisplayShader = shader;
	}

	public MapDisplayShader getMapDisplayShader() {
		return mapDisplayShader;
	}

	@Override
	public void resize(float width, float height) {
		super.resize(width, height);
		
		offscreenPG = papplet.createGraphics((int) width, (int) height, renderer);
		offscreenPG.smooth(papplet.g.quality);
		offscreenCutoffPG = papplet.createGraphics((int) width, (int) height, renderer);
		offscreenCutoffPG.smooth(papplet.g.quality);
		
		if (mapDisplayShader != null) {
			mapDisplayShader.resize(width, height);
		}
	}

	@Override
	public PGraphics getInnerPG() {
		return offscreenPG;
	}

	@Override
	public PGraphics getOuterPG() {
		return offscreenCutoffPG;
	}
	
	@Override
	protected void postDraw() {
		// Draws inner map (with inner marker) and outer marker
		offscreenCutoffPG.beginDraw();
		// REVISIT map background color
		offscreenCutoffPG.background(0);
		if (mapDisplayShader != null) {
			// NB: Uses offscreenPG (and not offscreenCutofPG) to not get 'Shader must be COLOR type' error 
			mapDisplayShader.shadeWithoutMarkers(offscreenPG);
		}
		offscreenCutoffPG.image(offscreenPG, 0, 0);
		for (MarkerManager<Marker> mm : markerManagerList) {
			mm.draw();
		}
		offscreenCutoffPG.endDraw();

		// Transforms (outer) map pane, and draws inner map + marker onto canvas
		// This cuts off marker at the border.
		PGraphics canvasPG = papplet.g;
		canvasPG.pushMatrix();
		canvasPG.translate(offsetX, offsetY);
		if (canvasPG.is3D()) {
		  canvasPG.applyMatrix(matrix);
		} else {
		  canvasPG.applyMatrix(matrix.m00, matrix.m01, matrix.m03,
		                       matrix.m10, matrix.m11, matrix.m13);		  
		}
		if (mapDisplayShader != null) {
			mapDisplayShader.shadeWithMarkers(canvasPG);
		}
		canvasPG.image(offscreenCutoffPG, 0, 0);
		canvasPG.popMatrix();
		//canvasPG.resetShader();
	}
}

@@ -3603,16 +3603,71 @@
 G);%0A%09%09%7D%0A
+%09%09canvasPG.pushStyle();%0A%09%09canvasPG.blendMode(REPLACE);%0A
 %09%09canvas
@@ -3701,16 +3701,38 @@
  0, 0);%0A
+%09%09papplet.popStyle();%0A
 %09%09canvas

disable blending when rendering the offscreen canvas in OpenGLMapDisplay.