jQuery.noConflict();

var STATE_ERROR = -1;
var STATE_LOADING = 1;
var STATE_SEL0 = 2
var STATE_SEL1 = 3;  // mouse is moved over the chart area - no selection yet
var STATE_SEL2 = 4;

var MOUSE_MOVE = 1;
var MOUSE_DOWN = 2;
var MOUSE_UP = 3;
var MOUSE_OUT = 4;
var MOUSE_CTX = 5;

var espaCharts = {};

function getEspaChart(name)
{
    return espaCharts[name];
}

function EspaLineChart(contextInfo, dateCorrection, data, settings)
{
    // set initial state
    this.state = STATE_LOADING;
    espaCharts[contextInfo.uniqueName] = this;

    // copy parameters
    this.contextInfo = contextInfo;
    this.settings = {oneZoomOutLevel: false, alwaysShowSelector: false, selectorDragNDrop: true, hasLegend: true};
    jQuery.extend(this.settings, settings);
    this.data = data;
    this.dateCorrection = dateCorrection;
    this.listeners = [];

    var this0 = this;

    jQuery(window).resize(function()
    {
        this0.calculateImagePosition(true);
    });
    jQuery(window).scroll(function()
    {
        this0.calculateImagePosition(true);
    });
    getElement = function(id)
    {
        return document.getElementById(contextInfo.baseId + ':' + id);
    };
    getTextElement = function(id, text)
    {
        return getTextNode(getElement(id), text);
    };
    finalizeEvent = function(e)
    {
        e = jQuery.event.fix(e || window.event || {});
        e.stopPropagation();
        e.preventDefault();
        return e;
    };
    setHandlers = function(elem, outHandler)
    {
        elem.oncontextmenu = function(e) {
            finalizeEvent(e);
            return false;
        };
        elem.onmousemove = function(e) {
            this0.mouseHandler(MOUSE_MOVE, finalizeEvent(e));
            return false;
        };
        elem.onmousedown = function(e) {
            this0.mouseHandler(MOUSE_DOWN, finalizeEvent(e));
            return false;
        };
        elem.onmouseup = function(e) {
            this0.mouseHandler(MOUSE_UP, finalizeEvent(e));
            return false;
        };
        if ((outHandler != undefined) && outHandler)
        {
            elem.onmouseout = function(e) {
                this0.mouseHandler(MOUSE_OUT, finalizeEvent(e));
                return false;
            };
        }
    };

    // initialize base elements
    this.elements = {
        errorContainer: getElement('error'),
        errorMessage:   getTextElement('error', 'error'),
        imageContainer: getElement('image:container'),
        image:          getElement('image'),
        selector:       getElement('selector'),
        legendContainer:getElement('legend:container'),
        legend:         this.settings.hasLegend ? getElement('legend') : undefined,
        legendTitle:    this.settings.hasLegend ? getTextElement('legend:title', 'date') : undefined
    };
    setHandlers(this.elements.image.parentNode);
    setHandlers(this.elements.image);
    setHandlers(this.elements.selector);

    // initialize data and elements
    jQuery.each(this.data, function(i, series) {
        series.tracker = getElement('tracker:' + i);
        series.trackerOffset = {
            x: .5 * parseInt(series.tracker.style.width),
            y: .5 * parseInt(series.tracker.style.height)
        };
        setHandlers(series.tracker);

        if (this0.settings.hasLegend)
        {
            series.legendTracker = getTextElement('legend:tracker:' + i, 'value');
        }
    });

    this.errorTimeout = undefined;

    this.history = [];
    this.historyIdx = 0;

    this.selection = [];

    this.loadImage();
}

EspaLineChart.prototype =
{
    getURLParams: function(extParams)
    {
        var params = {t: new Date().getTime(), i: this.contextInfo.uniqueName, l: false, w: false};
        jQuery.extend(params, extParams);
        return params;
    },

    getText: function(key)
    {
        return getResourceText(this.settings.locale, key);
    },

    clearErrorMessage: function()
    {
        clearWindowTimeout(this.errorTimeout);
        hideElement(this.elements.errorContainer);
        this.errorTimeout = undefined;
    },

    showErrorMessage: function(msg, timeout)
    {
        clearWindowTimeout(this.errorTimeout);
        setText(this.elements.errorMessage, msg);
        this.elements.errorContainer.style.color = 'red';
        this.elements.errorContainer.style.textAlign = 'center';
        showElement(this.elements.errorContainer);
        this.errorTimeout = setTimeout(
                'getEspaChart("' + this.contextInfo.uniqueName + '").clearErrorMessage();',
                (timeout == undefined) ? 5000 : timeout);
    },

    registerListener: function(listener)
    {
        this.listeners.push(listener);
    },

    /*
     ev
     0: before-load
     1: after-load
     2: error
     */
    triggerListeners: function(ev, data)
    {
        var this0 = this;
        jQuery.each(this.listeners, function(i, listener) {
            listener(this0, ev, data);
        });
    },

    loadImage: function(idx, tryShortCut)
    {
        this.state = STATE_LOADING;
        this.updateScreen();

        if ((idx != undefined) && (tryShortCut != undefined) && tryShortCut &&
            dateEquals(this.history[idx].start, this.imageInfo.dateFrom) &&
            dateEquals(this.history[idx].end, this.imageInfo.dateTo))
        {
            this.state = STATE_SEL0;
            this.updateScreen();
        }
        else
        {
            this.triggerListeners(0);

            this.clearErrorMessage();

            this.elements.image.src = this.contextInfo.imageLoading;


            if (idx == undefined)
            {
                this.loadImageInterval();
            }
            else
            {
                this.loadImageInterval(this.history[idx].start, this.history[idx].end);
            }
        }
    },

    doLoadImageInterval: function(start, end)
    {
        var args = {};
        if (start != undefined)
        {
            args.s = start.getTime();
        }
        if (end != undefined)
        {
            args.e = end.getTime();
        }
        args = this.getURLParams(args);

        var img = new Image();
        var this0 = this;
        img.onload = function()
        {
            this0.imageLoaded(img);
        };
        img.onabort = img.onerror = function()
        {
            top.location = top.location;
            //this0.dataError(this0.getText('error_loading_chart'));
        };
        img.src = this.contextInfo.exportURL + '?' + jQuery.param(args);
    },


    loadImageInterval: function(start, end)
    {
        this.doLoadImageInterval(start, end);
    },

    doImageLoaded: function(img)
    {

        var this0 = this;
        jQuery.ajax({
            global: false, async: true,
            type: 'POST', url: this0.contextInfo.infoURL,
            data: this.getURLParams(),
            dataType: 'json', cache: false,
            success: function(data) {
                this0.imageDataLoaded(img, data);
            },
            error: function(request, errorMsg, errorException) {
                this0.dataError(this0.getText('error_loading_data'));
            }
        });

    },

    imageLoaded: function(img)
    {
        this.doImageLoaded(img);
    },

    imageDataLoaded: function(img, data)
    {
        if ((data == undefined) || (data.error == undefined) || data.error)
        {
            var message = this.getText('error_loading_data');
            if ((data != undefined) && (data.errorMessage != undefined) && (data.errorMessage.length > 0))
            {
                message = this.getText(data.errorMessage);
            }

            if (this.historyIdx == 0)
            {
                this.dataError(message);
            }
            else
            {
                this.loadImage(-- this.historyIdx);
                this.showErrorMessage(message);
            }
        }
        else
        {
            this.triggerListeners(1, data);

            data.dateFrom = truncateDate(data.dateFrom);
            data.dateTo = truncateDate(data.dateTo);

            this.imageInfo = data;

            this.calculateImagePosition(true);

            this.history[this.historyIdx] = {start: data.dateFrom, end: data.dateTo};

            if (this.historyIdx == 0)
            {
                this.dateFirst = data.dateFrom;
            }

            this.elements.image.src = img.src;

            this.state = STATE_SEL0;

            this.updateScreen();

        }
    },

    dataError: function(msg)
    {
        this.triggerListeners(2, msg);

        this.state = STATE_ERROR;

        hideElement(this.elements.image);
        getTextNode(this.elements.image.parentNode, msg);
    },

    isActive: function()
    {
        switch (this.state)
                {
            default:
                return false;
            case STATE_SEL0:
            case STATE_SEL1:
            case STATE_SEL2:
                return true;
        }
    },

    calculateImagePosition: function(internal)
    {
        if (((internal != undefined) && internal) || this.isActive())
        {
            var elem = jQuery(this.elements.image.parentNode);
            var off = elem.offset();
            this.imageInfo.positionTop = off.top;
            this.imageInfo.positionLeft = off.left;
            this.imageInfo.offsetTop = off.top;
            this.imageInfo.offsetLeft = off.left;
        }
    },

    downloadImage: function(printerFriendly, filename)
    {
        if (this.isActive())
        {

            var args = this.getURLParams();
            args.s = this.imageInfo.dateFrom.getTime();
            args.e = this.imageInfo.dateTo.getTime();
            args.f = ((filename == undefined) || (filename.length == 0)) ?
                     (this.contextInfo.uniqueName + '.png') : filename;
            args.w = true;
            args.l = true;
            args.pf = ((printerFriendly == undefined) || (printerFriendly == false)) ? false : true;
            location.href = this.contextInfo.exportURL + '?' + jQuery.param(args);
        }
    },

    hideSelector: function()
    {
        hideElement(this.elements.selector);
    },

    hideTrackers: function()
    {
        if (this.settings.hasLegend)
        {
            hideElement(this.elements.legendTitle.parentNode);
            hideElement(this.elements.legendContainer);
        }
        jQuery.each(this.data, function(i, series) {
            hideElement(series.tracker);
        });
    },

    hideTrackersAlmost: function()
    {
        var showLegend = this.settings.hasLegend;

        jQuery.each(this.data, function(i, series) {
            hideElement(series.tracker);
            if (showLegend)
            {
                setText(series.legendTracker, ' ');
            }
        });

        if (showLegend)
        {
            hideElement(this.elements.legendTitle.parentNode);
            showElement(this.elements.legendContainer);
        }
    },

    showSelector: function()
    {
        var top = this.imageInfo.positionTop + this.imageInfo.areaTop;
        var left = this.imageInfo.positionLeft + this.imageInfo.areaLeft;
        var height = this.imageInfo.areaHeight;
        var width;

        if (this.state == STATE_SEL1)
        {
            left += this.selection[0].pos;
            width = 0;
        }
        else
        {
            left += mathMin(this.selection[0].pos, this.selection[1].pos);
            width = mathAbs(this.selection[0].pos - this.selection[1].pos);
        }

        elem = this.elements.selector;
        elem.style.top = top + 'px';
        elem.style.left = left + 'px';
        elem.style.height = height + 'px';
        elem.style.width = width + 'px';
        showElement(elem);
    },

    showTrackers: function()
    {
        var idx = (this.state == STATE_SEL1) ? 0 : 1;
        var selDate = this.selection[idx].date;
        var selIdx = this.selection[idx].idx;
        var cnt = this.imageInfo.dateCnt;
        var intervalStart = this.imageInfo.dateOffset;
        var intervalEnd = intervalStart + cnt;
        var showAll = false;
        var legendInfo = [];

        var this0 = this;
        jQuery.each(this.data, function(i, series) {
            var posX;
            var posY;
            var curIdx;
            var curDate;
            var curValue = series.values[selIdx];
            var curDispValue = series.dispValues[selIdx];
            if (typeof(curValue) == 'object')
            {
                var corr;
                if (curValue[0] <= (curValue[1] / 2))
                {
                    corr = - curValue[0] - .5;
                    if ((selIdx + corr) < intervalStart)
                    {
                        corr = curValue[1] - curValue[0] + .5;
                    }
                }
                else
                {
                    corr = curValue[1] - curValue[0] + .5;
                    if ((selIdx + corr) > intervalEnd)
                    {
                        corr = - curValue[0] - .5;
                    }
                }
                curIdx = selIdx + corr;
                if (curIdx < intervalStart || curIdx > intervalEnd)
                {
                    curIdx = -1;
                    curValue = Number.NEGATIVE_INFINITY;
                    curDispValue = '';
                }
                else
                {
                    curDate = this0.calculateDate(curIdx);
                    curValue = series.values[curIdx];
                    curDispValue = series.dispValues[curIdx];
                }
                showAll = true;
            }
            else
            {
                curIdx = selIdx;
                curDate = selDate;
            }
            if (curIdx != -1)
            {
                var relX = ((curIdx - intervalStart) * this0.imageInfo.areaWidth / cnt) + this0.imageInfo.areaLeft;
                var relY = this0.imageInfo.tickTop + this0.imageInfo.tickRange *
                                                     (1 - ((curValue - this0.imageInfo.valueMin) / this0.imageInfo.valueRange));
                posX = this0.imageInfo.positionLeft + relX - series.trackerOffset.x;
                posY = this0.imageInfo.positionTop + relY - series.trackerOffset.y;
            }
            legendInfo.push({
                series: series,
                idx: curIdx, val: curValue, dispVal: curDispValue, date: curDate,
                x: posX, y: posY});
        });

        jQuery.each(legendInfo, function(i, entry) {
            var text;
            if (entry.idx == -1)
            {
                text = this0.getText('no_data_short');
                hideElement(entry.series.tracker);
            }
            else
            {
                text = entry.dispVal;
                if (showAll)
                {
                    text += ' [' + formatDate(entry.date) + ']';
                }
                entry.series.tracker.style.left = entry.x + 'px';
                entry.series.tracker.style.top = entry.y + 'px';
                showElement(entry.series.tracker);
            }

            if (this0.settings.hasLegend)
            {
                setText(entry.series.legendTracker, text);
            }
        });

        if (this.settings.hasLegend)
        {
            setText(this.elements.legendTitle, formatDate(selDate));
            showElement(this.elements.legendTitle.parentNode);
            showElement(this.elements.legendContainer);
        }
    },

    updateScreen: function()
    {
        switch (this.state)
                {
            default:
                this.hideSelector();
                this.hideTrackers();
                break;
            case STATE_SEL0:
                this.hideSelector();
                this.hideTrackersAlmost();
                break;
            case STATE_SEL1:
                if (this.settings.alwaysShowSelector)
                {
                    this.showSelector();
                }
                else
                {
                    this.hideSelector();
                }
                this.showTrackers();
                break;
            case STATE_SEL2:
                this.showSelector();
                this.showTrackers();
                break;
        }

    },

    calculateDate: function(idx)
    {
        return truncateDate(new Date(this.dateFirst.getTime() +
                                     MILLISECONDS_PER_DAY * (idx + this.dateCorrection[idx])));
    },

    mouseHandler: function(type, e)
    {
        if (this.isActive())
        {
            if ((type == MOUSE_DOWN) && e.which && (e.which != 1))
            {
                type = MOUSE_CTX;
            }

            if (type == MOUSE_CTX)
            {
                if (this.historyIdx == 0)
                {
                    this.showErrorMessage(this.getText('zoom_out_impossible'));
                }
                else
                {
                    -- this.historyIdx;
                }
                this.loadImage(this.historyIdx, true);
            }
            else
            {
                this.calculateImagePosition(true);

                // following lines are needed to exactly determine x position (absoluteOffset) of image on a page
                var baseElementForAbsoluteOffset = this.elements.image;
                var absoluteXOffset = 0;
                while (baseElementForAbsoluteOffset != null) {
                    absoluteXOffset += baseElementForAbsoluteOffset.offsetLeft -
                                       baseElementForAbsoluteOffset.scrollLeft;
                    baseElementForAbsoluteOffset = baseElementForAbsoluteOffset.offsetParent;
                }
                //---

                var selPos = mathBoundary(e.pageX - absoluteXOffset - this.imageInfo.areaLeft, 0, this.imageInfo.areaWidth);

                var selIdx = this.imageInfo.dateOffset +
                             Math.floor(.5 + this.imageInfo.dateCnt * selPos / this.imageInfo.areaWidth);

                if (this.state == STATE_SEL0)
                {
                    this.state = STATE_SEL1;
                }
                var i = (this.state == STATE_SEL1) ? 0 : 1;
                this.selection[i] = {pos: selPos, idx: selIdx, date: this.calculateDate(selIdx)};

                if (this.settings.selectorDragNDrop)
                {
                    switch (type)
                            {
                        default:
                            break;
                        case MOUSE_DOWN:
                            this.selection[1] = this.selection[0];
                            this.state = STATE_SEL2;
                            break;
                        case MOUSE_UP:
                        case MOUSE_OUT:
                            if (this.state == STATE_SEL2)
                            {
                                this.state = STATE_LOADING;
                            }
                            break;
                    }
                }
                else
                {
                    switch (type)
                            {
                        default:
                            break;
                        case MOUSE_OUT:
                            if (this.state == STATE_SEL2)
                            {
                                break;
                            }
                        case MOUSE_DOWN:
                            if (this.state == STATE_SEL2)
                            {
                                this.state = STATE_LOADING;
                            }
                            else
                            {
                                this.selection[1] = this.selection[0];
                                this.state = STATE_SEL2;
                            }
                            break;
                    }
                }

                if (this.state == STATE_LOADING)
                {
                    if (mathAbs(this.selection[0].idx - this.selection[1].idx) <= 1)
                    {
                        this.showErrorMessage(this.getText('zoom_in_impossible'));
                    }
                    else
                    {
                        if (this.settings.oneZoomOutLevel)
                        {
                            this.historyIdx = 0;
                        }

                        this.history[++ this.historyIdx] = {
                            start: mathMin(this.selection[0].date, this.selection[1].date),
                            end: mathMax(this.selection[0].date, this.selection[1].date)};
                    }

                    this.loadImage(this.historyIdx, true);
                }
                else
                {
                    this.updateScreen();
                }
            }
        }
    }
};


function EspaBarChart(contextInfo, valueNames, data, settings)
{
    // set initial state
    this.state = STATE_LOADING;
    espaCharts[contextInfo.uniqueName] = this;

    // copy parameters
    this.contextInfo = contextInfo;
    this.valueNames = valueNames;
    this.data = data;
    this.rowCount = valueNames.length;
    this.seriesCount = data.length;
    this.settings = {isVertical: true};
    jQuery.extend(this.settings, settings);
    this.listeners = [];

    var this0 = this;
    getElement = function(id)
    {
        return document.getElementById(contextInfo.baseId + ':' + id);
    };
    getTextElement = function(id, text)
    {
        return getTextNode(getElement(id), text);
    };
    finalizeEvent = function(e)
    {
        e = jQuery.event.fix(e || window.event || {});
        e.stopPropagation();
        e.preventDefault();
        return e;
    };
    setHandlers = function(elem)
    {
        elem.oncontextmenu = function(e) {
            finalizeEvent(e);
            return false;
        };
        elem.onmousemove = function(e) {
            this0.mouseHandler(finalizeEvent(e));
            return false;
        };
        elem.onmousedown = function(e) {
            finalizeEvent(e);
            return false;
        };
    };

    // initialize base elements
    this.elements = {
        errorContainer: getElement('error'),
        errorMessage:   getTextElement('error', 'error'),
        imageContainer: getElement('image:container'),
        image:          getElement('image'),
        tooltipContainer:   getElement('tooltip'),
        tooltipMessage:     getTextElement('tooltip', 'tooltip')
    };
    // follownig lines sets crosshair cursor for the image
    this.elements.image.style.cursor = 'crosshair';

    setHandlers(this.elements.image);
    setHandlers(this.elements.tooltipContainer);

    this.errorTimeout = undefined;

    this.loadImage();
}

EspaBarChart.prototype =
{

    getURLParams: function()
    {
        var params = {t: new Date().getTime(), i: this.contextInfo.uniqueName, l: true, w: false};

        return params;
    },

    getText: function(key)
    {
        return getResourceText(this.settings.locale, key);
    },

    clearErrorMessage: function()
    {
        clearWindowTimeout(this.errorTimeout);
        hideElement(this.elements.errorContainer);
        this.errorTimeout = undefined;
    },

    showErrorMessage: function(msg, timeout)
    {
        clearWindowTimeout(this.errorTimeout);
        setText(this.elements.errorMessage, msg);
        this.elements.errorContainer.style.color = 'red';
        this.elements.errorContainer.style.textAlign = 'center';
        showElement(this.elements.errorContainer);
        this.errorTimeout = setTimeout(
                'getEspaChart("' + this.contextInfo.uniqueName + '").clearErrorMessage();',
                (timeout == undefined) ? 5000 : timeout);
    },

    registerListener: function(listener)
    {
        this.listeners.push(listener);
    },

    /*
     ev
     0: before-load
     1: after-load
     2: error
     */
    triggerListeners: function(ev, data)
    {
        var this0 = this;
        jQuery.each(this.listeners, function(i, listener) {
            listener(this0, ev, data);
        });
    },

    loadImage: function()
    {
        this.state = STATE_LOADING;
        this.updateScreen();

        this.triggerListeners(0);

        this.clearErrorMessage();
        this.elements.image.src = this.contextInfo.imageLoading;
        this.loadImageInterval();
    },

    loadImageInterval: function()
    {
        var args = this.getURLParams();

        var img = new Image();
        var this0 = this;
        img.onload = function()
        {
            this0.imageLoaded(img);
        };
        img.onabort = img.onerror = function()
        {
            top.location = top.location;
            //this0.dataError(this0.getText('error_loading_chart'));
        };
        img.src = this.contextInfo.exportURL + '?' + jQuery.param(args);
    },

    imageLoaded: function(img)
    {
        var this0 = this;
        jQuery.ajax({
            global: false, async: true,
            type: 'POST', url: this0.contextInfo.infoURL,
            data: this.getURLParams(),
            dataType: 'json', cache: false,
            success: function(data) {
                this0.imageDataLoaded(img, data);
            },
            error: function(request, errorMsg, errorException) {
                this0.dataError(this0.getText('error_loading_data'));
            }
        });
    },

    imageDataLoaded: function(img, data)
    {
        if ((data == undefined) || (data.error == undefined) || data.error)
        {
            var message = this0.getText('error_loading_data');
            if ((data != undefined) && (data.errorMessage != undefined) && (data.errorMessage.length > 0))
            {
                message = data.errorMessage;
            }

            this.dataError(message);
        }
        else
        {
            this.triggerListeners(1, data);

            data.wholeRowWidth = data.barWidth + data.gapWidthRows;
            data.wholeSeriesWidth = data.gapWidthSeries + data.wholeRowWidth * this.rowCount - data.gapWidthRows;
            this.imageInfo = data;
            this.calculateImagePosition(true);

            this.elements.image.src = img.src;

            this.state = STATE_SEL0;
            this.updateScreen();
        }
    },

    dataError: function(msg)
    {
        this.triggerListeners(2, msg);

        this.state = STATE_ERROR;

        hideElement(this.elements.image);
        getTextNode(this.elements.image.parentNode, msg);
    },

    isActive: function()
    {
        return this.state != STATE_LOADING;
    },



    calculateImagePosition: function(internal)
    {
        if (((internal != undefined) && internal) || this.isActive())
        {
            var elem = jQuery(this.elements.image.parentNode);
            var off = elem.offset();
            this.imageInfo.positionTop = off.top;
            this.imageInfo.positionLeft = off.left;
            this.imageInfo.offsetTop = off.top;
            this.imageInfo.offsetLeft = off.left;
        }
    },

    downloadImage: function(printerFriendly, filename)
    {
        if (this.isActive())
        {

            var args = this.getURLParams();
            args.f = ((filename == undefined) || (filename.length == 0)) ?
                     (this.contextInfo.uniqueName + '.png') : filename;
            args.w = true;
            args.l = true;
            args.pf = ((printerFriendly == undefined) || (printerFriendly == false)) ? false : true;
            location.href = this.contextInfo.exportURL + '?' + jQuery.param(args);
        }
    },

    hideTracker: function()
    {
        hideElement(this.elements.tooltipContainer);
    },

    updateScreen: function()
    {
    },

    mouseHandler: function(e)
    {
        if (this.isActive())
        {
            var isVert = this.settings.isVertical;
            var pos1;
            var pos2;

            if (isVert)
            {
                pos1 = e.pageX - this.imageInfo.offsetLeft;
                pos2 = e.pageY - this.imageInfo.offsetTop;
            }
            else
            {
                pos1 = e.pageY - this.imageInfo.offsetTop;
                pos2 = e.pageX - this.imageInfo.offsetLeft;
            }
            pos1 -= this.imageInfo.firstBar;
            var selSer = Math.floor(pos1 / this.imageInfo.wholeSeriesWidth);
            var posRel = pos1 - selSer * this.imageInfo.wholeSeriesWidth;
            var selRow = Math.floor(posRel / this.imageInfo.wholeRowWidth);
            var valInRange = true;
            if ((pos1 < 0) || ((posRel - selRow * this.imageInfo.wholeRowWidth) > this.imageInfo.barWidth) ||
                !inBoundary(selRow, 0, this.rowCount - 1) || !inBoundary(selSer, 0, this.seriesCount - 1))
            {
                valInRange = false;
            }
            else
            {
                var curSer = this.data[selSer];
                var curVal = curSer.values[selRow];
                if ((curVal == undefined) || (curVal == 0))
                {
                    valInRange = false;
                }
                else
                {
                    var pos2Scale;
                    if (curVal >= 0)
                    {
                        pos2 -= this.imageInfo.positionZeroMax;
                        pos2Scale = (this.imageInfo.positionMax - this.imageInfo.positionZeroMax) *
                                    curVal / this.imageInfo.valueMax;
                    }
                    else
                    {
                        pos2 = this.imageInfo.positionZeroMin - pos2;
                        pos2Scale = (this.imageInfo.positionZeroMin - this.imageInfo.positionMin) *
                                    curVal / this.imageInfo.valueMin;
                    }
                    valInRange = inBoundary(pos2, mathMin(0, pos2Scale), mathMax(0, pos2Scale));
                }
                if (valInRange)
                {
                    var text = curSer.name + ' = ' + curVal;
                    setText(this.elements.tooltipMessage, text);
                    var elem = this.elements.tooltipContainer;
                    elem.style.left = (e.pageX - this.imageInfo.offsetLeft + this.imageInfo.positionLeft) + 'px';
                    elem.style.top = (e.pageY - this.imageInfo.offsetTop + this.imageInfo.positionTop) + 'px';
                    showElement(elem);
                }
            }
            if (!valInRange)
            {
                this.hideTracker();
            }
        }
    }
};

function EspaStaticChart(contextInfo, valueNames, data, settings)
{
    // set initial state
    this.state = STATE_LOADING;
    espaCharts[contextInfo.uniqueName] = this;

    // copy parameters
    this.contextInfo = contextInfo;
}

EspaStaticChart.prototype =
{
    getURLParams: function()
    {
        var params = {t: new Date().getTime(), i: this.contextInfo.uniqueName, l: true, w: true};

        return params;
    },

    downloadImage: function(printerFriendly, filename)
    {
        var args = this.getURLParams();
        args.f = ((filename == undefined) || (filename.length == 0)) ?
                 (this.contextInfo.uniqueName + '.png') : filename;
        args.pf = ((printerFriendly == undefined) || (printerFriendly == false)) ? false : true;
        location.href = this.contextInfo.exportURL + '?' + jQuery.param(args);
    }
};

