/// <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="BarChartColumn.ts" />
var __extends = this.__extends || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    __.prototype = b.prototype;
    d.prototype = new __();
};
var FD;
(function (FD) {
    var BarChartVisualisation = (function (_super) {
        __extends(BarChartVisualisation, _super);
        function BarChartVisualisation(debug, fluidDiagram) {
            _super.call(this, debug, fluidDiagram);
            this.NodeMeshMap = {};
            this.colorArray = [
                [0x8293E3, 0x93E2D5, 0x89E894, 0xBED661, 0x78D5E3, 0x7AF5F5, 0xDCCEE4],
                [0xF4E790, 0xB5D045, 0xFB8335, 0x389090, 0xCAFFCC, 0x81C0C5, 0xE0C7A8],
                [0xffff00, 0xff6600, 0xff0000, 0xff33ff, 0x8800cc, 0x00cc00, 0x0055ff],
                [0xC5EAF8, 0x8AD5F0, 0x50C0E9, 0x2CB1E1, 0x1DA9DA, 0x0FA1D3, 0x0099CC],
                [0xE2F0B6, 0xC5E26D, 0xA8D324, 0x92C500, 0x83B600, 0x75A800, 0x669900],
                [0xFFECC0, 0xFFD980, 0xFFc641, 0xFFB61C, 0xFFA713, 0xFF9909, 0xFF8A00],
                [0xFFCACA, 0xFF9494, 0xFF5F5F, 0xF83A3A, 0xE92727, 0xDB1313, 0xCC0000]
            ];
            this.title = "title";
            this.leftMargin = 100;
            this.rightMargin = 0;
            this.topMargin = 0;
            this.Xtitle = "X title";
            this.Ytitle = "Y title";
            this.titlePopUP = "Left click to change title";
            this.XtitlePopUP = "Left click to change x-title";
            this.YtitlePopUP = "Left click to change y-title";
            this.visualisationToogle = false;
            this.separationMark = ".";
            this.floatSeperationMark = ",";
            this.blocks = [];
            this.normalizeMe = 0;
        }
        BarChartVisualisation.prototype.visualise = function () {
            this.backgroundColor = 0xE3E3E3;

            var tmpMat = new THREE.MeshBasicMaterial({ color: 0x5555cc });

            //create the columns
            var cNames = this.nodes[0].getData();
            this.blockCount = 0;

            for (var c in cNames) {
                this.blocks[this.blockCount] = new FD.BarChartBlock(c);
                this.blockCount++;
            }

            this.barCnt = this.findValToNormalize();
            this.calcSpace();
            this.createBars();
            this.update();
        };

        BarChartVisualisation.prototype.createBars = function () {
            for (var node in this.nodes) {
                var currentNode = this.nodes[node];

                //var textMouseHoover = currentNode.getUniqueId();
                var data = currentNode.getData();

                var barNum = 0;
                for (var d in data) {
                    var val = parseFloat(data[d]);
                    var hooverText = this.blocks[barNum].cName;
                    var actColour = this.colorArray[0][barNum % this.colorArray[0].length];
                    this.blocks[barNum].addEntry(val, actColour, hooverText, currentNode.getUniqueId());

                    //shadow
                    this.blocks[barNum].addShadowEntry(val, 0x000000, "shadow", currentNode.getUniqueId());

                    //overshadow
                    this.blocks[barNum].addOverShadowEntry(val, actColour, hooverText, currentNode.getUniqueId());

                    barNum++;
                }
            }
        };

        BarChartVisualisation.prototype.drawBars = function () {
            this.cubeWidth = (this.right - this.left) / this.barCnt;
            var lenghtEntries = this.blocks[0].entries.length;
            var blockOffset = 0;
            var name;

            for (var entry = 0; entry < lenghtEntries; entry++) {
                var labelMouseHoover = this.blocks[0].entries[entry].name;
                var offset = 0;
                for (var block in this.blocks) {
                    name = this.blocks[block].entries[entry].name;
                    var val = this.blocks[block].entries[entry].height;
                    var hooverText = this.blocks[block].entries[entry].hooverText + " : " + this.insertDelemeters(val);

                    val = val / this.normalizeMe * this.maxHeight;

                    var color = this.blocks[block].entries[entry].color;

                    //var hooverText = this.blocks[block].entries[entry].hooverText;
                    labelMouseHoover = labelMouseHoover.concat("\n" + hooverText);

                    var x = this.left + this.cubeWidth + blockOffset * this.cubeWidth + entry * this.cubeWidth;

                    //undershadow
                    //bar
                    var cube = new THREE.Mesh(new THREE.CubeGeometry(this.cubeWidth, val, 0), new THREE.MeshBasicMaterial({ color: color }));
                    cube.position.y = this.bottom + val / 2;
                    cube.position.x = x;
                    cube.position.z = 0;
                    cube.name = hooverText;

                    this.blocks[block].addID(entry, cube.id);
                    this.nodes[block].addGeometry(cube);

                    //Hover effect
                    //shadow black border
                    var shadow = new THREE.Mesh(new THREE.CubeGeometry(this.cubeWidth, val, 0), new THREE.MeshBasicMaterial({ color: 0x000000 }));
                    shadow.position.y = this.bottom + val / 2;
                    shadow.position.x = x;
                    shadow.position.z = 0.5;
                    shadow.name = hooverText;
                    shadow.visible = false;

                    this.blocks[block].addShadowID(entry, shadow.id);
                    this.nodes[block].addGeometry(shadow);

                    //overshadow
                    var overshadow = new THREE.Mesh(new THREE.CubeGeometry(this.cubeWidth - 4, val - 4, 0), new THREE.MeshBasicMaterial({ color: color }));
                    overshadow.position.y = this.bottom + val / 2;
                    overshadow.position.x = x;
                    overshadow.position.z = 1;
                    overshadow.name = hooverText;
                    overshadow.visible = false;

                    this.blocks[block].addOverShadowID(entry, overshadow.id);
                    this.nodes[block].addGeometry(overshadow);

                    blockOffset++;
                    offset++;
                }

                this.addLabel(this.left - 64 + entry * (offset + 1) * this.cubeWidth + (offset + 1) / 2 * this.cubeWidth, this.bottom - 40, name, -25, labelMouseHoover);
                //this.addLabel(this.left + this.cubeWidth +(blockOffset/2) * this.cubeWidth + entry * this.cubeWidth, this.bottom - 60, name, -25, labelMouseHoover);
            }
        };

        BarChartVisualisation.prototype.createNiceTickMarks = function (max) {
            var min = 0;
            var ntick = 10;

            //var nfrac:number;
            var d;
            var graphmin;
            var graphmax;
            var range;

            // alert("max " + max);
            range = this.nicenum(max - min, false);

            //  alert("range " + range);
            d = this.nicenum(range / (ntick - 1), true);

            //debugPrinter.print("d : " + d, this.debug);
            graphmin = Math.floor(min / d) * d;
            graphmax = Math.ceil(max / d) * d;

            //nfrac = Math.max(-Math.floor(Math.log(d)/ Math.LN10), 0);
            this.normalizeMe = graphmax;
            for (var x = graphmin; x < graphmax + 0.5 * d; x += d) {
                //for (var x = graphmax + 0.5 * d; x > graphmin ; x -= d) {
                var yScreenspace = x / this.normalizeMe * this.maxHeight;

                // this.createYCaptionMark(yScreenspace);
                //this.addLabel(this.left - 120, this.bottom + yScreenspace, this.thousandSeparation(x), 0, "");
                this.addLabel(this.left - 120, this.bottom + yScreenspace, this.insertDelemeters(x), 0, "");

                //print grid
                var linegeom = new THREE.Geometry();
                linegeom.vertices.push(new THREE.Vector3(this.left - 10, this.bottom + yScreenspace, 0));
                linegeom.vertices.push(new THREE.Vector3(this.right, this.bottom + yScreenspace, 0));
                var line = new THREE.Line(linegeom, new THREE.LineBasicMaterial({ color: 0x111111 }));

                this.fluidDiagrams.addSceneObject(line);
            }
        };

        BarChartVisualisation.prototype.nicenum = function (x, round) {
            var exp;
            var f;
            var nf;
            var powVal;

            exp = Math.floor(Math.log(x) / Math.LN10);
            powVal = Math.pow(10, exp);
            f = x / powVal;

            if (round == true) {
                if (f < 1.5) {
                    nf = 1;
                } else if (f < 3) {
                    nf = 2;
                } else if (f < 7) {
                    nf = 5;
                } else {
                    nf = 10;
                }
            } else {
                if (f <= 1) {
                    nf = 1;
                } else if (f <= 2) {
                    nf = 2;
                } else if (f <= 5) {
                    nf = 5;
                } else {
                    nf = 10;
                }
            }
            return nf * powVal;
        };

        BarChartVisualisation.prototype.calcSpace = function () {
            var margin = 60;
            this.cubeWidth = this.fluidDiagrams.width / this.blockCount;
            this.left = margin + this.leftMargin;

            this.right = this.fluidDiagrams.width - margin - this.rightMargin;
            this.bottom = margin + 60;
            this.top = this.fluidDiagrams.height - margin - this.topMargin;
            this.cubeWidth = (this.right - this.left) / this.barCnt;
            this.maxHeight = this.top - this.bottom;
        };

        BarChartVisualisation.prototype.createUI = function () {
            //print x Axis
            var linegeom = new THREE.Geometry();
            linegeom.vertices.push(new THREE.Vector3(this.left - 20, this.bottom, 0));
            linegeom.vertices.push(new THREE.Vector3(this.right, this.bottom, 0));
            var line = new THREE.Line(linegeom, new THREE.LineBasicMaterial({ color: 0x111111 }));
            this.fluidDiagrams.addSceneObject(line);

            //print y Axis
            var linegeom = new THREE.Geometry();
            linegeom.vertices.push(new THREE.Vector3(this.left, this.bottom - 20, 0));
            linegeom.vertices.push(new THREE.Vector3(this.left, this.top, 0));
            var line = new THREE.Line(linegeom, new THREE.LineBasicMaterial({ color: 0x111111 }));
            this.fluidDiagrams.addSceneObject(line);

            //title
            this.addLabel((this.right - this.left) / 2 + this.left, this.top + 30, this.title, 0, this.titlePopUP);

            //X title
            this.addLabel((this.right - this.left) / 2 + this.left, this.bottom - 100, this.Xtitle, 0, this.XtitlePopUP);

            //Y title
            this.addLabel(this.left - 200, (this.bottom - this.top) / 2 + this.top, this.Ytitle, 90, this.YtitlePopUP);

            //create Y ticks //print y Axis caption
            this.createNiceTickMarks(this.normalizeMe);
        };

        //    private createYCaptionMark(y:number) {
        //        var linegeom = new THREE.Geometry();
        //        linegeom.vertices.push(new THREE.Vector3(this.left - 10, this.bottom + y, 0));
        //        linegeom.vertices.push(new THREE.Vector3(this.left, this.bottom + y, 0));
        //        var line = new THREE.Line(linegeom, new THREE.LineBasicMaterial({ color: 0x111111 }));
        //        this.fluidDiagrams.addSceneObject(line);
        //    }
        BarChartVisualisation.prototype.findValToNormalize = function () {
            var barCnt = 0;

            var barOffsets = 0;
            for (var node in this.nodes) {
                barOffsets++;
                var currentNode = this.nodes[node];

                //currentNode.getNodeSceneGraph().translateX(this.left);
                var data = currentNode.getData();

                for (var d in data) {
                    var val = parseFloat(data[d]);

                    if (this.normalizeMe < val) {
                        this.normalizeMe = val;
                    }

                    //barNum++;
                    barCnt++;
                }
            }
            return barCnt + barOffsets;
        };

        BarChartVisualisation.prototype.addLabel = function (xOff, yOFF, name, angle, values) {
            var size = 128;
            var canvas1 = document.createElement('canvas');
            canvas1.height = 20;
            canvas1.width = size;
            var context1 = canvas1.getContext('2d');

            //        context1.fillStyle = "rgba(0,0,0,0.95)"; // black border
            //        context1.fillRect(0, 0, size + 8, size + 8);
            context1.font = "Bold 11px Arial";
            context1.textAlign = 'center';
            context1.fillStyle = "rgba(0,0,0,1)";

            //context1.fillText(name, 20, 10);
            context1.fillText(name, size / 2, 11);
            var metrics = context1.measureText(name);

            if (name == this.titlePopUP) {
                this.titleContext = context1;
            }

            // 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 textPlane = new THREE.PlaneGeometry(120, 20);
            var textMesh = new THREE.Mesh(textPlane, textMat);
            textMesh.rotation.z = angle * Math.PI / 180;
            textMesh.position = new THREE.Vector3(xOff + size / 2, yOFF, 0);

            //textMesh.name = this.thousandSeparation(values);
            textMesh.name = values; // this.insertDelemeters(values);
            this.fluidDiagrams.addSceneObject(textMesh);
            return metrics.width;
        };

        BarChartVisualisation.prototype.getNodeMeshMap = function () {
            return this.NodeMeshMap;
        };

        BarChartVisualisation.prototype.changeColorTheme = function (color) {
            for (var block in this.blocks) {
                for (var entry = 0; entry < this.blocks[block].entries.length; entry++) {
                    this.blocks[block].entries[entry].color = this.colorArray[color][block % this.colorArray[color].length];
                }
            }
            this.update();
        };

        BarChartVisualisation.prototype.changeColorOfSameKind = function (hexColor, name) {
            for (var block in this.blocks) {
                if (this.blocks[block].cName == name) {
                    for (var entry = 0; entry < this.blocks[block].entries.length; entry++) {
                        this.blocks[block].entries[entry].color = parseInt("0x" + hexColor, 16);
                    }
                }
            }
            this.update();
        };

        BarChartVisualisation.prototype.thousandSeparation = function (val) {
            return String(val).split("").reverse().join("").replace(/(\d{3}\B)/g, "$1" + this.separationMark).split("").reverse().join("");
        };

        BarChartVisualisation.prototype.insertDelemeters = function (val) {
            var integer = Math.floor(val);

            var decimal = val - integer;
            var intString = this.thousandSeparation(integer);

            //alert("integer " + integer + " " + intString + " " + decimal);
            if (decimal == 0)
                return intString;

            return intString + this.floatSeperationMark + decimal.toString().substring(2, 4);
        };

        BarChartVisualisation.prototype.update = function () {
            this.deleteScene();

            this.calcSpace();
            this.createUI();
            this.drawBars();

            this.drawLegend();
        };

        BarChartVisualisation.prototype.deleteBars = function () {
            for (var node in this.fluidDiagrams.rootNodes) {
                var n = this.fluidDiagrams.rootNodes[node];
                var geom = n.getAllGeometry();
                for (var geo in geom)
                    n.getNodeSceneGraph().remove(geom[geo]);
                geom.splice(0, 1);
            }
        };

        BarChartVisualisation.prototype.deleteScene = function () {
            this.deleteBars();

            var myList = this.fluidDiagrams.nodeSceneGraph.getDescendants();
            for (var desc in myList) {
                var tmp = myList[desc];
                this.fluidDiagrams.nodeSceneGraph.remove(tmp);
            }

            for (var desc in this.fluidDiagrams.geometryObjects) {
                var tmp = this.fluidDiagrams.geometryObjects[desc];
                this.fluidDiagrams.geometryObjects[desc].remove(tmp);
            }
        };

        BarChartVisualisation.prototype.toggleLegend = function () {
            this.visualisationToogle == true ? this.visualisationToogle = false : this.visualisationToogle = true;

            if (this.visualisationToogle == true) {
                this.topMargin = 0;
                this.rightMargin = 100;
            } else {
                this.topMargin = 0;
                this.rightMargin = 0;
            }
            this.update();
        };

        BarChartVisualisation.prototype.drawShadow = function (name /*,id:number*/ ) {
            for (var block in this.blocks) {
                if (name == this.blocks[block].cName) {
                    for (var entry = 0; entry < this.blocks[block].entries.length; entry++) {
                        for (var node in this.nodes) {
                            var allGeometry = this.nodes[node].getAllGeometry();
                            for (var cube in allGeometry) {
                                if (allGeometry[cube].id == this.blocks[block].shadowEntries[entry].id) {
                                    allGeometry[cube].visible = true;
                                } else if (allGeometry[cube].id == this.blocks[block].overShadowEntries[entry].id) {
                                    allGeometry[cube].visible = true;
                                    //                                if(allGeometry[cube].id == id){
                                    //                                    this.fluidDiagrams.eventHandler.setNewHoveredElement(allGeometry[cube]);
                                    //                                }
                                }
                            }
                        }
                    }
                }
            }
        };

        BarChartVisualisation.prototype.hideShadow = function (name) {
            for (var block in this.blocks) {
                if (name == this.blocks[block].cName) {
                    for (var entry = 0; entry < this.blocks[block].entries.length; entry++) {
                        for (var node in this.nodes) {
                            var allGeometry = this.nodes[node].getAllGeometry();
                            for (var cube in allGeometry) {
                                if (allGeometry[cube].id == this.blocks[block].shadowEntries[entry].id) {
                                    //alert("sdfsdf");
                                    allGeometry[cube].visible = false;
                                } else if (allGeometry[cube].id == this.blocks[block].overShadowEntries[entry].id) {
                                    allGeometry[cube].visible = false;
                                }
                            }
                        }
                    }
                }
            }
        };

        BarChartVisualisation.prototype.drawLegend = function () {
            if (this.visualisationToogle == true) {
                var cNames = this.nodes[0].getData();
                var cnt = 0;
                for (var name in cNames) {
                    this.addLabel(this.right + 20, this.top - 30 * cnt - 5, name, 0, "");
                    var cube = new THREE.Mesh(new THREE.CubeGeometry(20, 20, 1), new THREE.MeshBasicMaterial({ color: this.blocks[cnt].entries[0].color }));
                    cube.position.x = this.right + 20;
                    cube.position.y = this.top - 30 * cnt;
                    this.fluidDiagrams.addSceneObject(cube);
                    cnt++;
                }
            }
        };

        BarChartVisualisation.prototype.changeColorInBlocks = function (bar, color) {
            for (var block in this.blocks) {
                for (var entry in block) {
                    if (bar == entry) {
                        this.blocks[block].entries[entry].color = color;
                    }
                }
            }
        };
        return BarChartVisualisation;
    })(FD.FDVisualisation);
    FD.BarChartVisualisation = BarChartVisualisation;
})(FD || (FD = {}));
