/*
Created by Benedict Wright
*/

/// <reference path="../FDNode.ts" />
/// <reference path="../resources/jquery.d.ts" />
/// <reference path="../debugPrinter.ts" />
/// <reference path="../resources/three.d.ts" />
/// <reference path="../FDGeomObject.ts" />
/// <reference path="../FDHelpers.ts" />
/// <reference path="../FDVisualisation.ts" />
/// <reference path="PCcolumn.ts" />
module FD {
    export class ParallelCoordinatesVisualisation extends FDVisualisation {

        public columns: ParallelCoordinatesColumn[];
        private NodeMeshMap: { [index: string]: FDNode; } = {};
        public left: number;
        public top: number;
        public bottom: number;
        public colWidth: number;

        constructor(debug: Boolean, fluidDiagram: any) {
            super(debug, fluidDiagram);
            this.columns = new Array();
        }


        public visualise() {

            this.backgroundColor = 0xffffff;

            var tmpMat = <any>new THREE.MeshBasicMaterial({ color: 0x5555cc });
            //create the columns
            var cNames = this.nodes[0].getData();
            var colNum = 0;

            for (var c in cNames) {
                this.columns[colNum] = new ParallelCoordinatesColumn(c);
                colNum++;

            }
            
            this.colWidth = this.fluidDiagrams.width / colNum;
            //add horizontal lines to the bg of the scene for each column
            //this.left = (-this.fluidDiagrams.width / 2) + this.colWidth / 2;
            //this.bottom = -(this.fluidDiagrams.height / 2) + 60;
            //this.top = (this.fluidDiagrams.height / 2) - 60;
            this.left = this.colWidth/2;
            this.bottom = 60;
            this.top = this.fluidDiagrams.height-70;
    
            var filterMat = <any>new THREE.MeshBasicMaterial({ transparent: true, color: 0x000000 });
            var sortMat = <any>new THREE.MeshBasicMaterial({ transparent: true, color: 0x000000 });
            //sortMat.side = THREE.DoubleSide;

 //fill columns with data
            var nodeCount=0;
            for (var node in this.nodes) {
                var currentNode = <FDNode>this.nodes[node];
                //currentNode.getNodeSceneGraph().translateX(this.left);

                this.NodeMeshMap[currentNode.getUniqueId()] = currentNode;
                var index=0;
                var data = currentNode.getData();
                for (var d in data) {
                    var val = parseFloat(data[d]);
                    this.columns[index].addEntrie(currentNode.getUniqueId(), val);
                    index++;
                }
            nodeCount++;
            }
            debugPrinter.print("nodeCount: "+ nodeCount,true);

            var i = 0;
            for (var c in this.columns) {
                var linegeom = new THREE.Geometry();
                linegeom.vertices.push(new THREE.Vector3(0, this.top + 25, 0));
                linegeom.vertices.push(new THREE.Vector3(0, this.bottom - 25, 0));
                var line = new THREE.Line(linegeom, new THREE.LineBasicMaterial({ color: 0x111111 }));
//----------------                this.fluidDiagrams.addSceneObject(line);
                this.columns[c].setLine(line);


                //add lable to column
                var canvas1 = <any>document.createElement('canvas');
                canvas1.height = 20;
                canvas1.width = 100;
                var context1 = canvas1.getContext('2d');
                context1.font = "Bold 11px Arial";
                context1.fillStyle = "rgba(0,0,0,1)";
                context1.textAlign = 'center';
                context1.fillText(this.columns[c].cName, 50, 10);
                // canvas contents will be used for a texture
                var texture1 = new THREE.Texture(canvas1)
                texture1.needsUpdate = true;
                var textMat = new THREE.MeshBasicMaterial({ map: texture1 });
                textMat.transparent = true;
                textMat.side = THREE.DoubleSide;
                var textPlane = new THREE.PlaneGeometry(100, 20);
                var textMesh = new THREE.Mesh(textPlane, textMat);
                //textMesh.rotation.z = 90 * Math.PI / 180;
                textMesh.position = new THREE.Vector3(0, this.top + 50, 0);
//----------------                this.fluidDiagrams.addSceneObject(textMesh);
                this.columns[c].setLabel(textMesh);

                //create filter controls
                var tri = this.createTriangle();
                var triMesh = new THREE.Mesh(tri, filterMat);
                triMesh.position = new THREE.Vector3(0, this.top + 15, 0);
                triMesh.scale = new THREE.Vector3(7, 7, 1);
                triMesh.rotation.z = Math.PI;
                this.columns[c].setHighHandle(triMesh);
                this.columns[c].setMaxY(this.top + 15);

                var tri = this.createTriangle();
                var triMesh = new THREE.Mesh(tri, filterMat);
                triMesh.position = new THREE.Vector3(0, this.bottom - 15, 0);
                triMesh.scale = new THREE.Vector3(7, 7, 1);
                this.columns[c].setLowHandle(triMesh);
                this.columns[c].setMinY(this.bottom - 15);


                //create sort control
                var square = this.createFlipIcon();
                var squareMesh = new THREE.Mesh(square, sortMat);
                squareMesh.position = new THREE.Vector3(17, this.top + 22, 0);
                squareMesh.scale = new THREE.Vector3(16, 16, 1);
                this.columns[c].setSortHandle(squareMesh);


                //add column to scene
                this.columns[c].getColumnSceneGraph().position =new THREE.Vector3(this.left + i * this.colWidth, 0,0);
                this.fluidDiagrams.addSceneObject(this.columns[c].getColumnSceneGraph());




                //add min/max Lables
                var canvas1 = <any>document.createElement('canvas');
                canvas1.height = 20;
                canvas1.width = 40;
                var context1 = canvas1.getContext('2d');
                context1.font = "Bold 11px Arial";
                context1.textAlign = 'center';
                context1.fillStyle = "rgba(0,0,0,1)";
                context1.fillText(this.columns[c].getMax(), 20, 10);
                // canvas contents will be used for a texture
                var texture1 = new THREE.Texture(canvas1)
                texture1.needsUpdate = true;
                var textMat = new THREE.MeshBasicMaterial({ map: texture1 });
                textMat.transparent = true;
                textMat.side = THREE.DoubleSide;
                var textPlane = new THREE.PlaneGeometry(40, 20);
                var textMesh = new THREE.Mesh(textPlane, textMat);
                //textMesh.rotation.z = 90 * Math.PI / 180;
                textMesh.position = new THREE.Vector3(0, this.top + 34, 0);
                //this.fluidDiagrams.addSceneObject(textMesh);
                this.columns[c].setTopLable(textMesh);


                //add min/max Lables
                var canvas1 = <any>document.createElement('canvas');
                canvas1.height = 20;
                canvas1.width = 40;
                var context1 = canvas1.getContext('2d');
                context1.font = "Bold 11px Arial";
                context1.textAlign = 'center';
                context1.fillStyle = "rgba(0,0,0,1)";
                context1.fillText(this.columns[c].getMin(), 20, 10);
                // canvas contents will be used for a texture
                var texture1 = new THREE.Texture(canvas1)
                texture1.needsUpdate = true;
                var textMat = new THREE.MeshBasicMaterial({ map: texture1 });
                textMat.transparent = true;
                textMat.side = THREE.DoubleSide;
                var textPlane = new THREE.PlaneGeometry(40, 20);
                var textMesh = new THREE.Mesh(textPlane, textMat);
                //textMesh.rotation.z = 90 * Math.PI / 180;
                textMesh.position = new THREE.Vector3(0, this.bottom - 45, 0);

                //this.fluidDiagrams.addSceneObject(textMesh);
                this.columns[c].setBottomLable(textMesh);
                //normalize values to be between top and bottom for each column serperate;
                this.columns[c].normalizeTo(this.top - this.bottom);

                i++;
            }

            this.createLines();

        }

        public createLines() {

            for (var n in this.nodes) {
                var linegeom = new THREE.Geometry();
                linegeom.dynamic=true;
                linegeom.verticesNeedUpdate=true;
                var colNum = 0;
                for (var col in this.columns) {
                    var x = this.columns[col].getColumnSceneGraph().position.x;
                    var y = this.columns[col].entries[this.nodes[n].getUniqueId()]+this.bottom
                    var z = 0;
                    var vert = new THREE.Vector3(x,y,z);
                    this.columns[col].vertices.push(vert);
                    linegeom.vertices.push(vert);
                    //debugPrinter.print("y="+this.columns[col].entries[this.nodes[n].getUniqueId()],true);
                    colNum++;
                }
                linegeom.dynamic=true;
                linegeom.verticesNeedUpdate=true;
                var line = new THREE.Line(linegeom, new THREE.LineBasicMaterial({ color: 0x0000ff }));
                
                this.nodes[n].addGeometry(line);
            }

        }


        private createUnitLines() {

        }


        public getNodeMeshMap() {
            return this.NodeMeshMap;
        }


        private createTriangle(): THREE.Geometry {
            var triangleGeometry = new THREE.Geometry();
            triangleGeometry.vertices.push(new THREE.Vector3(0.0, 1.0, 0.0));
            triangleGeometry.vertices.push(new THREE.Vector3(-1.0, -1.0, 0.0));
            triangleGeometry.vertices.push(new THREE.Vector3(1.0, -1.0, 0.0));
            triangleGeometry.faces.push(new THREE.Face3(0, 1, 2));
            triangleGeometry.computeBoundingBox();
            triangleGeometry.computeFaceNormals();
            return triangleGeometry;
        }

        private createFlipIcon(): THREE.Geometry {
            var flipIcon = new THREE.Geometry();



            flipIcon.vertices.push(new THREE.Vector3(0.0, 0.2, 0.0));
            flipIcon.vertices.push(new THREE.Vector3(-0.4, -0.4, 0.0));
            flipIcon.vertices.push(new THREE.Vector3(0.4, -0.4, 0.0));



            flipIcon.vertices.push(new THREE.Vector3(-0.4, -0.5, 0.0));
            flipIcon.vertices.push(new THREE.Vector3(0.0, -1.1, 0.0));
            flipIcon.vertices.push(new THREE.Vector3(0.4, -0.5, 0.0));


            flipIcon.faces.push(new THREE.Face3(0, 1, 2));
            flipIcon.faces.push(new THREE.Face3(3, 4, 5));

            flipIcon.computeBoundingBox();
            flipIcon.computeFaceNormals();
            return flipIcon;
        }
    }
}
