/* ==================================================
 * Author: Sebastien CATHALAN
 * Web: www.apliko.fr
 * 
 * This file is used to demonstrate an industry's
 * implementation of the WebGL.
 * It is JUST a demo and nothing else!
 *
 * -----> DO NOT use it in production <-----
 *
 * ================================================== */
"use strict";
var js3dDemoInstance;
function js3dDemo () {
	js3dDemoInstance = this;
	// Colours table
	// We can have as many tables as we want, which contain an array of allowed colours
	// colour object:
	//		hex  : Hexadecimal colour value (eg: FFFFFF)
	//		pant : Pantone code name
	//		name : Literal English colour name
	//		cn   : Chinese colour name
	//		code : Can be used to store any other data
	this.colors = {};
	this.colors.classic = [{"hex":"000000","code":"02","pant":"Pantone Black C","cn":"\u9ed1\u8272","name":"Black"},{"hex":"FFFFFF","code":"020","pant":"Pantone 000C","cn":"\u767d\u8272","name":"White"},{"hex":"F68121","code":"01","pant":"Pantone 138c","cn":"\u91d1\u9ec4\u8272","name":"Gold"},{"hex":"00612C","code":"03","pant":"Pantone 350c","cn":"\u58a8\u7eff\u8272","name":"Bottle Green"},{"hex":"990000","code":"04","pant":"Pantone 222c","cn":"\u9152\u7ea2\u8272","name":"Burgundy"},{"hex":"663300","code":"05","pant":"Pantone 439c","cn":"\u5de7\u514b\u529b\u8272","name":"Brown"},{"hex":"FFF4D6","code":"06","pant":"Pantone 7499c","cn":"\u7c73\u767d\u8272","name":"Cream"},{"hex":"2E8C40","code":"07","pant":"Pantone 362c","cn":"\u7fe0\u7eff\u8272","name":"Emerald Green"},{"hex":"6A757B","code":"08","pant":"Pantone 430c","cn":"\u6df1\u7070\u8272","name":"Grey"},{"hex":"FF00FF","code":"09","pant":"Pantone 227c","cn":"\u6df1\u6885\u7ea2","name":"Hot Pink"},{"hex":"008C7F","code":"010","pant":"Pantone 3295c","cn":"\u8349\u7eff\u8272","name":"Jade Green"},{"hex":"00CC33","code":"011","pant":"Pantone 361c","cn":"\u8367\u5149\u7eff","name":"Lime"},{"hex":"981934","code":"012","pant":"Pantone 208c","cn":"\u67a3\u7ea2\u8272","name":"Maroon"},{"hex":"000066","code":"013","pant":"Pantone 2767c","cn":"\u5b9d\u84dd\u8272","name":"Navy Blue"},{"hex":"F25822","code":"014","pant":"Pantone 021c","cn":"\u6a59\u8272","name":"Orange"},{"hex":"94C6E1","code":"015","pant":"Pantone 276c","cn":"\u7c89\u84dd\u8272","name":"Powder Blue"},{"hex":"712E75","code":"016","pant":"Pantone 259c","cn":"\u7d2b\u8272","name":"Purple"},{"hex":"ED1B24","code":"017","pant":"Pantone 193c","cn":"\u7ea2\u8272","name":"Red"},{"hex":"0F75BD","code":"018","pant":"Pantone 288c","cn":"\u5f69\u84dd\u8272","name":"Royal Blue"},{"hex":"56C9F5","code":"019","pant":"Pantone 284c","cn":"\u5929\u84dd\u8272","name":"Sky Blue"},{"hex":"FBCB05","code":"021","pant":"Pantone 136c","cn":"\u91d1\u9ec4\u8272","name":"Amber Yellow"},{"hex":"FEF200","code":"022","pant":"Pantone 115c","cn":"\u86cb\u9ec4\u8272","name":"Canary Yellow"},{"hex":"F8BFC6","code":"023","pant":"Pantone 495c","cn":"\u7c89\u7ea2\u8272","name":"Light Pink"},{"hex":"D1BEDE","code":"024","pant":"Pantone 514c","cn":"\u7c89\u7d2b\u8272","name":"Lilac"},{"hex":"00A0DD","code":"025","pant":"Pantone 312c","cn":"\u6e56\u84dd\u8272","name":"Cyan"},{"hex":"006633","code":"026","pant":"Pantone 349","cn":"WS \u6df1\u7fe0\u7effG1","name":"WS Emerald Green"},{"hex":"9933CC","code":"027","pant":"Pantone 266","cn":"WS \u6d45\u7d2b\u8272G1","name":"WS Purple"},{"hex":"F5EEB7","code":"","pant":"Pantone 7499","cn":"\u9ec4\u8910\u8272","name":"Khaki"},{"hex":"CCCCCC","code":"","pant":"Pantone 441","cn":"\u82b1\u7070\u8272","name":"Marl Grey"}];
	this.colors.socks = [{"hex":"F68121","code":"C1935","pant":"","cn":"\u91d1\u9ec4\u8272","name":"Gold"},{"hex":"000000","code":"Black","pant":"","cn":"\u9ed1\u8272","name":"Black"},{"hex":"00612C","code":"E915","pant":"","cn":"\u58a8\u7eff\u8272","name":"Bottle Green"},{"hex":"990000","code":"F2111","pant":"","cn":"\u9152\u7ea2\u8272","name":"Burgundy"},{"hex":"663300","code":"Brown","pant":"","cn":"\u68d5\u8272","name":"Brown"},{"hex":"FFF4D6","code":"Cream","pant":"","cn":"\u7c73\u767d\u8272","name":"Cream"},{"hex":"2E8C40","code":"E1904","pant":"","cn":"\u7fe0\u7eff\u8272","name":"Emerald Green"},{"hex":"6A757B","code":"A1195","pant":"","cn":"\u6df1\u7070\u8272","name":"Grey"},{"hex":"FF00FF","code":"216","pant":"","cn":"\u6df1\u6885\u7ea2","name":"Hot Pink"},{"hex":"008C7F","code":"E66","pant":"","cn":"\u8349\u7eff\u8272","name":"Jade Green"},{"hex":"2E8C40","code":"E298","pant":"","cn":"\u8367\u5149\u7eff","name":"Lime"},{"hex":"981934","code":"E-2111","pant":"","cn":"\u67a3\u7ea2\u8272","name":"Maroon"},{"hex":"000066","code":"531","pant":"","cn":"\u5b9d\u84dd\u8272","name":"Navy Blue"},{"hex":"F25822","code":"840","pant":"","cn":"\u6a59\u8272","name":"Orange"},{"hex":"94C6E1","code":"J3924","pant":"","cn":"\u7c89\u84dd\u8272","name":"Powder Blue"},{"hex":"712E75","code":"2685U","pant":"","cn":"\u7d2b\u8272","name":"Purple"},{"hex":"ED1B24","code":"F499","pant":"","cn":"\u7ea2\u8272","name":"Red"},{"hex":"0F75BD","code":"J2594","pant":"","cn":"\u5f69\u84dd\u8272","name":"Royal Blue"},{"hex":"56C9F5","code":"J2045","pant":"","cn":"\u5929\u84dd\u8272","name":"Sky Blue"},{"hex":"FFFFFF","code":"White","pant":"","cn":"\u767d\u8272","name":"White"},{"hex":"FBCB05","code":"C1935C","pant":"","cn":"\u91d1\u9ec4\u8272","name":"Amber Yellow"},{"hex":"FEF200","code":"406","pant":"","cn":"\u86cb\u9ec4\u8272","name":"Canary Yellow"},{"hex":"F8BFC6","code":"F4891","pant":"","cn":"\u7c89\u7ea2\u8272","name":"Light Pink"},{"hex":"D1BEDE","code":"Lilac","pant":"","cn":"\u7c89\u7d2b\u8272","name":"Lilac"},{"hex":"00A0DD","code":"J-4502","pant":"","cn":"\u6e56\u84dd\u8272","name":"Cyan"}];
	this.colors.embroidery = [{"hex":"CCCCCC","code":"3376","pant":"","cn":"\u6d45\u7070\u8272","name":"Light Grey"},{"hex":"2E8C40","code":"3204","pant":"","cn":"\u7fe0\u7eff\u8272","name":"Emerald Green"},{"hex":"6A757B","code":"3340","pant":"","cn":"\u6df1\u7070\u8272","name":"Grey"},{"hex":"FF00FF","code":"2241","pant":"","cn":"\u6df1\u6885\u7ea2","name":"Hot Pink "},{"hex":"FEF200","code":"2378","pant":"","cn":"\u86cb\u9ec4\u8272","name":"Canary Yellow"},{"hex":"FBCB05","code":"2716","pant":"","cn":"\u91d1\u9ec4\u8272","name":"Amber Yellow"},{"hex":"000066","code":"3647","pant":"","cn":"\u5b9d\u84dd\u8272","name":"Navy Blue"},{"hex":"981934","code":"2346","pant":"","cn":"\u67a3\u7ea2\u8272","name":"Maroon"},{"hex":"FFF4D6","code":"2351","pant":"","cn":"\u7c73\u767d\u8272","name":"Cream"},{"hex":"00612C","code":"3024","pant":"","cn":"\u58a8\u7eff\u8272","name":"Bottle Green"},{"hex":"712E75","code":"3827","pant":"","cn":"\u7d2b\u8272","name":"Purple"},{"hex":"F25822","code":"2451","pant":"","cn":"\u6a59\u8272","name":"Orange"},{"hex":"FFFFFF","code":"2168","pant":"","cn":"\u767d\u8272","name":"White"},{"hex":"000000","code":"2170","pant":"","cn":"\u9ed1\u8272","name":"Black"},{"hex":"ED1B24","code":"2296","pant":"","cn":"\u7ea2\u8272","name":"Red"},{"hex":"F68121","code":"2387","pant":"","cn":"\u91d1\u9ec4\u8272","name":"Gold"},{"hex":"000099","code":"3686","pant":"","cn":"\u6d45\u5f69\u84dd","name":"Light Royal Blue"},{"hex":"56C9F5","code":"3635","pant":"","cn":"\u5929\u84dd\u8272","name":"Sky Blue"},{"hex":"0F75BD","code":"3704","pant":"","cn":"\u5f69\u84dd\u8272","name":"Royal Blue"},{"hex":"663300","code":"2783","pant":"","cn":"\u5de7\u514b\u529b\u8272","name":"Brown "},{"hex":"F8BFC6","code":"2262","pant":"","cn":"\u7c89\u7ea2\u8272","name":"Light Pink"},{"hex":"00A0DD","code":"3591","pant":"","cn":"\u6e56\u84dd\u8272","name":"Cyan"}];
	// Layers list with pre-setting
	//   - color : Property used to define the initial colour at start-up
	//   - fixed : true/false. If set to true, the layer is not editable and the file will stay untouched
	//   - coltable : Select the colours table. Eg: an embroidery layer don't have as many colours as a printed layer.
	this.imgList = [];
	this.imgList.push({img:null, fixed:false, coltable:'classic', color:'FFFFFF', pant:'Pantone 000C', src:'/public/js/project/js3d/textures/1024/layer1.png'});
	this.imgList.push({img:null, fixed:false, coltable:'classic', color:'94C6E1', pant:'Pantone 276c', src:'/public/js/project/js3d/textures/1024/layer2.png'});
	this.imgList.push({img:null, fixed:false, coltable:'classic', color:'000000', pant:'Pantone Black C', src:'/public/js/project/js3d/textures/1024/layer3.png'});
	this.imgList.push({img:null, fixed:false, coltable:'classic', color:'ED1B24', pant:'Pantone 193c', src:'/public/js/project/js3d/textures/1024/layer4.png'});
	this.imgList.push({img:null, fixed:true, src:'/public/js/project/js3d/textures/1024/fixed01.png'});
	this.imgLoaded = false;
	this.textureCanvas = null;	// The canvas that will store the final texture (merged layers)
	// ----------------------------------------------------------
	// hexToRGB:
	// ----------------------------------------------------------
	// Return an object with the properties R, G and B in Integer
	this.hexToRGB = function(hex) {
		if (hex == '000000') hex = '292929'; // We don't want the darkest black
		var long = parseInt(hex.replace(/^#/, ""), 16);
		return {
			R: (long >>> 16) & 0xff,
			G: (long >>> 8) & 0xff,
			B: long & 0xff
		};
	}
	// ----------------------------------------------------------
	// getOriginalPixels:
	// ----------------------------------------------------------
	// Return a canvas containing a copy of an original layer
	this.getOriginalPixels = function(img)
	{
		var canvas = document.createElement("canvas");
		var ctx = canvas.getContext("2d");
		canvas.width = img.width;
		canvas.height = img.height;
		ctx.drawImage(img, 0, 0, img.naturalWidth, img.naturalHeight, 0, 0, img.width, img.height);
		return canvas;
	}
	
	
	
	
	// ----------------------------------------------------------
	// applyLayer:
	// ----------------------------------------------------------
	// Colourize and merge a layer to the newly created texture
	this.applyLayer = function(img, newcolor) {
		var colorRGB = this.hexToRGB(newcolor+"");
		
		var c = document.createElement('canvas');
		c.width = img.width;
		c.height = img.height;
		
		var ctx = c.getContext('2d');
		ctx.drawImage(img, 0, 0);
/*
		// Slower solution : pixel by pixel
			var imgData = ctx.getImageData(0, 0, c.width, c.height );
			
			// Looping through all the pixels
			for (var i=0; i < imgData.data.length; i += 4) {
				
				// We don't colourize the transparent pixel (alpha=0)
				// Colourizing them all will give the same result but it will hurt by a lot the performances
				// FYI :
				// 		A pixel has 4 Bytes
				// 		BYTE#0 = Red
				// 		BYTE#1 = Green
				// 		BYTE#2 = Blue
				// 		BYTE#3 = Alpha
				if(imgData.data[i + 3] > 0) { 
					imgData.data[i] = colorRGB.R;
					imgData.data[i + 1] = colorRGB.G;
					imgData.data[i + 2] = colorRGB.B;
				}
			}
			ctx.putImageData(imgData,0,0);
*/
		
		// Faster solution : use Canvas 2D API function
			ctx.globalCompositeOperation = 'source-in';
			ctx.fillStyle = '#' + newcolor;
			ctx.fillRect(0, 0, c.width, c.height);
		this.textureCanvas.drawImg(c,0,0);	
		c.remove();
	}
	
	
	
	// ----------------------------------------------------------
	// doLoadImage:
	// ----------------------------------------------------------
	// Loop through the array imgList to load the images one by one.
	// When the images are all loaded, it calls drawTexture() to apply the texture to the 3D object.
	this.doLoadImage = function() {
		var imgFound = false;
		// Load the images one by one
		for(var x = 0; x < this.imgList.length; x++){
			if (this.imgList[x]['img']==null) {
				imgFound = true;
				this.imgList[x]['img'] = new Image();
				this.imgList[x]['img'].onload = function() { // Once an image is loaded we load the next one in the list
					js3dDemoInstance.doLoadImage(); // Load the next image
				}
				this.imgList[x]['img'].src = this.imgList[x]['src'];
				break;
			}
		}
		
		// The images have all been loaded, we can apply the texture to the 3D object
		if (!imgFound) {
			this.imgLoaded = true;
			this.drawTexture();
		}
	}
 
 
 
	// ----------------------------------------------------------
	// createColoursGrid:
	// ----------------------------------------------------------
	// Creates the colours selector UI and add it to the DOM
	this.createColoursGrid = function() {
		
		// Clean-up the DOM
		$(".toolbox .partColors .subList").empty(); 
		
		for(var x = 0; x < this.imgList.length; x++) {
			
			// Some images are "FIXED", that mean they are not allowed to be colorized (eg: logo, decoration,...) 
			if (this.imgList[x]['fixed']==false) {
				
				var col = $('<div class="colorbox"><div class="infocolor">'+this.imgList[x]['pant']+'</div></div>');
				col.data("layer",this.imgList[x])
				   .css('background-color', '#'+this.imgList[x]['color'])
				   .on('click', function() {
				   	
						// If the colour selector UI is already open for the same layer we don't create it
						if ( $('#colorSelector').is(":visible") && ($('#colorSelector').data('selectedLayer') === this) ) {
							$('#colorSelector').data('selectedLayer',null).hide();
						
						// The colour selector is not open yet, we set it with the correct color list because each 3D object can use a different list
						} else {
							$('#colorSelector').data('selectedLayer', this);
							// We take from the layer the colors list to be used
							var colorTable = $(this).data('layer')['coltable'];
							
							if ( $('#colorSelector').data('colorscheme') != colorTable ) { // Generate the colour selector UI
								$('#colorSelector').data('colorscheme', colorTable);
								$('#colorSelector .colorsList').empty();
								
								for(var y = 0; y < js3dDemoInstance.colors[colorTable].length; y++) {
									var colb = $('<div class="colorbox"></div>');
									colb.data('color', js3dDemoInstance.colors[colorTable][y])
									    .css('background-color', '#'+js3dDemoInstance.colors[colorTable][y]['hex'])
										.on('click', function() {									
												var selectedColor = $(this).data('color');
												var selectedBoxLayer = $("#colorSelector").data('selectedLayer');
												
												var selectedLayer = $(selectedBoxLayer).data('layer');
												selectedLayer['color'] = selectedColor['hex'];
												
												$(selectedBoxLayer).find('.infocolor').html(selectedColor['pant']);
												$(selectedBoxLayer).css('background-color', '#'+selectedColor['hex']);
												$("#colorSelector").hide();
												
												js3dDemoInstance.drawTexture();
										});
									
									$('#colorSelector .colorsList').append(colb);
								}
							}
							
							var pos = $(this).offset();
							pos.top = pos.top + $(this).height() + 3;
							pos.left = pos.left + $(this).width() - ($(this).width()/2);
							$('#colorSelector').css({top: pos.top, left: pos.left}).show();
						}
					});
					
					$(".toolbox .partColors .subList").append(col);
			}
		}
	} // END createColoursGrid()
	// ----------------------------------------------------------
	// drawTexture:
	// ----------------------------------------------------------
	// Merge all the layers with the selected colours to create a texture suitable for the 3D object
	this.drawTexture = function() {
		
		// Makes sure that the layers are ready (fully loaded) before using them
		if (this.imgLoaded && (this.textureCanvas!=null)) {
			var context = this.textureCanvas.getContext('2d');
			context.clearRect(0, 0, this.textureCanvas.width, this.textureCanvas.height);
		
			// Go through all the layers
			for(var x = 0; x < this.imgList.length; x++) {
				
				// if it's a fixed layer we merge as is
				if (this.imgList[x]['fixed']) {
					this.textureCanvas.drawImg(this.imgList[x]['img']);
					
				// The normal layer as to be colorized
				} else {
					this.applyLayer(this.imgList[x]['img'], this.imgList[x]['color']);
				}
			}
			
		}
	}
	// ----------------------------------------------------------
	// Constructor
	// 1. Initialise the 3D engine
	// 2. Load the 3D objects
	// 3. Load the Layers images
	// ----------------------------------------------------------
	if (BABYLON.Engine.isSupported()) {
		// Load the layers
			this.doLoadImage();
		// Add the buttons to the DOM (the buttons to change the layer's colour)
			this.createColoursGrid();
		
		
		// Babylon Initialisation
			var canvas = document.getElementById("renderCanvas");
			var engine = new BABYLON.Engine(canvas, true);
		// Add a function to draw the texture
			BABYLON.DynamicTexture.prototype.drawImg = function (img) {
				var size = this.getSize();
				this._context.drawImage(img, 0, 0);
				this.update(true);
			};
		// Request Babylon to load the 3D scene containing our 3D object as a json file
			BABYLON.SceneLoader.Load("", "../public/js/project/js3d/rugby_shirt_blank1.babylon.json", engine, function (newScene) {
		// Wait for textures and shaders to be ready
				newScene.executeWhenReady(function () {
		// Set the backside (the inside of our object to also display the texture)
					newScene.materials.forEach(function(entry) {
						entry.backFaceCulling = false;
					});
					console.log(newScene);
					
		// The texture will be easily accessible with the "textureCanvas" variable
					js3dDemoInstance.textureCanvas = new BABYLON.DynamicTexture("dynamictexture", 1024, newScene, true);
		// Go through all the object in the scene to attach the texture
		// and set some setting to control the surface of our texture (eg: the way the light will interact with the texture)
					newScene.meshes.forEach(function(entry) {
						entry.material.diffuseTexture = js3dDemoInstance.textureCanvas;
						entry.material.specularColor = {r:0.1, b:0.1, g:0.1}; 
						entry.material.diffuseColor = {r:1, b:1, g:1}; 					
						entry.material.backFaceCulling = false;
						entry.material.diffuseTexture.hasAlpha = true;
					});
					js3dDemoInstance.drawTexture();
		// Create a Rotating camera (that will turn around a pivot point)
					var camera = new BABYLON.ArcRotateCamera("Camera", 0, 1.5, 7, new BABYLON.Vector3(0, 0, 0), newScene);
					camera.wheelPrecision = 20;
					
		// Define the camera as the active (as if we were seeing through it)
					newScene.activeCamera = camera;
		// Attach the mouse and keyboard to the camera
					newScene.activeCamera.attachControl(canvas, false);
		// Create a hemispheric light
					var light = new BABYLON.HemisphericLight("Omni0", new BABYLON.Vector3(0, 1, 0), newScene);
		// Transparent scene background
					// newScene.autoClear = false;
					//newScene.clearColor = new BABYLON.Color3(250, 248, 245);
					newScene.clearColor = new BABYLON.Color4(0,0,0,0.0000000000000001); 
					
					
		// Everything has been set up correctly.
		// Makes Babylon loop to continuously render the scene
					engine.runRenderLoop(function() {
						newScene.render();
					});
				});
		// Loading progression event
			}, function (progress) {
				// Add a visual feedback about the loading
			});
	} // END - Constructor
}