define(['scripts/knockout-3.3.0','scripts/ACTComponent.js','scripts/three.min.js'], function(ko, ACTComponent, THREE) {

    function WebGLComponentViewModel(params, element) {
		this.base = new ACTComponent($(element), params);
		this.element = element;
	
		this.width = $(element).width();
		this.height = $(element).height();
		this.camHeight = this.height;
	
		this.camera = new THREE.OrthographicCamera( $(element).width() / - 2, $(element).width() / 2, $(element).height() / 2, $(element).height() / - 2, -500, 1000 );
		//this.camera = new THREE.PerspectiveCamera( 60, this.width / this.height, 1, 1000 );
		this.camera.position.x = 50;
		this.camera.position.y = 50;
		this.camera.position.z = 50;

		this.scene = new THREE.Scene();
		this.scene.add( this.camera );
		
		this.cubes = new THREE.Object3D();
		this.scene.add( this.cubes );
	
		this.renderer = new THREE.WebGLRenderer();
		this.renderer.setPixelRatio( window.devicePixelRatio );
		this.renderer.setClearColor(0xffffff);
		this.renderer.setSize( $(element).width(), $(element).height() );
		$("#webGLContainer").html( this.renderer.domElement );
	
		this.render = function () {
			requestAnimationFrame( this.render );
			this.controls.update();
			
			this.raycaster.setFromCamera( this.mouse, this.camera );
			var intersects = this.raycaster.intersectObjects( this.cubes.children );

			if (this.previousSel!=null) {
				this.previousSel.material.color.set( 0xcecece );
			}
			
			if (intersects.length>0) {
			for ( var i = 0; i < 1/*intersects.length*/; i++ ) {
				this.previousSel = intersects[ i ].object;
				intersects[ i ].object.material.color.set( 0xff0000 );
			}
			}
			
			this.renderer.render(this.scene, this.camera);
		}.bind(this);
		
		this.testX = 0;
		this.testY = 0;
		
		this.controls = new THREE.OrthographicTrackballControls( this.camera, $("#webGLContainer")[0] );
	
		this.raycaster = new THREE.Raycaster();
		this.mouse = new THREE.Vector2();
		this.previousSel = null;

		this.onMouseMove = function ( event ) {

			// calculate mouse position in normalized device coordinates
			// (-1 to +1) for both components

			if ((this.textX==event.clientX) && (this.testY==event.clientY)) {
				return;
			}
			this.testX = event.clientX;
			this.textY = event.clientY;
			
			this.mouse.x = ( event.layerX / this.width ) * 2 - 1;
			this.mouse.y = - ( event.layerY / this.height ) * 2 + 1;	

			
		}.bind(this);

		this.element.addEventListener( 'mousemove', this.onMouseMove, true );

		

		//light = new THREE.AmbientLight( 0xffffff );
		//this.scene.add( light );
		//light = new THREE.DirectionalLight( 0x222222 );
		//light.position.set( 10, 10, 10 );
		//this.scene.add( light );
		light = new THREE.DirectionalLight( 0xffffff );
		light.position.set( 1, 1, 1 );
		this.scene.add( light );

		light = new THREE.DirectionalLight( 0xffffff );
		light.position.set( -1, -1, -1 );
		this.scene.add( light );

		light = new THREE.AmbientLight( 0x222222 );
		this.scene.add( light );
		
		//this.controls = new THREE.OrbitControls( this.camera, this.renderer.domElement );
		//this.controls.damping = 0.2;
		//this.controls.addEventListener( 'change', this.render );

		/*var geometry = new THREE.Geometry();

		geometry.vertices.push(
			new THREE.Vector3( -10,  10, 0 ),
			new THREE.Vector3( -10, -10, 0 ),
			new THREE.Vector3(  10, -10, 0 )
		);

		geometry.faces.push( new THREE.Face3( 0, 1, 2 ) );

		geometry.computeBoundingSphere();*/
		/*var geometry = new THREE.BoxGeometry( 1, 1, 1 );
		var material = new THREE.MeshBasicMaterial( { color: 0xcecece } );
		var cube = new THREE.Mesh( geometry, material );
		this.scene.add( cube );*/

		this.onresize = function () {

				var aspect = this.width / this.height;
				//this.camera.aspect = aspect;
				this.camera.left = -aspect * this.camHeight/2;//this.width / -2;
				this.camera.right = aspect * this.camHeight/2;//this.width / 2;
				this.camera.top = this.camHeight / 2;
				this.camera.bottom = this.camHeight / -2;
				this.camera.updateProjectionMatrix();

				this.renderer.setSize( this.width, this.height );

				this.render();

			}.bind(this);
			
		this.base.onRefresh = function(obj) {
			

			
			
			
			var xMin = 0.;
			var yMin = 0.;
			var zMin = 0.;
			var xMax = 0.;
			var yMax = 0.;
			var zMax = 0.;
			var first = true;
			for (var i=0;i<obj.Bodies.length;i++) {
				var body = obj.Bodies[i];
				var geometry = new THREE.Geometry();
				for (var j=0;j<body.Faces.length;j++) {
					var face = body.Faces[j];
					var off = geometry.vertices.length;
					for (var k=0;k<face.Vertices.length;k++) {
						var v = face.Vertices[k];
						if (first) {
							xMin = v.X;
							xMax = v.X;
							yMin = v.Y;
							yMax = v.Y;
							zMin = v.Z;
							zMax = v.Z;
							first = false;
						}
						else {
							if (v.X>xMax) {
								xMax = v.X;
							}
							if (v.Y>yMax) {
								yMax = v.Y;
							}
							if (v.Z>zMax) {
								zMax = v.Z;
							}
							if (v.X<xMin) {
								xMin = v.X;
							}
							if (v.Y<yMin) {
								yMin = v.Y;
							}
							if (v.Z<zMin) {
								zMin = v.Z;
							}
						}
						geometry.vertices.push(
							new THREE.Vector3( v.X,  v.Y, v.Z )
						);
					}
					for (var k=0;k<face.Facets.length;k++) {
						var f = face.Facets[k];
						geometry.faces.push(
							new THREE.Face3( f.P1+off,  f.P2+off, f.P3+off )
						);
					}
					

				}
				geometry.computeFaceNormals();
				geometry.computeVertexNormals();
				geometry.computeBoundingSphere();
			
				var material = new THREE.MeshLambertMaterial( { color: 0xcecece, shading: THREE.SmoothShading } );//new THREE.MeshBasicMaterial( { color: 0xcecece } );
				var b = new THREE.Mesh( geometry, material );
				this.cubes.add( b );
			}
			console.log("X Min/Max: "+xMin+", "+xMax);
			console.log("Y Min/Max: "+yMin+", "+yMax);
			console.log("Z Min/Max: "+zMin+", "+zMax);
			
			this.camera.position.x = (xMin+xMax)/2;
			this.camera.position.y = (yMin+yMax)/2;
			this.camera.position.z = (zMin+zMax)/2;
			this.camHeight = yMax-yMin;
			
			
			this.controls.update();
			this.onresize();
			
			//window.requestAnimationFrame(this.render);
		}.bind(this);	

		//this.controls.update();
		//this.onresize();
		
		this.resizeFunction = function(height,width) {
			this.width = width;
			this.height = height;
			this.controls.update();
			this.onresize();
		}.bind(this);
		
		params.baseModel.resizeFunctions[params.baseModel.resizeFunctions.length] = this.resizeFunction;

		this.base.initialize();
		params.ready(true);		
    }

	return {
		createViewModel: function(params, componentInfo) {
            return new WebGLComponentViewModel(params, componentInfo.element);
        }
	};

});

