/**
 * Kepler - Core
 * 
 * All rights reserved.
 *
 */

	import { math, matrix4 } 	from './math.js';
	
	import renderSystem 	from './renderSystem.js';

	import assimp 			from './assimp.js';

	import preloader 		from './preloader.js';

	import texture 			from './texture.js';

	import sampler2D 		from './sampler2D.js';

	import resourceManager 	from './resourceManager.js';

	import pluginManager 	from './pluginManager.js';

	import entity 			from './entity.js';

	import material 		from './material.js';

	import utils 			from './utils.js';

	import viewport 		from './viewport.js';
	

	class keplerEngine
	{

		gl;

		math;

		resources;

		events;

		system;

		mainCamera;

		mainPlayer;

		assimpLoader;

		// public functions
		init;

		callback;
		
		samplerId = 0;

		samplerCubeID = 0;

		global_material_id = 0;

		entityID = 0;
		
		
		
		/**
		 * Initialize Kepler Engine
		 */
		constructor() {

			this.math 			= new math();

			this.viewports 		= new Array();
			
			var canvas 			= document.getElementById("keplerEngine");

			this.resources 		= new resourceManager( this );

			this.math 			= new math();

			this.assimpLoader 	= new assimp();

		}
		
		addViewport(viewport){
			
			this.viewports.push(viewport);
			
		}
		
		/**
		 * Application
		 */
		application( ) {
		
			var viewports = kepler.viewports;
			
			for(var c = 0; c<viewports.length; c++) {
				
				var viewport = viewports[c];

				viewport.system.createRenderPasses();
				
			}
			
			this.resources.finishCallback = function(){	
		
				kepler.tick();
			}


			this.resources.loadNextTexture();
	
		}
		

		registerPlugin( plugin ) {
			
			this.plugins.addPlugin( plugin );
			
		}
		
		render(){
			
			var viewports = kepler.viewports;
			
			for(var c = 0; c<viewports.length; c++) {

				var viewport = viewports[c];
				
				viewport.render();

				viewport.system.render();

			}

		}

		/**
		 * Tick
		 */
		tick() {

			requestAnimFrame( this.tick.bind( this ) );

			this.render();
		}

		/**
		 * create kepler object
		 * @param {string} name of class
		 */
		createObject( className ) {

			var instance 	= kepler[ className ];

			var object 		= new instance;

			return object;

		};

		/**
		 * load url
		 * @param {string} url 
		 */
		loadTextFileSynchronous(url) {

			var request;


			if (window.XMLHttpRequest) {

				request = new XMLHttpRequest();

				if (request.overrideMimeType) {

				  request.overrideMimeType('text/plain');

				}

			} else if (window.ActiveXObject) {

				request = new ActiveXObject('MSXML2.XMLHTTP.3.0');

			} else {

				throw 'XMLHttpRequest is disabled';

			}
			
			request.open('GET', url, false);

			request.send(null);
			
			if (request.readyState != 4) {

				throw error;
				
			}
			
			return request.responseText;

		}
		
		/*
		 *	Create error texture
		 */
		createErrorTexture() {
			
			var dataArray = [];
			
			var width = 512;

			var height = 512;
			
			for( var y = 0; y < height; y++ )
			{
				for( var x = 0; x < width; x++ )
				{
					dataArray.push(x / width);
					dataArray.push( y / width);

					dataArray.push(  x / x / width);
					dataArray.push(  y * x / width); 
				}
			}
			
			var text = this.textureFromArray(dataArray, width, height, true);
			var sampler = new sampler2D( this );
			sampler.texture = text;
		
			this.errorTexture = sampler;
		}

	/**
	 * Texture from array
	 * @param {(array)} array
	 * @param {(float)} width
	 * @param {(float)} height
	 * @param {(boolean)} is_float
	**/
	textureFromArray( array, width, height, is_float ) {
		var textureObject = new texture( this );
		
		if( is_float ) {
			textureObject.data = new Float32Array( array );
			textureObject.dataType = 'float';
		} else {
			textureObject.data = new Int32Array( array );
			textureObject.dataType = 'int';
		}
		
		textureObject.width = width;
		textureObject.height = height;
		
		return textureObject;
	}
		
		removeElementById(id)
		{
			return (elem=document.getElementById(id)).parentNode.removeChild(elem);
		}
		
		


		/**
		 * Texture from typed array
		 * @param {(typedArray)} typedArray
		 * @param {(float)} width
		 * @param {(float)} height
		 * @param {(viewport)} viewport
		**/
		textureFromTypedArray( typedArray, width, height ) {
			var textureObject = new texture(  );

			textureObject.data = typedArray;
			textureObject.dataType = 'int';	
			textureObject.width = width;
			textureObject.height = height;
			
			return textureObject;
		}


		/**
		 * Texture from typed array 32 bit
		 * @param {(array)} Array
		 * @param {(float)} width
		 * @param {(float)} height
		**/
		textureFromFloat32Array(array, width, height) {
			texture = new texture( this );
			texture.data = array;
			texture.dataType = 'float';
			texture.width = width;
			texture.height = height;
			
			return texture;
		}


		/**
		 * Texture from typed int array 32 bit
		 * @param {(array)} Array
		 * @param {(float)} width
		 * @param {(float)} height
		**/
		textureFromInt32Array(array, width, height) {
			texture = new texture( this );
			texture.data = 'int';
			texture.dataType = array;
			texture.width = width;
			texture.height = height;
			
			return texture;
		}

		dummyTextureFromImage() {
			
			
		}
		
		
		/**
		 * Texture from dom image
		 * @param {(dom object image)} image
		**/
		textureFromImage( image, viewport ) {
			
			var textureObject = new texture( );
			textureObject.setViewport( viewport );
			
			textureObject.data = image;
			textureObject.dataType = 'image';
			
			textureObject.width = image.width;
			textureObject.height = image.height;
			
			return textureObject;
		}


		/**
		 * Texture from DDS
		 * @param {(array)} image
		**/
		textureFromDDS( data ) {
			
			texture = new texture( this );
			
			texture.data = data;
			texture.dataType = 'COMPRESSED_RGBA';
			
			texture.width = data.width;
			texture.height = data.height;
			
			console.log(texture);

			return texture;
		}
		
		/**
		 * Create sampler
		 * @param {TextureOBject} texture
		 * @param {Canvas} textureCanvas 
		 */
		createSampler(texture, textureCanvas) {

			var image = texture.image;
			var width = image.width;
			var height = image.height;
			
			if(textureCanvas) {
				this.gl.bindTexture(this.gl.TEXTURE_2D, this.gl.createTexture());
				this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.gl.RGBA, this.gl.RGBA, this.gl.UNSIGNED_BYTE, texture); 
			} else {
				this.gl.bindTexture(this.gl.TEXTURE_2D, texture);
				this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.gl.RGBA, this.gl.RGBA, this.gl.UNSIGNED_BYTE, texture.image);
			}
			
			if (isPowerOfTwo(width) && isPowerOfTwo(height)){
				this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MAG_FILTER, this.gl.NEAREST);
				this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MIN_FILTER, this.gl.NEAREST);
			} else {

				this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_S, this.gl.CLAMP_TO_EDGE);
				this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_T, this.gl.CLAMP_TO_EDGE);
			}
			
			this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MAG_FILTER, this.gl.LINEAR);
			this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MIN_FILTER, this.gl.LINEAR);

			this.gl.bindTexture(this.gl.TEXTURE_2D, null);
		}
		

		/**
		 * Create sampler from Canvas
		 * @param {Canvas} canvas
		 * @param {int} idx 
		 */
		createSamplerFromCanvas(canvas, idx) {
			var texture =  this.gl.createTexture();

			this.gl.activeTexture(this.gl.TEXTURE0 + idx);
			this.gl.bindTexture(this.gl.TEXTURE_2D, texture);
			
			this.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL, false);
			this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.gl.RGBA, this.gl.RGBA, this.gl.UNSIGNED_BYTE, canvas);
			
			if (isPowerOfTwo(canvas.width) && isPowerOfTwo(canvas.height)){
				this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MAG_FILTER, this.gl.NEAREST);
				this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MIN_FILTER, this.gl.NEAREST);
			} else {
				this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MIN_FILTER, this.gl.LINEAR);
				this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_S, this.gl.CLAMP_TO_EDGE);
				this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_T, this.gl.CLAMP_TO_EDGE);
			}
			
			texture._className = 'textaaaure';

			this.gl.bindTexture(this.gl.TEXTURE_2D, null);
			
			return texture;
		}
		
		/**
		 * Check if int is power of two
		 * @param {int} number
		 */
		isPowerOfTwo(x) {
			return (x & (x - 1)) == 0;
		}


		/**
		 * check if object is array
		 * @return {(boolean)} 
		**/
		is_array(input){
			return typeof(input)=='object'&&(input instanceof Array);
		}
		

		/**
		 * Create Texture from pixel array
		 * @param {array} 2x2 array with pixel colors
		 * @param {int} width
		 * @param {int} height
		 */
		textureFromPixelArray(dataArray, width, height) {
			var dataTypedArray = new Float32Array(dataArray); 
			var texture = this.gl.createTexture();

			this.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL, false);
			this.gl.activeTexture(this.gl.TEXTURE0 + ++samplerId);
			this.gl.bindTexture(this.gl.TEXTURE_2D, texture);
			this.gl.texImage2D(this.gl.TEXTURE_2D, 0, this.gl.RGBA, width, height, 0, this.gl.RGBA, this.gl.FLOAT, dataTypedArray);
			
			this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MIN_FILTER, this.gl.LINEAR);
			this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_S, this.gl.CLAMP_TO_EDGE);
			this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_T, this.gl.CLAMP_TO_EDGE);
			
			texture._className = 'texture';
			
			return texture;
		}
		
	}
	
	

	
	export {keplerEngine as default};
	
