/**------------------------------------------------------------------------
 * Set of function and classes which deal with bond yield curves chart
 *
 * Dependencies:
 *  dojo.js, version 1.1
 *  yield_curves_data_utils.js
 *
 * Author:
 *  Bartlomiej.Pawlowski@swx.com
 *
 * @version $Id: yield_curves_chart_utils.js,v 1.3 2011/12/01 13:51:56 tkarb Exp $
 *
 *-----------------------------------------------------------------------*/

/**
 * The YieldCurvesChartUtils class provided various utility methods used to
 * create yield charts
 */
function YieldCurvesChartUtils(htmlUniqueKey) {

    if (!htmlUniqueKey) htmlUniqueKey = "";
    this.htmlUniqueKey = htmlUniqueKey;

    // ------------------------ constants
    this.pubstatics = {

        // chart layout on the bond overview page
        SIMPLE_CHART_LAYOUT : {
            chart_width     : 301,      // the whole surface width
            chart_height    : 143,      // the whole suface height
            grid_x          : 35,       // x coordinate of the grid zero-point
            grid_y          : 10,       // y coordinate of the grid zero-point
            grid_margin_right    : 20,       //
            grid_margin_bottom   : 30
        },

        // chart layout on the yield curves tool
        ADV_CHART_LAYOUT : {
            chart_width     : 375,      // the whole surface width
            chart_height    : 250,      // the whole suface height
            grid_x          : 45,       // x coordinate of the grid zero-point
            //grid_y          : 35,       // y coordinate of the grid zero-point
            grid_y          : 35,       // y coordinate of the grid zero-point
            grid_margin_right    : 10,       //
            grid_margin_bottom   : 30
        },

        // graph marker types
        MARKER_CICRLE      : "circle",
        MARKER_SQUARE      : "square",
        MARKER_RHOMBUS     : "rhombus",


        // max number of digits after comma in the yield value
        YIELD_PRECISION    : 3,

        // max numver of digits after comma in the time to maturity value
        TTM_PRECISION      : 2,

        TOOLTIP_GROUP_ID   : "tooltipsGroup",   // id of a div to which all the tooltip div are appended

        GRID_BG_COLOR   : [247, 247, 247], //"#f7f7f7",    // grid background color on a simple chart

        GRID_COLOR      : "#cbcbcb",     // Grid basic color on a simple chart

        CROSS_HAIR_COLOR   : "#aaaaaa" // Colour of the cross-hairs indicating the bond on the chart
    }

    // ------------------------ private variables

    var _objRef = this;

    var _dataUtils = new YieldDataUtils();

    // ------------------------ public methods

    /**
     * Create grid on the surface
     * @param surface (surface)
     * @param gridDesc (hash) see _gridDesc variable
     * @param xLabels (array of numbers) array with all x axis labels
     * @param yLabels (array of numbers) array with all y axis labels
     * @param opts (map) map with the following keys:
     *      gridColor, gridBgColor, xAxisLabel,
     *      step how often the x axis label should be displayd,
     *      ie. 1 means each will be displayed
     * @return map with the following keys
     *      gridGroup : dojo group obj,
     *      xCoords : map with the x coordinates of the x axis labels
     */
    this.createGrid = function (surface, gridDesc, xLabels, yLabels, opts) {
        var gridGroup = surface.createGroup();
        gridGroup.getNode().setAttribute("shape-rendering","crispEdges");

        var withVerticalLines = false;

        var xpx = gridDesc.width / (xLabels.length-1);
        var ypx = gridDesc.height / (yLabels.length-1);

        var path = [];

        var yTextCoords = new Array(yLabels.length);

        // x coordinates of the x axis labels
        var xAxisLabelsCoords = {};

        xAxisLabelsCoords[xLabels[0]] = gridDesc.x;
        yTextCoords[0] = gridDesc.y;

        // y lines
        path.push("\"M ");
        path.push(gridDesc.x);
        path.push(" ");
        path.push(gridDesc.y);
        path.push(" L ");
        path.push(gridDesc.x + gridDesc.width);
        path.push(" ");
        path.push(gridDesc.y);

        var i, dy, dx;
        for (i = 1; i < yLabels.length; i++) {
            dy = gridDesc.y + i * ypx;
            yTextCoords[i] = dy;

            path.push(" M ");
            path.push(gridDesc.x);
            path.push(" ");
            path.push(dy);
            path.push(" L ");
            path.push(gridDesc.x + gridDesc.width);
            path.push(" ");
            path.push(dy);


        }

        path.push("\"");
        gridGroup.createPath(path.join("")).setStroke({color: opts.gridColor});

        // x lines
        path = [];
        path.push("\"M ");
        path.push(gridDesc.x);
        path.push(" ");
        path.push(gridDesc.y);
        path.push(" L ");
        path.push(gridDesc.x);
        path.push(" ");
        path.push(gridDesc.y + gridDesc.height + 5);


        for (i = 1; i < xLabels.length; i++) {
            dx = gridDesc.x + i * xpx;
            xAxisLabelsCoords[xLabels[i]] = dx;

            if ( i == xLabels.length -1 ) {
                path.push(" M ");
                path.push(dx);
                path.push(" ");
                path.push(gridDesc.y);
                path.push(" L ");
                path.push(dx);
                path.push(" ");
                path.push(gridDesc.y + gridDesc.height + 5);
            }
            else {
                path.push(" M ");
                path.push(dx);
                path.push(" ");
                path.push((withVerticalLines ? gridDesc.y : (gridDesc.y + gridDesc.height)));
                path.push(" L ");
                path.push(dx);
                path.push(" ");
                path.push(gridDesc.y + gridDesc.height + 5);
            }

        }

        path.push("\"");
        gridGroup.createPath(path.join("")).setStroke({color: opts.gridColor});

        // make x labels
        var fontDesc = { family: "Arial", size: "8pt" };
        var textDesc = null;
        var k = 0;
        for ( var xLabel in xAxisLabelsCoords ) {
            //if ( k % 3 == 0 ) {
            if ( k % opts.xAxisLabelStep == 0 ) {
                textDesc = { x:xAxisLabelsCoords[xLabel]
                            ,y:gridDesc.y + gridDesc.height + 5 + 10
                            ,text: xLabel
                            ,align: "middle" };
                var t = gridGroup.createText(textDesc);
                t.setFont(fontDesc);
                t.setFill("black");
                //t.setStroke("black");
            }
            k++;
        }

        // make x label descritpion
        if ( opts.xAxisLabel ) {
            textDesc = { x:xAxisLabelsCoords[xLabel]
                                ,y:gridDesc.y + gridDesc.height + 5 + 10 + 13
                                ,text: opts.xAxisLabel
                                ,align: "end" };
            t = gridGroup.createText(textDesc);
            t.setFont(fontDesc);
            t.setFill("black");
        }

        if ( opts.yAxisLabel ) {
            textDesc = { x     : 5,
                         y     : 20,
                         text  : opts.yAxisLabel,
                         align : "start" };
            t = gridGroup.createText(textDesc);
            t.setFont(fontDesc);
            t.setFill("black");
        }

        // make y labels
        for ( k = 0; k < yTextCoords.length; k++ ) {
            var yLabel = yLabels[yTextCoords.length - 1 - k].toFixed(opts.yAxisLabelPrecision ? opts.yAxisLabelPrecision : 1);
            textDesc = {
                         x:     _calcYLabelXCoord(gridDesc.x, yLabel)
                        ,y:     yTextCoords[k] + 4
                        ,text:  yLabel + "%"
                        ,align: "middle"
                        };
            t = gridGroup.createText(textDesc);
            t.setFont(fontDesc);
            t.setFill("black");
         }
        //t.getNode().setAttribute("letter-spacing", "-2pt");


        // make background
        var rectWidth = opts.xAxisLabelStep;  // one rectagle width
        var rectTotalNo = Math.floor(xLabels.length / rectWidth); // total number of all rectangles

        var xCoords = [];   // x axis label coords

        for ( xLabel in xAxisLabelsCoords ) {
            xCoords.push(xAxisLabelsCoords[xLabel]);
        }

        var bgGroup = gridGroup.createGroup();

        for (i = 0; i < rectTotalNo; i++) {
            if ( i % 2 == 0 ) {
                var rectDesc = {
                    x: xCoords[i * rectWidth]
                   ,y: gridDesc.y
                   ,width: xCoords[(i+1) * rectWidth] - xCoords[i * rectWidth]
                   ,height: gridDesc.height
                   };
                var rect = bgGroup.createRect(rectDesc);
                rect.setFill(opts.gridBgColor);
                rect.setStroke({color: opts.gridBgColor});
            }
        }

        bgGroup.moveToBack();

        return { group: gridGroup, xCoords : xAxisLabelsCoords };
    }

    /**
     * Draw a graph based on the yield data
     * @param surface (dojo surface)
     * @param gridDesc see _gridDesc
     * @param minMaxYield (map)  { min: 5.33, max: 7.89 }
     * @param graphData (map) { "1D" : 2.3, "1Y" : 3.234, .... } values of the
     *        graph points
     * @param xPointsCoords
     * @param tooltipTextFun (function)
     * @param opts (map) with the following keys:
     *        graphColor, graphMarkerType
     * @return map with the following keys:
     *         group on which the graph was drawn
     *         tooltipDivs array ot div elements representing tooltips
     *         yCoords hash
     */
    this.createGraph = function(surface, gridDesc, minMaxYield, graphData,
                                xPointsCoords, tooltipTextFun, opts) {
        var graphGroup = surface.createGroup();

        var cYieldData = graphData;  // graph data (values of the graph marker points)

        var tooltipGroupNode = dojo.byId(this.pubstatics.TOOLTIP_GROUP_ID + this.htmlUniqueKey);

        var minYieldInt = Math.floor(minMaxYield.min);
        var maxYieldInt = Math.ceil(minMaxYield.max);

        //  y coordinates of the graph points
        var yGraphPointsCoords = {};

        //  y coordinates of the graph points
        var xGraphPointsCoords = xPointsCoords;

        var term;       // yield
        var marker;     // shape representing marker on the graph
        var cxcoord, cycoord;

        var divs = [];
        var div;    // for tooltips

        // create markers
        for ( term in cYieldData ) {
            cxcoord = xGraphPointsCoords[term];
            if ( cxcoord ) {
                cycoord = (gridDesc.height + gridDesc.y) - ( (cYieldData[term] - minYieldInt) * gridDesc.height) / ( maxYieldInt - minYieldInt ) ;

                yGraphPointsCoords[term] = cycoord;

                marker = _createMarker(graphGroup, opts.graphMarkerType, cxcoord, cycoord
                                       ,opts.graphColor);

                div = _createTooltipDiv(cxcoord, cycoord);

                tooltipGroupNode.appendChild(div);

                marker.connect("onmouseover",
                        //dojo.hitch(_objRef,
                        //dojo.hitch(_objRef._chartUtils,
                        //           _chartUtils.showTooltip, tooltipTextFun(term, cYieldData[term]), div, marker)
                        dojo.hitch(this,
                                   this.showTooltip, tooltipTextFun(term, cYieldData[term]), div, marker)

                   );
                marker.connect("onmouseout",
                        //dojo.hitch(_objRef,
                        //dojo.hitch(_objRef._chartUtils,
                        //           _chartUtils.hideTooltip, div, marker, opts.graphColor)
                        dojo.hitch(this,
                                   this.hideTooltip, div, marker, opts.graphColor)
                    );

                divs.push(div);
           }
        }

        // join markers
        var markersGroup = graphGroup.createGroup();
        var polyCoords = [];
        var i = 0;
        for ( term in yGraphPointsCoords ) {
           polyCoords.push(  { x: xGraphPointsCoords[term], y: yGraphPointsCoords[term] } );
        }

        var line = markersGroup.createPolyline(polyCoords).setStroke({ color: opts.graphColor });
        markersGroup.moveToBack();


        //alert(dojo.toJson(yGraphPointsCoords));

        return { group: graphGroup, tooltipDivs: divs, yCoords: yGraphPointsCoords };
    }

    /**
     * Create bond yield marker on the grid
     * @param
     * @return map with the following keys:
     *         group on which the graph was drawn
     *         tooltipDivs array ot div elements representing tooltips
     */
    this.createPoint = function(surface, x, y, tooltipText, opts) {
        var pointGroup = surface.createGroup();
        var divs = [];
        var div;    // for tooltips
        var tooltipGroupNode = dojo.byId(this.pubstatics.TOOLTIP_GROUP_ID + this.htmlUniqueKey);

        var marker = _createMarker(pointGroup, opts.pointMarkerType, x, y
                               ,opts.pointColor);

        // Add cross-hairs for bond
        var path = "";
        path = path.concat("\" M ")
        .concat(this.pubstatics.ADV_CHART_LAYOUT.grid_x)
        .concat(" " + y)
        .concat(" H " + (this.pubstatics.ADV_CHART_LAYOUT.chart_width - this.pubstatics.ADV_CHART_LAYOUT.grid_margin_right))
        .concat("\"");

        var line = pointGroup.createPath(path).setStroke({color: this.pubstatics.CROSS_HAIR_COLOR});
        line.moveToBack();

        path = "";
        path = path.concat("\" M ")
        .concat(x + " ")
        .concat(this.pubstatics.ADV_CHART_LAYOUT.grid_y)
        .concat(" V " + (this.pubstatics.ADV_CHART_LAYOUT.chart_height - this.pubstatics.ADV_CHART_LAYOUT.grid_margin_bottom))
        .concat("\"");

        line = pointGroup.createPath(path).setStroke({color: this.pubstatics.CROSS_HAIR_COLOR});
        line.moveToBack();

        div = _createTooltipDiv(x, y);

        tooltipGroupNode.appendChild(div);

        marker.connect("onmouseover",
                dojo.hitch(this,
                           this.showTooltip, tooltipText, div, marker)

           );
        marker.connect("onmouseout",
                dojo.hitch(this,
                           this.hideTooltip, div, marker, opts.pointColor)
            );

        divs.push(div);

        return { group: pointGroup, tooltipDivs : divs };
    }

    /**
     * @param labels2YearMap (hash) map with all possible x axis points
     */
    this.calcValueOnXY = function(data, labels2YearMap, xCoords,
                                  pointData, gridDesc) {

        var xAxisPoints = [];
        var dataLabels2Year;

        for ( var l in labels2YearMap ) {
            if ( data[l] )
                xAxisPoints.push(l);
        }

        dataLabels2Year = this.toYear(xAxisPoints);

        var range = this.calcXRange(dataLabels2Year, pointData.xval, pointData.yval);

        if ( range.min == "x" || range.max == "x" )
            return NaN;

        var yVals = {};
        yVals[range.min] = data[range.min];
        yVals[range.max] = data[range.max];
        yVals[pointData.xval + "Y"] = pointData.yval;

        var minMaxY = _dataUtils.getMinMax(yVals);

        var minMaxYInt = { min: Math.floor(minMaxY.min), max: Math.ceil(minMaxY.max) };

        var x1 = xCoords[range.min];
        var y1 = _calcYCoord(gridDesc, minMaxYInt, yVals[range.min]);

        var x2 = xCoords[range.max];
        var y2 = _calcYCoord(gridDesc, minMaxYInt, yVals[range.max]);

        // y coordinate of the bond yield value
        var y3 =  _calcYCoord(gridDesc, minMaxYInt, pointData.yval);

        var a = (y1 - y2) / (x1 - x2);
        var b = y1 - a * x1;

        var yy = a * pointData.xpx + b;

        var val = ((pointData.yval-minMaxYInt.min) * (gridDesc.y + gridDesc.height - yy )
                    + minMaxYInt.min * ( gridDesc.y + gridDesc.height - y3 ))
                    / (gridDesc.y + gridDesc.height - y3);
        return val;
    }

    /**
     * Create a legend
     * @param surface (dojo surface)
     * @param desc (hash) x, y, widht, height values for the legend border
     * @param items (array of {}) items to be displayed in the legend
     * @param opts (hash)
     * @return map with the following keys:
     *         group on which the graph was drawn
     *         tooltipDivs array ot div elements representing tooltips
     */
    this.createLegend = function(surface, desc, items, opts) {
        var legendGroup = surface.createGroup();
        legendGroup.getNode().setAttribute("shape-rendering","crispEdges");

        var path = "";
        path = path.concat("\"")
            .concat("M ").concat(" " + desc.x).concat(" " + desc.y)
            .concat(" H ").concat(" " + (desc.x + desc.width))
            .concat(" V ").concat(" " + (desc.y + desc.height))
            .concat(" H ").concat(" " + (desc.x))
            .concat(" z ")
            ;

        var legendBorder = legendGroup.createPath(path)
                        .setStroke({color: opts.borderColor});

        items.sort(function(a,b){return a.order - b.order;});

        var maxLegendItems = 3;
        var itemWidth = desc.width / (items.length
                                        ? (items.length > maxLegendItems
                                            ? maxLegendItems
                                            : items.length)
                                        : 1);

        // draw legend items
        var fontDesc = { family: "Arial", size: "8pt" };
        var marginLeft = 10; // px
        var lineWidth = 20; // width of the legend line with marker
        var yLine = desc.y + desc.height/2;

        for ( var i = 0; i < items.length && i < maxLegendItems; i++ ) {
            path ="";
            var xLine = (desc.x + (items[i].marginLeft ? items[i].marginLeft : marginLeft) + (i*itemWidth));
            path = path.concat("\"")
            .concat("M ").concat(" " + xLine)
            .concat(" " + yLine)
            .concat(" H ").concat(xLine + lineWidth)
            .concat("\"");

            var line =  legendGroup.createPath(path)
                        .setStroke({color: items[i].color});


            var marker = _createMarker(legendGroup, items[i].markerType,
                                       xLine + lineWidth/2, yLine,
                                       items[i].color);

            var textDesc = { x: xLine + lineWidth + 5
                                ,y: yLine + 4
                                ,text: items[i].text
                                //,align: "end"
                                };

            var t = legendGroup.createText(textDesc);
            t.setFont(fontDesc);
            t.setFill(items[i].textColor);

            //marginLeft = 0;

        }

        return { group: legendGroup, tooltipDivs: null };
    }

    /**
     * @param surface (dojo surface)
     * @param color (string)
     * @param markerType (string) of the MARKER_*
     */
    this.createLegendItem = function(surface, color, markerType) {
        var legendItemGroup = surface.createGroup();
        legendItemGroup.getNode().setAttribute("shape-rendering","crispEdges");
        var sDimensions = surface.getDimensions();

        var path = "";
        var lineWidth = sDimensions.width - 5;
        var yLine = sDimensions.height/2;

        path = path.concat("M 0 ").concat(" " + yLine)
                   .concat(" H ").concat(lineWidth)
                   .concat("\"");

        var line = legendItemGroup.createPath(path)
                   .setStroke({color: color});

        var marker = _createMarker(legendItemGroup, markerType, lineWidth/2, yLine, color);
    }

    /**
     * Make array with y axis labels
     * @param start (integer)
     * @param end (integer)
     * @param bigChart (boolean)
     * @return array of numbers
     */
    this.makeYLabels = function(start, end, bigChart) {
        var size = end - start;

        var maxSize = bigChart ? 6 : 4;    // max size without additional y lines
        var step;           // should be between 0 and 1
        var noValues;

        if ( size >= 13 ) {
            step = size / maxSize;
            noValues = 1 + Math.floor( size / step );
        }
        else if ( size >= maxSize ) {
            noValues = size + 1;
            step = 1;
        }
        else {
            step = size <= (bigChart ? 2 : 1) ? 0.25 : 0.5;
            noValues = 1 + Math.floor( size / step );
        }

        var yLabels = new Array();
        for ( var i = 0; i < noValues; i++ ) {
            yLabels.push(start + (i * step));
        }

        return yLabels;
    }


    /**
     * @param text (string) tooltip text
     * @param node (dom node) tooltip around node
     * @param shape (dojo shape) the graph marker
     */
    this.showTooltip = function(text, node, shape) {
        shape.setFill("red");
        dijit.showTooltip(text, node, ["after", "before"]);
    }

    /**
     * @param node (dom node) tooltip around node
     * @param shape (dojo shape) the graph marker
     * @param color (string) the shape default/original color
     */
    this.hideTooltip = function(node, shape, color) {
        dijit.hideTooltip(node);
        shape.setFill(color);
    }

    /**
     * Remove all tooltipDivs from tooltipGroupDiv
     * @param tooltipGroupNode (node), dom div element to which all tooltips
     *        divs are appended
     * @param tooltipDivs (array) array with div elements
     *
     */
    this.removeTooltips = function(tooltipGroupNode, tooltipDivs) {
        while ( tooltipDivs.length ) {
            var div = tooltipDivs.shift();
            tooltipGroupNode.removeChild(div);
            div = null;
        }
    }


    /**
     * Create mapping between x labels and years
     * @param xLabels (array) with x labels ( [ "1D, "1M",...] )
     * @return map that maps labels to years { "1D" : 0.002808, "1M" : 0.083333, ... }
     */
    this.toYear = function(xLabels) {
        var yearFactor = {
            D : 1/356
           ,M : 1/12
           ,Y : 1
        }

        var labelsMap = {}
        for ( var i = 0; i < xLabels.length; i++ ) {
            var num = parseInt(xLabels[i].substr(0, xLabels[i].length - 1));
            var ypart = xLabels[i].substr(xLabels[i].length - 1);
            labelsMap[xLabels[i]] = num * yearFactor[ypart];
        }

        return labelsMap;
    }

    /**
     * Calculate x, y (in pixels) coordinates of a point that represents the
     * valueX, valueY pair.
     * @param gridDesc
     * @param xAxisLabelsCoords (hash) with x coordinates (in pixels) of the x axis labels
     * @param labels2YearMap (hash) { "1D" : 0.0082.., }
     * @param minMaxYInt (hash) minimum and max Y axis values as integers
     * @param valueX (number)
     * @param valueY (number)
     * @return { x: XX (in px), y: YY (in px) }
     */
    this.calcPointCoords = function(gridDesc, xAxisLabelCoords, labels2YearMap,
                                    minMaxYInt, valueX, valueY) {
        var point = { x: 0, y: 0 };

        point.y = _calcYCoord(gridDesc, minMaxYInt, valueY);

        // calc x coord
        var range = this.calcXRange(labels2YearMap, valueX, valueY);

        if ( range.min == "x" ) {
            point.x = xAxisLabelCoords[keys[0]];
            return point;
        }

        if ( range.max == "x" ) {
            point.x = xAxisLabelCoords[keys[keys.length-1]];
            return point;
        }

        point.x = (xAxisLabelCoords[range.max] - xAxisLabelCoords[range.min]) * (valueX - labels2YearMap[range.min]) / (labels2YearMap[range.max] - labels2YearMap[range.min]) + xAxisLabelCoords[range.min];

        return point;
    }

    /**
     * Calculate range where the (valueX, valueY) point will be placed
     * on the x axis
     * @param (hash)
     * @param valueX (number)
     * @param valueY (number)
     */
    this.calcXRange = function(labels2YearMap, valueX, valueY) {
        var range = { min: "x", max: "x" };

        var dictTemp = new dojox.collections.Dictionary();
        for ( var i in labels2YearMap ) {
            dictTemp.add(i, labels2YearMap[i]);
        }

        var keys = dictTemp.getKeyList();

        for ( k = 0; k < keys.length; k++ ) {
            var v = dictTemp.item(keys[k]);
            if ( valueX <= v ) {
                if ( k - 1 >= 0 ) {
                    range.min = keys[k-1];
                    range.max = keys[k];
                    break;
                }
                else {
                    break;
                }
            }
        }
        return range;
    }

 // ------------------------ private methods
    /**
     *
     */
    function _calcYCoord(gridDesc, minMaxYInt, value) {
        var minYieldInt = Math.floor(minMaxYInt.min);
        var maxYieldInt = Math.ceil(minMaxYInt.max);

        var ycoord = (gridDesc.height + gridDesc.y) - ( (value - minYieldInt) * gridDesc.height) / ( maxYieldInt - minYieldInt ) ;

        return ycoord;

    }

    /**
     * @param yAxisXCoord (number) x coordinate of the Y axis
     * @param label (number) y axis label
     * @return (number) x coordinate of the Y axis label
     */
    function _calcYLabelXCoord(yAxisXCoord, label) {
        return yAxisXCoord - 10 - (label >= 10 ? 2 : 0) - _precision(label) * 5;
    }

    /**
     * @param num (number)
     * @return (number) number of digits after coma
     */
    function _precision(num) {
        var str = num.toString();
        var idx = str.indexOf(".");

        if ( idx != -1 )
            return str.substr(idx+1).length;

        return 0;
    }

    /**
     * Create a marker of a give type on a give group
     * @param group (dojo group)
     * @param type (string) of the MARKER_*
     * @param x (number) x coordinate of the marker middle point
     * @param y (number) y coordinate of the martker middle point
     * @param color (string) color of a marker
     *
     */
    function _createMarker(group, type, x, y, color) {
        var marker;     // shape representing marker on the graph

        var rectSize = 5;

        switch (type) {
            case _objRef.pubstatics.MARKER_CICRLE:
                marker = group.createCircle(
                    {
                        cx: x
                       ,cy: y
                       ,r: 3
                    });
                break;
            case _objRef.pubstatics.MARKER_SQUARE:
            case _objRef.pubstatics.MARKER_RHOMBUS:
                marker = group.createRect(
                    {
                        x: x - rectSize / 2
                       ,y: y - rectSize / 2
                       ,width: rectSize
                       ,height: rectSize
                    });
               if ( type == _objRef.pubstatics.MARKER_RHOMBUS )
                    marker.setTransform(
                        dojox.gfx.matrix.rotategAt(-45,
                                               x + (dojo.isIE ? 1 : 0), y));
                break;
            default:
                // by default circle
                 marker = group.createCircle(
                    {
                        cx: x
                       ,cy: y
                       ,r: 3
                    });


        }
        marker.setFill(color);


        return marker;
    }

    function _createTooltipDiv(x, y) {

        var div;
        div = document.createElement("div");
        dojo.style(div, "position", "absolute");
        dojo.style(div, "display", "none");
        dojo.style(div, "left", (x + 15) + "px");
        dojo.style(div, "top", (y + 10) + "px");

        return div;
    }
}

