/*
 * Copyright 2012-2019, kaj dijkstra Inc, 
 * Author, Kaj Dijkstra.
 * All rights reserved.
 *
 */
 
import keplerEngine from './kepler.js';
import scene from './scene.js';
import primitives from './primitives.js';
import samplerCube from './samplerCube.js';
import sampler2D from './sampler2D.js';
import shader from './shader.js';
import framebuffer from './framebuffer.js';
import {math, vector3, matrix4} from './math.js';
import renderPipeline from './renderPipeline.js';


// import render passes
import deferred from './renderPasses/deferred.js';
import uber from './renderPasses/uber.js';
import ssao from './renderPasses/ssao.js';
import convolution from './renderPasses/convolution.js';
import fxaa from './renderPasses/fxaa.js';
import highpassFilter from './renderPasses/highpassFilter.js';
import hdr from './renderPasses/hdr.js';
import depth from './renderPasses/depth.js';
import shadow from './renderPasses/shadow.js';
import tonemap from './renderPasses/tonemap.js';


/**
 * Rendersystem
**/
class renderSystem{

	constructor( ) {
		
		this.scene = new scene();	
		this.render_type = "forward"; // "Forward" or "Deferred"
		this.viewMode = 0;
		
		this.depthPasses = [];
		
	}
	
	setRenderMode( mode ) { // "deferred", "forward"
		
		this.render_type = mode;
	}
	
	setViewMode( mode ) { "lit", "unlit", "lighting Only", "Reflections", 
		
		this.viewMode = mode;
		
		var uberPass = this.deferredRenderPipeline.getRenderpass("uber");
		
		uberPass.shader.setUniform("viewMode", mode );
		
	}
	
	setViewport( viewPort ){
		
		this.viewPort = viewPort;
		this.gl = viewPort.gl;
		
		this.forwardRenderPipeline = new renderPipeline( this.viewPort );
		this.deferredRenderPipeline = new renderPipeline( this.viewPort );
		
	}

	createRenderPasses(){
		
		//this.createCubemapSampler();
		
		// create render passes
		var deferredPass 			= new deferred();
		var uberPass 				= new uber();
		var ssaoPass				= new ssao();
		var ssaoConvolutionXPass	= new convolution();
		var ssaoConvolutionYPass	= new convolution();
		var fxaaPass				= new fxaa();
		var highpassFilterPass		= new highpassFilter();
		var bloomConvolutionXPass	= new convolution();
		var bloomConvolutionYPass	= new convolution();
		var hdrPass					= new hdr();
		var shadowPass				= new shadow();
		var tonemapPass				= new tonemap();
		
		var forwardRenderPass 		= new deferred();
		
		deferredPass.render_type = "deferred";
		forwardRenderPass.render_type = "forward";
		
		
		// Add lights
		var lightEntitys = this.viewPort.scene.getLights();
		
	
		
		for(var c = 0; c<lightEntitys.length; c++) {
			
			var lightEntity = lightEntitys[c];
				
			var depthPass				= new depth();
			
			// Light properties
			depthPass.lightPosition = lightEntity.transform.position;
			depthPass.lightType 	= lightEntity.type;
			depthPass.showFrustum 	= lightEntity.showFrustum;
			depthPass.realtime		= false;
			
			if(lightEntity.degrees)
			depthPass.degrees 			= lightEntity.degrees;
			
			//depthPass.renderToViewport = true;
			
			
			this.deferredRenderPipeline.addRenderpass( depthPass, "depth" );
			
			this.forwardRenderPipeline.addRenderpass( depthPass, "depth" );
			
			this.depthPasses.push(depthPass);
			
			

		}
		console.log('lightEntity', lightEntity);
		// Add them to the render system in the right order
		// Deferred pipeline
		
		this.deferredRenderPipeline.addRenderpass( deferredPass, "deferred" );
		this.deferredRenderPipeline.addRenderpass( ssaoPass, "ssao" );
		this.deferredRenderPipeline.addRenderpass( shadowPass, "shadowmap" );
		
		
		this.deferredRenderPipeline.addRenderpass( ssaoConvolutionXPass, "ssaoConvolutionX" );
		this.deferredRenderPipeline.addRenderpass( ssaoConvolutionYPass, "ssaoConvolutionY" );
		this.deferredRenderPipeline.addRenderpass( uberPass, "uber" );
		
		
		//this.deferredRenderPipeline.addRenderpass( highpassFilterPass, "highpassFilter" );
		//this.deferredRenderPipeline.addRenderpass( bloomConvolutionXPass, "bloomConvolutionX" );
		//this.deferredRenderPipeline.addRenderpass( bloomConvolutionYPass, "bloomConvolutionY" );
		//this.deferredRenderPipeline.addRenderpass( hdrPass, "hdr" );
		
		
		this.deferredRenderPipeline.addRenderpass( fxaaPass, "fxaa" );
		//this.deferredRenderPipeline.addRenderpass( tonemapPass, "tonemap" );
		
		// Forward pipeline
		
		
		this.forwardRenderPipeline.addRenderpass( forwardRenderPass, "forward" );
		
		
		//shadowPass.renderToViewport = true;

		forwardRenderPass.renderToViewport = true;
		fxaaPass.renderToViewport = true;
		
		
		//depthPass.renderToViewport = true;
		//ssaoConvolutionYPass.renderToViewport = true;
		//uberPass.renderToViewport = true;
		
		// Set convolution Directions
		ssaoConvolutionXPass.setDirection("Horizontal");
		ssaoConvolutionYPass.setDirection("Vertical");
		
		// Route all the renderpasses
		ssaoPass.shader.setUniform("infoSampler", deferredPass.normalSampler);

		ssaoConvolutionXPass.shader.setUniform("image", shadowPass.framebuffer.getSampler() );
		ssaoConvolutionYPass.shader.setUniform("image", ssaoConvolutionXPass.framebuffer.getSampler() );

		uberPass.shader.setUniform("diffuseSampler", deferredPass.diffuseSampler);
		uberPass.shader.setUniform("normalSampler", deferredPass.normalSampler);
		uberPass.shader.setUniform("infoSampler", deferredPass.infoSampler);
		uberPass.shader.setUniform("ambientOcclusionSampler", ssaoConvolutionYPass.framebuffer.getSampler() );
		
		
		shadowPass.shader.setUniform("positionSampler", deferredPass.infoSampler );
		shadowPass.shader.setUniform("ambientOcclusionSampler", ssaoPass.framebuffer.getSampler() );
		//tonemapPass.shader.setUniform("colorSampler", uberPass.aaSampler );
		//uberPass.shader.setUniform("shadowDepthSampler", depthPass.framebuffer.getSampler() );
		//uberPass.shader.setUniform("lightViewProjection", depthPass.viewProjection );
		
		fxaaPass.shader.setUniform("deferredSampler", uberPass.framebuffer.getSampler() );
		
		//tonemapPass.shader.setUniform("colorSampler", fxaaPass.framebuffer.getSampler() );
		
		for(var c = 0; c<this.depthPasses.length; c++) {
			
			var depthpass = this.depthPasses[c];
			
			uberPass.shader.setUniform("shadowDepthSampler", depthPass.framebuffer.getSampler() );
			uberPass.shader.setUniform("lightViewProjection", depthPass.viewProjection );
			
		}
		
	}

	render( ) {

		if(this.render_type == "deferred") {
			
			var renderPasses = this.deferredRenderPipeline.getRenderPasses();
			
		} else {
			
			var renderPasses = this.forwardRenderPipeline.getRenderPasses();
			
		}
		

		for(var c = 0; c < renderPasses.length; c++) {
			
			var renderpass = renderPasses[c];
			if(renderpass.realtime) {
				
				renderpass.render();
				
			} else if( !renderpass.updated ){
				
				renderpass.render();
				renderpass.updated = true;
			}
			
			
			if(renderpass.renderToViewport) {
				
				return true;
				
			}
		}	

		this.gl.flush();
		
	}

	createShadowCam( eye, target, up ) {
		var width = 2048;
		var height = 2048;
		

		var width = 50;
		var height = width;
		var near = .0001;
		var far = 30;
		
		
		var shadowCamera = {};

		shadowCamera.view 			= matrix4.lookAt( eye, target, up );
		//shadowCamera.projection 	= matrix4.orthographic(-width, width, -height, height, -near, far);
		shadowCamera.projection 	= matrix4.perspective(math.degToRad(55), width / height, near, far);
		shadowCamera.viewProjection = matrix4.mul(shadowCamera.view, shadowCamera.projection);
		shadowCamera.far 			= far;
		

		return shadowCamera;
	}
	
	/**
	 * initialize webgl
	 * @param {(Dom canvas)} canvas
	**/
	initializeWebgl( canvas ) {
		
		//try {
		
			var width = canvas.offsetWidth;
			var height = canvas.offsetHeight;

			canvas.width = math.nextHighestPowerOfTwo(width);
			canvas.height = math.nextHighestPowerOfTwo(height);
			
			console.log('adjusted resolution to width:', canvas.width , 'height', canvas.height);
			
			this.canvas = canvas;
			
			//this.setLoadingText("Init Webgl");
			if(this.render_type == "forward")
			this.gl = canvas.getContext("webgl2");
			else
			this.gl = canvas.getContext("webgl2");	//, { antialias: false }
		//, { antialias: false }canvas.getContext("experimental-webgl",  {alpha: false});
			
			gl = this.gl;
			
			this.extensions = {};
			this.extensions.EXT_shader_texture_lod = this.gl.getExtension('EXT_shader_texture_lod');
			this.extensions.textureFloat = this.gl.getExtension('OES_texture_float');
			this.extensions.textureFloat = this.gl.getExtension('OES_texture_float');
			 
			this.extensions.textureHalf = this.gl.getExtension('OES_texture_half_float');
			this.extensions.elementIndexUint = this.gl.getExtension('OES_element_index_uint'); 
			this.extensions.derivatives = this.gl.getExtension('OES_standard_derivatives');
			this.extensions.texture3d = this.gl.getExtension("OES_texture_3D");
			this.extensions.depthTexture = this.gl.getExtension("WEBKIT_WEBGL_depth_texture");
			this.extensions.anisotropic = this.gl.getExtension("WEBKIT_EXT_texture_filter_anisotropic");
			this.extensions.textureCompression = this.gl.getExtension("WEBKIT_WEBGL_compressed_texture_s3tc");
			this.extensions.OES_half_float_linear = this.gl.getExtension("OES_half_float_linear");
			this.extensions.WEBGL_draw_buffers = this.gl.getExtension("WEBGL_draw_buffers");
			this.extensions.WEBGL_color_buffer_float = this.gl.getExtension("WEBGL_color_buffer_float");
			this.extensions.EXT_sRGB = this.gl.getExtension("EXT_sRGB");
			this.extensions.EXT_color_buffer_float = this.gl.getExtension("EXT_color_buffer_float");
			this.extensions.OES_texture_float_linear = this.gl.getExtension("OES_texture_float_linear");
			
			//this.setLoadingText("Init Kepler");
			
			if(this.extensions.elementIndexUint)
				this.indexType = this.gl.UNSIGNED_INT;
			else
				this.indexType = this.gl.UNSIGNED_SHORT;
			
			
			var formats = this.gl.getParameter(this.gl.COMPRESSED_TEXTURE_FORMATS);
			 
			this.extensions.dxt5Supported = false;
			
			for(var i = 0; i<formats.length; i++) {

				if(formats[i] == this.extensions.textureCompression.COMPRESSED_RGBA_S3TC_DXT5_EXT) {
					this.extensions.dxt5Supported = true;
				}
			}
			 
			console.log(this.extensions, formats);
			
			this.gl.viewportWidth = canvas.width;
			this.gl.viewportHeight = canvas.height;
			
			this.width = canvas.width;
			this.height = canvas.height;
			
			
			this.canvas = canvas;

			
			
			//return this.gl;
			
		//} catch (e) {  }
		
		//if (!this.gl) {
		//	alert("Could not initialise WebGL, sorry :-(");
		//}
		console.log(this.gl);
		return this.gl;
	}


	/**
	 * set graphics library
	 * @param {(string)} name
	**/
	setGraphicsLibrary(name) {
		/*
			
		*/
	}



}

export {renderSystem as default};
