jhanink
10/2/2013 - 4:59 PM

mainReportDashboardController.js

controllers.controller( 'ReportDashboardCtrl', ['$scope', '$rootScope', '$http', '$filter', '$timeout', '$location', '$dialog', 'MacAppUtils', 'MacCategoriesUtils', 'KeyMetricsGoalService', 'PrefsService', function ($scope, $rootScope, $http, $filter, $timeout, $location, $dialog, MacAppUtils, MacCategoriesUtils, KeyMetricsGoalService, PrefsService)
{
    gLog.noop("should have prefs here", $scope.prefs);

    $scope.appUtils = MacAppUtils;

    var mls = $filter('mls');

    $scope.maps =
    {
        KEY_METRICS_TYPE_MAP: {'clicks': 'Clicks','cost':'Cost','cpc':'CPC','cos':'COS','cts':'CTS','orders':'Orders','sales':'Sales'},
        TREND_METRICS_NAME_MAP: {'totalClicks': 'clicks','totalCost':'cost','cpc':'cpc','cos':'cos','cts':'cts','totalOrders':'orders','totalSales':'sales'},
        KEY_METRICS_FORMAT_MAP: {'clicks': 'number','cost':'currency','cpc':'currency','cos':'percent','cts':'percent','orders':'number','sales':'currency'},
        TREND_METRICS_TO_CHART_INSTANCE_MAP: {}, // gets set on init().
        METRICS_DEFAULT_ORDER: ['clicks','cost','cpc','cos','cts','orders','sales'],
        METRICS_DEFAULT_ORDER_ROI_DISABLED: ['clicks','cost','cpc']
    };

    $scope.updateChartInstanceMap = function() {
        // don't expose COST or COS for revshare merchants
        var map = {};
        var i = 0;

        for (var c=0;c<$scope.rdState.charts.length;c++) {
            var chart = $scope.rdState.charts[c];
            if (chart.metricType == 'cost' || chart.metricType == 'cos') {
                if (!$scope.gState.user.isRevshareMerchant) {
                    map[chart.metricType] = i++;
                }
            } else {
                map[chart.metricType] = i++;
            }
        }

        gLog.noop("TREND_METRICS_TO_CHART_INSTANCE_MAP", map);
        $scope.maps.TREND_METRICS_TO_CHART_INSTANCE_MAP = map;
    };

    $scope.maps.MONTHS_MAPS = (function() {
        var obj = {};
        for (var lang in Const.Months) {
            var arr = Const.Months[lang];
            obj[lang] = {};
            for (var i=0;i< arr.length;i++) {
                obj[lang][arr[i]] = i;
            }
        }
        return obj;
    })();

    // data
    $scope.rdData =
    {
        categories:[],
        keyMetrics: {},
        trendMetrics: {}
    };

    // state
    $scope.rdState = {
        charts:[],
        goals:{'cts':{isValid:true, isEditing:false},'cos':{isValid:true, isEditing:false}},
        templates: {
            keyMetrics: 'app/partials/blank.html',
            trendMetrics: 'app/partials/blank.html'
        },
        reverseMonthLookup: {},
        trendMetricsShowLastYear: false,
        isShowActualLegend: false,
        showLastYearLegend: false,
        canShowGoalLegend: false,
        currentlyMaximizedChart: Const.Value.NONE,
        keyMetricsReady: false,
        trendMetricsReady:false,
        currentTrendMetricsType:null
    };



    // keyMetricsDateRange: MTD | L30D | TODAY
    // trendMetricsDateRange: DAILY | WEEKLY | MONTHLY
    $scope.queryFilters =
    {
        categoryId:'0', keyMetricsDateRange:Const.L30D, trendMetricsDateRange:Const.DAILY
    };

    $scope.rdHelper =
    {
        getKeyMetricsClassName: function() {
            return $scope.isRoiEnabled()?'gHorizontalList':'gHorizontalListHalfWidth';
        },
        getNonEnglishCategoryElementStyle: function() {
            return MacAppUtils.isEnglishLanguage()?{}:{'padding-right':'40px'};
        },
        getInstanceForMetric: function (metricType) {
            return $scope.maps.TREND_METRICS_TO_CHART_INSTANCE_MAP[metricType];
        },
        isShowYearOverYear: function() {
            return $scope.rdState.trendMetricsShowLastYear;
        },
        isActiveKeyMetricsDateRange: function(dateRangeKey) {
            return $scope.queryFilters.keyMetricsDateRange === dateRangeKey;
        },
        setActiveKeyMetricsDateRange: function (dateRangeKey) {
            $scope.queryFilters.keyMetricsDateRange = dateRangeKey;
            $scope.loadKeyMetrics();
        },
        isShowGoalLegend: function() {
            var maximizedChart = $scope.rdState.currentlyMaximizedChart;
            return $scope.rdState.canShowGoalLegend
                && (maximizedChart === Const.Value.NONE || maximizedChart === Const.Metrics.CTS || maximizedChart === Const.Metrics.COS);
        },
        isShowActualLegend: function() {
            return this.isShowGoalLegend() || this.isShowYearOverYear();
        },
        isShowLastYearLegend: function() {
            return $scope.rdState.showLastYearLegend;
        },
        setTrendMetricsDateRange: function (dateRange) {
            if ($scope.queryFilters.trendMetricsDateRange === dateRange ) {return;}
            $scope.queryFilters.trendMetricsDateRange = dateRange;
            this.reloadAllCharts();
        },
        isTrendView: function(frequency) {
            return $scope.queryFilters.trendMetricsDateRange == frequency;
        },
        getKeyMetricDataFor: function(metricType) {
            var value;
            var metricFormat = $scope.maps.KEY_METRICS_FORMAT_MAP[metricType];
            if ($scope.rdData && $scope.rdData.keyMetrics && $scope.rdData.keyMetrics[metricType]) {
                value = $scope.rdData.keyMetrics[metricType].metricValue;
                if (typeof(value)=="undefined") {
                    return "--";
                }
            } else {
                value = 0;
            }
            if (metricFormat === 'currency') {
                return MacAppUtils.formatCurrencyDataValue(value);
            } else if (metricFormat === 'percent') {
                return MacAppUtils.formatFloatTwoDecimals(value) + "%";
            }
            return MacAppUtils.formatIntValue(value);
        },
        getDisplayMetricName: function(metricType) {
            return MacAppUtils.getMetricDisplayName(metricType, 'mls');
        },
        setMetricDataForChart: function (/*raw metric type name*/metricType, /*trend metrics raw data*/metricData) {
            // put local chart data into scope so it can be retrieved in directive scope to build highcharts config
            this.buildLocalDataForHighChartsConfig(metricType, metricData);
            // trigger redraw
            var localMetricName = $scope.maps.TREND_METRICS_NAME_MAP[metricType];
            var chartState = $scope.rdState.charts[$scope.maps.TREND_METRICS_TO_CHART_INSTANCE_MAP[localMetricName]];
            chartState.forceRedrawChart = Math.random();
        },
        buildLocalDataForHighChartsConfig: function(/*raw metric type name*/metricType, /*trend metrics raw data*/metricData) {
            var localMetricName = $scope.maps.TREND_METRICS_NAME_MAP[metricType];

            var metricDisplayName = this.getDisplayMetricName(metricType);
            var chartState = $scope.rdState.charts[$scope.maps.TREND_METRICS_TO_CHART_INSTANCE_MAP[localMetricName]];
            var isShowLastYear = $scope.rdHelper.isShowYearOverYear();

            gLog.noop('setMetricDataForChart['+chartState+']', metricData[metricType]);

            // if no data, show DATA UNAVAILABLE
            if (!metricData) {
                // this will be picked up by the watcher in the
                chartState.hasData = false;
                chartState.forceRedrawChart = Math.random();
                return;
            }

            // if we get here, we have data
            chartState.hasData = true;
            var loadedMetricData = metricData[metricType];
            gLog.noop('metricData ['+metricType+']', loadedMetricData);

            // we need to know clicks data to process other metrics
            var clicksMetricData = metricData[ Const.Metrics.TOTAL_CLICKS ];
            var salesMetricData = metricData[ Const.Metrics.TOTAL_SALES ];

            gLog.noop('metricData [totalClicks]', clicksMetricData);

            var localData = $scope.rdData.trendMetrics[localMetricName] = {
                currentYearSeries:[],
                lastYearSeries:[],
                xAxisLabels:[],
                weeklyMap:{},
                hasLastYearSeries:false,
                yMin:9999999,
                yMax:0,
                yMid:0,
                goalValue:-1000000,
                tableData: [],
                getLastYearSeries: function() {
                    if (isShowLastYear) {
                        return this.lastYearSeries;
                    }
                    return [];
                },
                canShowLastYear: function() {
                    return $scope.rdHelper.isShowYearOverYear() && localData.hasLastYearSeries;
                },
                goalValueConfig:null,
                tooltipConfig:{
                    borderWidth:1,
                    borderRadius:1,
                    borderColor:'#CCC',
                    backgroundColor:'#FFF',
                    shadow:false,
                    crosshairs:false,
                    valueDecimals:(localMetricName === 'Clicks' || localMetricName ==='Orders')?0:2,
                    shared:true
                }
            };

            var counter;
            // check if last year data exists
            for (counter=0; counter<loadedMetricData.length; counter++) {
                if (loadedMetricData[counter]['lastYearsValue']) {
                    localData.hasLastYearSeries = true;
                }
            }

            // used in ReportTableComponentCtrl - monthDateColumnSortFunction
            $scope.rdState.reverseMonthLookup = {};

            for (counter=0; counter<loadedMetricData.length; counter++)
            {
                var curYearValue = loadedMetricData[counter]['currentYearsValue'];
                var curYearValueRaw = loadedMetricData[counter]['currentYearsValue'];
                if (!curYearValue) {
                    curYearValue = 0;
                }
                var lastYearValue = loadedMetricData[counter]['lastYearsValue'];
                if (localData.hasLastYearSeries && !lastYearValue) {
                    lastYearValue = 0;
                }
                var yearOverYear = loadedMetricData[counter]['yearOverYear'];

                // get the smallest and largest to produce a graphing range for optimal scale
                localData.yMin = Math.min(localData.yMin, curYearValue);
                localData.yMax = Math.max(localData.yMax, curYearValue);

                // if showing last year, account for those values...
                if (localData.canShowLastYear()) {
                    localData.yMin = Math.min(localData.yMin, lastYearValue);
                    localData.yMax = Math.max(localData.yMax, lastYearValue);
                }

                // handle date formatting
                // TODO: (jh) formatting should be moved to the associated directive
                var dateISO = loadedMetricData[counter]['date'];
                var lastYear = MacAppUtils.dateFunctions.getPreviousYear(dateISO);
                var dateParts = MacAppUtils.dateFunctions.getDateParts(dateISO);

                var formattedMonth = MacAppUtils.dateFunctions.formatMonthShort(dateISO);
                var formattedMonthDay = MacAppUtils.dateFunctions.formatMonthDay(dateISO);
                var formattedMonthYear = MacAppUtils.dateFunctions.formatMonthYear(dateISO);
                var formattedMonthYearLastYear = MacAppUtils.dateFunctions.formatMonthYear(lastYear);
                var formattedDateCurrentYear = MacAppUtils.dateFunctions.formatMonthDayYear(dateISO);
                var formattedDateLastYear = MacAppUtils.dateFunctions.formatMonthDayYear(lastYear);
                var formattedDateWithSlashes = MacAppUtils.dateFunctions.formatStandard(dateISO);

                // build a date-range to display in graph hover weekly view.
                // This ONLY applies when in single current year view
                var weekBeginDate = loadedMetricData[counter]['date'];
                var weekEndDate = MacAppUtils.dateFunctions.addDays(weekBeginDate, 6);
                var dateRangeString = MacAppUtils.dateFunctions.formatMonthDayYear(weekBeginDate) + ' - '
                    + MacAppUtils.dateFunctions.formatMonthDayYear(weekEndDate);

                // X-Axis labels
                var formattedDateForTrendMetricsWeeklyView = mls('date.week') + loadedMetricData[counter]['weekNo'];

                if ($scope.rdHelper.isTrendView(Const.WEEKLY)) {
                    localData.xAxisLabels.push(formattedDateForTrendMetricsWeeklyView);
                    localData.weeklyMap[formattedDateForTrendMetricsWeeklyView] = {
                        year: loadedMetricData[counter]['weekYear']
                    };
                } else if ($scope.rdHelper.isTrendView(Const.MONTHLY)) {
                    localData.xAxisLabels.push(formattedMonth);
                } else { // 'DAILY'
                    localData.xAxisLabels.push(formattedMonthDay);
                }

                // Point Values
                if ($scope.rdHelper.isTrendView(Const.WEEKLY)) {
                    if (!localData.canShowLastYear()) {
                        localData.currentYearSeries.push([formattedDateForTrendMetricsWeeklyView + '<br/><span style="font:12px Helvetica Neue,Helvetica,Arial ">'+dateRangeString+'</span>',(curYearValue?curYearValue:0)]);
                    } else {
                        localData.currentYearSeries.push([formattedDateForTrendMetricsWeeklyView,(curYearValue?curYearValue:0)]);
                    }
                } else if ($scope.rdHelper.isTrendView(Const.MONTHLY)) {
                    localData.currentYearSeries.push([formattedMonthYear,(curYearValue?curYearValue:0)]);
                } else { // 'DAILY'
                    localData.currentYearSeries.push([formattedDateCurrentYear,(curYearValue?curYearValue:0)]);
                }

                if (localData.canShowLastYear()) {
                    if ($scope.rdHelper.isTrendView(Const.WEEKLY)) {
                        localData.lastYearSeries.push([formattedDateForTrendMetricsWeeklyView,(lastYearValue?lastYearValue:0)]);
                    } else if ($scope.rdHelper.isTrendView(Const.MONTHLY)) {
                        localData.lastYearSeries.push([formattedMonthYearLastYear,(lastYearValue?lastYearValue:0)]);
                    } else { // 'DAILY'
                        localData.lastYearSeries.push([formattedDateLastYear,(lastYearValue?lastYearValue:0)]);
                    }
                }

                // data for tabular view
                var tempTableDatum = {};
                if ($scope.rdHelper.isTrendView(Const.DAILY)) {
                    tempTableDatum = {'date':dateParts.dateString};
                } else if ($scope.rdHelper.isTrendView(Const.WEEKLY)) {
                    tempTableDatum = {'date':dateParts.dateString,'week':formattedDateForTrendMetricsWeeklyView};
                } else if ($scope.rdHelper.isTrendView(Const.MONTHLY)) {
                    tempTableDatum = {'date':formattedMonthYear};
                    $scope.rdState.reverseMonthLookup[formattedMonthYear] = MacAppUtils.numberFunctions.numericContents(dateISO);
                }

                tempTableDatum['currentYear'] = MacAppUtils.formatMetricDataValue(localMetricName,curYearValueRaw);
                tempTableDatum['YoY'] = MacAppUtils.formatYoYValueForMetric(metricType, yearOverYear);

                localData.tableData.unshift( tempTableDatum );
            }

            if ($scope.kmGoals.hasGoal(localMetricName))
            {
                localData.goalValueConfig = {
                    value: $scope.kmGoals.getGoalValue(localMetricName),
                    width: 1,
                    color: '#F5Af02',
                    zIndex:1
                };
            }

            // local inline helper function
            var formatHeaderDateValue = function(pointKey)
            {
                if ($scope.rdHelper.isTrendView(Const.DAILY) || $scope.rdHelper.isTrendView(Const.WEEKLY)) {
                    return pointKey.split(",")[0];
                } else {
                    return pointKey.split(" ")[0];
                }
            };

            // local inline helper function
            var formatPointValue = function(yValue)
            {
                if (localMetricName === Const.Metrics.CLICKS || localMetricName === Const.Metrics.ORDERS) {
                    return $filter('number')(yValue, 0);
                } else if (localMetricName === Const.Metrics.COST || localMetricName === Const.Metrics.CPC || localMetricName === Const.Metrics.SALES) {
                    return $filter('currency')(yValue);
                } else if (localMetricName === Const.Metrics.COS || localMetricName === Const.Metrics.CTS) {
                    return $filter('number')(yValue, 2) + '%';
                }
            };
            // local inline helper function
            var getPointKeyYearLabel = function(point, isThisYear)
            {
                var pointKey = point.key;
                if ($scope.rdHelper.isTrendView(Const.WEEKLY)) {
                    yearValue = localData.weeklyMap[pointKey].year;
                } else if ($scope.rdHelper.isTrendView(Const.DAILY)){
                    yearValue = pointKey.split(", ")[1];
                } else if ($scope.rdHelper.isTrendView(Const.MONTHLY)) {
                    yearValue = pointKey.split(" ")[1];
                }

                if (!isThisYear && $scope.rdHelper.isTrendView(Const.WEEKLY)) {
                    return parseInt(yearValue) -1;
                }
                return yearValue;
            };

            // graph hover tooltip config
            if (localData.canShowLastYear())
            {
                localData.tooltipConfig.formatter = function() {
                    var pointA = this.points[0];
                    var pointB = this.points[1];

                    return '<span style="font:13px Helvetica Neue,Helvetica,Arial;font-weight:bold;">' + metricDisplayName + ' </span><span style="font:12px Helvetica Neue,Helvetica,Arial;color:gray">( ' + formatHeaderDateValue(pointA.key)+ ' )</span>'
                        + "<br/>"
                        + '<span style="font:12px Helvetica Neue,Helvetica,Arial;color:'+pointA.series.color+'">' + getPointKeyYearLabel(pointA, true) + '</span>' + ": "
                        + '<span style="font:12px Helvetica Neue,Helvetica,Arial;font-weight:bold">'+ formatPointValue(pointA.y) +'</span>'
                        + "<br/>"
                        + '<span style="font:12px Helvetica Neue,Helvetica,Arial;color:'+pointB.series.color+'">' + getPointKeyYearLabel(pointB, false) +'</span>'+ ": "
                        + '<span style="font:12px Helvetica Neue,Helvetica,Arial;font-weight:bold">'+ formatPointValue(pointB.y) +'</span>';
                };
            }
            else
            {
                localData.tooltipConfig.formatter = function() {
                    var point = this.points[0];
                    return '<span style="font:12px Helvetica Neue,Helvetica,Arial;">'+point.key+'</span>'
                        + "<br/>"
                        + '<span style="font:12px Helvetica Neue,Helvetica,Arial;color:'+point.series.color+'">'+metricDisplayName+'</span>: '
                        +'<span style="font:12px Helvetica Neue,Helvetica,Arial;font-weight:bold">'+formatPointValue(point.y)+'</span>';
                };
            }

            // show/hide legends
            if (localData.goalValueConfig && localData.goalValueConfig.value > 0 ) {
                $scope.rdState.canShowGoalLegend = true;
            }

            if ($scope.rdHelper.isShowYearOverYear() ) {
                $scope.rdState.showLastYearLegend = true;
            }

            if ($scope.rdState.canShowGoalLegend || $scope.rdHelper.isShowYearOverYear() ) {
                $scope.rdState.isShowActualLegend = true;
            }

            localData.yMid = (localData.yMax + localData.yMin)/2;

            gLog.noop('tableData for metric ('+localMetricName+')', localData.tableData);
            if ($scope.kmGoals.hasGoal(localMetricName)) {
                gLog.noop('metrics goal for ('+localMetricName+') ['+localData.goalValueConfig.value+']');
            }
            gLog.noop('('+localMetricName+') yMin ('+localData.yMin+') yMax ('+localData.yMax+') yMid ('+localData.yMid+')');
            gLog.noop('setMetricDataForChart ['+metricType+'] currentYearSeries', localData.currentYearSeries);

            localData.xAxisLabelStep = (function() {
                if ($scope.rdHelper.isTrendView(Const.DAILY)) {
                    return 7;
                } else if ($scope.rdHelper.isTrendView(Const.MONTHLY)) {
                    return 2;
                } else {
                    return 7;
                }
            })();
            return localData;
        },
        reloadAllCharts: function(metricType) {
            $scope.rdState.isLoadingTrendMetrics = true;
            $scope.loadTrendMetrics(metricType);
        },
        forceRedrawAllTables: function() {
            var state = $scope.rdState;
            for (var i=0;i<state.charts.length;i++) {
                var chartState = state.charts[i];
                if (chartState.chartType === Const.Charts.Type.TABLE) {
                    chartState.forceRedrawChart = Math.random();
                }
            }
        }
    };


    $scope.init = function()
    {
        var chartsOrder = PrefsService.get(Const.Prefs.CHARTS_ORDER);

        // handle bi-directional changes in roiEnabled status
        // affects the dashboard metrics displayed
        if (chartsOrder) {
            if ($scope.isRoiEnabled() && chartsOrder.length < $scope.maps.METRICS_DEFAULT_ORDER.length) {
                chartsOrder = $scope.maps.METRICS_DEFAULT_ORDER
                gLog.debug("roi has been enabled. set to roi-enabled default and update prefs.", chartsOrder);
                PrefsService.set(Const.Prefs.CHARTS_ORDER, chartsOrder);
            } else if(!$scope.isRoiEnabled() && chartsOrder.length > $scope.maps.METRICS_DEFAULT_ORDER_ROI_DISABLED.length) {
                chartsOrder = $scope.maps.METRICS_DEFAULT_ORDER_ROI_DISABLED
                gLog.debug("roi has been disabled. set to roi-disabled default and update prefs.", chartsOrder);
                PrefsService.set(Const.Prefs.CHARTS_ORDER, chartsOrder);
            } else {
                gLog.debug("charts order set from saved preferences", chartsOrder);
            }
        } else {
            if ($scope.isRoiEnabled()) {
                chartsOrder = $scope.maps.METRICS_DEFAULT_ORDER;
            } else {
                chartsOrder = $scope.maps.METRICS_DEFAULT_ORDER_ROI_DISABLED;
            }
            gLog.debug("no prefs for charts order. set to default", chartsOrder);
        }

        // NOTE: this is used for trend metrics and will be sorted using chartsOrder.
        $scope.rdState.charts = [];
        // NOTE: this order is important and is used for the key metrics section
        $scope.rdState.keyMetricsList = [];

        var charts = {};
        charts[Const.Metrics.CLICKS] = {metricType:Const.Metrics.CLICKS, chartType:Const.Charts.Type.GRAPH, hasData: true};
        $scope.rdState.keyMetricsList.push(charts[Const.Metrics.CLICKS]);

        // hide COST from non revshare merchants
        if (!$scope.gState.user.isRevshareMerchant) {
            charts[Const.Metrics.COST] = {metricType:Const.Metrics.COST, chartType:Const.Charts.Type.GRAPH, hasData: true};
            $scope.rdState.keyMetricsList.push(charts[Const.Metrics.COST]);
        }

        charts[Const.Metrics.CPC] = {metricType:Const.Metrics.CPC, chartType:Const.Charts.Type.GRAPH, hasData: true};
        $scope.rdState.keyMetricsList.push(charts[Const.Metrics.CPC]);

        if ($scope.isRoiEnabled()) {

            // hide COS from non revshare merchants
            if (!$scope.gState.user.isRevshareMerchant) {
                charts[Const.Metrics.COS] = {metricType:Const.Metrics.COS, chartType:Const.Charts.Type.GRAPH, hasData: true};
                $scope.rdState.keyMetricsList.push(charts[Const.Metrics.COS]);
            }
            charts[Const.Metrics.CTS] = {metricType:Const.Metrics.CTS, chartType:Const.Charts.Type.GRAPH, hasData: true};
            $scope.rdState.keyMetricsList.push(charts[Const.Metrics.CTS]);
            charts[Const.Metrics.ORDERS] = {metricType:Const.Metrics.ORDERS, chartType:Const.Charts.Type.GRAPH, hasData: true};
            $scope.rdState.keyMetricsList.push(charts[Const.Metrics.ORDERS]);
            charts[Const.Metrics.SALES] = {metricType:Const.Metrics.SALES, chartType:Const.Charts.Type.GRAPH, hasData: true};
            $scope.rdState.keyMetricsList.push(charts[Const.Metrics.SALES]);
        }


        for (var i=0;i<chartsOrder.length;i++) {
            var chart = chartsOrder[i];
            if (charts[chart]) {
                $scope.rdState.charts.push(charts[chart]);
            }
        }

        gLog.debug("rdState.charts", $scope.rdState.charts);

        $scope.updateChartInstanceMap();

        // load data
        $timeout(function() {
            $scope.loadCategories();
            $scope.loadKeyMetrics();
            $scope.loadTrendMetrics();
        },1);

        $scope.setActiveMenuState('Reports', 'Dashboard');
    };


    $scope.loadCategories = function()
    {
        MacCategoriesUtils.loadCategories(function (data) {
            $scope.rdData.categories = data;
            $scope.rdData.categories.unshift({id:'0', name:'-- '+ mls('g.all')+ ' --'});
        });
    };


    $scope.loadKeyMetrics = function()
    {
        var url = '/proxy/v1/accounts/merchantId/reports/daily/metrics/summary?period='+$scope.queryFilters.keyMetricsDateRange+'&type=json&r='+MacAppUtils.getNextRandom()+"&callingContext="+$location.path();
        gLog.debug('loadKeyMetrics url', url);
        var startTime = new Date().getTime();
        $http.get(url).success( function(data)
        {
            var deltaTime = new Date().getTime() - startTime;
            gLog.debug('KeyMetrics Data ('+deltaTime+' ms)', data.campaignSummary);

            $scope.rdData.keyMetrics = data.campaignSummary;

            // stateful Goals Service Object.
            $scope.kmGoals = KeyMetricsGoalService.newInstance($scope, $scope.rdData, /*kmData property*/'keyMetrics', $scope.rdState, 'goals', $scope.rdHelper.reloadAllCharts);

            if ($scope.isRoiEnabled()) {
                $scope.rdState.goals = {
                    cts: {isEditing:false, value:MacAppUtils.formatFloatTwoDecimals($scope.rdData.keyMetrics[Const.Metrics.CTS].goalValue)}
                };

                if (!$scope.isRevshareMerchant()) {
                    $scope.rdState.goals[Const.Metrics.COS] = {isEditing:false, value:MacAppUtils.formatFloatTwoDecimals($scope.rdData.keyMetrics[Const.Metrics.COS].goalValue)};
                }
            }
            $scope.rdState.templates.keyMetrics = 'app/partials/reports/keyMetrics.html';

            // loading keymetrics will only trigger charts update once.
            if (!$scope.rdState.keyMetricsReady) {
                $scope.rdState.keyMetricsReady = true;
                $scope.setupChartsWhenReady();
            }
        });
    };


    $scope.loadTrendMetrics = function(metricType)
    {
        var categoryParam = ($scope.queryFilters.categoryId=='0')?'':'&categoryId='+ $scope.queryFilters.categoryId;
        var url = '/proxy/v1/accounts/merchantId/reports/categories/metrics/list?freq='+$scope.queryFilters.trendMetricsDateRange+categoryParam+'&type=json&r='+MacAppUtils.getNextRandom()+"&callingContext="+$location.path();
        gLog.debug('loadTrendMetrics url', url);
        var startTime = new Date().getTime();

        return $http.get(url).success( function(data)
        {
            // this will get set later
            $scope.rdState.isShowActualLegend = false;
            $scope.rdState.canShowGoalLegend = false;
            $scope.rdState.showLastYearLegend = false;

            $scope.rdState.isLoadingTrendMetrics = false;

            var deltaTime = new Date().getTime() - startTime;
            gLog.debug('TrendMetrics Data ('+deltaTime+' ms)', data.metrics);

            // prepare visualization
            $scope.rdData.trendMetricsRawData = data.metrics;

            $scope.rdState.trendMetricsReady = true;
            $scope.rdState.currentTrendMetricsType = metricType;
            $scope.setupChartsWhenReady();

        });
    };

    // this is a collaboration routine between keymetrics load and trendmetrics load.
    $scope.setupChartsWhenReady = function() {

        if (!$scope.rdState.keyMetricsReady || !$scope.rdState.trendMetricsReady) {
            return;
        }

        var metricType = $scope.rdState.currentTrendMetricsType;
        var metricsData = $scope.rdData.trendMetricsRawData;

        if (Const.Metrics.COS === metricType)
        {
            if (!$scope.gState.user.isRevshareMerchant) {
                $scope.rdHelper.setMetricDataForChart(Const.Metrics.COS, metricsData);
            }
        }
        else if (Const.Metrics.CTS === metricType)
        {
            $scope.rdHelper.setMetricDataForChart(Const.Metrics.CTS, metricsData);
        }
        else {
            $scope.rdHelper.setMetricDataForChart(Const.Metrics.TOTAL_CLICKS, metricsData);
            if (!$scope.gState.user.isRevshareMerchant) {
                $scope.rdHelper.setMetricDataForChart(Const.Metrics.TOTAL_COST, metricsData);
            }
            $scope.rdHelper.setMetricDataForChart(Const.Metrics.CPC, metricsData);
            if ($scope.isRoiEnabled()) {
                if (!$scope.gState.user.isRevshareMerchant) {
                    $scope.rdHelper.setMetricDataForChart(Const.Metrics.COS, metricsData);
                }
                $scope.rdHelper.setMetricDataForChart(Const.Metrics.CTS, metricsData);
                $scope.rdHelper.setMetricDataForChart(Const.Metrics.TOTAL_ORDERS, metricsData);
                $scope.rdHelper.setMetricDataForChart(Const.Metrics.TOTAL_SALES, metricsData);
            }
        }
    };

}]);