/*
 * Copyright 2019, kaj dijkstra, 
 * Author, Kaj Dijkstra.
 * All rights reserved.
 *
 */

import scene 		from './scene.js';

import shader 		from './shader.js';

import mesh 		from './mesh.js';

import material 	from './material.js';

import sampler2D 	from './sampler2D.js';

import entity 		from './entity.js';

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

import boundingBox 	from './boundingBox.js';

/**
 * Player object
**/
class assimp
{
	constructor() {

		this.baseUrl = "";
		this.modelPath = 'media/models/';
		
		this.meshes = [];
		this.scene  = new scene();
		this.shader = new shader();
		
		this.filesToLoad = [];
		this.name = "new";
		
		this.models = [];

		this.animations;
		
		this.skeleton;
		
		this.lightNames = ["PhotometricLight", "FPoint"];
		
		this.shadingModelIDS = [];
		
		this.bindMaterial("$ColladaAutoName$_108", 10.0);
		this.bindMaterial("Box002", 1.0);
		
		this.json;
		
		this.materialCache;
		
	}


	stringStartsWith( string, compare ) {
		if (string.substring(0, compare.length) == compare) 
			return true;
		else
			return false;
	}

	nameIsLight( name ) {
		for(var c = 0; c<this.lightNames.length; c++) {
			if(this.stringStartsWith(name, this.lightNames[c])) {
				
				return true;
					
			}
		}
		
		return false;
	}


	addModel( json ) {
		
		
		
		this.models.push(json);
	}

	bindMaterial( entityName, shadingModelID ) {
		this.shadingModelIDS.push({name:entityName, id:shadingModelID});
	}

	getShadingIdByEntityName( entityName ) {
		for(var c = 0; c<this.shadingModelIDS.length; c++) {
			console.log(this.shadingModelIDS[c].name, entityName);
			if(this.shadingModelIDS[c].name == entityName)
				return this.shadingModelIDS[c].id;
			
		}
		
		return 0;
	}

	serializeUrl( url, part_two ) {
		if(url) {
			// Remove backslash
			var urlParts = url.split("\\");
			
			url = urlParts[urlParts.length-1];
			
			
			
			// Force extension to png
			urlParts = url.split(".");
			
			
			
			urlParts[urlParts.length-1] = "png";
			
			url = urlParts.join(".");
			
			// type
			urlParts = url.split("_");
			if(urlParts.length > 1) {
				urlParts[urlParts.length-1] = part_two + ".png";
				
			} else {
				
				
			}

			url = urlParts.join("_");

			//remove slash
			urlParts = url.split("/");
			
			return urlParts[ urlParts.length - 1 ];

		} else {
			 
			 return false;
		 }
	}
	/**
	 * update object
	**/
	load( jsonFilename, scene ) {

		console.log("load file", this.modelPath + jsonFilename);
		
		var filenameParts 	= jsonFilename.split(".");
		
		this.name 			= filenameParts[0];

		this.scene 			= scene;

		var data 			= this.loadTextFileSynchronous( this.baseUrl + this.modelPath + jsonFilename );

		this.processFiles(data);
		
		console.log("filesToLoad", jsonFilename, this);

	}
	
	get_filesize(url, callback) {

		var xhr = new XMLHttpRequest();

		xhr.open("HEAD", url, true); // Notice "HEAD" instead of "GET",
									 //  to get only the header
							
		xhr.onreadystatechange = function(ev) {
			
			if (this.readyState == this.DONE) {

				console.log('evevev', ev.target.responseURL);
				var url = ev.target.responseURL;
				var size = parseInt(ev.target.getResponseHeader("Content-Length"));
				//kepler.loader.add(url, size );
				
			}
		};
		
		xhr.engine = kepler;
		xhr.send();
	}
	
	
	/**
	 * load url
	 * @param {string} url 
	 */
	loadTextFileSynchronous(url, callback) {
/*
		this.get_filesize( url );



		var fileContent = kepler.resources.getFile(url)
		
		if(fileContent) {
			return fileContent.data;
		}
		*/
		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.onprogress = callback = function (evt) {
			
			console.log("onupdate", evt);
			
			//kepler.loader.update( evt.target.responseURL, evt.loaded, evt.total ); 

		};
			
		request.onload = function (evt) {
			if (request.readyState === request.DONE) {
				if (request.status === 200) {
					//console.log(request.response);
					//console.log(request.responseText);
					this.assimp.filesToLoad.push({data: request.responseText, filename: request.responseURL });
					//'this.assimp.filesToLoad.push(evt.responseText);
					
		
					
				}
			}
		};
		
		
		request.onreadystatechange = function (evt) {
			
			console.log("finish", evt.target.readyState);
			
			if(evt.target.readyState == 4) {

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

		request.engine = this.engine;

		request.assimp = this;

		request.send();
		
		var data = request.responseText;

		return data;
	}

	
	processFiles(json)
	{

		//var json = this.filesToLoad[0];
		
		this.json 	= JSON.parse( json );

		this.json.parsedMeshes = new Array();

		var materials 		= this.json.materials;

		var meshes 			= this.json.meshes;

		var rootnode 		= this.json.rootnode;

		var children		= rootnode.children;
	
		this.animations 	= this.json.animations;


		var materialCache 	= new Array();
		
		
		// get materials
		for(var c = 0; c < materials.length; c++) {
			
			var Material = materials[c];
			var properties = Material.properties;
			
			var name = this.getPropertyByName(properties, '?mat.name', 0).value;
			var diffuseAdress = this.serializeUrl( this.getPropertyByName(properties, '$tex.file', 1).value, "diff");
			var normalAdress = this.serializeUrl( this.getPropertyByName(properties, '$tex.file', 1).value, "ddn");
			var roughAdress = this.serializeUrl( this.getPropertyByName(properties, '$tex.file', 1).value, "rough");
			var depthAdress = this.serializeUrl( this.getPropertyByName(properties, '$tex.file', 1).value, "depth");
			
			
			var diffuseColor = this.getPropertyByName(properties, "$clr.diffuse", 0).value;
			var opacity = this.getPropertyByName(properties, "$mat.opacity", 0).value;
			var roughness = this.getPropertyByName(properties, "$mat.shinpercent", 0).value;
			

console.log('diffuseAdress', diffuseAdress);
		var normalTexture = kepler.resources.getTexture("0_floorTiles_ddn.png");
		var normalSampler = new sampler2D();
		normalSampler.addTexture(normalTexture);
		
		var diffuseTexture = kepler.resources.getTexture("0_floorTiles_diff.png");
		var diffuseSampler = new sampler2D();
		diffuseSampler.addTexture(diffuseTexture);
			
			
			var currentMaterial = new material(  );
		
			//if(diffuseAdress)
			//currentMaterial.addTexture(diffuseSampler);
			//currentMaterial.addNormal(normalSampler);
			
			if(!diffuseColor) {
				currentMaterial.diffuseColor = [1,1,1];
				//currentMaterial.diffuseColor = [Math.random(), Math.random(), Math.random()];
			} else {
				currentMaterial.diffuseColor = diffuseColor;
				
			}
			
			
				//currentMaterial.diffuseColor = [Math.random(), Math.random(), Math.random()];
			if(kepler.resources.getTexture( this.name + "/" + diffuseAdress )){
				//currentMaterial.addTexture(diffuseSampler);
				//currentMaterial.addNormal(normalSampler);
			} else {
				
				
			}
				//instanceMaterial.addRoughness(roughnessSampler);
				//instanceMaterial.shadingModelID = material.id;
				currentMaterial.roughness = 0.0;
				
				currentMaterial.alpha = 1;
				//currentMaterial.create();
				currentMaterial.roughness = .01;
				currentMaterial.reflectance = .01;
				
			materialCache[c] = currentMaterial;

		}
		
		// get meshes
		for(var mesh_id = 0; mesh_id < meshes.length; mesh_id++) {
			
			this.json.parsedMeshes[mesh_id] = [];
			
			var meshInfo = meshes[mesh_id];
			
			this.parseMesh( meshInfo,  mesh_id );
		
			
		}

		this.addModel( this.json );
		
		
		
		
		//kepler.resources.loadNextTexture();
		
		this.buildModels(materialCache);
		
	}

			parseMesh( meshInfo, mesh_id ) {
				
				
	/*
				if(meshInfo.faces.length > 60000) {
					var cutFaces = meshInfo.faces.splice(60000, meshInfo.faces.length);
					
					var newMesh = JSON.parse(JSON.stringify( meshInfo ));
					
					newMesh.faces = cutFaces;
					newMesh.name = "sliced mesh";

					
					this.parseMesh( newMesh, mesh_id );
				}
				*/
				//facesOriginal = 

				//console.log("meshInfo.faces", meshInfo.faces.length);
				
				
				//flatten
				var indices = [];
				var vertices = [];
				var normals = [];
				
				for(var i = 0; i<meshInfo.faces.length; i++) {
					var face = meshInfo.faces[i];
					
					
					
					indices[i * 3] = face[0];
					indices[i * 3 + 1] = face[1];
					indices[i * 3 + 2] = face[2];

				}
				
				
				var min = getMin(indices);
				var max = getMax(indices);
				
				
				var minVert = min;
				var maxVert = ((max  )  ) - minVert; // number of items (x,y,z) = 3, 3 x 3 = face
				
				var minUV = min;
				var maxUV = ((max)) - minUV;
				
				
				for(var i = 0; i<indices.length; i++) {

				//	indices[i] = indices[i] ;// - min;


				}
				
				//console.log(min, max);

				//console.log("meshInfo.vertices", meshInfo.vertices.length);
				
				

						
				function getMax(arr) {
					let len = arr.length;
					let max = -Infinity;

					while (len--) {
						max = arr[len] > max ? arr[len] : max;
					}
					return max;
				}
						
				function getMin(arr) {
					let len = arr.length;
					let min = Infinity;

					while (len--) {
						min = arr[len] < min ? arr[len] : min;
					}
					return min;
				}
				
				//console.log(getMax(indices));
				
				var currentMesh = new mesh();
			
				if( meshInfo.texturecoords ){

					console.log( meshInfo, "Meshinfo" );
					
					var sliced_vertices 	= meshInfo.vertices;//.splice(minVert, maxVert);//.slice(min, max);

					var sliced_normals 		= meshInfo.normals;//splice(minVert, maxVert);

					var sliced_tangents 	= meshInfo.tangents;
					
					var sliced_uv 			= meshInfo.texturecoords[0];//.slice(minUV, maxUV);
	
					currentMesh.createMeshFromArrays( indices, sliced_vertices, sliced_normals, sliced_uv, sliced_tangents, meshInfo.bitangents );

					currentMesh.material 	= meshInfo.materialindex;
					
				}
				
				this.json.parsedMeshes[mesh_id].push(currentMesh);
				
			
			
					
			}


	parseNode( currentAssimpJson, assimpNode, parentEntity, scene, materialCache ) {
		
		var currentEntity = new entity(this.engine);
		currentEntity.name = assimpNode.name;
		currentEntity.transform.world = matrix4.fromArray(assimpNode.transformation);
		currentEntity.transform.local = matrix4.fromArray(assimpNode.transformation);
		
		if(this.nameIsLight(currentEntity.name)) {
			currentEntity.type = "PointLight";

			scene.addEntity( currentEntity );
		} else {
			
			if(assimpNode.meshes) {
				currentEntity.type = "Actor";
			} else {
				currentEntity.type = "transform";
				scene.addEntity( currentEntity );
			}

		}
		
		if(assimpNode.meshes) {
			
			
			var meshID = assimpNode.meshes[0];
			var meshes = currentAssimpJson.parsedMeshes[meshID];
			
			for(var c = 0;c<meshes.length;c++) {
				
				var currentMesh = meshes[c];
				
				var currentEntity = new entity(this.engine);
				currentEntity.name = assimpNode.name;
				currentEntity.transform.world = matrix4.fromArray(assimpNode.transformation);
				currentEntity.transform.local = matrix4.fromArray(assimpNode.transformation);
				currentEntity.type = "Actor";
				
				//if(global_material_id < 30) {
				//var mesh = currentAssimpJson.parsedMeshes[meshID];

				var transformation = assimpNode.transformation;
				//var materialInfo = mesh.material;//new material();
				var materialID = currentMesh.material;
				
				
				var Material = materialCache[materialID];
				
				
				if(Material) {

					
				
					currentMesh.addMaterial(Material);

					
					
					currentEntity.addMesh(currentMesh);
					
					//currentEntity.transform.world = matrix4.mul( matrix4.fromArray(transformation), matrix4.fromArray( rootnode.transformation ) );
					
					
					currentEntity.transform.local = matrix4.fromArray(transformation);
					currentEntity.transform.position = matrix4.getWorldPosition(currentEntity.transform.local);
					currentEntity.transform.scale = matrix3.getScale( currentEntity.transform.local );
					currentEntity.transform.rotation =  matrix3.getRotation( currentEntity.transform.local );
					currentEntity.transform.world = currentEntity.transform.local;//matrix4.mul( parentEntity.transform.world, entity.transform.local );
					//entity.objectTransform = matrix4.mul( matrix4.fromArray(transformation), matrix4.fromArray( rootnode.transformation ) );

					var normMatrix = matrix3.normalizeMatrix( currentEntity.transform.local  ) ;

					//currentEntity.mesh.boundingBox = new boundingBox();
					//currentEntity.mesh.boundingBox.fitBoxToPoints_( currentMesh.subMeshes[0].vertices, normMatrix );

					scene.addEntity( currentEntity, currentEntity.transform.local, materialCache );

				}
					
				//}
				
				
				
				
				parentEntity.addChild(currentEntity);
				
				
			}
			

			
			
			
			
		} else {
			parentEntity.addChild(currentEntity);
			
		}
		
		
		
		//if(child.name == "Bip001") {
			
			//this.parseSkeleton( child );

		//}
		
		if(assimpNode.children) {
			var children = assimpNode.children;
			
			for(var i = 0; i < children.length; i++) {
				var child = children[i];
				
				this.parseNode(currentAssimpJson, child, currentEntity, scene, materialCache);
			}
		}

		//console.log(this.engine.system.scene);
	}



	buildModels( materialCache ) {
		
		var scene = this.scene;
		//var materialCache = this.materialCache;
		
		var rootEntity = new entity(this.engine);
		rootEntity.name = "root";
		rootEntity.transform.world = matrix4.identity();
		
		//this.engine.system.scene.rootEntity = rootEntity;
		scene.rootEntity = rootEntity;
		
	
		if(materialCache) {

			for(var c = 0; c<materialCache.length; c++) {
				var materialInfo = materialCache[c];
				/*
				var currentMaterial = new material(  );
					
					

				var diffuseTexture = materialInfo.diffuseTexture; //kepler.resources.getTexture( materialInfo.name + "_diffuse");
				
				if(diffuseTexture) {
					var diffuseSampler = new sampler2D();
					
					diffuseSampler.addTexture(diffuseTexture);
					
					//currentMaterial.addTexture(diffuseSampler);
					
					console.log(materialInfo.name + "_diffuse", currentMaterial);
				} else{
					console.log("noo _diffuse", currentMaterial);
					
				}
				
				var normalTexture = kepler.resources.getTexture(materialInfo.name + "_normal");
				
				if(normalTexture) {
					var normalSampler = new sampler2D();
					normalSampler.addTexture(normalTexture);
					//currentMaterial.addNormal(normalSampler);
				}
				
				var roughnessTexture = kepler.resources.getTexture(materialInfo.name + "_normal");
				
				if(roughnessTexture) {
					var roughnessSampler = new sampler2D();
					roughnessSampler.addTexture(roughnessTexture);
					//currentMaterial.addRoughness(roughnessSampler);
				}
				
				var depthTexture = kepler.resources.getTexture(materialInfo.name + "_depth");
				
				if(depthTexture) {
					//var roughnessSampler = new sampler2D(this.engine);
					//roughnessSampler.addTexture(depthTexture);
					//material.addDisplacement(roughnessSampler);
				}
				
				

				currentMaterial.diffuseColor = materialInfo.diffuseColor;
				currentMaterial.roughness = materialInfo.roughness;
				
				
				currentMaterial.alpha = materialInfo.opacity;
				
				//var shadingModelID = this.getShadingIdByEntityName(material.id);

				//material.setShadingModelID(shadingModelID);
				
				//currentMaterial.create();
				
				materialCache[c] = currentMaterial;
				*/
			}
			
			var models = this.models;
			
// matrix4.fromArray( rootnode.transformation );
			
			
		
			for(var c = 0; c<models.length; c++) {
				var currentAssimpJson = models[c];
				var rootnode = currentAssimpJson.rootnode;
				var children = rootnode.children;
			

				
				this.parseNode(currentAssimpJson, rootnode, rootEntity, scene, materialCache);
			}
		}
	}

	parseSkeleton( child ) {

		this.skeleton = this.engine.createObject("skeleton");
		
		this.skeleton.parse(child, this.rootnode);
		this.skeleton.parseAnimation(this.animations[0].channels);
		
		
		
		var bones = this.skeleton.bones;
		
		
		for(var c = 0; c<bones.length; c++) {
			
			var bone = bones[c];
			
			this.skeleton.animate(bone, 0);
			
			
			
			var transform = bone.globalTransformation;
			
			var mesh = this.meshes[1];
			
				var currentEntity = new entity(this.engine);
				
				
				//var diffuseTexture = kepler.resources.getTexture(mesh.material.name + "_diffuse");
				//var diffuseSampler = new sampler2D(this.engine);
				//diffuseSampler.texture = diffuseTexture;

				var material = mesh.material;
				//material.addTexture(diffuseSampler);

				
				mesh.addMaterial(material);

				currentEntity.addMesh(mesh);
				currentEntity.bone = bone;
				currentEntity.transform.world = transform;

				
				bone.entity = currentEntity;
				
				//this.engine.system.scene.addEntity(entity);
			
		}
		
		//this.animate();
		
		
		//console.log(this.skeleton);
	}


	animate( ) {
		var entitys = this.scene.getEntitys();

		for(var c = 0; c<entitys.length; c++) {
			
			var bone = entitys[c].bone;
			if(bone) {
				
				var bone = this.skeleton.animate(bone, floor(asdasd/2));

				entitys[c].transform.world = bone.globalTransformation;
			}
			
		}
		
	}




	getPropertyByName( properties, name, semantic ) {

		for(var c = 0; c<properties.length; c++) {
			var property = properties[c];
			
			if(property.key == name && property.semantic == semantic)
				return property;
		}
		
		return false;
	}
}

export {assimp as default};