﻿function showTooltip(x, y, contents) {
    $('<div id="tooltip">' + contents + '</div>').css({
        position: 'absolute',
        display: 'none',
        top: y,
        left: x,
        border: '1px solid #fdd',
        padding: '2px',
        'background-color': '#fee',
        opacity: 0.80
    }).appendTo("body").fadeIn(200);
    $("#tooltip").mouseover(function() {
        $("#tooltip").remove();
        workoutGraph.oldHoverItem = null;
    });
}

var workoutGraph = {
    activeGraphs: [],
    workout: null,
    names: ["Speed", "Alt", "HR"],
    labels: { Speed: "Vel", Alt: "Alt", HR: "HR" },
    data: {
        Speed: { PointsArray: [], YTicks: [], markings: [] },
        Alt: { PointsArray: [], YTicks: [], markings: [] },
        HR: { PointsArray: [], YTicks: [], markings: [] }
    },
    plotColors: { Speed: "#99CCFF", Alt: "#55AA88", HR: "#ff8888" },
    btnColors: { Speed: "#5577AA", Alt: "#55AA77", HR: "#993333" },

    oldHoverItem: null,

    Hidden: true,


    showHide: function(buttonId) {
        workoutGraph.draw(buttonId);
    },

    updateButtons: function() {
        if (workoutGraph.hasHeartRate) {
            $("#btnGraphHR").css("display", "inherit");
            $("#btnsephr").css("display", "inherit");
            $("#workoutGraphButtons").css("width", "125px");
        }
        $("#btnGraphSpeed").css("color", "#000000");
        $("#btnGraphAlt").css("color", "#000000");
        $("#btnGraphHR").css("color", "#000000");
        for (var k = 0; k < workoutGraph.activeGraphs.length; ++k) {
            var name = workoutGraph.activeGraphs[k];
            $("#btnGraph" + name).css("color", workoutGraph.btnColors[name]);
        }
    },
    isActive: function(graphType) {
        for (var k = 0; k < workoutGraph.activeGraphs.length; ++k) {
            if (workoutGraph.activeGraphs[k] === graphType) return true;
        }
        return false;
    },
    deActivate: function(graphType) {
        for (var k = 0; k < workoutGraph.activeGraphs.length; ++k) {
            if (workoutGraph.activeGraphs[k] === graphType) {
                workoutGraph.activeGraphs.splice(k, 1);
            }
        }
    },

    draw: function(toggleWhich) {
        if (toggleWhich != null) {
            var toggleName = workoutGraph.names[toggleWhich];
            if (workoutGraph.isActive(toggleName)) {
                workoutGraph.deActivate(toggleName);
            }
            else {
                if (workoutGraph.activeGraphs.length > 1) {
                    workoutGraph.activeGraphs.splice(0, 1);
                }
                workoutGraph.activeGraphs.push(toggleName);
            }
        }
        workoutGraph.updateButtons();
        $("#graph").html("");
        if (workoutGraph.activeGraphs.length > 0) {
            var series = [];
            workoutGraph.yAxes = [];
            for (var k = 0; k < workoutGraph.activeGraphs.length; ++k) {
                var graphName = workoutGraph.activeGraphs[k];
                if (k > 0) {
                    series.push({
                        label: workoutGraph.labels[graphName],
                        data: workoutGraph.data[graphName].PointsArray,
                        color: workoutGraph.plotColors[graphName],
                        yaxis: k + 1,
                        points: { show: false }, lines: { show: true }
                    });
                }
                else {
                    series.push({
                        label: workoutGraph.labels[graphName],
                        data: workoutGraph.data[graphName].PointsArray,
                        color: workoutGraph.plotColors[graphName],
                        points: { show: false }, lines: { show: true }
                    });
                }
                workoutGraph.yAxes.push(graphName);
            }
            if (workoutGraph.Hidden) {
                $('#workoutGraph').show();
            }


            var plotOptions = {
                yaxis: {
                    mode: null,
                    ticks: workoutGraph.data[workoutGraph.yAxes[0]].YTicks,
                    tickFormatter: workoutGraph.tickFormYAxis
                },
                y2axis: {
                    mode: null,
                    ticks: (workoutGraph.yAxes[1] ? workoutGraph.data[workoutGraph.yAxes[1]].YTicks : null),
                    tickFormatter: workoutGraph.tickFormYAxis
                },
                xaxis: {
                    tickFormatter: workoutGraph.tickFormXAxis
                },
                grid: {
                    color: "#FFFFFF",
                    backgroundColor: "rgba(0,0,0,0.5)",
                    borderWidth: 1,
                    labelMargin: 5,
                    hoverable: true,
                    clickable: true,
                    markings: workoutGraph.data.Speed.markings,
                    markingsLineWidth: 2,
                    markingsColor: "rgba(0,255,0,0.5)"
                },
                legend: {
                    show: false,
                    position: "nw",
                    backgroundOpacity: 0.0
                },
                selection: { mode: "x" }
            };
            $.plot($("#graph"), series, plotOptions);
            workoutGraph.Hidden = false;

        }
        else {
            $('#workoutGraph').hide();
            workoutGraph.Hidden = true;
        }
    },
    MAXPOINTS: 60,
    COORDINATES_PER_POINT: 4,
    DISTANCE_PER_POINT: 20,
    makeDataFromMap: function(data, minX, maxX) {
        if (data) workoutGraph.workout = data.map;
        if (!minX) minX = -1;
        if (!maxX) maxX = 9000;

        var map = workoutGraph.workout;
        var xms = $("#ms").val();
        var coordinatesCount = 0;
        for (var k = 0; k < map.length; ++k) {
            for (var k2 = 0; k2 < map[k].Coordinates.length; ++k2) {
                var distance = Convertor.toDistanceKM(map[k].Coordinates[k2].DFS, xms);
                if (distance >= minX && distance <= maxX)
                    coordinatesCount += 1;
            }
        }
        if (coordinatesCount < workoutGraph.COORDINATES_PER_POINT) { return; } // do not zoom beyond possible.
        workoutGraph.data =
        {
            Speed: { PointsArray: [], YTicks: [], markings: [] },
            Alt: { PointsArray: [], YTicks: [], markings: [] },
            HR: { PointsArray: [], YTicks: [], markings: [] }

        };
        var graphPoints = Math.floor(
            Math.min(2 + coordinatesCount / workoutGraph.COORDINATES_PER_POINT,
                workoutGraph.MAXPOINTS)
        );
        var cPerPoint = Math.ceil(coordinatesCount / graphPoints);
        var firstCoordinate = map[0].Coordinates[0];
        lastCoordinate = null;
        var count = 0;

        workoutGraph.hasHeartRate = false;

        var sumHeartRate = 0.0;
        var lastHeartrate = null;
        for (var i = 0; i < map.length; ++i) {
            if (!map[i].IsPause) {
                for (var j = 0; j < map[i].Coordinates.length; ++j) {
                    distance = Convertor.toDistanceKM(map[i].Coordinates[j].DFS, xms);
                    var heartrate = map[i].Coordinates[j].HR ? map[i].Coordinates[j].HR : (lastHeartrate ? lastHeartrate : 80.0);
                    sumHeartRate += heartrate;
                    if (distance >= minX && distance <= maxX) {
                        if (count % cPerPoint == 0 || (i == map.length - 1 && j == map[i].Coordinates.length - 1)) {
                            var c = map[i].Coordinates[j];
                            if (c.HR) { workoutGraph.hasHeartRate = true; }
                            c.index = count;
                            if (!lastCoordinate) { lastCoordinate = c; }
                            if (!firstCoordinate) { firstCoordinate = c; }
                            if (c.TS != lastCoordinate.TS) {
                                var speed = Convertor.toSpeedFull(
								(c.DFS - lastCoordinate.DFS) / ((c.TS - lastCoordinate.TS) / 1000),
								xms
							);
                                var avgSpeed = Convertor.toSpeedFull(
								(c.DFS - firstCoordinate.DFS) / ((c.TS - firstCoordinate.TS + 0.1) / 1000),
								xms
							);
                                if ((c.DFS - lastCoordinate.DFS < workoutGraph.DISTANCE_PER_POINT)
                            && (!(i == 0 && j == 0))) { ++count; continue; } // 30 meters
                                var altitude = Convertor.toAltitude(c.Alt, xms);
                                lastHeartrate = heartrate;
                                workoutGraph.data.Speed.PointsArray.push([distance, speed, lastCoordinate.index, c.index]);
                                workoutGraph.data.Alt.PointsArray.push([distance, altitude, lastCoordinate.index, c.index]);
                                workoutGraph.data.HR.PointsArray.push([distance, heartrate, lastCoordinate.index, c.index]);
                                var updateWhich = function(which, value, avg) {
                                    if (!which.YTicks.length) { which.YTicks = [9999, -9999, 0]; }
                                    which.YTicks[0] = Math.min(which.YTicks[0], value);
                                    which.YTicks[1] = avg;
                                    which.YTicks[2] = Math.max(which.YTicks[2], value);
                                }
                                updateWhich(workoutGraph.data.Speed, speed, avgSpeed);
                                updateWhich(workoutGraph.data.Alt, altitude);
                                updateWhich(workoutGraph.data.HR, heartrate, sumHeartRate / count);
                            }
                            lastCoordinate = c;
                        }
                    }
                    ++count;
                }
            }
            if (map[i].IsPause) {
                var last = map[i].Coordinates.length - 1;
                if (last > 0) {
                    var d1 = Convertor.toDistanceKM(map[i].Coordinates[0].DFS, xms);
                    var d2 = Convertor.toDistanceKM(map[i].Coordinates[last].DFS, xms);
                    workoutGraph.data.Speed.markings.push({ xaxis: { from: d1, to: d2} });
                }
            }
        }
        workoutGraph.data.Alt.YTicks[1] = (workoutGraph.data.Alt.YTicks[0] + workoutGraph.data.Alt.YTicks[2]) / 2.0;

    },
    drawJSON: function(data) {
        //workoutGraph.data = null;
        //workoutGraph.data = data.graph;
        workoutGraph.makeDataFromMap(data);
        workoutGraph.draw();
    },
    // "" missing.
    tickFormXAxis: function(val, axis) {
        return (Math.round(val * 100) / 100) + " " + Convertor.DISTANCE_KM[$("#ms").val()];
    },

    tickFormYAxis: function(val, axis) {
        if (val > 10) return Math.round(val);
        else { return (Math.round(val * 10) / 10).toFixed(1); }
    },
    hoverCallBack: function(startPointIndex, endPointIndex) {
    },
    init: function() {
        $("#graph").bind("plothover", function(event, pos, item) {
            if (!item) {
                if (pos.x < 0) { pos.x = 0; }
                var points = workoutGraph.data.Speed.PointsArray;
                if (!(pos.x < 0 || pos.x >= 0)) { pos.x = points[points.length - 1][0] / 2.0; }
                var k = Math.floor(points.length / (points[points.length - 1][0] - points[0][0]) * (pos.x - points[0][0]));

                var oldDist = 99999;
                while (points[k] && points[k][0] < pos.x) {
                    oldDist = Math.abs(points[k][0] - pos.x);
                    ++k;
                }
                --k;
                while (points[k] && points[k][0] > pos.x) {
                    oldDist = Math.abs(points[k][0] - pos.x);
                    --k;
                }
                if (k >= points.length) { k = points.length - 1; }
                if (k < 0) { k = 0; }
                item = { dataIndex: k, pageX: pos.pageX, pageY: pos.pageY, series: { label: "vel" }, notooltip: true };
            }
            if (item /*&& item.dataIndex != workoutGraph.oldHoverItem*/) {


                var pSi = workoutGraph.data.Speed.PointsArray[item.dataIndex][2];
                var pEi = workoutGraph.data.Speed.PointsArray[item.dataIndex][3];
                var pVal = workoutGraph.data.Speed.PointsArray[item.dataIndex][1];
                var pValAlt = workoutGraph.data.Alt.PointsArray[item.dataIndex][1];
                if (workoutGraph.data.HR.PointsArray.length > 0) {
                    var pValHR = workoutGraph.data.HR.PointsArray[item.dataIndex][1];
                }
                var pAtDistance = workoutGraph.data.Speed.PointsArray[item.dataIndex][0];
                var tooltiptext = "";
                if (item.series.label == "Vel") {
                    tooltipText = pVal.toFixed(1) + " " + Convertor.SPEED[$("#ms").val()] + " / "
                                + Convertor.toPaceString(pVal, $("#ms").val());
                }
                else if (item.series.label == "Alt") {
                    tooltipText = Math.round(pValAlt) + " " + Convertor.ALTITUDE[$("#ms").val()]
                }
                else if (item.series.label == "HR") {
                    tooltipText = Math.round(pValHR) + " bpm";
                }
                if (!item.notooltip && item.dataIndex != workoutGraph.oldHoverItem) {
                    $("#tooltip").remove();
                    workoutGraph.oldHoverItem = item.dataIndex;
                    showTooltip(item.pageX - 10, item.pageY - 40,
                            tooltipText + "<br /> at "
                            + Math.round(pAtDistance * 100) / 100 + " " + Convertor.DISTANCE_KM[$("#ms").val()]
                        );

                }
                else if (item.notooltip) {
                    $("#tooltip").remove();
                    workoutGraph.oldHoverItem = null;
                }
                workoutGraph.hoverCallBack(pSi, pEi);
            }
            else if (!item) {
                $("#tooltip").remove();
            }
        });
        $("#graph").bind("plotselected", function(event, ranges) {
            workoutGraph.makeDataFromMap(null, ranges.xaxis.from, ranges.xaxis.to);
            workoutGraph.draw();
        });
        $("#graph").bind("dblclick", function(event) {
            workoutGraph.makeDataFromMap();
            workoutGraph.draw();
        });
    }
}

$(workoutGraph.init());