/*
 * Created by Diab, Dokter, Hatbauer, Rocnik
 *
 * ivis Group 1 - Summer Term 2013
 *
**/

/// <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="../FluidDiagrams.ts" />
/// <reference path="ScatterPlotEventHandler.ts" />
module FD {
    export class ScatterPlotVisualisation extends FDVisualisation {

        private xDataIndex: number;
        private yDataIndex: number;
        private xDataLabel: string;
        private yDataLabel: string;
        private iconSizeDataIndex: number;
        private iconSizeDataLabel: string;
        private minX: number;
        private maxX: number;
        private minY: number;
        private maxY: number;
        private xSteps: number;
        private ySteps: number;
        private left: number;
        private right: number;
        public top: number;
        public bottom: number;
        private margin: number;
        private NodeMeshMap: { [index: string]: FDNode; } = {};
        private dataSelectionWindow: string;
        private iconSelectionWindow: string;

        private colorSelectionWindow: string;
        private icons: string[] = ["Rect (solid)", "Circle (solid)", "Triangle (solid)",
            "Star (solid)", "Diamond (solid)",
            "Rect (outlined)", "Circle (outlined)", "Triangle (outlined)",
            "Star (outlined)", "Diamond (outlined)"];
        private colors: string[] = ["#000000", "#ff0000", "#ffff00", "#0000ff", "#00ff00", "#ff00ff"];


        private defaultXIndex = 0;
        private defaultYIndex = 0;
        private defaultIconIndex = 0;
        /**
       * Creates a ScatterPlotVisualisation object
       *
       * @constructor
       * @param debug: switch debug mode on/off
       * @param fluidDiagram: FluidDiagrams object (needed because the factory was 
       *                      not used)
       */
        constructor(debug: Boolean, fluidDiagram: FluidDiagrams) {
            super(debug, fluidDiagram);
            this.margin = 60;
        }

        /**
         * Register a html UI element
         *
         * @function registerDataSelectionWindow
         * @param container: UI element
         * @param defaultXIndex: default index of x axis selector
         * @param defaultXIndex: default index of y axis selector
         */
        public registerDataSelectionWindow(containerName: string, defaultXIndex= 0, defaultYIndex= 0) {
            this.dataSelectionWindow = containerName;
            this.defaultXIndex = defaultXIndex;
            this.defaultYIndex = defaultYIndex;

        }

        /**
         * Register a html UI element
         *
         * @function registerIconSelectionWindow
         * @param container: UI element
         * @param defaultIconIndex: default index of icon selector
         */
        public registerIconSelectionWindow(containerName: string, defaultIconIndex= 0) {
            this.iconSelectionWindow = containerName;
        }

        /**
         * Register a html UI element
         *
         * @function registerColorSelectionWindow
         * @param container: UI element
         */
        public registerColorSelectionWindow(containerName: string) {
            this.colorSelectionWindow = containerName;
        }

        /**
         * Initial creation of the scatter plot rendering
         * setup of rendering window dimensions, node geometry
         * and axes/lables
         *
         * @function visualise   
         */
        public visualise() {
            //basic setup
            this.backgroundColor = 0xFAFAFA;
            var tmpMat = <any>new THREE.MeshBasicMaterial({ color: 0x5555cc });

            this.left = (-this.fluidDiagrams.width / 2) + this.margin;
            this.bottom = -(this.fluidDiagrams.height / 2) + this.margin;
            this.top = (this.fluidDiagrams.height / 2) - this.margin;
            this.right = (this.fluidDiagrams.width / 2) - this.margin;
            this.xSteps = 14;
            this.ySteps = 11;

            debugPrinter.print("width: " + this.fluidDiagrams.width, this.debug);
            debugPrinter.print("height: " + this.fluidDiagrams.height, this.debug);
            debugPrinter.print("(l/t/r/b): " + this.left + "/" + this.top + "/"
                + this.right + "/" + this.bottom, this.debug);

            var cNames = this.nodes[0].getData();
            this.initDataSelectionWindow(cNames);
            this.initIconSelectionWindow();


            this.initColorSelectionWindow();

            this.getXComboSelection();
            this.getYComboSelection();
            this.getIconSizeComboSelection();

            this.minX = this.getMin(this.xDataIndex);
            this.maxX = this.getMax(this.xDataIndex);
            this.minY = this.getMin(this.yDataIndex);
            this.maxY = this.getMax(this.yDataIndex);

            debugPrinter.print("minX: " + this.minX, this.debug);
            debugPrinter.print("maxX: " + this.maxX, this.debug);
            debugPrinter.print("minY: " + this.minY, this.debug);
            debugPrinter.print("maxY: " + this.maxY, this.debug);

            this.createAxes();

            this.createLabel(0, this.top + 20, 0, "graphTitle", "Scatter Plot");
            this.createLabel(0, this.bottom - 40, 0, "xLabel", this.xDataLabel);
            this.createLabel(this.left - 45, 0, 90, "yLabel", this.yDataLabel);

            this.createUnitLines();
            this.createElements();

        }

        /**
         * Scatter plot rendering is updated here on 
         * selection widget changes.
         * This basically dumps all nodes and then
         * does the same thing like the visualise method.
         *
         * @function update
         */
        public update() {

            // remove all scene graph nodes
            var myList = <THREE.Object3D[]>this.fluidDiagrams.nodeSceneGraph.getDescendants();
            for (var desc in myList) {
                var tmp = <THREE.Mesh>myList[desc];
                this.fluidDiagrams.nodeSceneGraph.remove(tmp);
            }

            // remove all geometry objects
            for (var desc in this.fluidDiagrams.geometryObjects) {
                var tmp = <THREE.Mesh>this.fluidDiagrams.geometryObjects[desc];
                this.fluidDiagrams.geometryObjects[desc].remove(tmp);
            }

            // update data source from dropdown list
            this.getXComboSelection();
            this.getYComboSelection();
            this.getIconSizeComboSelection();

            // update min/max values from data source
            this.minX = this.getMin(this.xDataIndex);
            this.maxX = this.getMax(this.xDataIndex);
            this.minY = this.getMin(this.yDataIndex);
            this.maxY = this.getMax(this.yDataIndex);

            // recreate title and axis labels
            this.createLabel(0, this.top + 20, 0, "graphTitle", "Scatter Plot");
            this.createLabel(0, this.bottom - 40, 0, "xLabel", this.xDataLabel);
            this.createLabel(this.left - 45, 0, 90, "yLabel", this.yDataLabel);

            // recreate axes, tick marks and value labels
            this.createAxes();
            this.createUnitLines();

            // recreate data item scene graph nodes
            this.createElements();
        }

        /**
          * Creation of data element geometry
          *
          * @function createElements
          */
        private createElements() {
            var sortMat = <any>new THREE.MeshBasicMaterial(
                { transparent: true, color: <any> this.getColorRadioSelection() });
            var outlineMat = <any>new THREE.MeshBasicMaterial(
                { wireframe: true, transparent: true, color: <any> this.getColorRadioSelection() });
            var iconSizeDataMin = this.getMin(this.iconSizeDataIndex);
            var iconSizeDataMax = this.getMax(this.iconSizeDataIndex);
            var iconScale = 0.9 / (iconSizeDataMax - iconSizeDataMin);

            for (var n in this.nodes) {
                var currentNode = <FDNode>this.nodes[n];
                var data = currentNode.getData();
                var j = 0;
                var xVal = 0;
                var yVal = 0;
                var iconSizeVal = 0;
                for (var d in data) {
                    if (j == this.xDataIndex) {
                        xVal = parseFloat(data[d]);
                        break;
                    }
                    j++;
                }
                j = 0;
                for (var d in data) {
                    if (j == this.yDataIndex) {
                        yVal = parseFloat(data[d]);
                        break;
                    }
                    j++;
                }
                j = 0;
                for (var d in data) {
                    if (j == this.iconSizeDataIndex) {
                        iconSizeVal = parseFloat(data[d]);
                        break;
                    }
                    j++;
                }

                // correct scaling needed here!      
                var xFactor = (xVal - this.minX) / (this.maxX - this.minX);
                var yFactor = (yVal - this.minY) / (this.maxY - this.minY);

                var x = (xFactor * (this.fluidDiagrams.width - this.margin * 2)) - (this.fluidDiagrams.width - this.margin * 2) / 2;
                var y = (yFactor * (this.fluidDiagrams.height - this.margin * 2)) - (this.fluidDiagrams.height - this.margin * 2) / 2;
                var icon = this.getIconRadioSelection();

                var iconSize = 1.0;
                if (this.iconSizeDataIndex != -1)
                    iconSize = ((iconSizeVal - iconSizeDataMin) * iconScale) + 0.1;

                if (icon == 0) {
                    var square = this.createSquare(iconSize);
                    var squareMesh = new THREE.Mesh(square, sortMat);
                    squareMesh.position = new THREE.Vector3(x, y, 0);
                    squareMesh.scale = new THREE.Vector3(10, 10, 1);
                    squareMesh.name = "node " + currentNode.getUniqueId();
                    this.nodes[n].addGeometry(squareMesh);
                }
                if (icon == 1) {
                    var circle = this.createCircle(iconSize);
                    var circleMesh = new THREE.Mesh(circle, sortMat);
                    circleMesh.position = new THREE.Vector3(x, y, 0);
                    circleMesh.scale = new THREE.Vector3(10, 10, 1);
                    circleMesh.name = "node " + currentNode.getUniqueId();
                    this.nodes[n].addGeometry(circleMesh);
                }
                if (icon == 2) {
                    var triangle = this.createTriangle(iconSize);
                    var triangleMesh = new THREE.Mesh(triangle, sortMat);
                    triangleMesh.position = new THREE.Vector3(x, y, 0);
                    triangleMesh.scale = new THREE.Vector3(10, 10, 1);
                    triangleMesh.name = "node " + currentNode.getUniqueId();
                    this.nodes[n].addGeometry(triangleMesh);
                }
                if (icon == 3) {
                    var star = this.createStar(iconSize);
                    var starMesh = new THREE.Mesh(star, sortMat);
                    starMesh.position = new THREE.Vector3(x, y, 0);
                    starMesh.scale = new THREE.Vector3(10, 10, 1);
                    starMesh.name = "node " + currentNode.getUniqueId();
                    this.nodes[n].addGeometry(starMesh);
                }
                if (icon == 4) {
                    var diamond = this.createDiamond(iconSize);
                    var diamondMesh = new THREE.Mesh(diamond, sortMat);
                    diamondMesh.position = new THREE.Vector3(x, y, 0);
                    diamondMesh.scale = new THREE.Vector3(10, 10, 1);
                    diamondMesh.name = "node " + currentNode.getUniqueId();
                    this.nodes[n].addGeometry(diamondMesh);
                }
                if (icon == 5) {
                    var square = this.createSquare(iconSize);
                    var squareMesh = new THREE.Mesh(square, outlineMat);
                    squareMesh.position = new THREE.Vector3(x, y, 0);
                    squareMesh.scale = new THREE.Vector3(10, 10, 1);
                    squareMesh.name = "node " + currentNode.getUniqueId();
                    this.nodes[n].addGeometry(squareMesh);
                }
                if (icon == 6) {
                    var circle = this.createCircle(iconSize);
                    var circleMesh = new THREE.Mesh(circle, outlineMat);
                    circleMesh.position = new THREE.Vector3(x, y, 0);
                    circleMesh.scale = new THREE.Vector3(10, 10, 1);
                    circleMesh.name = "node " + currentNode.getUniqueId();
                    this.nodes[n].addGeometry(circleMesh);
                }
                if (icon == 7) {
                    var triangle = this.createTriangle(iconSize);
                    var triangleMesh = new THREE.Mesh(triangle, outlineMat);
                    triangleMesh.position = new THREE.Vector3(x, y, 0);
                    triangleMesh.scale = new THREE.Vector3(10, 10, 1);
                    triangleMesh.name = "node " + currentNode.getUniqueId();
                    this.nodes[n].addGeometry(triangleMesh);
                }
                if (icon == 8) {
                    var star = this.createStar(iconSize);
                    var starMesh = new THREE.Mesh(star, outlineMat);
                    starMesh.position = new THREE.Vector3(x, y, 0);
                    starMesh.scale = new THREE.Vector3(10, 10, 1);
                    starMesh.name = "node " + currentNode.getUniqueId();
                    this.nodes[n].addGeometry(starMesh);
                }
                if (icon == 9) {
                    var diamond = this.createDiamond(iconSize);
                    var diamondMesh = new THREE.Mesh(diamond, outlineMat);
                    diamondMesh.position = new THREE.Vector3(x, y, 0);
                    diamondMesh.scale = new THREE.Vector3(10, 10, 1);
                    diamondMesh.name = "node " + currentNode.getUniqueId();
                    this.nodes[n].addGeometry(diamondMesh);
                }

            }

        }

        /**
         * Creation of the axis tick marks geometry
         *
         * @function createUnitLines   
         */
        private createUnitLines() {
            // x axis tick marks
            var xAxislength = this.right - this.left;
            var xStep = xAxislength / this.xSteps;
            var xDataRange = this.maxX - this.minX;
            var xDataStep = xDataRange / this.xSteps;
            var xDataVal = this.minX;
            var steps = 0;
            for (var i = 0; i < xAxislength + 1; i += xStep) {
                //tickmark
                var linegeom = new THREE.Geometry();
                linegeom.vertices.push(new THREE.Vector3(this.left + i, this.bottom, 0));
                linegeom.vertices.push(new THREE.Vector3(this.left + i, this.bottom - 10, 0));
                var line = new THREE.Line(linegeom, new THREE.LineBasicMaterial({ color: 0x111111 }));
                this.fluidDiagrams.addSceneObject(line);

                //value label   
                this.createLabel(this.left + i, this.bottom - 20, 0, "xDataVal " + steps, xDataVal.toFixed(2));
                xDataVal += xDataStep;
                steps++;
            }

            // y axis tick marks
            var yAxislength = this.top - this.bottom;
            var yStep = yAxislength / this.ySteps;
            var yDataRange = this.maxY - this.minY;
            var yDataStep = yDataRange / this.ySteps;
            var yDataVal = this.minY;
            var steps = 0;
            for (var i = 0; i < yAxislength; i += yStep) {
                var linegeom = new THREE.Geometry();
                linegeom.vertices.push(new THREE.Vector3(this.left, this.bottom + i, 0));
                linegeom.vertices.push(new THREE.Vector3(this.left - 10, this.bottom + i, 0));
                var line = new THREE.Line(linegeom, new THREE.LineBasicMaterial({ color: 0x111111 }));
                this.fluidDiagrams.addSceneObject(line);

                //value label   
                this.createLabel(this.left - 25, this.bottom + i, 0, "yDataVal " + steps, yDataVal.toFixed(2));
                yDataVal += yDataStep;
                steps++;
            }
        }

        /**
         * Creation of the axes geometry
         *
         * @function createAxes
         */
        private createAxes() {
            //print x Axis
            var linegeom = new THREE.Geometry();
            linegeom.vertices.push(new THREE.Vector3(this.left - 10, this.bottom, 0));
            linegeom.vertices.push(new THREE.Vector3(this.right + 10, this.bottom, 0));
            var line = new THREE.Line(linegeom, new THREE.LineBasicMaterial({ color: 0x111111 }));
            line.name = "xAxis";
            this.fluidDiagrams.addSceneObject(line);

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

        /**
         * Creation of the labels geometry
         *
         * @function createLabel
         * @param pos_x: position on x axis
         * @param pos_y: position on y axis
         * @param angle: rotation angle
         * @param nodeName: name for the node in the scene graph
         * @param text: label content
         */
        private createLabel(pos_x: number, pos_y: number, angle: number, nodeName: string, text: string) {
            //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(text, 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 = angle * Math.PI / 180;
            textMesh.position = new THREE.Vector3(pos_x, pos_y, 0);
            textMesh.name = nodeName;
            this.fluidDiagrams.addSceneObject(textMesh);
        }

        /**
          * Simple getter
          *
          * @function getNodeMeshMap
          * @return NodeMeshMap
          */
        public getNodeMeshMap() {
            return this.NodeMeshMap;
        }

        /**
         * Gets the minimum value out of a single coloumn from 
         * the current dataset.
         *
         * @function getMin
         * @param col: the coloumn to use (out of the current dataset)
         * @return min: the minimum value as a number
         */
        private getMin(col: number): number {
            var min = Number.MAX_VALUE;
            for (var i in this.nodes) {
                var currentNode = <FDNode>this.nodes[i];
                var data = currentNode.getData();
                var j = 0;
                for (var d in data) {
                    if (j == col)
                        var val = parseFloat(data[d]);
                    j++;
                }
                if (val < min) {
                    min = val;
                }
            }
            return min;
        }

        /**
         * Gets the maximum value out of a single coloumn from 
         * the current dataset.
         *
         * @function getMax
         * @param col: the coloumn to use (out of the current dataset)
         * @return max: the maximum value as a number
         */
        private getMax(col: number): number {
            var max = Number.MIN_VALUE;
            for (var i in this.nodes) {
                var currentNode = <FDNode>this.nodes[i];
                var data = currentNode.getData();
                var j = 0;
                for (var d in data) {
                    if (j == col)
                        var val = parseFloat(data[d]);
                    j++;
                }
                if (val > max) {
                    max = val;
                }
            }
            return max;
        }

        /**
         * Generates a THREE Geometry object with the shape
         * of a STAR. Which will be used as one Scatter in the
         * ScatterPlot representation.
         *
         * @function createStar
         * @param iconSize: the size of the icon - between 0 and 1
         * @return THREE.Geometry object
         */
        private createStar(iconSize: number): THREE.Geometry {
            var starGeometry = new THREE.Geometry();
            starGeometry.vertices.push(new THREE.Vector3(0.0, iconSize, 0.0));
            starGeometry.vertices.push(new THREE.Vector3(-iconSize, -iconSize / 2, 0.0));
            starGeometry.vertices.push(new THREE.Vector3(iconSize, -iconSize / 2, 0.0));
            starGeometry.vertices.push(new THREE.Vector3(0, -iconSize, 0.0));
            starGeometry.vertices.push(new THREE.Vector3(iconSize, iconSize / 2, 0.0));
            starGeometry.vertices.push(new THREE.Vector3(-iconSize, iconSize / 2, 0.0));
            starGeometry.faces.push(new THREE.Face3(0, 1, 2));
            starGeometry.faces.push(new THREE.Face3(3, 4, 5));
            starGeometry.computeBoundingBox();
            starGeometry.computeFaceNormals();
            return starGeometry;
        }

        /**
         * Generates a THREE Geometry object with the shape
         * of a TRIANGLE. Which will be used as one Scatter in the
         * ScatterPlot representation.
         *
         * @function createCirlce
         * @param iconSize: the size of the icon - between 0 and 1
         * @return THREE.Geometry object
         */
        private createTriangle(iconSize: number): THREE.Geometry {
            var triangleGeometry = new THREE.Geometry();
            triangleGeometry.vertices.push(new THREE.Vector3(0.0, iconSize, 0.0));
            triangleGeometry.vertices.push(new THREE.Vector3(-iconSize, -iconSize, 0.0));
            triangleGeometry.vertices.push(new THREE.Vector3(iconSize, -iconSize, 0.0));
            triangleGeometry.faces.push(new THREE.Face3(0, 1, 2));
            triangleGeometry.computeBoundingBox();
            triangleGeometry.computeFaceNormals();
            return triangleGeometry;
        }

        /**
         * Generates a THREE Geometry object with the shape
         * of a SQUARE. Which will be used as one Scatter in the
         * ScatterPlot representation.
         *
         * @function createCirlce
         * @param iconSize: the size of the icon - between 0 and 1
         * @return THREE.Geometry object
         */
        private createSquare(iconSize: number): THREE.Geometry {
            var squareGeom = new THREE.Geometry();
            squareGeom.vertices.push(new THREE.Vector3(0, 0, 0));
            squareGeom.vertices.push(new THREE.Vector3(0, -iconSize, 0));
            squareGeom.vertices.push(new THREE.Vector3(iconSize, -iconSize, 0));
            squareGeom.vertices.push(new THREE.Vector3(iconSize, 0, 0));
            squareGeom.faces.push(new THREE.Face4(0, 1, 2, 3));
            squareGeom.computeBoundingBox();
            squareGeom.computeFaceNormals();
            return squareGeom;
        }

        /**
         * Generates a THREE Geometry object with the shape
         * of a DIAMOND. Which will be used as one Scatter in the
         * ScatterPlot representation.
         *
         * @function createDiamond
         * @param iconSize: the size of the icon - between 0 and 1
         * @return THREE.Geometry object
         */
        private createDiamond(iconSize: number): THREE.Geometry {
            var diamondGeom = new THREE.Geometry();
            diamondGeom.vertices.push(new THREE.Vector3(iconSize, 0, 0));
            diamondGeom.vertices.push(new THREE.Vector3(0, iconSize, 0));
            diamondGeom.vertices.push(new THREE.Vector3(-iconSize, 0, 0));
            diamondGeom.vertices.push(new THREE.Vector3(0, -iconSize, 0));
            diamondGeom.faces.push(new THREE.Face4(0, 1, 2, 3));
            diamondGeom.computeBoundingBox();
            diamondGeom.computeFaceNormals();
            return diamondGeom;
        }

        /**
         * Generates a THREE Geometry object with the shape
         * of a CIRCLE. Which will be used as one Scatter in the
         * ScatterPlot representation.
         *
         * @function createCirlce
         * @param iconSize: the size of the icon - between 0 and 1
         * @return THREE.Geometry object
         */
        private createCircle(iconSize: number): THREE.Geometry {
            var circleGeom = new THREE.Geometry();
            var radius = iconSize;
            var resolution = 16;
            for (var i = 0; i < resolution; i++) {
                //x,y startpoint
                var start = 2 * Math.PI * i / resolution;
                var x1 = Math.cos(start);
                var y1 = Math.sin(start);
                //x,y endpoint
                var end = 2 * Math.PI * (i + 1) / resolution;
                var x2 = Math.cos(end);
                var y2 = Math.sin(end);
                //push connection line
                circleGeom.vertices.push(
                    new THREE.Vector3(0, 0, 0),
                    new THREE.Vector3(x1 * radius, y1 * radius, 0),
                    new THREE.Vector3(x2 * radius, y2 * radius, 0)
                    );
                var face = new THREE.Face3(i * 3, i * 3 + 1, i * 3 + 2);
                circleGeom.faces.push(face);
            }
            circleGeom.computeBoundingBox();
            circleGeom.computeFaceNormals();
            return circleGeom;
        }

        /**
         * Initialises the dataSelectionWindow in the div specified
         * by the registerDataSelectionWindow
         * Generates Comboboxes for data selection on x/y axes
         * based on the given param.
         *
         * @function initDataSelectionWindow
         * @param columnNames: a array of possible data sources
         */
        private initDataSelectionWindow(columnNames: any) {
            var container = <any>document.getElementById(this.dataSelectionWindow);
            var table = <any>document.createElement("table");
            var tr1 = <any>document.createElement("tr");
            var tr2 = <any>document.createElement("tr");
            var tr3 = <any>document.createElement("tr");
            var td11 = <any>document.createElement("td");
            var td12 = <any>document.createElement("td");
            var td21 = <any>document.createElement("td");
            var td22 = <any>document.createElement("td");
            var td31 = <any>document.createElement("td");
            var td32 = <any>document.createElement("td");
            var xAxesCombo = <any>document.createElement("select");
            xAxesCombo.id = "xAxesCombo";
            var yAxesCombo = <any>document.createElement("select");
            yAxesCombo.id = "yAxesCombo";
            var iconSizeCombo = <any>document.createElement("select");
            iconSizeCombo.id = "iconSizeCombo";
            var xLabel = <any>document.createTextNode("X-Axis: ");
            var yLabel = <any>document.createTextNode("Y-Axis: ");
            var iconSizeLabel = <any>document.createTextNode("Icon Size: ");

            var i = 0;
            for (var col in columnNames) {
                var xoption = <any>document.createElement("option");
                xoption.text = col;
                xoption.value = col;
                var yoption = <any>document.createElement("option");
                yoption.text = col;
                yoption.value = col;
                var iconSizeOption = <any>document.createElement("option");
                iconSizeOption.text = col;
                iconSizeOption.value = col;
                xAxesCombo.appendChild(xoption);
                yAxesCombo.appendChild(yoption);
                iconSizeCombo.appendChild(iconSizeOption);
                i++;
            }

            var iconSizeOption = <any>document.createElement("option");
            iconSizeOption.text = "none";
            iconSizeOption.value = "none";
            iconSizeCombo.appendChild(iconSizeOption);

            //set defaults
            xAxesCombo.selectedIndex = this.defaultXIndex;
            yAxesCombo.selectedIndex = this.defaultYIndex;
            iconSizeCombo.selectedIndex = this.defaultIconIndex;

            td11.appendChild(xLabel);
            td12.appendChild(xAxesCombo);
            td21.appendChild(yLabel);
            td22.appendChild(yAxesCombo);
            td31.appendChild(iconSizeLabel);
            td32.appendChild(iconSizeCombo)
    tr1.appendChild(td11);
            tr1.appendChild(td12);
            tr2.appendChild(td21);
            tr2.appendChild(td22);
            tr3.appendChild(td31);
            tr3.appendChild(td32);
            table.appendChild(tr1);
            table.appendChild(tr2);
            table.appendChild(tr3);
            container.appendChild(table);
        }

        /**
         * Initialises the colorSelectionWindow in the div specified
         * by the registerColorSelectionWindow
         * Generates radio buttons for color selection
         *
         * @function initColorSelectionWindow
         */
        private initColorSelectionWindow() {
            var container = <any>document.getElementById(this.colorSelectionWindow);
            var table = <any>document.createElement("table");

            for (var i in this.colors) {
                var tr = <any>document.createElement("tr");
                var td1 = <any>document.createElement("td");

                td1.style.backgroundColor = this.colors[i];
                td1.width = 30;

                var td2 = <any>document.createElement("td");
                var radio = <any>document.createElement("input");
                radio.type = "radio";
                radio.name = "colorRadio";
                radio.id = "cradio_" + i;

                //enable the first one of the radios as default
                if (i == "0")
                    radio.checked = true;

                td2.appendChild(radio);
                tr.appendChild(td1);
                tr.appendChild(td2);
                table.appendChild(tr);
            }
            container.appendChild(table);
            debugPrinter.print("initColorSelectionWindow", this.debug);
        }

        /**
         * Sets the xDataLabel as well as the index of the 
         * data used for the x-axes in the data structure
         * as choosen by the user from the combobox
         *
         * @function getXComboSelection
         */
        private getXComboSelection() {
            var xAxesCombo = <any>document.getElementById("xAxesCombo");
            this.xDataLabel = xAxesCombo.options[xAxesCombo.selectedIndex].value;
            this.xDataIndex = xAxesCombo.selectedIndex;
        }

        /**
         * Sets the yDataLabel as well as the index of the 
         * data used for the y-axes in the data structure
         * as choosen by the user from the combobox
         *
         * @function getYComboSelection
         */
        private getYComboSelection() {
            var yAxesCombo = <any>document.getElementById("yAxesCombo");
            this.yDataLabel = yAxesCombo.options[yAxesCombo.selectedIndex].value;
            this.yDataIndex = yAxesCombo.selectedIndex;
        }

        /**
         * Sets the iconSizeLabel as well as the index of the
         * data used for the iconSize in the data structure
         * as choosen by the user from the combobox
         *
         * @function getIconSizeComboSelection
         */
        private getIconSizeComboSelection() {
            var iconSizeCombo = <any>document.getElementById("iconSizeCombo");
            this.iconSizeDataLabel = iconSizeCombo.options[iconSizeCombo.selectedIndex].value;
            this.iconSizeDataIndex = iconSizeCombo.selectedIndex;
            if (this.iconSizeDataLabel == "none")
                this.iconSizeDataIndex = -1;
        }

        /**
         * Adds all elements needed for the icon selection to the
         * div in the html which was specified by the 
         * registerIconSelectionWindow function above.
         *
         * @function initIconSelectionWindow
         */
        private initIconSelectionWindow() {
            var container = <any>document.getElementById(this.iconSelectionWindow);
            var iconLabel = <any>document.createTextNode("Icon: ");
            var iconCombo = <any>document.createElement("select");
            iconCombo.id = "iconCombo";

            for (var i in this.icons) {
                var iconoption = <any>document.createElement("option");
                iconoption.text = this.icons[i];
                iconoption.value = i;
                iconCombo.appendChild(iconoption);

            }

            container.appendChild(iconLabel);
            container.appendChild(iconCombo);
            debugPrinter.print("initIconSelectionWindow", this.debug);
        }

        /**
         * Gets the selected radio button index which was
         * selected by the user in the iconSelectionWindow
         *
         * @function getIconRadioSelection
         * @return the selected radio button index
         */
        public getIconRadioSelection(): any {
            var iconCombo = <any>document.getElementById("iconCombo");
            return iconCombo.selectedIndex;
        }

        /**
         * Gets the selected radio button index which was
         * selected by the user in the color selection
         *
         * @function getColorRadioSelection
         * @return the color code (in rgb hex) according
         *         to the selected radio button index
         */
        public getColorRadioSelection(): number {
            for (var i in this.colors) {
                var radio = <any>document.getElementById("cradio_" + i);
                if (radio.checked == true) {
                    //return i;
                    if (i == "0") {
                        return 0x000000;
                    }
                    else if (i == "1") {
                        return 0xff0000;
                    }
                    else if (i == "2") {
                        return 0xffff00;
                    }
                    else if (i == "3") {
                        return 0x0000ff;
                    }
                    else if (i == "4") {
                        return 0x00ff00;
                    }
                    else if (i == "5") {
                        return 0xff00ff;
                    }
                }


            }
            return 0x000000;
        }

        /**
         * Adds a eventHandler to the comboboxes and radiobuttons
         * used in the iconSelection and the dataSelection window.
         *
         * @function initEventHandlers
         * @param eventHandler: a function which is called by
         *                      the onchange event
         */
        public initEventHandlers(eventHandler: any) {
            //for radios
            for (var i in this.colors) {
                var radio = <any>document.getElementById("cradio_" + i);
                radio.onchange = eventHandler;
            }

            //for data
            var xAxesCombo = <any>document.getElementById("xAxesCombo");
            xAxesCombo.onchange = eventHandler;
            var yAxesCombo = <any>document.getElementById("yAxesCombo");
            yAxesCombo.onchange = eventHandler;
            var iconSizeCombo = <any>document.getElementById("iconSizeCombo");
            iconSizeCombo.onchange = eventHandler;
            var iconCombo = <any>document.getElementById("iconCombo");
            iconCombo.onchange = eventHandler;
        }
    }
}
