(function () {
    var $injector = angular.injector(['ng']);
    $injector.invoke(function ($http, $rootScope) {
        $rootScope.$apply(function () {
            $http.post('/rest/user/login', {
            }).then(function successCallback(res) {
                angular.module("app").constant("USER", res.data.user);
                angular.bootstrap(document, ['app']);
            });
        });
    });
})();
var app = angular.module('app', ['ui.bootstrap', 'amChartsDirective', 'ngRoute', 'pascalprecht.translate']);
app.filter('html', ['$sce', function ($sce) {
    return function (text) {
        return $sce.trustAsHtml(text);
    };
}]);
app.filter('useFilter', function ($filter) {
    return function () {
        if (typeof arguments[0] == 'undefined') {
            return '';
        };
        var filterName = [].splice.call(arguments, 1, 1)[0];
        return $filter(filterName).apply(null, arguments);
    };
})
app.filter('useFilter2', function ($filter) {
    return function () {
        if (typeof arguments[0] == 'undefined') {
            return '--';
        };
        var filterName = [].splice.call(arguments, 1, 1)[0];
        return $filter(filterName).apply(null, arguments);
    };
})
app.filter('exists', function ($filter) {
    return function (v) {
        if (v === 0 || v == '0.00') {
            return '--';
        }
        if (!v) {
            return '';
        };
        return v;
    };
})
app.filter('secondsToHHmmss', function ($filter) {
    return function (seconds) {
        if (seconds) {
            return $filter('date')(new Date(0, 0, 0).setSeconds(seconds), 'HH:mm:ss');
        }
        return '00:00:00';
    };
})
app.filter('mcdate', function ($filter) {
    return function (datum) {
        var d = new Date(datum);
        return d.getDate() + '/' + (d.getMonth() + 1) + '/' + d.getFullYear() + ' - ' + d.getHours() + ':' + d.getMinutes();
    };
})
app.filter('minzero', function ($filter) {
    return function (int) {
        return (int < 0) ? 0 : int;
    };
})
app.filter('path', function () {
    return function (url) {
        return url = url.substring(url.indexOf("/"));
    };
})
app.filter('truefalse', function () {
    return function (b) {
        return (b) ? 'Yes' : 'No';
    };
})
app.filter('string', function () {
    return function (b) {
        return b;
    };
})
app.filter('objToArray', function () {
    return function (input, attribute) {
        if (!angular.isObject(input)) return input;
        var array = [];
        for (var objectKey in input) {
            array.push(input[objectKey]);
        }
        return array;
    }
})
app.factory('h', function ($rootScope, $http) {
    return {
        siteId: function () {
            if ($rootScope.user.site) {
                if ($rootScope.user.site._id) {
                    return $rootScope.user.site._id.$oid;
                }
            }
        },
        login: function (cb) {
            $http.post('/rest/user/login', {
            }).then(function successCallback(res) {
                $rootScope.user = res.data.user;
                cb();
            });
        },
        colors: function () {
            return angular.extend([], ['#E91E63', '#3F51B5', '#00BCD4', '#8BC34A', '#FF9800', '#795548', '#607D8B', '#00CC00', '#0000CC', '#DDDDDD', '#999999', '#333333', '#990000'], $rootScope.user.reseller.config.chartcolors)
        },
        metrics: function (key) {
            var allMetrics = {
                analytics: {
                    sessions: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
                    users: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
                    pageviews: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
                    pageviewsPerSession: { typefilter: 'number', filtercomparator: 2, 'datemerge': 'avg' },
                    avgSessionDuration: { typefilter: 'secondsToHHmmss', filtercomparator: 0, 'datemerge': 'avg' },
                    percentNewSessions: { typefilter: 'number', filtercomparator: 0, 'after': '%', 'datemerge': 'avg' },
                    bounceRate: { typefilter: 'number', filtercomparator: 0, 'after': '%', 'datemerge': 'avg', 'reversesign': true },
                    goalCompletionsAll: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
                    goalValueAll: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
                    goalConversionRateAll: { typefilter: 'number', filtercomparator: 0, 'after': '%', 'datemerge': 'avg' },
                    goalAbandonRateAll: { typefilter: 'number', filtercomparator: 0, 'after': '%', 'datemerge': 'avg' },
                    uniquePageviews: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
                    avgTimeOnPage: { typefilter: 'secondsToHHmmss', filtercomparator: 0, 'datemerge': 'avg' },
                    entrances: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
                    exitRate: { typefilter: 'number', filtercomparator: 0, 'after': '%', 'datemerge': 'avg' },
                    pageValue: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
                    exits: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
                    ROAS: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'avg' },
                    costPerTransaction: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'avg' },
                    totalValue: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
                    adCost: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
                    CPC: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'avg' },
                    adClicks: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
                    transactions: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
                    uniquePurchases: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
                    totalValue: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
                    revenuePerTransaction: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'avg' },
                    itemQuantity: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
                    itemsPerPurchase: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'avg' },
                },
                copernica: {
                    Placeholder: { name: '', typefilter: 'number', filtercomparator: 0 },
                    subject: { name: 'Subject', typefilter: 'number', filtercomparator: 0 },
                    type: { name: 'Type', typefilter: 'string' },
                    destinations: { name: 'Destinations', typefilter: 'number', filtercomparator: 0 },
                    abuses: { name: 'Abuses', typefilter: 'number', filtercomparator: 0 },
                    clicks: { name: 'Clicks', typefilter: 'number', filtercomparator: 0 },
                    uniqueclicks: { name: 'Unique Clicks', typefilter: 'number', filtercomparator: 0 },
                    deliveries: { name: 'Deliveries', typefilter: 'number', filtercomparator: 0 },
                    errors: { name: 'Errors', typefilter: 'number', filtercomparator: 0 },
                    impressions: { name: 'Impressions', typefilter: 'number', filtercomparator: 0 },
                    uniqueimpressions: { name: 'Unique Impressions', typefilter: 'number', filtercomparator: 0 },
                    retries: { name: 'Retries', typefilter: 'number', filtercomparator: 0 },
                    unsubscribes: { name: 'Unsubscribes', typefilter: 'number', filtercomparator: 0 },
                },
                facebookads: {
                    clicks: { name: 'Klikken', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
                    impressions: { name: 'Impressies', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
                    cpc: { name: 'cpc', typefilter: 'number', filtercomparator: 2, 'before': '€', 'datemerge': 'avg' },
                    cpm: { name: 'cpm', typefilter: 'number', filtercomparator: 2, 'before': '€', 'datemerge': 'avg' },
                    ctr: { name: 'Ctr', typefilter: 'number', filtercomparator: 2, 'after': '%', 'datemerge': 'avg' },
                    Conversions: { name: 'Conversions', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
                    Cost: { name: 'Cost', typefilter: 'number', filtercomparator: 0, 'before': '€', 'datemerge': 'sum' },
                    CostPerConversion: { name: 'spend / conversie', typefilter: 'number', filtercomparator: 0, 'before': '€', 'datemerge': 'avg' },
                    ConversionRate: { name: 'Conversie ratio', typefilter: 'number', filtercomparator: 0, 'after': '%', 'datemerge': 'avg' },
                    AveragePosition: { name: 'Gemiddelde positie', typefilter: 'number', filtercomparator: 0, 'datemerge': 'avg' },
                    ConversionValue: { name: 'Totale conversiewaarde', typefilter: 'number', filtercomparator: 0, 'before': '€', 'datemerge': 'sum' },
                    relevance_score: { name: 'Relevantie Score', typefilter: 'number', filtercomparator: 0, hide: { 'panel': true }, 'datemerge': 'avg' },
                    spend: { name: 'Kosten', typefilter: 'number', filtercomparator: 2, 'before': '€', 'datemerge': 'sum' },
                },
                facebookinsights: {
                    fans: { name: 'Fans', typefilter: 'number', filtercomparator: 0 },
                    interacties: { name: 'Interactions', typefilter: 'number', filtercomparator: 0 },
                    bereik: { name: 'Bereik', typefilter: 'number', filtercomparator: 0 },
                },
                googlexads: {
                    Clicks: { name: 'Clicks', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
                    Impressions: { name: 'Impressions', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
                    Date: { name: 'Date', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
                    AverageCpc: { name: 'Avg cost / Click', typefilter: 'number', filtercomparator: 2, 'before': '€', 'datemerge': 'avg' },
                    Ctr: { name: 'Ctr', typefilter: 'number', filtercomparator: 0, 'after': '%', 'datemerge': 'avg' },
                    Conversions: { name: 'Conversions', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
                    Cost: { name: 'Cost', typefilter: 'number', filtercomparator: 2, 'before': '€', 'datemerge': 'sum' },
                    CostPerConversion: { name: 'Cost / conversion', typefilter: 'number', filtercomparator: 2, 'before': '€', 'datemerge': 'avg' },
                    ConversionRate: { name: 'Conversion rate', typefilter: 'number', filtercomparator: 0, 'after': '%', 'datemerge': 'avg' },
                    AbsoluteTopImpressionPercentage: { name: 'AbsoluteTopImpressionPercentage', typefilter: 'number', filtercomparator: 0, 'after': '%', 'datemerge': 'avg' },
                    ConversionValue: { name: 'Conversion value', typefilter: 'number', filtercomparator: 0, 'before': '€', 'datemerge': 'sum' },
                    SearchImpressionShare: { name: 'Zoekimpressie aandeel', typefilter: 'number', filtercomparator: 2, 'after': '%', 'datemerge': 'avg' },
                    SearchAbsoluteTopImpressionShare: { name: 'Top Positie', typefilter: 'number', filtercomparator: 2, 'after': '%', 'datemerge': 'avg' },
                    roas: { name: 'ROAS', typefilter: 'number', filtercomparator: 2, 'after': '%', 'datemerge': 'avg' },
                },
                instagram: {
                    impressions: { name: 'Fans', typefilter: 'number', filtercomparator: 0 },
                    reach: { name: 'Interactions', typefilter: 'number', filtercomparator: 0 },
                    follower_count: { name: 'Bereik', typefilter: 'number', filtercomparator: 0 },
                    profile_views: { name: 'Bereik', typefilter: 'number', filtercomparator: 0 },
                    website_clicks: { name: 'Bereik', typefilter: 'number', filtercomparator: 0 },
                    email_contacts: { name: 'Bereik', typefilter: 'number', filtercomparator: 0 },
                    get_directions_clicks: { name: 'Bereik', typefilter: 'number', filtercomparator: 0 },
                    phone_call_clicks: { name: 'Bereik', typefilter: 'number', filtercomparator: 0 },
                    text_message_clicks: { name: 'Bereik', typefilter: 'number', filtercomparator: 0 },
                },
                linkedin: {
                    Placeholder: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
                    shareCount: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
                    likeCount: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
                    engagement: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
                    clickCount: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
                    impressionCount: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
                    commentCount: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
                    networksize: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
                    networksizeexternal: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
                    networksizeinternal: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
                },
                linkedinxads: {
                    impressions: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
                    clicks: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
                    oneClickLeads: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
                    costInLocalCurrency: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
                    externalWebsiteConversions: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
                    costInLocalCurrency: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
                    networksize: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
                    networksizeexternal: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
                    networksizeinternal: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
                },
                mailchimp: {
                    Placeholder: { name: '', typefilter: 'number', filtercomparator: 0 },
                    member_count: { name: 'Aanmeldingen', typefilter: 'number', filtercomparator: 0 },
                    list_rating: { name: 'Rating', typefilter: 'number', filtercomparator: 0 },
                    click_rate: { name: 'Klik Ratio', typefilter: 'number', filtercomparator: 0, 'after': '%' },
                    open_rate: { name: 'Open Ratio', typefilter: 'number', filtercomparator: 0, 'after': '%' },
                    emails_sent: { name: 'Email verstuurd', typefilter: 'number', filtercomparator: 0 },
                    send_time: { name: 'Verstuurd op', typefilter: 'mcdate', filtercomparator: 0 },
                    unsubscribed: { name: 'Afmeldingen', typefilter: 'number', filtercomparator: 0 },
                    unsubscribe_count: { name: 'Afmeldingen', typefilter: 'number', filtercomparator: 0 },
                    cleaned_count: { name: 'Verwijderd', typefilter: 'number', filtercomparator: 0 },
                    bounces: { name: 'Bounce', typefilter: 'number', filtercomparator: 0 },
                    total_orders: { name: 'Orders', typefilter: 'number', filtercomparator: 0 },
                    recipient_clicks: { name: 'klikken', typefilter: 'number', filtercomparator: 0 },
                    total_revenue: { name: 'Totale opbrangest', typefilter: 'number', filtercomparator: 0, 'after': '€' },
                },
                mybusiness: {
                    Placeholder: { name: '', typefilter: 'number', filtercomparator: 0 },
                    QUERIES_DIRECT: { name: 'Directe zoekopdrachten', typefilter: 'number', filtercomparator: 0 },
                    QUERIES_INDIRECT: { name: 'Indirecte zoekopdrachten', typefilter: 'number', filtercomparator: 0 },
                    VIEWS_MAPS: { name: 'Google maps', typefilter: 'number', filtercomparator: 0 },
                    VIEWS_SEARCH: { name: 'Google zoeken', typefilter: 'number', filtercomparator: 0 },
                    QUERIES_DIRECT: { name: 'Bedrijf zoekopdacht', typefilter: 'number', filtercomparator: 0 },
                    QUERIES_INDIRECT: { name: 'Categorie zoekopdracht', typefilter: 'number', filtercomparator: 0 },
                    PHOTOS_VIEWS_MERCHANT: { name: 'Van eigenaars', typefilter: 'number', filtercomparator: 0 },
                    PHOTOS_VIEWS_CUSTOMERS: { name: 'Van bezoekers', typefilter: 'number', filtercomparator: 0 },
                    PHOTOS_COUNT_MERCHANT: { name: 'Van eigenaar', typefilter: 'number', filtercomparator: 0 },
                    PHOTOS_COUNT_CUSTOMERS: { name: 'Van bezoekers', typefilter: 'number', filtercomparator: 0 },
                    Date: { name: 'Datum', typefilter: 'number', filtercomparator: 0 },
                    AverageCpc: { name: 'Gemiddelde kosten per klik', typefilter: 'number', filtercomparator: 2, 'before': '€' },
                    Ctr: { name: 'Ctr', typefilter: 'number', filtercomparator: 0, 'after': '%' },
                    Conversions: { name: 'Conversions', typefilter: 'number', filtercomparator: 0 },
                    Cost: { name: 'Cost', typefilter: 'number', filtercomparator: 0, 'before': '€' },
                    CostPerConversion: { name: 'Kosten per conversie', typefilter: 'number', filtercomparator: 0, 'before': '€' },
                    ConversionRate: { name: 'Conversie ratio', typefilter: 'number', filtercomparator: 0, 'after': '%' },
                    AveragePosition: { name: 'Gemiddelde positie', typefilter: 'number', filtercomparator: 1 },
                    ConversionValue: { name: 'Totale conversiewaarde', typefilter: 'number', filtercomparator: 0, 'before': '€' },
                },
                searchconsole: {
                    clicks: { typefilter: 'number', filtercomparator: 0, 'reverse': true, 'datemerge': 'sum' },
                    ctr: { typefilter: 'number', filtercomparator: 2, 'after': '%', 'reverse': true, 'datemerge': 'avg' },
                    impressions: { typefilter: 'number', filtercomparator: 0, 'reverse': true, 'datemerge': 'sum' },
                    Date: { typefilter: 'number', filtercomparator: 0 },
                    position: { typefilter: 'number', filtercomparator: 1, 'reverse': false, 'reversesign': true, 'datemerge': 'avg' },
                },
                youtube: {
                    commentCount: { name: 'Clicks', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
                    subscriberCount: { name: 'Impressions', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
                    videoCount: { name: 'Date', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
                    viewCount: { name: 'Avg cost / Click', typefilter: 'number', filtercomparator: 0, 'datemerge': 'avg' },
                    views: { name: 'Ctr', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
                    shares: { name: 'Conversions', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
                    likes: { name: 'Cost', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
                    dislikes: { name: 'Cost / conversion', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
                    comments: { name: 'Conversion rate', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
                    subscribersGained: { name: 'AbsoluteTopImpressionPercentage', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
                    subscribersLost: { name: 'Conversion value', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
                    estimatedMinutesWatched: { name: 'Zoekimpressie aandeel', typefilter: 'number', filtercomparator: 1, 'datemerge': 'sum' },
                    annotationCloseRate: { name: 'Top Positie', typefilter: 'number', filtercomparator: 2, 'after': '%', 'datemerge': 'avg' },
                    annotationClickThroughRate: { name: 'ROAS', typefilter: 'number', filtercomparator: 2, 'after': '%', 'datemerge': 'avg' },
                    averageViewDuration: { name: 'ROAS', typefilter: 'secondsToHHmmss', filtercomparator: 0, 'datemerge': 'avg' },
                },
                analytics4: {
                    totalUsers: { name: 'totalUsers', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
                    screenPageViews: { name: 'screenPageViews', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
                    screenPageViewsPerSession: { name: 'screenPageViewsPerSession', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
                    sessions: { name: 'Sessions', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
                    newUsers: { name: 'Users', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
                    pageviews: { name: 'Pageviews', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
                    pageviewsPerSession: { name: 'Pageviews / session', typefilter: 'number', filtercomparator: 2, 'datemerge': 'avg' },
                    averageSessionDuration: { name: 'Average session duration', typefilter: 'secondsToHHmmss', filtercomparator: 0, 'datemerge': 'avg' },
                    percentNewSessions: { name: 'Percentrage new sessions', typefilter: 'number', filtercomparator: 0, 'after': '%', 'datemerge': 'avg' },
                    bounceRate: { name: 'Bounce Ratio', typefilter: 'number', filtercomparator: 0, 'after': '%', 'datemerge': 'avg' },
                    goalCompletionsAll: { name: 'Goals', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
                    goalValueAll: { name: 'Goalvalue', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
                    goalConversionRateAll: { name: 'Goalconversion ratio', typefilter: 'number', filtercomparator: 0, 'after': '%', 'datemerge': 'avg' },
                    goalAbandonRateAll: { name: 'Doel verlatings ratio', typefilter: 'number', filtercomparator: 0, 'after': '%', 'datemerge': 'avg' },
                    uniquePageviews: { name: 'Unique Pageviews', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
                    avgTimeOnPage: { name: 'Avg time on page', typefilter: 'secondsToHHmmss', filtercomparator: 0, 'datemerge': 'avg' },
                    entrances: { name: 'Entrances', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
                    exitRate: { name: 'Exit rate', typefilter: 'number', filtercomparator: 0, 'after': '%', 'datemerge': 'avg' },
                    pageValue: { name: 'Pagevalue', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
                    exits: { name: 'Exits', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
                    ROAS: { name: 'ROAS', typefilter: 'number', filtercomparator: 0, 'datemerge': 'avg' },
                    costPerTransaction: { name: 'Cost per transaction', typefilter: 'number', filtercomparator: 0, 'datemerge': 'avg' },
                    totalValue: { name: 'Total value', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
                    adCost: { name: 'Ad Cost', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
                    CPC: { name: 'CPC', typefilter: 'number', filtercomparator: 0, 'datemerge': 'avg' },
                    adClicks: { name: 'Ad Clicks', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
                    transactions: { name: 'Transacions', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
                    uniquePurchases: { name: 'Unique Purchases', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
                    totalValue: { name: 'Total Value', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
                    revenuePerTransaction: { name: 'Revenue per Transaction', typefilter: 'number', filtercomparator: 0, 'datemerge': 'avg' },
                    itemQuantity: { name: 'Item Quentity', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
                    itemsPerPurchase: { name: 'items / purchase', typefilter: 'number', filtercomparator: 0, 'datemerge': 'avg' },
                    eventCount: { name: 'items / purchase', typefilter: 'number', filtercomparator: 0, 'datemerge': 'avg' },
                    eventCountPerUser: { name: 'items / purchase', typefilter: 'number', filtercomparator: 0, 'datemerge': 'avg' },
                    mobileDeviceBranding: { name: 'Mobile device model', typefilter: 'text', filtercomparator: 3 },
                    itemsPurchased: { name: 'Items purchased', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
                    itemRevenue: { name: 'Item revenue', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
                    conversions: { name: 'Conversions', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
                    eventValue: { name: 'Event value', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
                    sessionConversionRate: { name: 'Session conversion rate', typefilter: 'number', filtercomparator: 0, 'after': '%', 'datemerge': 'avg' },
                    userEngagementDuration: { name: 'User engagement duration', typefilter: 'secondsToHHmmss', filtercomparator: 0, 'datemerge': 'sum' },
                    engagementRate: { name: 'User engagement rate', typefilter: 'number', filtercomparator: 2, 'after': '%', 'datemerge': 'avg' },
                }
            }
            return allMetrics[key];
        }
    }
});
app.directive('bullet', function ($compile) {
    return {
        restrict: 'E',
        scope: {
            type: '='
        },
        template: '',
    };
});
app.directive("clientscript", function () {
    var updateScripts = function (element) {
        return function (script) {
            element.empty();
            var scriptTag = angular.element(document.createElement("script"));
            scriptTag.text(script)
            element.append(scriptTag);
        };
    };
    return {
        restrict: "EA",
        scope: {
            scripts: "="
        },
        link: function (scope, element) {
            scope.$watch("scripts", updateScripts(element));
        }
    };
})
app.filter('maxserp', function () {
    return function (text, length, end) {
        if (text == 100 || text === undefined) {
            return '--';
        }
        return text;
    }
})
app.directive('change', function () {
    return {
        restrict: 'E',
        replace: true,
        scope: {
            type: '@'
        },
        template: '{{change}} ',
        link: function (scope) {
            scope.$watch('type', function () {
                if (scope.type == '0') {
                    scope.change = '--';
                } else if (scope.type < 1) {
                    scope.change = scope.type + ' ';
                    scope.class = 'fa fa-long-arrow-down text-warning';
                } else {
                    scope.change = scope.type + ' ';
                    scope.class = 'fa fa-long-arrow-up text-success';
                }
            });
        }
    };
});
app.directive('infiniteScroll', [
    '$rootScope', '$window', '$timeout',
    function ($rootScope, $window, $timeout) {
        return {
            link: function (scope, elem, attrs) {
                var checkWhenEnabled, handler, scrollDistance, scrollEnabled;
                $window = angular.element($window);
                scrollDistance = 0;
                if (attrs.infiniteScrollDistance != null) {
                    scope.$watch(attrs.infiniteScrollDistance, function (value) {
                        return scrollDistance = parseInt(value, 10);
                    });
                }
                scrollEnabled = true;
                checkWhenEnabled = false;
                if (attrs.infiniteScrollDisabled != null) {
                    scope.$watch(attrs.infiniteScrollDisabled, function (value) {
                        scrollEnabled = !value;
                        if (scrollEnabled && checkWhenEnabled) {
                            checkWhenEnabled = false;
                            return handler();
                        }
                    });
                }
                handler = function () {
                    var elementBottom, remaining, shouldScroll, windowBottom;
                    windowBottom = $window.height() + $window.scrollTop();
                    elementBottom = elem.offset().top + elem.height();
                    remaining = elementBottom - windowBottom;
                    shouldScroll = remaining <= $window.height() * scrollDistance;
                    if (shouldScroll && scrollEnabled) {
                        if ($rootScope.$$phase) {
                            return scope.$eval(attrs.infiniteScroll);
                        } else {
                            return scope.$apply(attrs.infiniteScroll);
                        }
                    } else if (shouldScroll) {
                        return checkWhenEnabled = true;
                    }
                };
                $window.on('scroll', handler);
                scope.$on('$destroy', function () {
                    return $window.off('scroll', handler);
                });
                return $timeout((function () {
                    if (attrs.infiniteScrollImmediateCheck) {
                        if (scope.$eval(attrs.infiniteScrollImmediateCheck)) {
                            return handler();
                        }
                    } else {
                        return handler();
                    }
                }), 0);
            }
        };
    }
])
app.filter('cleanurl', function () {
    return function (url) {
        return url.replace(/(^\w+:|^)\/\//, '');
    };
});
app.filter('mstotime', function () {
    return function (bytes) {
        return (bytes > 1000) ? Math.round(bytes / 10) / 100 + 's' : Math.round(bytes) + 'ms';
    };
});
app.filter('filename', function () {
    return function (url) {
        url = url.split(/[?#]/)[0].replace(/\/$/, "");
        return url.substring(url.lastIndexOf('/') + 1)
    };
});
app.directive('ngGauge', gaugeMeterDirective)
    .provider('ngGauge', gaugeMeterProviderFn);
gaugeMeterProviderFn.$inject = [];
function gaugeMeterProviderFn() {
    var defaultOptions = {
        size: 200,
        value: undefined,
        min: 0,
        max: 100,
        cap: 'butt',
        thick: 6,
        type: 'full',
        foregroundColor: 'rgba(0, 150, 136, 1)',
        backgroundColor: 'rgba(0, 0, 0, 0.1)',
        duration: 1500,
        fractionSize: null,
        labelOnly: false,
    };
    this.setOptions = function (customOptions) {
        if (!(customOptions && angular.isObject(customOptions)))
            throw new Error('Invalid option type specified in the ngGaugeProvider');
        defaultOptions = angular.merge(defaultOptions, customOptions);
    };
    var ngGauge = {
        getOptions: function () {
            return angular.extend({}, defaultOptions);
        }
    };
    this.$get = function () {
        return ngGauge;
    };
}
gaugeMeterDirective.$inject = ['ngGauge'];
function gaugeMeterDirective(ngGauge) {
    var tpl = '
' +
        '{{prepend}}' +
        '{{value | number}}' +
        '{{value | number: fractionSize}}' +
        '{{append}}' +
        '{{ label }}' +
        '
';
    var Gauge = function (element, options) {
        this.element = element.find('canvas')[0];
        this.text = element.find('span');
        this.legend = element.find('b');
        this.unit = element.find('u');
        this.context = this.element.getContext('2d');
        this.options = options;
        this.init();
    };
    Gauge.prototype = {
        init: function () {
            this.setupStyles();
            this.create(null, null);
        },
        setupStyles: function () {
            this.context.canvas.width = this.options.size;
            this.context.canvas.height = this.options.size;
            this.context.lineCap = this.options.cap;
            this.context.lineWidth = this.options.thick;
            var lfs = this.options.size * 0.30,
                llh = this.options.size;
            this.text.css({
                display: 'inline-block',
                fontWeight: 'normal',
                width: '100%',
                position: 'absolute',
                textAlign: 'center',
                overflow: 'hidden',
                textOverflow: 'ellipsis',
                fontSize: lfs + 'px',
                lineHeight: llh + 'px'
            });
            this.unit.css({
                textDecoration: 'none',
                fontSize: '0.6em',
                fontWeight: 200,
                opacity: 0.8
            });
            var fs = this.options.labelOnly ? lfs * 0.8 : this.options.size / 13;
            var lh = this.options.labelOnly ? llh : (5 * fs) + parseInt(this.options.size);
            this.legend.css({
                display: 'inline-block',
                width: '100%',
                position: 'absolute',
                textAlign: 'center',
                overflow: 'hidden',
                textOverflow: 'ellipsis',
                fontWeight: 'normal',
                fontSize: fs + 'px',
                lineHeight: lh + 'px'
            });
        },
        create: function (nv, ov) {
            var self = this,
                type = this.getType(),
                bounds = this.getBounds(type),
                duration = this.getDuration(),
                min = this.getMin(),
                max = this.getMax(),
                value = this.clamp(this.getValue(), min, max),
                start = bounds.head,
                unit = (bounds.tail - bounds.head) / (max - min),
                displacement = unit * (value - min),
                tail = bounds.tail,
                color = this.getForegroundColorByRange(value),
                requestID,
                startTime;
            if (nv && ov) {
                displacement = unit * nv - unit * ov;
            }
            function animate(timestamp) {
                timestamp = timestamp || new Date().getTime();
                var runtime = timestamp - startTime;
                var progress = Math.min(runtime / duration, 1); // never exceed 100%
                var previousProgress = ov ? (ov * unit) : 0;
                var middle = start + previousProgress + displacement * progress;
                self.drawShell(start, middle, tail, color);
                if (runtime < duration) {
                    requestID = window.requestAnimationFrame(function (timestamp) {
                        animate(timestamp);
                    });
                } else {
                    cancelAnimationFrame(requestID);
                }
            }
            requestAnimationFrame(function (timestamp) {
                startTime = timestamp || new Date().getTime();
                animate(timestamp);
            });
        },
        getBounds: function (type) {
            var head, tail;
            if (type == 'semi') {
                head = Math.PI;
                tail = 2 * Math.PI;
            } else if (type == 'full') {
                head = 1.5 * Math.PI;
                tail = 3.5 * Math.PI;
            } else if (type === 'arch') {
                head = 0.8 * Math.PI;
                tail = 2.2 * Math.PI;
            }
            return {
                head: head,
                tail: tail
            };
        },
        drawShell: function (start, middle, tail, color) {
            var
                context = this.context,
                center = this.getCenter(),
                radius = this.getRadius(),
                foregroundColor = color,
                backgroundColor = this.getBackgroundColor();
            this.clear();
            middle = Math.max(middle, start); // never below 0%
            middle = Math.min(middle, tail); // never exceed 100%
            context.beginPath();
            context.strokeStyle = backgroundColor;
            context.arc(center.x, center.y, radius, middle, tail, false);
            context.stroke();
            context.beginPath();
            context.strokeStyle = foregroundColor;
            context.arc(center.x, center.y, radius, start, middle, false);
            context.stroke();
        },
        clear: function () {
            this.context.clearRect(0, 0, this.getWidth(), this.getHeight());
        },
        update: function (nv, ov) {
            this.create(nv, ov);
        },
        destroy: function () {
            this.clear();
        },
        getRadius: function () {
            var center = this.getCenter();
            return center.x - this.getThickness();
        },
        getCenter: function () {
            var x = this.getWidth() / 2,
                y = this.getHeight() / 2;
            return {
                x: x,
                y: y
            };
        },
        getValue: function () {
            return this.options.value;
        },
        getMin: function () {
            return this.options.min;
        },
        getMax: function () {
            return this.options.max;
        },
        getWidth: function () {
            return this.context.canvas.width;
        },
        getHeight: function () {
            return this.context.canvas.height;
        },
        getThickness: function () {
            return this.options.thick;
        },
        getBackgroundColor: function () {
            return this.options.backgroundColor;
        },
        getForegroundColor: function () {
            return this.options.foregroundColor;
        },
        getForegroundColorByRange: function (value) {
            var isNumber = function (value) {
                return value != undefined && !isNaN(parseFloat(value)) && !isNaN(Number(value));
            };
            var match = Object.keys(this.options.thresholds)
                .filter(function (item) { return isNumber(item) && Number(item) <= value; })
                .sort(function (a, b) { return Number(a) > Number(b); }).reverse()[0];
            return match !== undefined ? this.options.thresholds[match].color || this.getForegroundColor() : this.getForegroundColor();
        },
        getLineCap: function () {
            return this.options.cap;
        },
        getType: function () {
            return this.options.type;
        },
        getDuration: function () {
            return this.options.duration;
        },
        clamp: function (value, min, max) {
            return Math.max(min, Math.min(max, value));
        }
    };
    return {
        restrict: 'E',
        replace: true,
        template: tpl,
        scope: {
            append: '@?',
            backgroundColor: '@?',
            cap: '@?',
            foregroundColor: '@?',
            label: '@?',
            labelOnly: '@?',
            prepend: '@?',
            size: '@?',
            thick: '@?',
            type: '@?',
            duration: '@?',
            value: '=?',
            min: '=?',
            max: '=?',
            thresholds: '=?',
            fractionSize: '=?'
        },
        link: function (scope, element) {
            var defaults = ngGauge.getOptions(); // fetching default settings from provider
            scope.min = angular.isDefined(scope.min) ? scope.min : defaults.min;
            scope.max = angular.isDefined(scope.max) ? scope.max : defaults.max;
            scope.value = angular.isDefined(scope.value) ? scope.value : defaults.value;
            scope.size = angular.isDefined(scope.size) ? scope.size : defaults.size;
            scope.cap = angular.isDefined(scope.cap) ? scope.cap : defaults.cap;
            scope.thick = angular.isDefined(scope.thick) ? scope.thick : defaults.thick;
            scope.type = angular.isDefined(scope.type) ? scope.type : defaults.type;
            scope.duration = angular.isDefined(scope.duration) ? scope.duration : defaults.duration;
            scope.labelOnly = angular.isDefined(scope.labelOnly) ? scope.labelOnly : defaults.labelOnly;
            scope.foregroundColor = angular.isDefined(scope.foregroundColor) ? scope.foregroundColor : defaults.foregroundColor;
            scope.backgroundColor = angular.isDefined(scope.backgroundColor) ? scope.backgroundColor : defaults.backgroundColor;
            scope.thresholds = angular.isDefined(scope.thresholds) ? scope.thresholds : {};
            scope.fractionSize = angular.isDefined(scope.fractionSize) ? scope.fractionSize : defaults.fractionSize;
            var gauge = new Gauge(element, scope);
            scope.$watch('value', watchData, false);
            scope.$watch('min', watchData, false);
            scope.$watch('max', watchData, false);
            scope.$watch('cap', watchOther, false);
            scope.$watch('thick', watchOther, false);
            scope.$watch('type', watchOther, false);
            scope.$watch('size', watchOther, false);
            scope.$watch('duration', watchOther, false);
            scope.$watch('foregroundColor', watchOther, false);
            scope.$watch('backgroundColor', watchOther, false);
            scope.$watch('thresholds', watchOther, false);
            scope.$watch('fractionSize', watchData, false);
            scope.$on('$destroy', function () { });
            scope.$on('$resize', function () { });
            function watchData(nv, ov) {
                if (!gauge) return;
                if (!angular.isDefined(nv) || angular.equals(nv, ov)) return;
                gauge.update(nv, ov);
            }
            function watchOther(nv, ov) {
                if (!angular.isDefined(nv) || angular.equals(nv, ov)) return;
                gauge.destroy();
                gauge.init();
            }
        }
    };
}
app.config(['$routeProvider', '$locationProvider', 'USER', '$sceProvider', '$translateProvider', function AppConfig($routeProvider, $locationProvider, USER, $sceProvider, $translateProvider) {
    angular.lowercase = angular.$$lowercase;
    $translateProvider.useStaticFilesLoader({
        prefix: '/translations/',
        suffix: '.json?r=' + Math.random()
    });
    /* ZET */
    $translateProvider.preferredLanguage(USER.site.locale.lang);
    $translateProvider.useSanitizeValueStrategy('sce');
    $sceProvider.enabled(false);
    $routeProvider
        .when('/', {
            title: 'APP',
            templateUrl: viewfolder + '/home/index.html?r=' + r,
            nav: 'dashboard'
        })
        /* help*/
        .when('/help', {
            title: 'Help',
            templateUrl: viewfolder + '/help/index.html?r=' + r,
            nav: 'help'
        })
        /* onpage seo*/
        .when('/onpage-seo', {
            title: 'ONPAGE',
            templateUrl: viewfolder + '/onpage/index.status.html?r=' + r,
            nav: 'onpage'
        })
        .when('/onpage-seo/scan/:pageid', {
            title: 'ONPAGE SCAN',
            templateUrl: viewfolder + '/onpage/scan.html?r=' + r,
            nav: 'onpage',
            controller: function ($scope, $routeParams) {
                $scope.pageid = $routeParams.pageid;
            },
        })
        .when('/onpage-seo/:viewrulelabel', {
            title: 'ONPAGE',
            templateUrl: viewfolder + '/onpage/index.status.html?r=' + r,
            nav: 'onpage',
            controller: function ($scope, $routeParams) {
                $scope.viewrulelabel = $routeParams.viewrulelabel;
            },
        })
        .when('/onpage-seo/:viewrulelabel/:viewrule', {
            title: 'ONPAGE',
            templateUrl: viewfolder + '/onpage/index.status.html?r=' + r,
            nav: 'onpage',
            controller: function ($scope, $routeParams) {
                $scope.viewrulelabel = $routeParams.viewrulelabel;
                $scope.viewrule = $routeParams.viewrule;
            },
        })
        /* linkbuilding*/
        .when('/content/', {
            title: 'Content Intelligence',
            templateUrl: viewfolder + '/content/index.html?r=' + r,
            nav: 'content'
        })
        .when('/content/:modelid', {
            title: 'Content Intelligence',
            templateUrl: viewfolder + '/content/model.html?r=' + r,
            nav: 'content',
            controller: function ($scope, $routeParams) {
                $scope.modelid = $routeParams.modelid;
            },
        })
        /* linkbuilding*/
        .when('/linkbuilding/assistant', {
            title: 'Linkbuilding',
            templateUrl: viewfolder + '/linkbuilding/assistant.html?r=' + r,
            nav: 'linkbuilding'
        })
        .when('/linkbuilding/template', {
            title: 'Linkbuilding',
            templateUrl: viewfolder + '/linkbuilding/template.html?r=' + r,
            nav: 'linkbuilding'
        })
        .when('/linkbuilding/wizzard', {
            title: 'Linkbuilding',
            templateUrl: viewfolder + '/linkbuilding/wizzard.html?r=' + r,
            nav: 'linkbuilding'
        })
        .when('/linkbuilding/manager', {
            title: 'Linkbuilding',
            templateUrl: viewfolder + '/linkbuilding/manager.html?r=' + r,
            nav: 'linkbuilding'
        })
        .when('/llm-visibility', {
            title: 'llmvisibility',
            templateUrl: viewfolder + '/llm-visibility/index.html?r=' + r,
            nav: 'llmvisibility'
        })
        /* reports*/
        .when('/analytics/:report/:view', {
            title: 'SITES',
            templateUrl: viewfolder + '/api/analytics.html?r=' + r,
            nav: 'analytics',
            controller: function ($scope, $routeParams) {
                $scope.urlreport = $routeParams.report;
                $scope.urlview = $routeParams.view;
            },
        })
        .when('/analytics4/:report/:view', {
            title: 'SITES',
            templateUrl: viewfolder + '/api/analytics4.html?r=' + r,
            nav: 'analytics4',
            controller: function ($scope, $routeParams) {
                $scope.urlreport = $routeParams.report;
                $scope.urlview = $routeParams.view;
            },
        })
        .when('/searchconsole/:report/:view', {
            title: 'SEARCHCONSOLE',
            templateUrl: viewfolder + '/api/searchconsole.html?r=' + r,
            nav: 'tools',
            controller: function ($scope, $routeParams) {
                $scope.urlreport = $routeParams.report;
                $scope.urlview = $routeParams.view;
            },
        })
        .when('/searchconsole/:report/:view/:urlfilter', {
            title: 'SEARCHCONSOLE',
            templateUrl: viewfolder + '/api/searchconsole.html?r=' + r,
            nav: 'tools',
            controller: function ($scope, $routeParams) {
                $scope.urlreport = $routeParams.report;
                $scope.urlview = $routeParams.view;
                $scope.urlfilter = $routeParams.urlfilter;
            },
        })
        .when('/youtube/:report/:view', {
            title: 'youtube',
            templateUrl: viewfolder + '/api/youtube.html?r=' + r,
            nav: 'tools',
            controller: function ($scope, $routeParams) {
                $scope.urlreport = $routeParams.report;
                $scope.urlview = $routeParams.view;
            },
        })
        .when('/hub/:report/:view', {
            title: 'Performarnce Hub',
            templateUrl: viewfolder + '/api/hub.html?r=' + r,
            nav: 'tools',
            controller: function ($scope, $routeParams) {
                $scope.urlreport = $routeParams.report;
                $scope.urlview = $routeParams.view;
            },
        })
        .when('/hub/:report/:view/:urlfilter', {
            title: 'Performarnce Hub',
            templateUrl: viewfolder + '/api/hub.html?r=' + r,
            nav: 'tools',
            controller: function ($scope, $routeParams) {
                $scope.urlreport = $routeParams.report;
                $scope.urlview = $routeParams.view;
                $scope.urlfilter = $routeParams.urlfilter;
            },
        })
        .when('/mailchimp/:report/:view', {
            title: 'mailchimp',
            templateUrl: viewfolder + '/api/mailchimp.html?r=' + r,
            nav: 'tools',
            controller: function ($scope, $routeParams) {
                $scope.urlreport = $routeParams.report;
                $scope.urlview = $routeParams.view;
            },
        })
        .when('/mailchimp/:report/:view/:filter', {
            title: 'mailchimp',
            templateUrl: viewfolder + '/api/mailchimp.html?r=' + r,
            nav: 'tools',
            controller: function ($scope, $routeParams) {
                $scope.urlreport = $routeParams.report;
                $scope.urlview = $routeParams.view;
                $scope.urlfilter = $routeParams.filter;
            },
        })
        .when('/copernica/:report/:view', {
            title: 'copernica',
            templateUrl: viewfolder + '/api/copernica.html?r=' + r,
            nav: 'tools',
            controller: function ($scope, $routeParams) {
                $scope.urlreport = $routeParams.report;
                $scope.urlview = $routeParams.view;
            },
        })
        .when('/copernica/:report/:view/:filter', {
            title: 'copernica',
            templateUrl: viewfolder + '/api/copernica.html?r=' + r,
            nav: 'tools',
            controller: function ($scope, $routeParams) {
                $scope.urlreport = $routeParams.report;
                $scope.urlview = $routeParams.view;
                $scope.urlfilter = $routeParams.filter;
            },
        })
        .when('/facebookads/:report/:view', {
            title: 'facebookads',
            templateUrl: viewfolder + '/api/facebookxads.html?r=' + r,
            nav: 'ads',
            controller: function ($scope, $routeParams) {
                $scope.urlreport = $routeParams.report;
                $scope.urlview = $routeParams.view;
            },
        })
        .when('/facebookinsights/:report/:view', {
            title: 'facebookinsights',
            templateUrl: viewfolder + '/api/facebookinsights.html?r=' + r,
            nav: 'tools',
            controller: function ($scope, $routeParams) {
                $scope.urlreport = $routeParams.report;
                $scope.urlview = $routeParams.view;
            },
        })
        .when('/instagram/:report/:view', {
            title: 'instagram',
            templateUrl: viewfolder + '/api/instagram.html?r=' + r,
            nav: 'tools',
            controller: function ($scope, $routeParams) {
                $scope.urlreport = $routeParams.report;
                $scope.urlview = $routeParams.view;
            },
        })
        .when('/linkedin/:report/:view', {
            title: 'linkedin',
            templateUrl: viewfolder + '/api/linkedin.html?r=' + r,
            nav: 'tools',
            controller: function ($scope, $routeParams) {
                $scope.urlreport = $routeParams.report;
                $scope.urlview = $routeParams.view;
            },
        })
        .when('/linkedinxads/:report/:view', {
            title: 'linkedinxads',
            templateUrl: viewfolder + '/api/linkedinxads.html?r=' + r,
            nav: 'tools',
            controller: function ($scope, $routeParams) {
                $scope.urlreport = $routeParams.report;
                $scope.urlview = $routeParams.view;
            },
        })
        .when('/googleads/:report/:view', {
            title: 'googleads',
            templateUrl: viewfolder + '/api/googlexads.html?r=' + r,
            nav: 'ads',
            controller: function ($scope, $routeParams) {
                $scope.urlreport = $routeParams.report;
                $scope.urlview = $routeParams.view;
            },
        })
        .when('/mybusiness/:report/:view', {
            title: 'MYBUSINESS',
            templateUrl: viewfolder + '/api/mybusiness.html?r=' + r,
            nav: 'tools',
            controller: function ($scope, $routeParams) {
                $scope.urlreport = $routeParams.report;
                $scope.urlview = $routeParams.view;
            },
        })
        .when('/planning', {
            title: 'planning',
            templateUrl: viewfolder + '/planning/index.html?r=' + r,
            nav: 'planning',
        })
        .when('/site', {
            title: 'SITES',
            templateUrl: viewfolder + '/site/index.html?r=' + r,
            nav: 'sites',
        })
        .when('/site/upgrade/:orderstate', {
            title: 'SITES',
            templateUrl: viewfolder + '/site/upgrade.html?r=' + r,
            nav: 'sites',
            controller: function ($scope, $routeParams) {
                $scope.orderstate = $routeParams.orderstate;
            },
            allowguest: true
        })
        .when('/site/upgrade', {
            title: 'SITES',
            templateUrl: viewfolder + '/site/upgrade.html?r=' + r,
            nav: 'sites',
            allowguest: true
        })
        .when('/sites', {
            title: 'SITES',
            templateUrl: viewfolder + '/sites/index.html?r=' + r,
            nav: 'sites',
        })
        .when('/sites/new', {
            title: 'Add a new site',
            templateUrl: viewfolder + '/sites/first.html?r=' + r,
            nav: 'sites',
        })
        .when('/rank-tracker', {
            title: 'Rank Tracker',
            templateUrl: viewfolder + '/rank-tracker/index.html?r=' + r,
            nav: 'ranktracker',
        })
        .when('/rank-tracker/competitors', {
            title: 'Rank Tracker - Competitors',
            templateUrl: viewfolder + '/rank-tracker/competitors.html?r=' + r,
            nav: 'ranktracker',
        })
        .when('/rank-tracker/insights', {
            title: 'Rank Tracker - Insights',
            templateUrl: viewfolder + '/rank-tracker/insights.html?r=' + r,
            nav: 'ranktracker',
        })
        .when('/keywordtool', {
            title: 'Rank Tracker',
            templateUrl: viewfolder + '/keywordtool/index.html?r=' + r,
            nav: 'keywordtool',
        })
        .when('/insights', {
            title: 'Insights',
            templateUrl: viewfolder + '/insights/index.html?r=' + r,
            nav: 'insights',
        })
        .when('/insights/:report', {
            title: 'Insights',
            templateUrl: viewfolder + '/insights/index.html?r=' + r,
            nav: 'tools',
            controller: function ($scope, $routeParams) {
                $scope.urlreport = $routeParams.report;
            },
        })
        /*report*/
        .when('/report', {
            title: 'Report',
            templateUrl: viewfolder + '/report/index.html?r=' + r,
            nav: 'report',
        })
        .when('/report/:report_id', {
            title: 'Report',
            templateUrl: viewfolder + '/report/report.html?r=' + r,
            nav: 'report',
            controller: function ($scope, $routeParams) {
                $scope.report_id = $routeParams.report_id;
            },
        })
        .when('/reportpage/:key', {
            title: 'Report',
            templateUrl: viewfolder + '/report/page.html?r=' + r,
            nav: 'report',
            controller: function ($scope, $routeParams) {
                $scope.key = $routeParams.key;
            },
        })
        /* guest*/
        .when('/sites/first', {
            title: 'Add your first site',
            templateUrl: viewfolder + '/sites/first.html?r=' + r,
            nav: 'sites',
            allowguest: true,
        })
        .when('/user/login', {
            title: 'LOGIN',
            allowguest: true,
            nav: 'user',
            class: 'fullscreen',
            templateUrl: viewfolder + '/user/login.html?r=' + r,
        })
        .when('/user', {
            title: 'USER',
            nav: 'user',
            templateUrl: viewfolder + '/user/index.html?r=' + r,
        })
        .when('/user/register', {
            title: 'LOGIN',
            nav: 'user',
            class: 'fullscreen',
            templateUrl: viewfolder + '/user/register.html?r=' + r,
            allowguest: true,
        })
        .when('/user/recover', {
            title: 'RECOVER PASSWORD',
            templateUrl: viewfolder + '/user/recover.html?r=' + r,
            nav: 'user',
            class: 'fullscreen',
            allowguest: true,
        })
        .when('/settings/reseller', {
            title: 'RESELLER',
            templateUrl: viewfolder + '/reseller/index.html?r=' + r,
            nav: 'user',
            allowguest: true,
        })
        .when('/settings/site', {
            title: 'RESELLER',
            templateUrl: viewfolder + '/site/index.html?r=' + r,
            nav: 'user',
            allowguest: false,
        })
        .otherwise({
            redirectTo: '/'
        });
    // enable html5Mode for pushstate ('#'-less URLs)
    $locationProvider.html5Mode(true);
}]);
app.run(['$route', '$rootScope', '$location', '$window', 'USER', function ($route, $rootScope, $location, $window, USER) {
    $rootScope.r = r;
    $rootScope.user = USER;
    //set menu state
    $rootScope.app = {
        body: { class: ['md-open', 'closed'] }
    };
    $rootScope.$on('$routeChangeSuccess', function (event, current, prev) {
        $rootScope.app = {
            body: { class: ['md-open', 'closed'] }
        };
        $rootScope.modal = {};
        if (!$rootScope.user._id && !$route.current.allowguest) {
            $location.path('/user/login');
        } else if (!$rootScope.user.site._id && !$route.current.allowguest) {
            $location.path('/sites/first');
        } else if (!$route.current.allowguest && $rootScope.user.site._id && current.originalPath != '/site/upgrade' && $rootScope.user.site.status.expire - (Date.now() / 1000) < 0) {
            //if ($rootScope.user.reseller.config.own) {
            $location.path('/site/upgrade');
            //}
        }
        $rootScope.app.meta = { nav: $route.current.nav, class: $route.current.class, title: USER.reseller.config.name + ' - ' + $route.current.title, description: $route.current.description };
        $rootScope.app.sitesdropdown = false;
    });
}])
app.controller('core', ['$scope', '$rootScope', '$location', 'h', '$templateRequest', '$window', '$http', '$route', '$translate', '$http',
    function($scope, $rootScope, $location, h, $templateRequest, $window, $http, $route, $translate, $http) {
        $scope.fnToggleMenu = function() {
            $rootScope.app.body.class = ($rootScope.app.body.class[0] == 'md-open') ? ['md-closed', 'open'] : ['md-open', 'closed'];
        }
        $scope.fnLogout = function() {
            $http.post('/rest/user/logout').then(function successCallback(res) {
                h.login(function() { $location.path('/user/login'); });
            });
        }
        $scope.fnModal = function(url) {
            $rootScope.modal = {};
            $rootScope.modal.show = true;
            $rootScope.modal.url = viewfolder+'/' + url + '.html';
        }
        $scope.fnCloseModal = function() {
            $rootScope.modal = {};
        }
        $scope.fnClick = function(path) {
            $location.path(path);
        }
        $scope.fnGoto = function(path) {
            //$location.path(path);
            $window.location.href = path;
        }
        $scope.fnSetLang = function(lang) {
            $rootScope.user.site.locale.lang = lang;
            $translate.use(lang);
            $http.get('/rest/global/lang.set', {
                params: {
                    'lang': lang,
                }
            });
        }
        $scope.fnChangeSite = function(site) {
            $http.post('/rest/sites/change', { websiteid: site._id.$oid }).then(function successCallback(res) {
                h.login(function() {
                    $rootScope._pages = false;
                    $rootScope._history = false;
                    if ($location.path() == '/site/upgrade') {
                        $scope.fnClick('/');
                    }
                    $route.reload();
                });
            });
        }
        $scope.fnSitesDropdown = function(site) {
            $rootScope.app.sitesdropdown = !$rootScope.app.sitesdropdown;
        }
        $scope.fnDaysLeft = function() {
            return Math.ceil(($rootScope.user.site.status.expire - (Date.now() / 1000)) / (24 * 60 * 60));
        }
        $scope.isValidSite = function() {
            return ($rootScope.user.site.status.expire > (Date.now() / 1000)) ? true : false;
        }
        $scope.colors = ['#E91E63', '#3F51B5', '#00BCD4', '#8BC34A', '#FF9800', '#795548', '#607D8B', '#00CC00', '#0000CC', '#DDDDDD', '#999999', '#333333', '#990000']
        $scope.fnPdf = function() {
            console.log('asdasdasd');
            var imgs = document.getElementsByTagName('canvas');
            for (var i in imgs) {
                if (typeof(imgs[i]) == 'object') {
                    var img = imgs[i].toDataURL("image/png");
                    var replace = document.createElement("img");
                    replace.src = img;
                    imgs[i].parentNode.replaceChild(replace, imgs[i]);
                }
            }
            $http.post("/rest/report/page.download", {
                html: angular.element('.reportcontainer').html()
            }).then(function successCallback(res) {
                $scope.fnGoto('https://pdfssl1.seoserver.nl/engels/page.php?website_id=' + h.siteId() + '&reseller_id=' + $scope.user.reseller._id.$oid + '&key=' + res.data.k)
                /*$http.get('https://pdfssl1.seoserver.nl/engels/page.php', { 'params': { 'website_id': h.siteId(), 'reseller_id': $scope.user.reseller._id.$oid, 'key': res.data.k } }).then(function successCallback(pdf) {
                    var newBlob = new Blob([pdf.data], { type: "application/pdf" })
                    console.log(newBlob);
                });*/
            });
        }
    }
]);
app.controller('home', ['$scope', '$timeout', '$http', '$rootScope', '$filter', 'h',
    function($scope, $timeout, $http, $rootScope, $filter, h) {
        //if ($rootScope.user.firstrun) {
        if ($rootScope.user.firstrun) {
            $scope.fnModal('home/modal.firstrun');
        }
        $scope.fnCloseFirstRun = function() {
            $http.get('/rest/user/firstrun.set');
            $rootScope.user.firstrun = false;
            $scope.fnCloseModal();
        }
        $scope.pagecharts = {};
        $scope.curtemplate = {};
        $scope.colors = h.colors();
        $scope.page = {
            'widgets': [{
                'type': 'analytics_timeline',
                'metrics': ['sessions', 'users', 'pageviews', 'pageviewsPerSession', 'avgSessionDuration', 'percentNewSessions', 'bounceRate', 'goalCompletionsAll', 'goalValueAll', 'goalConversionRateAll', 'uniquePageviews', 'avgTimeOnPage', 'entrances', 'exitRate', 'pageValue', 'transactions', 'uniquePurchases', 'totalValue', 'revenuePerTransaction', 'itemQuantity', 'itemsPerPurchase'],
                'metric': 'sessions',
                'colspan': 6
            }, {
                'type': 'analytics_chart',
                'dimensions': ['channelGrouping', 'keyword', 'source', 'country', 'userAgeBracket', 'userGender', 'socialNetwork', 'deviceCategory', 'adMatchedQuery', 'productName', 'productCategory', 'pagePath', 'landingPagePath', 'exitPagePath'],
                'dimension': 'landingPagePath',
                'charts': ['pie', 'bar', 'progress'],
                'chart': 'bar',
                'metrics': ['sessions', 'users', 'pageviews', 'pageviewsPerSession', 'avgSessionDuration', 'percentNewSessions', 'bounceRate', 'goalCompletionsAll', 'goalValueAll', 'goalConversionRateAll', 'uniquePageviews', 'avgTimeOnPage', 'entrances', 'exitRate', 'pageValue', 'transactions', 'uniquePurchases', 'totalValue', 'revenuePerTransaction', 'itemQuantity', 'itemsPerPurchase'],
                'metric': 'sessions',
                'colspan': 6
            }, 
            {
                'type': 'analytics4_timeline',
                'class': 'mt-4',
                'metrics': ['sessions', 'totalUsers', 'screenPageViews', 'screenPageViewsPerSession', 'averageSessionDuration', 'newUsers', 'bounceRate', 'eventCount', 'eventCountPerUser'],
                'metric': 'sessions',
                'colspan': 6
            },
            
            {
                'type': 'searchconsole_timeline',
                'class': 'mt-4',
                'metrics': ['clicks', 'ctr', 'position', 'impressions'],
                'metric': 'clicks',
                'colspan': 6
            }, {
                'type': 'searchconsole_chart',
                'dimensions': ['query', 'page', 'country', 'device'],
                'dimension': 'query',
                'charts': ['pie', 'bar', 'progress'],
                'chart': 'bar',
                'metrics': ['clicks', 'ctr', 'position', 'impressions'],
                'metric': 'clicks',
                'colspan': 6
            }, {
                'type': 'searchconsole_keywords',
                'colspan': 6
            }, {
                'type': 'googleads_timeline',
                'class': 'mt-4',
                'metrics': ['Clicks', 'Impressions', 'Cost', 'AverageCpc', 'Ctr', 'Conversions', 'CostPerConversion', 'ConversionRate', 'ConversionValue', 'SearchImpressionShare', 'SearchAbsoluteTopImpressionShare', 'roas'],
                'metric': 'Clicks',
                'colspan': 6
            }, {
                'type': 'googleads_performance_chart',
                'dimensions': ['CampaignName', 'AdGroupName', 'Query'],
                'dimension': 'CampaignName',
                'charts': ['pie', 'bar', 'progress'],
                'chart': 'bar',
                'metrics': ['Clicks', 'Impressions', 'Cost', 'AverageCpc', 'Ctr', 'Conversions', 'CostPerConversion', 'ConversionRate', 'ConversionValue', 'SearchImpressionShare', 'SearchAbsoluteTopImpressionShare', 'roas'],
                'metric': 'Clicks',
                'colspan': 6
            }, {
                'type': 'googleads_conversion_chart',
                'dimensions': ['ConversionTypeName'],
                'dimension': 'ConversionTypeName',
                'charts': ['pie', 'bar', 'progress'],
                'chart': 'bar',
                'metrics': ['Conversions', 'CostPerConversion', 'ConversionRate', 'ConversionValue'],
                'metric': 'Conversions',
                'colspan': 6
            }, {
                'type': 'facebookinsights_timeline',
                'class': 'mt-4',
                'metrics': ['page_fans_total', 'page_impressions', 'engagements'],
                'metric': 'page_fans_total',
                'colspan': 6
            }, {
                'type': 'facebookads_timeline',
                'metrics': ['clicks', 'impressions', 'cpc', 'cpm', 'spend', 'ctr'],
                'metric': 'clicks',
                'colspan': 6
            }, {
                'type': 'ranktracer',
                'class': 'mt-4',
                'colspan': 6
            }, {
                'type': 'onpage_seo',
                'colspan': 12
            }, {
                'type': 'onpage_changes',
                'colspan': 6
            }, {
                'type': 'onpage_changes_donut',
                'colspan': 6
            }],
            'widths': [
                { 'colspan': 3, 'width': '25%' },
                { 'colspan': 4, 'width': '33%' },
                { 'colspan': 6, 'width': '50%' },
                { 'colspan': 8, 'width': '66%' },
                { 'colspan': 9, 'width': '75%' },
                { 'colspan': 12, 'width': '100%' },
            ]
        }
        $scope.fnPctChange = function(o, n) {
            if (n == 0) {
                return '0%';
            }
            var pct = ((n - o) / o) * 100;
            var npct = $filter('number')(pct, 2);
            if (pct < 0) {
                return '' + npct + '%';
            }
            return '+ ' + npct + '%';
        }
        $scope.do = function(obj, method, param) {
            if (obj == 'fnWidgets') {
                fnWidgets[method](param);
            } else if (obj == 'fnTemplates') {
                fnTemplates[method](param);
            }
        }
        var fnTemplates = {
            list: function() {
                $http.get('/rest/home/template.list', {
                    params: {
                        websiteid: h.siteId(),
                    }
                }).then(function successCallback(res) {
                    $scope.templates = res.data;
                });
            },
            use: function(widgets) {
                $scope.widgets = widgets;
                fnWidgets.save();
                $scope.fnCloseModal();
            },
            create: function() {
                var cleanwidgets = angular.copy($scope.widgets).map(function(c) {
                    delete c.widget;
                    return c;
                })
                $scope.curtemplate.widgets = cleanwidgets;
                $http.post('/rest/home/template.save', { websiteid: h.siteId(), 'template': $scope.curtemplate }).then(function successCallback(res) {
                    $scope.fnCloseModal();
                });
            },
            save: function(template) {
                var cleanwidgets = angular.copy($scope.widgets).map(function(c) {
                    delete c.widget;
                    return c;
                })
                template.widgets = cleanwidgets;
                template.name = ($scope.curtemplate.name) ? $scope.curtemplate.name : template.name;
                template.description = ($scope.curtemplate.description) ? $scope.curtemplate.description : template.description;
                $http.post('/rest/home/template.save', { websiteid: h.siteId(), 'template': template }).then(function successCallback(res) {
                    $scope.fnCloseModal();
                });
            },
            delete: function(template) {
                $http.post('/rest/home/template.delete', template).then(function successCallback(res) {
                    $scope.fnCloseModal();
                });
            },
        }
        var fnWidgets = {
            'add': function(widget) {
                $http.post('/rest/home/widget.add', angular.extend({ websiteid: h.siteId() }, widget)).then(function successCallback(res) {
                    $scope.fnCloseModal();
                    fnWidgets.list();
                    $scope.page.edit = false;
                });
            },
            'save': function() {
                $http.post('/rest/home/widgets.save', angular.extend({ websiteid: h.siteId() }, { 'widgets': $scope.widgets })).then(function successCallback(res) {
                    $scope.fnCloseModal();
                    fnWidgets.list();
                    $scope.page.edit = false;
                });
            },
            'delete': function(widget) {
                angular.forEach($scope.widgets, function(v, k) {
                    if (v.k == widget.k) {
                        $scope.widgets.splice(k, 1);
                        fnWidgets.save();
                    }
                })
            },
            'reorder': function(o) {
                o.widget.order = o.widget.order - 0.1;
                angular.forEach($filter('orderBy')($scope.widgets, 'order', false), function(v, k) {
                    v.order = k + 1;
                });
            },
            'pre_add': function() {
                fnTemplates.list();
                $scope.fnModal('home/modal.widgets');
            },
            'pre_edit': function() {
                $scope.page.edit = true;
            },
            'list': function() {
                $http.get('/rest/home/widgets.list', {
                    params: {
                        websiteid: h.siteId(),
                    }
                }).then(function successCallback(res) {
                    if (res.data.length == 0) {
                        res.data = [
                            { "type": "onpage_seo", "metric": null, 'colspan': 12, 'order': 1, 'k': 'k1' },
                            { "type": "analytics4_timeline", "metric": "sessions", 'colspan': 4, 'order': 2, 'k': 'k2' },
                            { "type": "onpage_changes", "metric": null, 'colspan': 4, 'order': 3, 'k': 'k3' },
                            { "type": "searchconsole_keywords", "metric": null, 'colspan': 4, 'order': 4, 'k': 'k4' },
                            { "type": "searchconsole_timeline", "metric": 'clicks', 'colspan': 6, 'order': 5, 'k': 'k5' },
                            { "type": "ranktracer", "metric": null, 'colspan': 6, 'order': 6, 'k': 'k6' },
                        ];
                    }
                    $scope.widgets = res.data;
                    angular.forEach($scope.widgets, function(v, k) {
                        fnWidgetGenerator[v.type](v);
                    })
                });
            }
        }
        fnWidgets.list();
        var _charts = {
            init: function(type, dataset, dimension, metric, dateformat) {
                return _charts[type](dataset, dimension, metric, dateformat);
            },
            progress: function(dataset, dimension, metric) {
                return $filter('orderBy')(dataset, metric, true).slice(0, 5);
            },
            bar: function(dataset, dimension, metric) {
                dataset = $filter('orderBy')(dataset, metric, true).slice(0, 8);
                //inject color attribute with value
                if (typeof dataset != undefined) {
                    for (var i = 0; i < dataset.length; i++) { dataset[i].color = $scope.colors[i]; }
                }
                return {
                    data: dataset.slice(0, 6),
                    type: 'serial',
                    categoryField: dimension,
                    rotate: false,
                    legend: {
                        enabled: false
                    },
                    categoryAxis: {
                        gridPosition: "start",
                        parseDates: false,
                        labelRotation: 0,
                        gridThickness: 0,
                        labelFunction: function(value, valueText, axis) { return (value.length > 19) ? value.substr(0, 17) + '...' : value },
                    },
                    valueAxes: [{
                        position: "left",
                        axisAlpha: 0,
                        labelsEnabled: true,
                        dashLength: 4,
                        color: '#dedede',
                    }],
                    graphs: [{
                        fillColorsField: "color",
                        balloonText: "[[category]]: [[value]]",
                        type: "column",
                        columnWidth: 0.40,
                        title: "Zoekwoord waarde",
                        valueField: metric,
                        fillAlphas: 1,
                        lineColor: '#009688',
                        autoColor: true,
                    }],
                }
            },
            pie: function(dataset, dimension, metric) {
                dataset = $filter('orderBy')(dataset, metric, true).slice(0, 12);
                return {
                    data: dataset.slice(0, 9),
                    type: 'pie',
                    categoryField: dimension,
                    "precision": 0,
                    "decimalSeparator": ",",
                    "thousandsSeparator": ".",
                    legend: {
                        enabled: false,
                        position: 'right',
                        autoMargins: false,
                        marginRight: 100,
                    },
                    titleField: dimension,
                    valueField: metric,
                    labelRadius: 5,
                    radius: '42%',
                    innerRadius: '60%',
                    labelText: '[[title]]',
                }
            },
            timeline(dataset, dimension, metric, dateformat) {
                return {
                    data: dataset,
                    type: 'serial',
                    categoryField: dimension,
                    rotate: false,
                    dataDateFormat: dateformat,
                    categoryAxis: { gridPosition: "start", parseDates: true, gridThickness: 0 },
                    valueAxes: [{ position: "left", axisAlpha: 0, labelsEnabled: true, dashLength: 4, color: '#dedede', }],
                    graphs: [{
                        'balloonText': "Amount 
 [[value]]",
                        "bullet": "round",
                        "bulletBorderAlpha": 1,
                        "bulletColor": "#FFFFFF",
                        "useLineColorForBulletBorder": true,
                        "fillAlphas": 0.3,
                        "lineThickness": 2,
                        "lineAlpha": 1,
                        "bulletSize": 7,
                        "title": "Expenses",
                        "valueField": metric,
                        'lineColor': fnWidgetGenerator.color()
                    }],
                }
            }
        }
        var fnWidgetGenerator = {
            i: -1,
            'color': function(i) {
                var colors = h.colors();
                fnWidgetGenerator.i += 1;
                return colors[fnWidgetGenerator.i];
            },
            'analytics_timeline': function(widget) {
                $http.get('/rest/analytics/v4', {
                    params: { 't':'123','dimension': 'date', 'end': 'TODAY', 'metrics': widget.metric, 'start': '30DAYSAGO', websiteid: h.siteId(), }
                }).then(function successCallback(res) {
                    widget.widget = _charts.init('timeline', res.data.data, 'ga:date', widget.metric, 'YYYYMMDD')
                    widget.widget.action = res.data.action;
                });
            },
            'analytics4_timeline': function(widget) {
                $http.get('/rest/analytics4/report', {
                    params: { 't':'123','dimension': 'date', 'end': 'TODAY', 'metrics': widget.metric, 'start': '30DAYSAGO', websiteid: h.siteId(), }
                }).then(function successCallback(res) {
                    widget.widget = _charts.init('timeline', res.data.data, 'date', widget.metric, 'YYYYMMDD')
                    widget.widget.action = res.data.action;
                });
            },
            'analytics_chart': function(widget) {
                $http.get('/rest/analytics/v4', {
                    params: { 'dimension': widget.dimension, 'end': 'TODAY', 'metrics': widget.metric, 'start': '30DAYSAGO', websiteid: h.siteId() }
                }).then(function successCallback(res) {
                    widget.widget = _charts.init(widget.chart, res.data.data, 'ga:' + widget.dimension, widget.metric)
                    widget.widget.action = res.data.action;
                });
            },
            'googleads_timeline': function(widget) {
                $http.get('/rest/googlexads/report', {
                    params: { 'dimension': 'Date', 'end': 'TODAY', 'metrics': widget.metric, 'start': '30DAYSAGO', websiteid: h.siteId(), 'report': 'ACCOUNT_PERFORMANCE_REPORT' }
                }).then(function successCallback(res) {
                    widget.widget = _charts.init('timeline', res.data.data, 'Date', widget.metric, 'YYYY-MM-DD')
                    widget.widget.action = res.data.action;
                });
            },
            'googleads_performance_chart': function(widget) {
                var report = { 'CampaignName': 'CAMPAIGN_PERFORMANCE_REPORT', 'AdGroupName': 'ADGROUP_PERFORMANCE_REPORT', 'Query': 'SEARCH_QUERY_PERFORMANCE_REPORT' };
                $http.get('/rest/googlexads/report', {
                    params: { 'dimension': widget.dimension, 'end': 'TODAY', 'metrics': widget.metric, 'start': '30DAYSAGO', websiteid: h.siteId(), 'report': report[widget.dimension] }
                }).then(function successCallback(res) {
                    widget.widget = _charts.init(widget.chart, res.data.data, widget.dimension, widget.metric)
                    widget.widget.action = res.data.action;
                });
            },
            'googleads_conversion_chart': function(widget) {
                $http.get('/rest/googlexads/report', {
                    params: { 'dimension': widget.dimension, 'end': 'TODAY', 'metrics': widget.metric, 'start': '30DAYSAGO', websiteid: h.siteId(), 'report': 'ACCOUNT_PERFORMANCE_REPORT' }
                }).then(function successCallback(res) {
                    widget.widget = _charts.init(widget.chart, res.data.data, widget.dimension, widget.metric)
                    widget.widget.action = res.data.action;
                });
            },
            'facebookinsights_timeline': function(widget) {
                $http.get('/rest/facebookinsights/report', {
                    params: { 'dimension': 'date', 'end': 'TODAY', 'start': '30DAYSAGO', websiteid: h.siteId(), 'endpoint': 'insights', 'report': 'timeline' }
                }).then(function successCallback(res) {
                    if (widget.metric == 'engagements') {
                        var data = res.data.sets[widget.metric].data.reduce(function(acc, cur) {
                            if (cur.type == 'engagements') {
                                acc.push({ 'change': cur.value, 'date': cur.date });
                            }
                            return acc;
                        }, []);
                    } else {
                        var data = res.data.sets[widget.metric].data
                    }
                    widget.widget = _charts.init('timeline', data, 'date', 'change', 'YYYY-MM-DD')
                    widget.widget.action = res.data.action;
                });
            },
            'facebookads_timeline': function(widget) {
                $http.get('/rest/facebookads/report', {
                    params: { 'dimension': 'date', 'end': 'TODAY', 'start': '30DAYSAGO', websiteid: h.siteId(), 'level': 'account', 'endpoint': 'insights', 'metrics': widget.metric }
                }).then(function successCallback(res) {
                    widget.widget = _charts.init('timeline', res.data.data, 'date', widget.metric, 'YYYY-MM-DD')
                    widget.widget.action = res.data.action;
                });
            },
            'onpage_changes': function(widget) {
                $http.get('/rest/onpage/rules', { 'params': { 'lang': $scope.user.site.locale.lang } }).then(function successCallback(res) {
                    $scope.onpage = res.data;
                    $http.get('/rest/onpage/changes', {
                        params: {
                            websiteid: h.siteId(),
                        }
                    }).then(function successCallback(res) {
                        widget.widget = res.data.data;
                    });
                });
            },
            'onpage_changes_donut': function(widget) {
                $http.get('/rest/onpage/changes', { 'params': { websiteid: h.siteId() } }).then(function successCallback(res) {
                    var stats = [{ 'label': 'change', 'value': 0, 'color': '#808080' }, { 'label': 'done', 'value': 0, 'color': '#4caf50' }, { 'label': 'issue', 'value': 0, 'color': '#ff9800' }];
                    for (var i in res.data.data) {
                        if (res.data.data[i].r === true) {
                            stats[1].value += 1;
                        } else if (res.data.data[i].r === false) {
                            stats[2].value += 1;
                        } else {
                            stats[0].value += 1;
                        }
                    }
                    widget.widget = { data: stats, type: 'pie', marginLeft: 0, marginRight: 0, marginTop: 10, categoryField: 'label', "precision": 0, "decimalSeparator": ",", "thousandsSeparator": ".", legend: { enabled: false, position: 'right', autoMargins: false, marginRight: 100, }, titleField: 'label', valueField: 'value', "colorField": "color", labelRadius: 5, radius: '42%', innerRadius: '60%', labelText: '[[label]]', }
                });
            },
            'onpage_seo': function(widget) {
                $http.get('/rest/onpage/list', {
                    params: {
                        websiteid: h.siteId(),
                    }
                }).then(function successCallback(res) {
                    widget.widget = res.data;
                    widget.widget.avg = { 'all': 0, 'technical': 0, 'content': 0, 'mobile': 0, 'indexability': 0 }
                    if(widget.widget.history){
                    var l = widget.widget.history.length;
                    angular.forEach(widget.widget.history, function(value, key) {
                        widget.widget.avg['all'] += value.all / l
                        widget.widget.avg['technical'] += value.technical / l
                        widget.widget.avg['content'] += value.content / l
                        widget.widget.avg['mobile'] += value.mobile / l
                        widget.widget.avg['indexability'] += value.indexability / l
                    });
                }
                });
            },
            'ranktracer': function(widget) {
                $http.get('/rest/rank-tracker/list', {
                    params: {
                        websiteid: h.siteId(),
                    }
                }).then(function successCallback(res) {
                    for (var i in res.data) {
                        res.data[i].summary.google.pos = res.data[i].summary.google.pos || 100
                        res.data[i].summary.googlemobile.pos = res.data[i].summary.googlemobile.pos || 100
                        res.data[i].health = 100 - ((res.data[i].summary.google.worst - res.data[i].summary.google.pos + .5) / (res.data[i].summary.google.worst - res.data[i].summary.google.best)) * 100;
                    }
                    widget.widget = res.data;
                });
            },
            'searchconsole_keywords': function(widget) {
                $http.get('/rest/searchconsole/report', {
                    params: { 'dimension': 'query', 'end': 'TODAY', 'metrics': 'clicks,ctr,position,impressions', 'start': '30DAYSAGO', 'report': 'searchAnalytics', websiteid: h.siteId(), }
                }).then(function successCallback(res) {
                    widget.widget = res.data;
                });
            },
            'searchconsole_chart': function(widget) {
                $http.get('/rest/searchconsole/report', {
                    params: { 'dimension': widget.dimension, 'end': 'TODAY', 'metrics': widget.metric, 'start': '30DAYSAGO', websiteid: h.siteId(), }
                }).then(function successCallback(res) {
                    widget.widget = _charts.init(widget.chart, res.data.data, widget.dimension, widget.metric);
                    widget.widget.action = res.data.action;
                });
            },
            'searchconsole_timeline': function(widget) {
                $http.get('/rest/searchconsole/report', {
                    params: { 't':'123','dimension': 'date', 'end': 'TODAY', 'metrics': widget.metric, 'start': '30DAYSAGO', websiteid: h.siteId(), 'report': 'searchAnalytics' }
                }).then(function successCallback(res) {
                    widget.widget = _charts.init('timeline', res.data.data, 'date', widget.metric, 'YYYY-MM-DD')
                    widget.widget.action = res.data.action;
                });
            },
        };
    }
]);
app.controller('help', ['$scope', '$timeout', '$http', '$rootScope', 'h',
    function($scope, $timeout, $http, $rootScope, h) {
        $http.get('https://www.marketingtracer.com/help/listjson', {
            params: {
                lang: $rootScope.user.site.locale.lang,
            }
        }).then(function successCallback(res) {
            $scope.topics = res.data;
        });
        $scope.getText = function(_id, sub_id, subtopic) {
            $http.get('https://www.marketingtracer.com/help/subtopicjson', {
                params: {
                    lang: $rootScope.user.site.locale.lang,
                    _id: _id,
                    sub_id: sub_id,
                }
            }).then(function successCallback(res) {
                subtopic.html = res.data;
            });
        }
        var users = {
            userList: function() {
                $http.get('/rest/user/reseller.site.list', {
                    params: {
                        websiteid: h.siteId(),
                    }
                }).then(function successCallback(res) {
                    $scope.users = res.data;
                });
            },
            matchUser: function(UserId) {
                for (var i in $scope.users) {
                    if ($scope.users[i]._id.$oid == UserId) {
                        return $scope.users[i].name;
                    }
                }
                return '';
            }
        }
    }
]);
app.controller("ranktracker", [
  "$scope",
  "$timeout",
  "$http",
  "$rootScope",
  "$filter",
  "h",
  function ($scope, $timeout, $http, $rootScope, $filter, h) {
    $scope.rankings = [];
    $scope.page = {
      bFilterStar: false,
      label: "",
      lgchart: "",
      labels: {},
      filter: {},
      sortType: "q",
      collapse: {},
      chartlg: false,
      locale: $rootScope.user.site.locale,
      fnChartLg: function (c) {
        this.chartlg = this.chartlg == c ? false : c;
      },
      sortReverse: false,
      fnSort: function (s) {
        if ($scope.page.sortType == s) {
          $scope.page.sortReverse = !$scope.page.sortReverse;
        } else {
          $scope.page.sortReverse = false;
        }
        $scope.page.sortType = s;
      },
      provider: "google",
    };
    $scope.fnCustomDate = {
      init: function () {
        var d = new Date();
        d.setMonth(d.getMonth() - 1);
        $scope.customdate = { start: d, end: new Date(), show: false };
      },
      set: function () {
        $scope.customdate.show = false;
        $rootScope.reportdates.start = Math.round($scope.customdate.start.getTime() / 1000);
        $rootScope.reportdates.end = Math.round($scope.customdate.end.getTime() / 1000);
        $rootScope.reportdates.description = "Custom";
        $scope.getKeywords();
      },
    };
    $scope.dateoptions = [
      { start: false, end: false, description: "All times" },
      { start: "TODAY", end: "TODAY", description: "Today" },
      { start: "YESTYERDAY", end: "YESTYERDAY", description: "Yesterday" },
      { start: "7DAYSAGO", end: "TODAY", description: "Past 7 days" },
      { start: "14DAYSAGO", end: "TODAY", description: "Past 14 days" },
      { start: "30DAYSAGO", end: "TODAY", description: "Past 30 days" },
      { start: "1YEARAGO", end: "TODAY", description: "Past year" },
      { start: "THISMONTH", end: "TODAY", description: "This month" },
      { start: "LASTMONTH", end: "TODAY", description: "Previous month" },
    ];
    if (!$rootScope.reportdates) {
      $rootScope.reportdates = { start: false, end: false, description: "All time" };
    }
    $scope.fnDateSelection = function (reportdates) {
      $rootScope.reportdates.start = reportdates.start;
      $rootScope.reportdates.end = reportdates.end;
      $rootScope.reportdates.description = reportdates.description;
      $scope.getKeywords();
      $scope.getVisibility();
    };
    $scope.do = function (obj, method, param) {
      if (obj == "fnSingle") {
        fnSingle[method](param);
      } else {
        fnMultiple[method](param);
      }
    };
    var fnSingle = {
      getParams: function (ranking) {
        return {
          websiteid: h.siteId(),
          ids: [ranking._id.$oid],
        };
      },
      pre_options: function (ranking) {
        ranking.pre_options = !ranking.pre_options;
        if (ranking.pre_options) {
          $http
            .get("/rest/rank-tracker/history", {
              params: {
                websiteid: h.siteId(),
                ranking_id: ranking._id.$oid,
                provider: $scope.page.provider,
                start: $rootScope.reportdates.start,
                end: $rootScope.reportdates.end,
              },
            })
            .then(function successCallback(res) {
              var data = res.data;
            });
        }
      },
      options: function (ranking) {
        $http
          .post(
            "/rest/rank-tracker/edit",
            angular.extend(
              {
                "summary.google.start": ranking.summary.google.start,
                "summary.googlemobile.start": ranking.summary.googlemobile.start,
                "meta.label": ranking.meta.label,
                url: ranking.url,
                fields: ["summary.google.start", "summary.googlemobile.start", "meta.label", "url"],
              },
              fnSingle.getParams(ranking)
            )
          )
          .then(function successCallback(res) {
            $scope.getKeywords();
          });
      },
      sanitize: function (ranking) {
        $http.post("/rest/rank-tracker/sanitize", angular.extend({ "q": ranking.q }, fnSingle.getParams(ranking))).then(function successCallback(res) {
          $scope.getKeywords();
        });
      },
      delete: function (ranking) {
        $http.post("/rest/rank-tracker/delete", fnSingle.getParams(ranking)).then(function successCallback(res) {
          $scope.getKeywords();
        });
      },
      star: function (ranking) {
        $http.post("/rest/rank-tracker/edit", angular.extend({ "meta.star": !ranking.meta.star, fields: ["meta.star"] }, fnSingle.getParams(ranking))).then(function successCallback(res) {
          $scope.getKeywords();
        });
      },
    };
    var fnMultiple = {
      getParams: function (ranking) {
        var ids = [];
        for (var i in $scope.rankings) {
          if ($scope.rankings[i].checked) {
            ids.push($scope.rankings[i]._id.$oid);
          }
        }
        return {
          websiteid: h.siteId(),
          ids: ids,
        };
      },
      multioptions: function () {
        $scope.page.multioptions = false;
        for (var i in $scope.rankings) {
          if ($scope.rankings[i].checked) {
            $scope.page.multioptions = true;
            break;
          }
        }
      },
      check: function (ranking) {
        ranking.checked = !ranking.checked;
        fnMultiple.multioptions();
      },
      checkall: function (label) {
        $scope.page.labels[label] = !$scope.page.labels[label];
        for (var i in $scope.rankings) {
          if ($scope.rankings[i].meta.label == label) {
            $scope.rankings[i].checked = $scope.page.labels[label];
          }
        }
        fnMultiple.multioptions();
      },
      options: function (ranking) {
        $http
          .post(
            "/rest/rank-tracker/edit",
            angular.extend(
              {
                "meta.label": $scope.page.label,
                fields: ["meta.label"],
              },
              fnMultiple.getParams(ranking)
            )
          )
          .then(function successCallback(res) {
            $scope.getKeywords();
          });
      },
      delete: function (ranking) {
        $http.post("/rest/rank-tracker/delete", fnMultiple.getParams(ranking)).then(function successCallback(res) {
          $scope.getKeywords();
        });
      },
      resetvolume: function (ranking) {
        $http.post("/rest/rank-tracker/resetvolume", fnMultiple.getParams(ranking)).then(function successCallback(res) {
          $scope.getKeywords();
        });
      },
      export: function (ranking) {
        $http.post("/rest/rank-tracker/export", fnMultiple.getParams(ranking)).then(function successCallback(res) {
          var element = document.createElement("a");
          element.setAttribute("href", "data:text/html;," + encodeURIComponent(res.data.csv));
          element.setAttribute("download", "export.csv");
          element.style.display = "none";
          document.body.appendChild(element);
          element.click();
          document.body.removeChild(element);
        });
      },
      exportxls: function (ranking) {
        $http.post("/rest/rank-tracker/exportxls", fnMultiple.getParams(ranking)).then(function successCallback(res) {
          var element = document.createElement("a");
          element.setAttribute("href", "data:text/html;," + encodeURIComponent(res.data.csv));
          element.setAttribute("download", "export.xls");
          element.style.display = "none";
          document.body.appendChild(element);
          element.click();
          document.body.removeChild(element);
        });
      },
    };
    // ranking grafiek'heschiedenis
    $scope.fnRankingHistory = function (ranking, provider) {
      if (ranking.active && $scope.page.provider == provider) {
        ranking.active = false;
        return;
      }
      $scope.page.provider = provider;
      for (var x in $scope.rankings) {
        $scope.rankings[x].active = false;
      }
      ranking.active = true;
      $http
        .get("/rest/rank-tracker/history", {
          params: {
            websiteid: h.siteId(),
            ranking_id: ranking._id.$oid,
            provider: $scope.page.provider,
            start: $rootScope.reportdates.start,
            end: $rootScope.reportdates.end,
          },
        })
        .then(function successCallback(res) {
          var data = res.data;
          var graphs = [];
          var _d = {};
          var d = [];
          let urlkeyexists = {};
          for (var i in data) {
            if (data[i]?.data?.length > 0 || typeof data[i]?.data === "object") {
              if (data[i]?.data?.length === 0) {
                // stupid array identifies as object!
              } else {
                console.log(data[i]?.data);
                console.log(data[i]?.data?.length);
                console.log(typeof data[i]?.data);
                for (var y in data[i].data) {
                  _d[data[i].data[y].date] = _d[data[i].data[y].date] || { date: data[i].data[y].date };
                  _d[data[i].data[y].date][i] = data[i].data[y].pos;
                }
                graphs.push({
                  balloonText: data[i].url + "
position: [[value]]",
                  title: data[i].url,
                  bullet: "round",
                  bulletBorderAlpha: 1,
                  bulletColor: "#FFFFFF",
                  useLineColorForBulletBorder: true,
                  fillAlphas: 0,
                  lineThickness: 2,
                  lineAlpha: 1,
                  bulletSize: 7,
                  valueField: i,
                  connect: false,
                });
              }
            }
          }
          for (var i in _d) {
            d.push(_d[i]);
          }
          ranking.chart = {
            data: d,
            type: "serial",
            theme: "light",
            marginLeft: 0,
            marginRight: 0,
            marginTop: 10,
            categoryField: "date",
            rotate: false,
            pathToImages: "vendor/amchart/images/",
            dataDateFormat: "YYYYMMDD",
            legend: {
              position: "bottom",
              enabled: true,
              useGraphSettings: true,
            },
            categoryAxis: {
              gridPosition: "start",
              parseDates: true,
              labelRotation: 45,
            },
            valueAxes: [
              {
                reversed: true,
                position: "left",
                axisAlpha: 0,
                labelsEnabled: true,
                minimum: 1,
              },
            ],
            graphs: graphs,
          };
        });
    };
    // haal alle sleutelwoorden op
    $scope.getKeywords = function (a) {
      // all active plans
      $scope.urls = {};
      var startDate = $scope.custominit ? $scope.custominit.start : $rootScope.reportdates.start;
      $scope.page.bFilterStar = $scope.custominit ? $scope.custominit.bFilterStar : $scope.page.bFilterStar;
      if ($scope.page.bFilterStar == true) {
        $scope.page.filter.meta = { star: true };
      }
      $http
        .get("/rest/rank-tracker/list", {
          params: {
            websiteid: h.siteId(),
            start: startDate,
            end: $rootScope.reportdates.end,
          },
        })
        .then(function successCallback(res) {
          $scope.page.rankinglength = res.data.length;
          if ($scope.page.rankinglength === 0) {
            //$scope.fnModal("rank-tracker/modal.addkeyword");
          }
          $scope.change = { nverlies: 0, nwinst: 0, nsame: 0, verlies: 0, winst: 0, totaal: 0, n: 0 };
          $scope.pie = { top3: 0, top10: 0, top100: 0, overig: 0 };
          $scope._rankings = angular.copy(res.data);
          //$scope.rankings = res.data;
          $scope.sortranking();
        });
    };
    $scope.switchstar = function () {
      if ($scope.page.filter.meta) {
        delete $scope.page.filter.meta;
      } else {
        $scope.page.filter.meta = { star: true };
      }
      $scope.sortranking();
    };
    $scope.sortranking = function () {
      $scope.rankings = $filter("filter")($scope._rankings, $scope.page.filter);
      if ($scope.rankings.length > 0) {
        for (var i in $scope.rankings) {
          if ($scope.rankings[i].active) {
            var active = i;
          }
        }
      }
      var sorted = {};
      // some stats
      var totalenhancements = {};
      for (var i in $scope.rankings) {
        var ranking = $scope.rankings[i];
        ranking.meta.label = ranking.meta.label || "--";
        if (ranking?.url && ranking.url.indexOf("http") != 0) {
          ranking.url = "https://" + ranking.url;
        }
        var tmpg = ranking?.summary?.google?.pos || 100;
        var tmpgm = ranking?.summary?.googlemobile?.pos || 100;
        ranking.summary = ranking?.summary || { google: { pos: tmpg }, googlemobile: { pos: tmpgm } };
        //ranking.summary.google = ranking?.summary?.google || {pos:100}
        //ranking.summary.googlemobile.pos = ranking.summary.googlemobile.pos || 100
        if (active && i == active) {
          $scope.fnRankingHistory(ranking, $scope.page.provider);
        }
        // kan weg
        if (ranking.summary.google.pos < 4) {
          ++$scope.pie.top3;
        } else if (ranking.summary.google.pos < 11) {
          ++$scope.pie.top10;
        } else if (ranking.summary.google.pos < 100) {
          ++$scope.pie.top100;
        } else {
          ++$scope.pie.overig;
        }
        //health
        ranking.health = 100 - ((ranking.summary.google.worst - ranking.summary.google.pos + 0.5) / (ranking.summary.google.worst - ranking.summary.google.best)) * 100;
        if (ranking.health > 100) {
          ranking.health = 100;
        }
        sorted[ranking.meta.label] = sorted[ranking.meta.label] || [];
        sorted[ranking.meta.label].push(ranking);
        //change
        if (ranking.summary.google.start > ranking.summary.google.pos) {
          $scope.change.nwinst += 1;
          $scope.change.winst += ranking.summary.google.start - ranking.summary.google.pos;
        } else if (ranking.summary.google.start < ranking.summary.google.pos) {
          $scope.change.nverlies += 1;
          $scope.change.verlies += ranking.summary.google.pos - ranking.summary.google.start;
        } else {
          $scope.change.nsame += 1;
        }
        // enhancements
        var enhancements = {};
        if (typeof ranking.summary.google.enhancements == "object" && ranking.summary.google.enhancements != null) {
          if (typeof ranking.summary.google.enhancements.other == "object") {
            ranking.summary.google.enhancements.other = ranking.summary.google.enhancements.other || {};
            ranking.summary.google.enhancements.other = Object.values(ranking.summary.google.enhancements.other);
          }
          if (typeof ranking.summary.google.enhancements.my == "object") {
            ranking.summary.google.enhancements.my = ranking.summary.google.enhancements.my || {};
            ranking.summary.google.enhancements.my = Object.values(ranking.summary.google.enhancements.my);
          }
          ranking.summary.google.enhancements.other = ranking.summary.google.enhancements.other || [];
          ranking.summary.google.enhancements.my = ranking.summary.google.enhancements.my || [];
          ranking.summary.google.enhancements.other.forEach(function (v, k) {
            totalenhancements[v] = totalenhancements[v] || { v: v, my: 0, other: 0 };
            totalenhancements[v].other += 1;
            enhancements[v] = enhancements[v] || { v: v, my: 0, other: 0 };
            enhancements[v].other += 1;
          });
          ranking.summary.google.enhancements.my.forEach(function (v, k) {
            totalenhancements[v] = totalenhancements[v] || { v: v, my: 0, other: 0 };
            totalenhancements[v].my += 1;
            enhancements[v] = enhancements[v] || { v: v, my: 0, other: 0 };
            enhancements[v].my += 1;
          });
        }
        ranking.enhancements = Object.values(enhancements).sort(function (a, b) {
          return a.v < b.v ? -1 : 1;
        });
        $scope.totalenhancements = Object.values(totalenhancements).sort(function (a, b) {
          return a.v < b.v ? -1 : 1;
        });
        $scope.change.n += 1;
        $scope.change.totaal += ranking.summary.google.start - ranking.summary.google.pos;
      }
      let sortedranking = [];
      Object.keys(sorted).forEach(function (k) {
        let _sorted = sorted[k];
        sortedranking.push({ label: k, rankings: _sorted });
      });
      $scope.sortedranking = sortedranking;
    };
    $scope.charts = {};
    $scope.changes = {};
    var chart = {
      small: {
        type: "serial",
        categoryField: "date",
        dataDateFormat: "YYYYMMDD",
        autoMargins: false,
        categoryAxis: { parseDates: true, gridAlpha: 0, axisAlpha: 0 },
        valueAxes: [{ gridAlpha: 0, axisAlpha: 0, color: "#FFFFFF", stackType: "regular" }],
      },
      large: {
        type: "serial",
        categoryField: "date",
        dataDateFormat: "YYYYMMDD",
        autoMargins: true,
        categoryAxis: { gridPosition: "start", parseDates: true, gridThickness: 0 },
        valueAxes: [{ position: "left", axisAlpha: 0, labelsEnabled: true, dashLength: 4, color: "#dedede", stackType: "regular" }],
      },
      visibility: function (data, type) {
        $scope.charts.visibility = angular.extend({}, chart[type], {
          data: data,
          graphs: [
            {
              balloonText: "Visibility: [[value]]%",
              fillAlphas: 0,
              lineAlpha: 1,
              bulletAlpha: 0.7,
              valueField: "visibility",
              lineColor: h.colors()[1],
            },
          ],
        });
        $scope.charts.visibilitylg = angular.extend({}, chart["large"], {
          data: data,
          graphs: [
            {
              balloonText: "Visibility: [[value]]%",
              lineAlpha: 1,
              valueField: "visibility",
              lineColor: h.colors()[1],
              bullet: "round",
              bulletBorderAlpha: 1,
              bulletColor: "#FFFFFF",
              useLineColorForBulletBorder: true,
              fillAlphas: 0,
              lineThickness: 2,
              lineAlpha: 1,
              bulletSize: 7,
            },
          ],
        });
        $scope.changes.visibility = { cur: data[data.length - 1].visibility, start: data[0].visibility, dif: data[data.length - 1].visibility - data[0].visibility };
      },
      avgpos: function (data, type) {
        var _data = data.reduce(function (acc, cur) {
          if (cur.avg) {
            acc.push(cur);
          }
          return acc;
        }, []);
        if (_data.length == 1) {
          _data.unshift({ date: "20191031", avg: 0 });
        }
        $scope.charts.avgpos = angular.extend({}, chart[type], {
          data: _data,
          graphs: [
            {
              balloonText: "Avg position: [[value]]",
              lineAlpha: 1,
              valueField: "avg",
              lineColor: h.colors()[3],
            },
          ],
          valueAxes: [{ gridAlpha: 0, axisAlpha: 0, color: "#FFFFFF", stackType: "regular", reversed: true }],
        });
        $scope.charts.avgposlg = angular.extend({}, chart["large"], {
          data: _data,
          graphs: [
            {
              balloonText: "Avg position: [[value]]",
              valueField: "avg",
              lineColor: h.colors()[3],
              lineAlpha: 1,
              bullet: "round",
              bulletBorderAlpha: 1,
              bulletColor: "#FFFFFF",
              useLineColorForBulletBorder: true,
              fillAlphas: 0,
              lineThickness: 2,
              lineAlpha: 1,
              bulletSize: 7,
            },
          ],
          valueAxes: [{ gridAlpha: 0, axisAlpha: 0, color: "#FFFFFF", stackType: "regular", reversed: true }],
        });
        $scope.changes.avgpos = { cur: _data[_data.length - 1].avg, start: _data[0].avg, dif: (_data[_data.length - 1].avg - _data[0].avg) * -1 };
      },
      enhancement: function (data, type) {
        var _data = data.reduce(function (acc, cur) {
          if (cur.my_enh || cur.other_enh) {
            acc.push(cur);
          }
          return acc;
        }, []);
        if (_data.length == 1) {
          _data.unshift({ date: "20191031", my_enh: 0, other_enh: 0 });
        }
        $scope.charts.enhancement = angular.extend({}, chart[type], {
          data: _data,
          graphs: [
            {
              balloonText: "My enhancements: [[value]]",
              fillAlphas: 0.6,
              lineAlpha: 1,
              valueField: "my_enh",
              lineColor: h.colors()[4],
            },
            {
              balloonText: "Total enhancements: [[value]]",
              fillAlphas: 0.6,
              lineAlpha: 1,
              valueField: "other_enh",
              lineColor: "#DDDDDD",
            },
          ],
        });
        $scope.charts.enhancementlg = angular.extend({}, chart["large"], {
          data: _data,
          graphs: [
            {
              balloonText: "My enhancements: [[value]]",
              bullet: "round",
              lineAlpha: 1,
              bullet: "round",
              bulletBorderAlpha: 1,
              bulletColor: "#FFFFFF",
              useLineColorForBulletBorder: true,
              fillAlphas: 0.6,
              lineThickness: 2,
              lineAlpha: 1,
              bulletSize: 7,
              valueField: "my_enh",
              lineColor: h.colors()[4],
            },
            {
              balloonText: "Total enhancements: [[value]]",
              bullet: "round",
              lineAlpha: 1,
              bullet: "round",
              bulletBorderAlpha: 1,
              bulletColor: "#FFFFFF",
              useLineColorForBulletBorder: true,
              fillAlphas: 0.6,
              lineThickness: 2,
              lineAlpha: 1,
              bulletSize: 7,
              valueField: "other_enh",
              lineColor: "#DDDDDD",
            },
          ],
        });
        $scope.changes.enhancement = { cur: _data[_data.length - 1]?.my_enh, start: _data[0]?.my_enh, dif: _data[_data.length - 1]?.my_enh - _data[0]?.my_enh };
      },
      top: function (data, type) {
        var _data = data.reduce(function (acc, cur) {
          if (cur.top3 || cur.top10 || cur.top50 || cur.top100 || cur.norank) {
            acc.push(cur);
          }
          return acc;
        }, []);
        $scope.charts.top = angular.extend({}, chart[type], {
          data: _data,
          graphs: [
            { balloonText: "Not ranked: [[value]]", fillAlphas: 0.6, lineAlpha: 0.6, valueField: "norank", lineColor: "#DDDDDD" },
            { balloonText: "Top100: [[value]]", fillAlphas: 0.25, lineAlpha: 0.25, valueField: "top100", lineColor: h.colors()[2] },
            { balloonText: "Top50: [[value]]", fillAlphas: 0.45, lineAlpha: 0.45, valueField: "top50", lineColor: h.colors()[2] },
            { balloonText: "Top10: [[value]]", fillAlphas: 0.65, lineAlpha: 0.65, valueField: "top10", lineColor: h.colors()[2] },
            { balloonText: "Top3: [[value]]", fillAlphas: 0.85, lineAlpha: 0.85, valueField: "top3", lineColor: h.colors()[2] },
            { balloonText: "Top1: [[value]]", fillAlphas: 1, lineAlpha: 1, valueField: "top1", lineColor: h.colors()[2] },
          ],
        });
        $scope.changes.top = {
          cur: _data[_data.length - 1],
          start: _data[0],
          dif: {
            top1: _data[_data.length - 1].top1 - _data[0].top1 || 0,
            top3: _data[_data.length - 1].top3 - _data[0].top3 || 0,
            top10: _data[_data.length - 1].top10 - _data[0].top10 || 0,
            top50: _data[_data.length - 1].top50 - _data[0].top50 || 0,
            top100: _data[_data.length - 1].top100 - _data[0].top100 || 0,
            norank: _data[_data.length - 1].norank - _data[0].norank || 0,
          },
        };
      },
    };
    // haal alle sleutelwoorden op
    $scope.getVisibility = function (a) {
      $http
        .get("/rest/rank-tracker/visibility", {
          params: {
            websiteid: h.siteId(),
            start: $rootScope.reportdates.start,
            end: $rootScope.reportdates.end,
          },
        })
        .then(function successCallback(res) {
          chart.avgpos(res.data, "small");
          chart.visibility(res.data, "small");
          chart.enhancement(res.data, "small");
          chart.top(res.data, "small");
        });
    };
    $scope.fnAddKeywords = function () {
      $http
        .post("/rest/rank-tracker/add", {
          keywords: $scope.page.addkeywords,
          locale: $scope.page.locale,
          websiteid: h.siteId(),
        })
        .then(function successCallback(res) {
          $scope.getKeywords();
          $scope.fnCloseModal();
          $scope.page.addkeywords = "";
        });
    };
    $scope.getKeywords();
    $scope.getVisibility();
    $http.get("/rest/locale/language.list").then(function successCallback(res) {
      $scope.languages = res.data;
    });
    $http.get("/rest/locale/country.list").then(function successCallback(res) {
      $scope.countries = res.data;
    });
    $scope.fnSearchCity = function (q) {
      $http.get("/rest/locale/city.list", { params: { q: q } }).then(function successCallback(res) {
        $scope.cities = res.data;
      });
    };
    $scope.setCity = function (city) {
      $scope.page.locale.city = city.city;
      $scope.page.locale.uule = city.uule;
      $scope.cities = [];
    };
  },
]);
app.controller('ranktrackerinsights', ['$scope', '$timeout', '$http', '$rootScope', '$filter', 'h',
    function($scope, $timeout, $http, $rootScope, $filter, h) {
        $scope.rankings = [];
        if($scope.custominit){
            $scope.page = {'timeframe': '31d'};
        $scope.mds = [
            { 'title': '31-day mean - position improvement', 'timeframe':'31d', 'start': 'r31d', 'end': 'r62d', 'dif': 's31dc', 'vol': 's31dvol', 'order': '-median.s31dc', 'lengthindex': '31dl', 'comp': 'gt' },
            { 'title': '31-day mean - position loss', 'timeframe':'31d', 'start': 'r31d', 'end': 'r62d', 'dif': 's31dc', 'vol': 's31dvol', 'order': 'median.s31dc', 'lengthindex': '31dw', 'comp': 'lt' },
        ];
        } else {
            $scope.page = {'timeframe': '3d'};
        $scope.mds = [
            { 'title': '3-day mean - position improvement', 'timeframe':'3d', 'start': 'r3d', 'end': 'r6d', 'dif': 's3dc', 'vol': 's3dvol', 'order': '-median.s3dc', 'lengthindex': '3dw', 'comp': 'gt' },
            { 'title': '3-day mean - traffic improvement', 'timeframe':'3d', 'start': 'r3d', 'end': 'r6d', 'dif': 's3dc', 'vol': 's3dvol', 'order': '-median.s3dvol', 'lengthindex': '3dw', 'comp': 'gt' },
            { 'title': '3-day mean - position loss', 'timeframe':'3d', 'start': 'r3d', 'end': 'r6d', 'dif': 's3dc', 'vol': 's3dvol', 'order': 'median.s3dc', 'lengthindex': '3dl', 'comp': 'lt' },
            { 'title': '3-day mean - traffic loss', 'timeframe':'3d', 'start': 'r3d', 'end': 'r6d', 'dif': 's3dc', 'vol': 's3dvol', 'order': 'median.s3dvol', 'lengthindex': '3dl', 'comp': 'lt' },
            { 'title': '7-day mean - position improvement', 'timeframe':'7d', 'start': 'r7d', 'end': 'r14d', 'dif': 's7dc', 'vol': 's7dvol', 'order': '-median.s7dc', 'lengthindex': '7dw', 'comp': 'gt' },
            { 'title': '7-day mean - traffic improvement', 'timeframe':'7d', 'start': 'r7d', 'end': 'r14d', 'dif': 's7dc', 'vol': 's7dvol', 'order': '-median.s7dvol', 'lengthindex': '7dw', 'comp': 'gt' },
            { 'title': '7-day mean - position loss', 'timeframe':'7d', 'start': 'r7d', 'end': 'r14d', 'dif': 's7dc', 'vol': 's7dvol', 'order': 'median.s7dc', 'lengthindex': '7dl', 'comp': 'lt' },
            { 'title': '7-day mean - traffic loss', 'timeframe':'7d', 'start': 'r7d', 'end': 'r14d', 'dif': 's7dc', 'vol': 's7dvol', 'order': 'median.s7dvol', 'lengthindex': '7dl', 'comp': 'lt' },
            { 'title': '31-day mean - position improvement', 'timeframe':'31d', 'start': 'r31d', 'end': 'r62d', 'dif': 's31dc', 'vol': 's31dvol', 'order': '-median.s31dc', 'lengthindex': '31dl', 'comp': 'gt' },
            { 'title': '31-day mean - traffic improvement', 'timeframe':'31d', 'start': 'r31d', 'end': 'r62d', 'dif': 's31dc', 'vol': 's31dvol', 'order': '-median.s31dvol', 'lengthindex': '31dl', 'comp': 'gt' },
            { 'title': '31-day mean - position loss', 'timeframe':'31d', 'start': 'r31d', 'end': 'r62d', 'dif': 's31dc', 'vol': 's31dvol', 'order': 'median.s31dc', 'lengthindex': '31dw', 'comp': 'lt' },
            { 'title': '31-day mean - traffic loss', 'timeframe':'31d', 'start': 'r31d', 'end': 'r62d', 'dif': 's31dc', 'vol': 's31dvol', 'order': 'median.s31dvol', 'lengthindex': '31dw', 'comp': 'lt' },
        ];
        }
        $scope.exists = function(prop, comp) {
            return function(item) {
                return item.median.hasOwnProperty(prop) && (comp == 'lt') ? item.median[prop] < 0 : item.median[prop] > 0
            }
        }
        var competitors = {
            listinsights: function() {
                $http.get("/rest/rank-tracker/median", {
                    params: {
                        websiteid: h.siteId(),
                    }
                }).then(function successCallback(res) {
                    $scope.insights = res.data;
                    $scope.lengths = $scope.insights.reduce(function(acc, cur) {
                        if (cur.median.s3dc > 0) {
                            acc['3dw'] += 1;
                        } else if (cur.median.s3dc < 0) {
                            acc['3dl'] += 1;
                        }
                        if (cur.median.s7dc > 0) {
                            acc['7dw'] += 1;
                        } else if (cur.median.s7dc < 0) {
                            acc['7dl'] += 1;
                        }
                        if (cur.median.s7dc > 0) {
                            acc['31dw'] += 1;
                        } else if (cur.median.s31dc < 0) {
                            acc['31dl'] += 1;
                        }
                        return acc;
                    }, { '3dl': 0, '3dw': 0, '7dl': 0, '7dw': 0, '31dl': 0, '31dw': 0 })
                });
            },
        }
        competitors.listinsights();
        // ranking grafiek'heschiedenis
        $scope.fnRankingHistory = function(ranking, provider) {
            if (ranking.active && $scope.page.provider == provider) {
                ranking.active = false;
                return;
            }
            $scope.page.provider = provider;
            for (var x in $scope.rankings) {
                $scope.rankings[x].active = false;
            }
            ranking.active = true;
            $http.get("/rest/rank-tracker/history", {
                params: {
                    websiteid: h.siteId(),
                    ranking_id: ranking._id.$oid,
                    provider: 'google',
                }
            }).then(function successCallback(res) {
                var data = res.data;
                var graphs = [];
                var _d = {};
                var d = [];
                for (var i in data) {
                    for (var y in data[i].data) {
                        _d[data[i].data[y].date] = _d[data[i].data[y].date] || { 'date': data[i].data[y].date };
                        _d[data[i].data[y].date][i] = data[i].data[y].pos;
                    }
                    graphs.push({
                        balloonText: data[i].url + "
position: [[value]]",
                        "title": data[i].url,
                        "bullet": "round",
                        "bulletBorderAlpha": 1,
                        "bulletColor": "#FFFFFF",
                        "useLineColorForBulletBorder": true,
                        "fillAlphas": 0,
                        "lineThickness": 2,
                        "lineAlpha": 1,
                        "bulletSize": 7,
                        "valueField": i,
                        "connect": false,
                    })
                }
                for (var i in _d) {
                    d.push(_d[i]);
                }
                ranking.chart = {
                    data: d,
                    type: 'serial',
                    theme: 'light',
                    marginLeft: 0,
                    marginRight: 0,
                    marginTop: 10,
                    categoryField: 'date',
                    rotate: false,
                    pathToImages: 'vendor/amchart/images/',
                    dataDateFormat: 'YYYYMMDD',
                    legend: {
                        position: "bottom",
                        enabled: true,
                        "useGraphSettings": true,
                    },
                    categoryAxis: {
                        gridPosition: "start",
                        parseDates: true,
                        labelRotation: 45
                    },
                    valueAxes: [{
                        reversed: true,
                        position: "left",
                        axisAlpha: 0,
                        labelsEnabled: true,
                        minimum: 1,
                    }],
                    graphs: graphs,
                }
            });
        }
        // set competitors
        $scope.fnAddCompetitors = function() {
            $http.post('/rest/rank-tracker/competitors.edit', {
                competitors: $scope.competitors,
                websiteid: h.siteId()
            }).then(function successCallback(res) {
                competitors.listinsights();
                competitors.listkeywords();
                $scope.fnCloseModal();
            });
        }
    }
]);
app.controller('ranktrackercompetitors', ['$scope', '$timeout', '$http', '$rootScope', '$filter', 'h',
    function($scope, $timeout, $http, $rootScope, $filter, h) {
        $scope.rankings = [];
$scope.blazak = {};
        $scope.page = {
            label: '',
            labels: {},
            table: {
                'curpage': 0,
                'itemsperpage': 14,
                'offset': 0,
                'filter': {},
                'order': { 'k': 'url', 'r': false },
                'fnOrder': function(k, b) {
                    this.order.r = (k == this.order.k) ? !this.order.r : b;
                    this.order.k = k;
                },
                fnSetOffset: function() {
                    this.offset = this.itemsperpage * (this.curpage - 1);
                },
                fnFilterProperty: function() {
                    var pages = angular.copy($rootScope._pages);
                    $scope.pages = $filter('filter')(pages, $scope.page.table.filter);
                }
            },
            date: 'alltime',
            dates: ['alltime', '4weeks', '4months', 'thismonth'],
            tab: 'my',
            provider: 'google'
        }
        $scope.do = function(obj, method, param) {
            if (obj == 'fnSingle') {
                fnSingle[method](param);
            } else {
                fnMultiple[method](param);
            }
        }
        $scope.export = function () {
            $http.post("/rest/rank-tracker/exportcompetitors", {
                websiteid: h.siteId(),
            }).then(function successCallback(res) {
              var element = document.createElement("a");
              element.setAttribute("href", "data:text/html;," + encodeURIComponent(res.data.csv));
              element.setAttribute("download", "export.csv");
    
              element.style.display = "none";
              document.body.appendChild(element);
    
              element.click();
    
              document.body.removeChild(element);
            });
          };
        var competitors = {
            listcompetitors: function() {
                $http.get("/rest/rank-tracker/competitors.list", {
                    params: {
                        websiteid: h.siteId(),
                    }
                }).then(function successCallback(res) {
                    $scope.competitors = res.data;
                    if ($scope.competitors.length === 0 && $rootScope.user.site.role < 6) {
                        $scope.fnModal('rank-tracker/modal.editcompetitors');
                    }
                });
            },
            listkeywords: function() {
                if ($scope.rankings.length > 0) {
                    for (var i in $scope.rankings) {
                        if ($scope.rankings[i].active) {
                            var active = i;
                        }
                    }
                }
                var sorted = {};
                // all active plans 
                $scope.urls = {}
                $http.get('/rest/rank-tracker/competitors.listkeywords', {
                    params: {
                        websiteid: h.siteId(),
                    }
                }).then(function successCallback(res) {
                    $scope.page.rankinglength = res.data.length;
                    $scope.rankings = res.data;
                    // some stats
                    for (var i in $scope.rankings) {
                        var ranking = $scope.rankings[i];
                        ranking.summary.google.pos = ranking.summary.google.pos || 100
                        ranking.summary.googlemobile.pos = ranking.summary.googlemobile.pos || 100
                        sorted[ranking.meta.label] = sorted[ranking.meta.label] || [];
                        sorted[ranking.meta.label].push(ranking);
                    }
                    $scope.sortedranking = sorted;
                });
            }
        }
        competitors.listcompetitors();
        competitors.listkeywords();
        // ranking grafiek'heschiedenis
        $scope.fnRankingHistory = function(ranking, provider) {
            provider = 'google';
            console.log(ranking);
            if (ranking.active && $scope.page.provider == provider) {
                ranking.active = false;
                return;
            }
            $scope.page.provider = provider;
            for (var x in $scope.rankings) {
                $scope.rankings[x].active = false;
            }
            ranking.active = true;
            $http.get("/rest/rank-tracker/competitors.history", {
                params: {
                    websiteid: h.siteId(),
                    ranking_id: ranking._id.$oid,
                    provider: $scope.page.provider,
                }
            }).then(function successCallback(res) {
                var data = res.data;
                var graphs = [];
                var _d = {};
                var d = [];
                for (var i in data) {
                    console.log(data[i]);
                    for (var y in data[i].data) {
                        _d[data[i].data[y].date] = _d[data[i].data[y].date] || { 'date': data[i].data[y].date };
                        _d[data[i].data[y].date][i] = data[i].data[y].pos;
                    }
                    graphs.push({
                        balloonText: data[i].url + "
position: [[value]]",
                        "title": data[i].url,
                        "bullet": "round",
                        "bulletBorderAlpha": 1,
                        "bulletColor": "#FFFFFF",
                        "useLineColorForBulletBorder": true,
                        "fillAlphas": 0,
                        "lineThickness": 2,
                        "lineAlpha": 1,
                        "bulletSize": 7,
                        "valueField": i,
                        "connect": false,
                    })
                }
                for (var i in _d) {
                    d.push(_d[i]);
                }
                ranking.chart = {
                    data: d,
                    type: 'serial',
                    theme: 'light',
                    marginLeft: 0,
                    marginRight: 0,
                    marginTop: 10,
                    fontFamily: 'Roboto',
                    categoryField: 'date',
                    rotate: false,
                    pathToImages: 'vendor/amchart/images/',
                    dataDateFormat: 'YYYYMMDD',
                    legend: {
                        position: "bottom",
                        enabled: true,
                        "useGraphSettings": true,
                    },
                    categoryAxis: {
                        gridPosition: "start",
                        parseDates: true,
                        labelRotation: 45
                    },
                    valueAxes: [{
                        reversed: true,
                        position: "left",
                        axisAlpha: 0,
                        labelsEnabled: true,
                        minimum: 1,
                    }],
                    graphs: graphs,
                }
            });
        }
        // set competitors
        $scope.fnAddCompetitors = function() {
            $http.post('/rest/rank-tracker/competitors.edit', {
                competitors: $scope.competitors,
                websiteid: h.siteId()
            }).then(function successCallback(res) {
                competitors.listcompetitors();
                competitors.listkeywords();
                $scope.fnCloseModal();
            });
        }
    }
]);
app.controller('linkbuildingassistant', ['$scope', '$http', '$rootScope', '$window', '$filter', 'h',
    function($scope, $http, $rootScope, $window, $filter, h) {
        $scope.page = {
            'quickselect': {},
            'importtab': false,
            'categories': [],
            'tags': {},
            'dates': [],
            'kdates': {},
            'newlink': { 'moz': { 'targetscope': 'page', 'n': '50' } },
            'multiplelinks': {},
            'filter': {},
            table: {
                'curpage': 0,
                'itemsperpage': 100,
                'offset': 0,
                fnSetOffset: function() {
                    this.offset = this.itemsperpage * (this.curpage - 1);
                },
            }
        }
        /* months*/
        var thismonth = new Date().getMonth() + 3;
        for (var i = 0; i < 15; i++) {
            var date = new Date(new Date().getFullYear(), thismonth, 0);
            $scope.page.dates.push({ 'date': date });
            $scope.page.kdates[date.toString()] = date;
            thismonth = thismonth - 1;
        }
        // do
        $scope.do = function(obj, method, param) {
            if (obj == 'fnSingle') {
                return fnSingle[method](param);
            } else if (obj == 'fnWizzard') {
                return fnWizzard[method](param);
            } else if (obj == 'fnTemplates') {
                return fnTemplates[method](param);
            } else {
                return fnMultiple[method](param);
            }
        }
        // link
        var fnLinks = {
            list: function() {
                $http.get("/rest/linkbuilding/link.list", {
                    params: {
                        websiteid: h.siteId(),
                    }
                }).then(function successCallback(res) {
                    $scope.page.multioptions = false;
                    $scope.page.checkall = false;
                    for (var i in res.data) {
                        var date = new Date(res.data[i].date * 1);
                        res.data[i].monthstring = date.toLocaleString('default', { year: 'numeric', 'month': 'long' })
                        res.data[i].d =  res.data[i].date*1;
                        res.data[i].date = $scope.page.kdates[date.toString()];
                        if (res.data[i].my.tag) {
                            $scope.page.tags[res.data[i].my.tag] = res.data[i].my.tag;
                        }
                    }
                    res.data = $filter('orderBy')(res.data, 'd', true)
                    $scope.links = res.data;
                });
            },
        }
        // categories
        var fnCategories = {
            list: function() {
                if ($scope.categories) {
                    return;
                }
                $http.get('/rest/linkbuilding/manager.categories.list').then(function successCallback(res) {
                    $scope.categories = res.data;
                });
            }
        }
        // categories
        var fnTemplates = {
            list: function() {
                $http.get('/rest/linkbuilding/template.list', {
                    params: {
                        'websiteid': h.siteId(),
                    }
                }).then(function successCallback(res) {
                    $scope.mailTemplates = res.data;
                });
            },
            'get_mails_by_key': function(key) {
                for (var i in $scope.mailTemplates) {
                    if ($scope.mailTemplates[i].key == key) {
                        return $scope.mailTemplates[i].mails;
                    }
                }
            }
        }
        //wizzard
        var fnWizzard = {
            'moz-domain': function() {
                $http.post("/rest/linkbuilding/wizzard.moz.domain",
                    angular.extend({ 'domain': $scope.page.mozdomain }, { websiteid: h.siteId() })
                ).then(function successCallback(res) {
                    fnLinks.list();
                });
            },
            'add_url': function() {
                $http.post("/rest/linkbuilding/link.add.url",
                    angular.extend($scope.page.newlink, { websiteid: h.siteId(), 'date': new Date(new Date().getFullYear(), new Date().getMonth() + 1, 0) })
                ).then(function successCallback(res) {
                    $scope.page.newlink = { 'moz': { 'targetscope': 'page', 'n': '50' } };
                    fnLinks.list();
                });
            },
            'add_bulk': function() {
                $http.post("/rest/linkbuilding/link.add.bulk",
                    angular.extend({ 'my': $scope.page.newlink.my, 'bulk': $scope.page.newlink.bulk, 'allowduplicates': $scope.page.newlink.allowduplicates }, { websiteid: h.siteId(), 'date': new Date(new Date().getFullYear(), new Date().getMonth() + 1, 0) })
                ).then(function successCallback(res) {
                    $scope.page.newlink = { 'moz': { 'targetscope': 'page', 'n': '50' } };
                    fnLinks.list();
                });
            },
            'add_search': function() {
                $http.post("/rest/linkbuilding/link.add.search",
                    angular.extend($scope.page.newlink, { websiteid: h.siteId(), 'date': new Date(new Date().getFullYear(), new Date().getMonth() + 1, 0) })
                ).then(function successCallback(res) {
                    $scope.page.newlink = { 'moz': { 'targetscope': 'page', 'n': '50' } };
                    fnLinks.list();
                });
            },
            'add_moz': function() {
                $http.post("/rest/linkbuilding/link.add.moz",
                    angular.extend($scope.page.newlink, { websiteid: h.siteId(), 'date': new Date(new Date().getFullYear(), new Date().getMonth() + 1, 0) })
                ).then(function successCallback(res) {
                    $scope.page.newlink = { 'moz': { 'targetscope': 'page', 'n': '50' } };
                    fnLinks.list();
                });
            },
            'list_google_alerts': function() {
                $http.get("/rest/linkbuilding/rss.list.google.alerts", {
                    params: {
                        websiteid: h.siteId(),
                    }
                }).then(function successCallback(res) {
                    $scope.page.google_alerts = res.data;
                });
            },
            'add_google_alerts': function() {
                $http.post("/rest/linkbuilding/rss.add.google_alerts",
                    angular.extend({}, { 'alert': $scope.page.newlink.google_alerts }, { websiteid: h.siteId() })
                ).then(function successCallback(res) {
                    $scope.page.newlink = { 'moz': { 'targetscope': 'page', 'n': '50' } };
                                        $scope.page.importtab = false;
                    fnLinks.list();
                });
            },   
            'remove_google_alert': function(alert) {
                $http.post("/rest/linkbuilding/rss.remove.google.alerts",
                    angular.extend({}, { 'alert': alert }, { websiteid: h.siteId() })
                ).then(function successCallback(res) {
                    fnWizzard.list_google_alerts();
                    $scope.page.newlink = { 'moz': { 'targetscope': 'page', 'n': '50' } };
                });
            },
        }
        $scope.fnCopyText = function(text) {
            var body = angular.element($window.document.body);
            var textarea = angular.element('');
            textarea.css({
                position: 'fixed',
                opacity: '0'
            });
            textarea.val(text);
            body.append(textarea);
            textarea[0].select();
            try {
                var successful = document.execCommand('copy');
                if (!successful) throw successful;
            } catch (err) {
            }
            textarea.remove();
        }
        // single link actions
        var fnSingle = {
            'getParams': function(link) {
                return {
                    'websiteid': h.siteId(),
                    'ids': [link._id.$oid],
                }
            },
            'pre_edit': function(link) {
                fnCategories.list();
                $scope.page.curlink = link;
                $scope.fnModal('linkbuilding/modal/single-edit')
            },
            'edit': function(link) {
                var fields = ['partner.url', 'my.status', 'my.url', 'my.anchor', 'date', 'text', 'trade.anchor', 'trade.url', 'partner.type', 'partner.domain.contactform', 'partner.domain.email', 'partner.domain.manager.email', 'partner.domain.manager.name', 'partner.domain.manager.CatId'];
                $http.post("/rest/linkbuilding/link.edit",
                    angular.extend(link, fnSingle.getParams(link), { 'fields': fields })
                ).then(function successCallback(res) { fnLinks.list(); })
            },
            'pre_mail': function(link) {
                if (!link.mail && $scope.mailTemplates[0] !== undefined) {
                    link.mail = { key: $scope.mailTemplates[0].key }
                }
                $scope.page.curlink = link;
                $scope.fnModal('linkbuilding/modal/mail')
            },
            'mail': function(link) {
                $http.post("/rest/linkbuilding/link.mail",
                    angular.extend(link, fnSingle.getParams(link))
                ).then(function successCallback(res) {
                    fnLinks.list();
                })
            },
            'contactform': function(link) {
                $scope.page.curlink = link;
                $scope.page.curlink.mailtemplate = $scope.mailTemplates[$scope.mailTemplates.length - 1];
                $scope.fnModal('linkbuilding/modal/contactform')
            },
            'getmailbody': function(link) {
                var text = link.mailtemplate.mails[0].body;
                // strip tags
                text = text.replace(/(<([^>]+)>)/ig, "");
                //replace
                text = text.replace(/\[partner_link\]/g, link.partner.url);
                text = text.replace(/\[partner_domain\]/g, link.partner.domain.domain);
                console.log(text);
                return text;
            },
            'checkstatus': function(link) {
                link.inprogress = true;
                $http.get("/rest/linkbuilding/link.checkstatus", {
                    'params': { websiteid: h.siteId(), '_id': link['_id']['$oid'] }
                }).then(function successCallback(res) {
                    link.inprogress = false;
                    link.my = res.data.my
                });
            },
            'delete': function(link) {
                $http.post("/rest/linkbuilding/link.delete",
                    fnSingle.getParams(link)
                ).then(function successCallback(res) {
                    fnLinks.list();
                });
            }
        }
        // multiple link actions
        var fnMultiple = {
            getParams: function() {
                var ids = [];
                for (var i in $scope.links) {
                    if ($scope.links[i].checked) {
                        ids.push($scope.links[i]._id.$oid)
                    }
                }
                return {
                    'websiteid': h.siteId(),
                    'ids': ids,
                }
            },
            multioptions: function() {
                $scope.page.multioptions = false;
                for (var i in $scope.links) {
                    if ($scope.links[i].checked) {
                        $scope.page.multioptions = true;
                        break
                    }
                }
            },
            check: function(array) {
                var event = array[0];
                var link = array[1];
                if (event.ctrlKey || event.shiftKey) {
                    var forceselect = false;
                    var _links = $filter('filter')($scope.links, $scope.page.filter);
                    // var _links = $scope.links;
                    for (var _link in _links) {
                        // curlink zetten
                        var curlink = _links[_link];
                        // eingen link gevonden
                        if (forceselect == true) {
                            if (curlink == link) {
                                forceselect = false;
                                break;
                            }
                            if (curlink.checked == true) {
                                forceselect = false;
                                break;
                            }
                            curlink.checked = true;
                        }
                        // 1e selectie = true
                        if (forceselect == false) {
                            if (curlink.checked == true) {
                                forceselect = true;
                            }
                            if (curlink == link) {
                                forceselect = true;
                            }
                        }
                    }
                }
                link.checked = !link.checked;
                fnMultiple.multioptions();
            },
            checkall: function() {
                $scope.page.checkall = !$scope.page.checkall;
                var _links = $filter('filter')($scope.links, $scope.page.filter);
                for (var i in _links) {
                    _links[i].checked = $scope.page.checkall;
                }
                fnMultiple.multioptions();
            },
            quickselect: function(m) {
                for (var i in $scope.links) {
                    var bool = true
                    var t = false
                    if ($scope.page.quickselect.email) {
                        t = true;
                        bool = ($scope.links[i].partner.domain.email) ? bool : false;
                    }
                    if ($scope.page.quickselect.contactform) {
                        t = true;
                        bool = ($scope.links[i].partner.domain.contactform) ? bool : false;
                    }
                    if ($scope.page.quickselect.nocontact) {
                        t = true;
                        bool = ($scope.links[i].partner.domain.email || $scope.links[i].partner.domain.contactform) ? false : bool;
                    }
                    if (t) {
                        $scope.links[i].checked = bool;
                    }
                }
                fnMultiple.multioptions();
            },
            _findallstatus: function() {
                for (var i in $scope.links) {
                    if ($scope.links[i].checked) {
                        $http.get("/rest/linkbuilding/link.checkstatus", {
                            'params': { websiteid: h.siteId(), '_id': $scope.links[i]['_id']['$oid'] }
                        }).then(function successCallback(res) {
                            $scope.links[i].inprogress = false;
                            $scope.links[i].checked = false;
                            fnMultiple._findallstatus();
                        });
                        break;
                    }
                }
            },
            findallstatus: function() {
                for (var i in $scope.links) {
                    if ($scope.links[i].checked) {
                        $scope.links[i].inprogress = true;
                    }
                }
                fnMultiple._findallstatus();
            },
            _findallcontact: function() {
                for (var i in $scope.links) {
                    if ($scope.links[i].checked) {
                        $http.get("/rest/linkbuilding/link.findcontact", {
                            'params': { websiteid: h.siteId(), '_id': $scope.links[i]['_id']['$oid'] }
                        }).then(function successCallback(res) {
                            $scope.links[i] = res.data;
                            var date = new Date($scope.links[i].date * 1);
                            $scope.links[i].monthstring = date.toLocaleString('default', { year: 'numeric', 'month': 'long' })
                            $scope.links[i].date = $scope.page.kdates[date.toString()];
                            $scope.links[i].inprogress = false;
                            $scope.links[i].checked = false;
                            fnMultiple._findallcontact();
                        });
                        break;
                    }
                }
            },
            findallcontact: function() {
                for (var i in $scope.links) {
                    if ($scope.links[i].checked) {
                        $scope.links[i].inprogress = true;
                    }
                }
                fnMultiple._findallcontact();
            },
            'status': function() {
                $http.post("/rest/linkbuilding/link.edit",
                    angular.extend({ 'fields': ['my.status'] },
                        fnMultiple.getParams(),
                        $scope.page.multiplelinks)
                ).then(function successCallback(res) {
                    fnLinks.list();
                })
            },            
            'date': function() {
                $http.post("/rest/linkbuilding/link.edit",
                    angular.extend({ 'fields': ['date'] },
                        fnMultiple.getParams(),
                        $scope.page.multiplelinks)
                ).then(function successCallback(res) {
                    fnLinks.list();
                })
            },
            'tag': function() {
                $http.post("/rest/linkbuilding/link.edit",
                    angular.extend({ 'fields': ['my.tag'] },
                        fnMultiple.getParams(),
                        $scope.page.multiplelinks)
                ).then(function successCallback(res) {
                    fnLinks.list();
                })
            },
            pre_edit: function(link) {
            },
            edit: function(link) {
                $http.post("/rest/rank-tracker/edit",
                    angular.extend({
                        'my.status': $scope.page.multiplelinks.status,
                        'fields': ['my.status']
                    }, fnMultiple.getParams(link))).then(function successCallback(res) {
                    fnLinks.list();
                })
            },
            pre_mail: function() {
                $scope.page.multiplelinks.mail = { key: $scope.mailTemplates[0].key }
                $scope.fnModal('linkbuilding/modal/multiple.mail')
            },
            'mail': function(link) {
                $http.post("/rest/linkbuilding/link.mail",
                    angular.extend($scope.page.multiplelinks, fnMultiple.getParams())
                ).then(function successCallback(res) {
                    fnLinks.list();
                })
            },
            delete: function(link) {
                $http.post("/rest/linkbuilding/link.delete", fnMultiple.getParams(link)).then(function successCallback(res) { fnLinks.list(); })
            }
        }
        $scope.fnExportAll = function() {
            var text = '';
            var out = '';
            for (var _link in $scope.links) {
                var curlink = $scope.links[_link];
                text = text + curlink.url + "\r\n";
                out += $filter('date')(new Date(curlink.d), 'dd-MM-yyyy') + ';'
                out += curlink.partner.url+';'
                if(curlink.my.url){
                    out += curlink.my.url+';'
                } else {
                    out += ';'
                }
                if(curlink.my.url){
                out += curlink.my.anchor + ';'
                } else {
                    out += ';'
                }
                out += curlink.my.status + ';'
                out += "\n";
            }
            var element = document.createElement('a');
            element.setAttribute('href', 'data:text/html;,' + encodeURIComponent(out));
            element.setAttribute('download', 'linkbuilding_export.csv');
            element.style.display = 'none';
            document.body.appendChild(element);
            element.click();
            document.body.removeChild(element);
        }
        // list links
        fnLinks.list();
        fnTemplates.list();
    }
]);
app.controller('linkbuildingtemplate', ['$scope', '$timeout', '$http', '$rootScope', '$filter', 'h',
    function($scope, $timeout, $http, $rootScope, $filter, h) {
        //haal Template templates op
        var getTemplates = function() {
            $http.get('/rest/linkbuilding/template.list', {
                params: {
                    'websiteid': h.siteId(),
                }
            }).then(function successCallback(res) {
                $scope.mailTemplates = res.data;
            });
        };
        getTemplates();
        $scope.curTemplate = { workflow: [] };
        $scope.fnNewTemplate = function() {
            $scope.hideTemplateoptions = true;
            $scope.templatetab = 1
            $scope.curTemplate = { method: 'manual', provider:"", mails: [{ 'type': 'primary' }] };
        }
        $scope.fnRemoveFollowUp = function(index) {
            $scope.curTemplate.mails.splice(index, 1);
        }
        $scope.fnAddFollowUp = function() {
            $scope.curTemplate.mails.push({ method: 'manual', 'type': 'followup' });
        }
        $scope.fnCloseTemplate = function(curTemplate) {
            $scope.hideTemplateoptions = false;
            $scope.templatetab = 0
        }
        $scope.fnAddWorkFlow = function() {
            $scope.curTemplate.workflow.push({ persoon: USER.UserId + "" });
        }
        $scope.fnRemoveWorkFlow = function(index) {
            $scope.curTemplate.workflow.splice(index, 1);
        }
        $scope.fnAddTemplate = function() {
            $http.post('/rest/linkbuilding/template.add', { 'websiteid': h.siteId(), 'template': $scope.curTemplate }).then(function successCallback(res) {
                getTemplates();
                $scope.templatetab = 0;
                $scope.hideTemplateoptions = false;
            });
        }
        $scope.fnShowEditTemplate = function(mailTemplate) {
            $scope.templatetab = 1
            $scope.curTemplate = mailTemplate;
        }
        $scope.fnDeleteTemplate = function(mailTemplate) {
            $http.post('/rest/linkbuilding/template.delete', { 'websiteid': h.siteId(), 'template': mailTemplate}).then(function successCallback(res) {
                getTemplates();
                $scope.templatetab = 0;
                $scope.hideTemplateoptions = false;
            });
        }
    }
]);
app.controller('user', ['$scope', '$rootScope', '$http', '$location', '$translate', 'h',
    function($scope, $rootScope, $http, $location, $translate, h) {
        $scope.curUser = {};
        $scope.page = {};
        var _cb = {
            loginfailed: function() {
                $scope.page.message = { 'key': 'user.global.message_login_failed', class: 'text-warning' }
            },
            loginok: function(res) {
                $rootScope.user = res.user;
                //console.log($rootScope.user);
                $location.path('/');
            },
            registrationnotvalid: function() {
                $scope.page.message = { 'key': 'user.global.message_registration_failed', class: 'text-warning' }
            },
            registrationexists: function() {
                $scope.page.message = { 'key': 'user.global.message_login_exists', class: 'text-warning' }
            },
            registrationok: function(res) {
                $rootScope.user = res.user;
                $scope.fnGoto('/sites/first');
                //h.login($location.path('/sites/first'));
            },
            recoverfailed: function() {
                $scope.page.message = { 'key': 'user.global.message_recover_failed', class: 'text-warning' }
            },
            recoverok: function() {
                $scope.page.message = { 'key': 'user.global.message_recover_ok', class: 'text-warning' }
            },
        }
        $scope.checklogin = function() {
            if ($rootScope.user._id) {
                $location.path('/');
            }
            if (!$rootScope.user.reseller.config.own && $location.path() == '/user/register') {
                $location.path('/user/login');
            }
        }
        $scope.userdetails = {
            init: function() {
                $http.get('/rest/user/user.get').then(function successCallback(res) {
                    $scope.curUser = res.data;
                });
            },
            'set': function() {
                $http.post('/rest/user/user.set', $scope.curUser);
            },
            'invoice': function(key) {
                $scope.fnGoto('http://pdf1.seoserver.nl/invoice/marketingtracerclient.php?_id=' + $rootScope.user._id + '&key=' + key)
            }
        }
        $scope.fnLogin = function() {
            $http.post('/rest/user/login', $scope.curUser).then(function successCallback(res) {
                _cb[res.data.cb](res.data)
            });
        }
        $scope.fnRegister = function() {
            $http.post('/rest/user/register', $scope.curUser).then(function successCallback(res) {
                _cb[res.data.cb](res.data)
            });
        }
        $scope.fnRecover = function() {
            $http.post('/rest/user/recover', $scope.curUser).then(function successCallback(res) {
                _cb[res.data.cb](res.data)
            });
        }
    }
]);
app.controller('sites', ['$scope', '$rootScope', '$http', '$location', 'h',
    function($scope, $rootScope, $http, $location, h) {
        $scope.rand = function(min,max){
            return Math.floor(Math.random() * (max - min + 1) + min)
        }
        $scope.bShowAdminDelete = function(site) {
            return (site.status.expire > (Date.now() / 1000)) ? false : true;
        }
        $scope.page = {
            pending: false,
            orderstate: 'init'
        };
        if ($scope.orderstate) {
            $scope.page.orderstate = $scope.orderstate;
        }
        $scope.curSite = {};
        $scope.do = function(obj, method, param) {
            if (obj == 'fnSite') {
                fnSite[method](param);
            }
        }
        var fnSite = {
            'wemessage': function() {
                $scope.fnGoto('/rest/pay/wemessage.start')
            },
            'list': function() {
                $http.get('/rest/sites/list').then(function successCallback(res) {
                    $scope.sites = res.data;
                });
            },
            'add': function() {
                $http.post('/rest/sites/add', $scope.curSite).then(function successCallback(res) {
                    _cb[res.data.cb](res.data)
                });
            },
            'adminupgrade': function() {
                $http.post('/rest/sites/adminupgrade', { websiteid: h.siteId() })
            },
            'unpark': function() {
                $http.post('/rest/sites/adminunpark', { websiteid: h.siteId() }).then(function successCallback(res) {
                    h.login(function() { $scope.fnClick('/') });
                });
            },
            'admindelete': function(site) {
                $http.post('/rest/sites/remove', site).then(function successCallback(res) {
                    side.hidden = true;
                });
            },
            'delete': function(site) {
                $http.post('/rest/sites/remove', $scope.curSite).then(function successCallback(res) {
                    $scope.curSite = {};
                    h.login(function() {});
                    fnSite.list();
                });
            },
            'pre_edit': function(site) {
                $http.get('/rest/locale/language.list').then(function successCallback(res) {
                    $scope.languages = res.data;
                });
                $http.get('/rest/locale/country.list').then(function successCallback(res) {
                    $scope.countries = res.data;
                });
                $scope.curSite = site;
                $scope.fnModal('sites/modal/edit');
            },
            'edit': function(site) {
                $http.post('/rest/sites/edit', site).then(function successCallback(res) {
                });
            },
            'order_options': function() {
                $http.get('/rest/pay/options.list').then(function successCallback(res) {
                    $scope.options = res.data;
                    var index = ($rootScope.user.site.locale.lang == 'nl') ? 0 : 1;
                    $scope.order = { 'currency': $scope.options.currency[index], 'method': $scope.options.methods[index] };
                });
            },
            'pre_order': function(package) {
                $http.post('/rest/sites/edit', site).then(function successCallback(res) {
                });
            },
        }
        var _cb = {
            domainvalid: function(site) {
                h.login(function() {
                    $location.path('/');
                });
            },
            domaininvalid: function() {
                $scope.page.message = { html: 'The domain is invalid', class: 'text-warning' }
            },
            domainduplicate: function() {
                $scope.page.message = { html: 'This domain is not available for trials versions.', class: 'text-warning' }
            },
            deletefailed: function() {
                $scope.page.message = { html: 'Registration failed, the user with email adress ' + $scope.curUser.email + ' allready exists. Did you mean to ', class: 'text-danger' }
            },
        }
    }
]);
app.controller('site', ['$scope', '$timeout', '$http', '$rootScope', '$location', '$anchorScroll', '$filter', 'h',
    function($scope, $timeout, $http, $rootScope, $location, $anchorScroll, $filter, h) {
        $scope.page = {
            newteammember: {},
            newmenu: {}
        };
        $scope.roles = [
            { 'role': 4, 'name': 'owner' },
            { 'role': 5, 'name': 'normal user' },
            { 'role': 6, 'name': 'guest' },
        ]
        $scope.do = function(obj, method, param) {
            if (obj == 'fnSite') {
                fnSite[method](param);
            } else if (obj == 'fnPage') {
                fnPage[method](param);
            }
        }
        $http.get('/rest/locale/language.list').then(function successCallback(res) {
            $scope.languages = res.data;
        });
        $http.get('/rest/locale/country.list').then(function successCallback(res) {
            $scope.countries = res.data;
        });
        var fnSite = {
            get: function() {
                $http.get('/rest/sites/get', {
                    params: {
                        'websiteid': h.siteId(),
                    }
                }).then(function successCallback(res) {
                    if (res.data._id) {
                        $scope.page.tab = 'edit';
                        $scope.user.site.users = res.data.users;
                        $scope.user.site.names = res.data.names;
                        $scope.user.site.api = res.data.api;
                    } else {
                        $scope.page.tab = 'intro';
                    }
                });
            },
            'searchcity': function(q) {
                $http.get('/rest/locale/city.list', { 'params': { 'q': q } }).then(function successCallback(res) {
                    $scope.cities = res.data;
                });
            },
            'setcity': function(city) {
                $scope.user.site.locale.city = city.city;
                $scope.user.site.locale.uule = city.uule;
                $scope.cities = [];
            },
            'add': function() {
                $http.post('/rest/sites/teammember.add',
                    angular.extend({ 'websiteid': h.siteId() }, $scope.page.newteammember)
                ).then(function successCallback(res) {
                    $scope.page.newteammember = {};
                    fnSite.get();
                });
            },
            'park': function() {
                $http.post('/rest/sites/adminpark', { websiteid: h.siteId() }).then(function successCallback(res) {
                    h.login(function() { $scope.fnClick('/') });
                });
            },
            'delete': function(teammember) {
                $http.post('/rest/sites/teammember.delete',
                    angular.extend({ 'websiteid': h.siteId() }, teammember)
                ).then(function successCallback(res) {
                    fnSite.get();
                });
            },
            'update': function(reseller) {
                $http.post('/rest/sites/teammembers.update',
                    angular.extend({ 'websiteid': h.siteId() }, $scope.user.site)
                ).then(function successCallback(res) {
                    fnSite.get();
                });
            },
            'edit': function(site) {
                if (!$scope.user.site.locale.city || !$scope.user.site.locale.uule) {
                    $scope.user.site.locale.uule = '';
                    $scope.user.site.locale.city = '';
                }
                $http.post('/rest/sites/edit',
                    angular.extend({ 'websiteid': h.siteId() }, $scope.user.site)
                ).then(function successCallback(res) {
                });
            },
            'addmenu': function() {
                $scope.user.site.menu = $scope.user.site.menu || [];
                $scope.user.site.menu.push($scope.page.newmenu);
                  fnSite.edit($scope.user.site);
            },
            'removemenu': function(index) {
                $scope.user.site.menu.splice(index, 1);
                fnSite.edit($scope.user.site);
            },
        }
        fnSite.get();
    }
]);
app.controller('contentlist', ['$scope', '$http', '$rootScope', '$filter', '$location', 'h', '$timeout',
    function($scope, $http, $rootScope, $filter, $location, h, $timeout) {
        $scope.page = { 'newmodel': { 'lang': $rootScope.user.site.locale.lang } };
        var content = {
            listModels: function() {
                $http.get('/rest/content/model.list', {
                    params: {
                        websiteid: h.siteId(),
                    }
                }).then(function successCallback(res) {
                    $scope.models = res.data.data;
                    content.checkProgress();
                });
            },
            addModel: function(model) {
                $http.post('/rest/content/model.add', angular.extend({ websiteid: h.siteId() }, model)).then(function successCallback(res) {
                    $scope.page.newmodel = {}
                    content.listModels();
                });
            },
            createModel: function(model) {
                $http.post('/rest/content/model.create', angular.extend({ websiteid: h.siteId() }, model)).then(function successCallback(res) {
                    model.status = 'checking';
                });
            },
            deleteModel: function(model) {
                $http.post('/rest/content/model.delete', angular.extend({ websiteid: h.siteId() }, model)).then(function successCallback(res) {
                    content.listModels();
                });
            },
            checkProgress: function() {
                var l = false;
                for (var i in $scope.models) {
                    if ($scope.models[i].status == 'pending') {
                        l = true;
                    }
                }
                if (l) {
                    $timeout(function() {
                        content.listModels()
                    }, 5000);
                }
            }
        }
        $scope.do = function(method, param) {
            content[method](param);
        }
        content.listModels()
    }
]);
app.directive('wrapInTag', function () {
    return {
        restrict: 'A',
        link: function (scope, elm, attr) {
            console.log(attr);
            var tag = attr.tag || 'strong';
            var words = eval(attr.words) || [];
            var text = attr.text;
            for (var i = 0; i < words.length; i++) {
                text = text.replace(words[i], '<' + tag + '>' + words[i] + '' + tag + '>');
            }
            elm.html(text);
        }
    }
});
app.controller('contentmodel', ['$scope', '$http', '$rootScope', '$filter', '$location', 'h', '$timeout',
    function ($scope, $http, $rootScope, $filter, $location, h, $timeout) {
        $scope.page = {
            states: {}, 'tab': 'research', 'type': 'article', 'tones': {
                "informative": true,
                "persuasive": false,
                "emotional": false,
                "witty": true,
                "funny": false,
                "professional": true,
                "informal": false
            }
        };
        $scope.mypage = {};
        $scope.page.states.explore = { 'open': false, 'cluster': 1 }
        var model = {
            getModel: function () {
                $http.get('/rest/content/model.get', {
                    params: {
                        'websiteid': h.siteId(),
                        'modelid': $scope.modelid
                    }
                }).then(function successCallback(res) {
                    $scope.q = res.data.q;
                    $scope.clusters = res.data.clusters;
                    $scope.dna = res.data.dna;
                    $scope.wordfreq = res.data.wordfreq;
                    $scope.trans = res.data.trans;
                    $scope.r = res.data.r;
                    $scope.lsi = res.data.lsi;
                    $scope.target = res.data.target;
                    $scope.pages = res.data.pages;
                    $scope.write = res.data.write;
                    $scope.x = {};
                    for (var i in $scope.wordfreq) {
                        $scope.x[$scope.wordfreq[i].word] = $scope.wordfreq[i].avg;
                        $scope.wordfreq[i].maxminavg = $scope.wordfreq[i].max - $scope.wordfreq[i].avg
                    }
                    charts.tfchart();
                    charts.dnaChart();
                    model.getMyPage();
                });
            },
            setMyPage: function () {
                $scope.mypage.pending = true;
                $http.post('/rest/content/model.setmypage', angular.extend({ websiteid: h.siteId(), 'modelid': $scope.modelid }, $scope.mypage)).then(function successCallback(res) {
                    model.getMyPage()
                });
            },
            writestatus: function () {
                var l = false;
                $http.get('/rest/content/model.get', {
                    params: {
                        'websiteid': h.siteId(),
                        'modelid': $scope.modelid
                    }
                }).then(function successCallback(res) {
                    if (res.data.write.status == 'pending') {
                        l = true;
                    }
                    if (l) {
                        $timeout(function () {
                            model.writestatus();
                        }, 5000);
                    } else {
                        
                        model.getMyPage();
                        $scope.write = res.data.write;
                    }
                });
            },
            write: function () {
                $scope.write = $scope.write || {};
                $scope.write.status = 'pending';
                $scope.page.tab = 'write';
                $http.post('/rest/content/model.pre_write', angular.extend({ websiteid: h.siteId(), 'modelid': $scope.modelid }, { 'type': $scope.page.type, 'tones': $scope.page.tones })).then(function successCallback(res) {
                    model.writestatus();
                    // need to set up checks here!
                });
            },
            getMyPage: function () {
                $scope.mypage.pending = true;
                $http.get('/rest/content/model.getmypage', {
                    params: {
                        'websiteid': h.siteId(),
                        'modelid': $scope.modelid
                    }
                }).then(function successCallback(res) {
                    $scope.mypage = res.data;
                    if (res.data.mna) {
                        for (var i in $scope.wordfreq) {
                            var word = $scope.wordfreq[i].word;
                            $scope.wordfreq[i].my = res.data.counter[word] || 0;
                        }
                        $scope.mna = res.data.mna;
                        charts.tfchart();
                        charts.dnaChart();
                        $scope.mypage.pending = false;
                        model.getSpamandSuggestions();
                        $scope.page.tab = 'write';
                    }
                });
            },
            getSpamandSuggestions: function () {
                $scope.kwspam = [];
                $scope.kwsuggestions = [];
                for (var i in $scope.wordfreq) {
                    var f = $scope.wordfreq[i];
                    if (f.my > f.max) {
                        $scope.kwspam.push({ 'word': f.word, 'my': f.my, 'max': f.max });
                    }
                    if (f.my < f.avg) {
                        $scope.kwsuggestions.push({ 'word': f.word, 'my': f.my, 'avg': f.avg });
                    }
                }
            },
            exploreCluster(cluster) {
                lines = [];
                $scope.page.states.explore = { 'open': true, 'cluster': cluster }
                for (var i in $scope.clusters) {
                    for (var y in $scope.clusters[i]['lines']) {
                        var line = $scope.clusters[i]['lines'][y]['text'];
                        var src = $scope.clusters[i]['lines'][y]['src'];
                        var fit = $scope.clusters[i]['lines'][y]['dna'][cluster];
                        if ($scope.clusters[i]['lines'][y]['text'].length > 133) {
                            lines.push({ 'line': line, 'fit': fit, 'src': src, 'wordscore': $scope.clusters[i]['lines'][y]['wordscore'], 'score': $scope.clusters[i]['lines'][y]['score'] });
                        }
                    }
                }
                $scope.page.lines = lines;
            },
            exploreWord: function (word) {
                $scope.page.states.explore.open = false;
                var s = word.split(' ');
                var boldarray = [];
                for (var i in s) {
                    for (var w in $scope.trans[s[i]]) {
                        boldarray.push(w)
                    }
                }
                suggestions = [];
                for (var i in $scope.clusters) {
                    for (var y in $scope.clusters[i]['lines']) {
                        var sent = $scope.clusters[i]['lines'][y];
                        if (sent.clean.indexOf(' ' + word + ' ') !== -1) {
                            suggestions.push(sent)
                            $scope.page.states.exploreword = { 'open': true, 'word': word, 'boldarray': boldarray, 'suggestions': suggestions }
                        }
                    }
                }
            }
        }
        model.getModel();
        $scope.do = function (method, param) {
            model[method](param);
        }
        var charts = {
            tfchart: function () {
                var d = angular.copy($filter('orderBy')($scope.wordfreq, 'avg', true));
                var d = d.map(function (c) {
                    c.word = ($scope.trans[c.word]) ? Object.keys($scope.trans[c.word])[0] : c.word;
                    return c;
                })
                $scope.tfidfchart = {
                    data: d,
                    type: "serial",
                    //autoMarginOffset: 20,
                    marginLeft: 16,
                    categoryField: "word",
                    legend: {
                        enabled: false
                    },
                    chartScrollbar: {
                        "enabled": true,
                        "hideResizeGrips": true,
                        "offset": 10,
                        "scrollbarHeight": 10
                    },
                    categoryAxis: {
                        gridPosition: "start",
                        parseDates: false,
                        gridThickness: 0,
                        "labelRotation": 45
                    },
                    valueAxes: [{
                        "stackType": "regular",
                        dashLength: 4,
                        color: '#dedede',
                        position: "top",
                        axisAlpha: 0,
                        labelsEnabled: false
                    }],
                    graphs: [{
                        balloonText: "AVG distribution top 10 result
 [[value]]",
                        type: "column",
                        title: "Keyword value",
                        valueField: "avg",
                        fillAlphas: 1,
                        lineColor: '#28a745',
                    }, {
                        balloonText: "Max distribution top 10 result
 [[value]]",
                        type: "column",
                        title: "Keyword value",
                        valueField: "maxminavg",
                        fillAlphas: 1,
                        lineColor: '#dddddd',
                    }, {
                        balloonText: "My distribution 
 [[value]]",
                        "bullet": "round",
                        "bulletBorderAlpha": 1,
                        "bulletColor": "#FFFFFF",
                        "useLineColorForBulletBorder": true,
                        "fillAlphas": 0,
                        "lineThickness": 2,
                        "lineAlpha": 1,
                        "bulletSize": 7,
                        "valueField": "my",
                        lineColor: '#ffc107',
                    }],
                    zoom: [0, 18]
                }
            },
            dnaChart: function () {
                var dna = [];
                var mna = [];
                var ordered_clusters = $filter('orderBy')($scope.clusters, 'score', true);
                for (var i in ordered_clusters) {
                    if ($scope.mna) {
                        $scope.max_fit = (Math.max(...$scope.dna), Math.max(...$scope.mna))
                        dna.push({ 'cluster': ordered_clusters[i].cluster, 'dna': $scope.dna[ordered_clusters[i].cluster] * 100, 'mna': $scope.mna[ordered_clusters[i].cluster] * 100, 'i': (i * 1) + 1 })
                    } else {
                        $scope.max_fit = Math.max(...$scope.dna);
                        dna.push({ 'cluster': ordered_clusters[i].cluster, 'dna': $scope.dna[ordered_clusters[i].cluster] * 100, 'i': (i * 1) + 1 })
                    }
                }
                $scope.dnachart = {
                    "type": "radar",
                    data: dna,
                    "theme": "none",
                    "valueAxes": [{
                        "labelsEnabled": false,
                        "axisTitleOffset": 14,
                        "minimum": 0,
                        "axisAlpha": 0.15
                    }],
                    "startDuration": 2,
                    "graphs": [{
                        "balloonText": "Cluster [[i]] 
Goal: [[value]]%",
                        "bullet": "round",
                        "lineThickness": 2,
                        "fillAlphas": 0.8,
                        "valueField": "dna",
                        lineColor: '#28a745',
                    }, {
                        "balloonText": "Cluster [[i]] 
My page: [[value]]%",
                        "bullet": "round",
                        "color": "#dedede",
                        "fillAlphas": 0.3,
                        "lineThickness": 2,
                        "valueField": "mna",
                    }],
                    "categoryField": "i",
                    "export": {
                        "enabled": true
                    }
                };
            },
        }
        $scope.untrans = function (w) {
            var s = w.split(' ');
            for (var i in s) {
                s[i] = Object.keys($scope.trans[s[i]])[0];
            }
            return s.join(' ');
        }
    }
]);
app.controller('report', ['$scope', '$timeout', '$http', '$rootScope', '$controller', '$window', 'h',
    function($scope, $timeout, $http, $rootScope, $controller, $window, h) {
        // nieuw of huidig rapport
        $scope.page = { 'newreport': { show: false }, dates: [], kdates: {},'simpleview':true };
        var d = new Date();
        var thismonth = d.getMonth() + 1;
        var thismonth = new Date().getMonth() + 3;
        for (var i = 0; i < 15; i++) {
            var date = new Date(new Date().getFullYear(), thismonth, 0);
            $scope.page.dates.push({ 'date': date });
            $scope.page.kdates[date.toString()] = date;
            thismonth = thismonth - 1;
        }
        $scope.do = function(obj, method, param) {
            if (obj == 'fnReport') {
                fnReport[method](param);
            }
        }
        var fnReport = {
            list: function() {
                $http.get('/rest/report/report.list', {
                    params: {
                        websiteid: h.siteId(),
                    }
                }).then(function successCallback(res) {
                    $scope.reports = res.data;
                    angular.forEach(res.data, function(k, v) {
                        var date = new Date(k.download.date * 1);
                        k.download.date = $scope.page.kdates[date.toString()];
                        k.download = k.download || { status: '' }
                        if (k.download.status == 'pending') {
                            $timeout(function() {
                                fnReport.list();
                            }, 10000);
                        }
                    })
                });
            },
            'add': function(report) {
                $http.post('/rest/report/report.add',
                    angular.extend({ websiteid: h.siteId() }, report)
                ).then(function successCallback(res) {
                    fnReport.list();
                });
            },
            create: function(report) {
                $http.post('/rest/report/report.generate', angular.extend({ websiteid: h.siteId() }, report))
                report.download.status = 'pending'
                fnReport.update(report);
            },
            'update': function(report) {
                report.download = report.download || {};
                report.download.date = report.download.date || new Date();
                report.download.date = Math.round(report.download.date.getTime() / 1000)
                if(report.download.enddate){
                    if($scope.page.simpleview == true){
                        delete report.download.enddate
                    } else {
                        
                    console.log(report.download.enddate);
                    report.download.enddate = report.download.enddate || new Date();
                    report.download.enddate = Math.round(report.download.enddate.getTime() / 1000) 
                    }
                }
                $http.post('/rest/report/report.update',
                    angular.extend({ websiteid: h.siteId() }, report)
                ).then(function successCallback(res) {
                    fnReport.list();
                });
            },
            'download': function(report) {
                console.log(report);
                $window.location.href = '/rest/report/report.download/?websiteid=' + h.siteId() + '&reportid=' + report.report_id;
            },
            'delete': function(report) {
                $http.post('/rest/report/report.delete',
                    angular.extend({ websiteid: h.siteId() }, report)
                ).then(function successCallback(res) {
                    fnReport.list();
                });
            },
        }
        fnReport.list();
    }
]);
app.controller('reportitem', ['$scope', '$timeout', '$http', '$rootScope', '$location', '$anchorScroll', '$filter', 'h',
    function($scope, $timeout, $http, $rootScope, $location, $anchorScroll, $filter, h) {
        $scope.do = function(obj, method, param) {
            if (obj == 'fnReport') {
                fnReport[method](param);
            } else if (obj == 'fnPage') {
                fnPage[method](param);
            }
        }
        $scope.reportcategories = [{
                'translate': 'menu.ranktracker',
                'types': [
                    { 'translate': 'menu.ranktracker.ranktracker', 'view': 'rank-tracker/index.html', 'init': { 'startdate': false } },
                    { 'translate': 'menu.ranktracker.ranktrackerstarred', 'view': 'rank-tracker/index.html', 'init': { 'startdate': false,'bFilterStar':true } },
                    { 'translate': 'menu.ranktracker.competitors', 'view': 'rank-tracker/competitors.html', 'init': '' },
                    { 'translate': 'menu.ranktracker.insights', 'view': 'rank-tracker/insights.html', 'init': { 'timeframe': '31d' }  },
                ]
            },
            /* {
                 'translate': 'menu.linkbuilding.linkbuilding',
                 'types': [
                     { 'translate': 'menu.linkbuilding.assistant', 'view': 'linkbuilding/assistant.html', 'init': '' },
                 ]
             },*/
            {
                'translate': 'menu.onpage.onpage',
                'types': [
                    { 'translate': 'menu.onpage.overview', 'view': 'onpage/index.status.html', 'init': { 'viewrulelabel': 'all' } }
                ]
            },
            {
                'translate': 'menu.analytics.analytics',
                'types': [
                    { 'parent': 'menu.analytics.channels.channels', 'translate': 'menu.analytics.channels.all', 'view': 'api/analytics.html', 'init': { 'urlreport': 'channels', 'urlview': 'all' } },
                    { 'parent': 'menu.analytics.channels.channels', 'translate': 'menu.analytics.channels.organic', 'view': 'api/analytics.html', 'init': { 'urlreport': 'channels', 'urlview': 'organic' } },
                    { 'parent': 'menu.analytics.channels.channels', 'translate': 'menu.analytics.channels.paid', 'view': 'api/analytics.html', 'init': { 'urlreport': 'channels', 'urlview': 'paid' } },
                    { 'parent': 'menu.analytics.channels.channels', 'translate': 'menu.analytics.channels.display', 'view': 'api/analytics.html', 'init': { 'urlreport': 'channels', 'urlview': 'display' } },
                    { 'parent': 'menu.analytics.channels.channels', 'translate': 'menu.analytics.channels.social', 'view': 'api/analytics.html', 'init': { 'urlreport': 'channels', 'urlview': 'social' } },
                    { 'parent': 'menu.analytics.channels.channels', 'translate': 'menu.analytics.channels.referral', 'view': 'api/analytics.html', 'init': { 'urlreport': 'channels', 'urlview': 'referral' } },
                    { 'parent': 'menu.analytics.channels.channels', 'translate': 'menu.analytics.channels.email', 'view': 'api/analytics.html', 'init': { 'urlreport': 'channels', 'urlview': 'email' } },
                    { 'parent': 'menu.analytics.channels.channels', 'translate': 'menu.analytics.channels.other', 'view': 'api/analytics.html', 'init': { 'urlreport': 'channels', 'urlview': 'other' } },
                    { 'parent': 'menu.analytics.audience.audience', 'translate': 'menu.analytics.audience.local', 'view': 'api/analytics.html', 'init': { 'urlreport': 'audience', 'urlview': 'local' } },
                    { 'parent': 'menu.analytics.audience.audience', 'translate': 'menu.analytics.audience.age', 'view': 'api/analytics.html', 'init': { 'urlreport': 'audience', 'urlview': 'age' } },
                    { 'parent': 'menu.analytics.audience.audience', 'translate': 'menu.analytics.audience.gender', 'view': 'api/analytics.html', 'init': { 'urlreport': 'audience', 'urlview': 'gender' } },
                    { 'parent': 'menu.analytics.audience.audience', 'translate': 'menu.analytics.audience.device', 'view': 'api/analytics.html', 'init': { 'urlreport': 'audience', 'urlview': 'device' } },
                    { 'parent': 'menu.analytics.audience.audience', 'translate': 'menu.analytics.audience.mobile', 'view': 'api/analytics.html', 'init': { 'urlreport': 'audience', 'urlview': 'mobile' } },
                    { 'parent': 'menu.analytics.conversions.conversions', 'translate': 'menu.analytics.conversions.goals', 'view': 'api/analytics.html', 'init': { 'urlreport': 'conversions', 'urlview': 'goals' } },
                    { 'parent': 'menu.analytics.conversions.conversions', 'translate': 'menu.analytics.conversions.ecommerce', 'view': 'api/analytics.html', 'init': { 'urlreport': 'conversions', 'urlview': 'ecommerce' } },
                    { 'parent': 'menu.analytics.pages.pages', 'translate': 'menu.analytics.pages.all', 'view': 'api/analytics.html', 'init': { 'urlreport': 'pages', 'urlview': 'all' } },
                    { 'parent': 'menu.analytics.pages.pages', 'translate': 'menu.analytics.pages.landing', 'view': 'api/analytics.html', 'init': { 'urlreport': 'pages', 'urlview': 'landing' } },
                    { 'parent': 'menu.analytics.pages.pages', 'translate': 'menu.analytics.pages.exit', 'view': 'api/analytics.html', 'init': { 'urlreport': 'pages', 'urlview': 'exit' } },
                ]
            },
            {
                'translate': 'menu.analytics4.analytics',
                'types': [
                    { 'parent': 'menu.analytics.channels.channels', 'translate': 'menu.analytics.channels.all', 'view': 'api/analytics4.html', 'init': { 'urlreport': 'channels', 'urlview': 'all' } },
                    { 'parent': 'menu.analytics.channels.channels', 'translate': 'menu.analytics.channels.organic', 'view': 'api/analytics4.html', 'init': { 'urlreport': 'channels', 'urlview': 'organic' } },
                    { 'parent': 'menu.analytics.channels.channels', 'translate': 'menu.analytics.channels.paid', 'view': 'api/analytics4.html', 'init': { 'urlreport': 'channels', 'urlview': 'paid' } },
                    { 'parent': 'menu.analytics.channels.channels', 'translate': 'menu.analytics.channels.display', 'view': 'api/analytics4.html', 'init': { 'urlreport': 'channels', 'urlview': 'display' } },
                    { 'parent': 'menu.analytics.channels.channels', 'translate': 'menu.analytics.channels.social', 'view': 'api/analytics4.html', 'init': { 'urlreport': 'channels', 'urlview': 'social' } },
                    { 'parent': 'menu.analytics.channels.channels', 'translate': 'menu.analytics.channels.referral', 'view': 'api/analytics4.html', 'init': { 'urlreport': 'channels', 'urlview': 'referral' } },
                    { 'parent': 'menu.analytics.channels.channels', 'translate': 'menu.analytics.channels.email', 'view': 'api/analytics4.html', 'init': { 'urlreport': 'channels', 'urlview': 'email' } },
                    { 'parent': 'menu.analytics.channels.channels', 'translate': 'menu.analytics.channels.other', 'view': 'api/analytics4.html', 'init': { 'urlreport': 'channels', 'urlview': 'other' } },
                                   ]
            },
            {
                'translate': 'menu.searchconsole.searchconsole',
                'types': [
                    { 'translate': 'menu.searchconsole.keywords', 'view': 'api/searchconsole.html', 'init': { 'urlreport': 'campaigns', 'urlview': 'keywords' } },
                    { 'translate': 'menu.searchconsole.pages', 'view': 'api/searchconsole.html', 'init': { 'urlreport': 'campaigns', 'urlview': 'pages' } },
                    { 'translate': 'menu.searchconsole.country', 'view': 'api/searchconsole.html', 'init': { 'urlreport': 'campaigns', 'urlview': 'country' } },
                    { 'translate': 'menu.searchconsole.device', 'view': 'api/searchconsole.html', 'init': { 'urlreport': 'campaigns', 'urlview': 'device' } },
                ]
            },
            {
                'translate': 'menu.googleads.googleads',
                'types': [
                    { 'translate': 'menu.googleads.all', 'view': 'api/googlexads.html', 'init': { 'urlreport': 'campaigns', 'urlview': 'all' } },
                    { 'translate': 'menu.googleads.adgroups', 'view': 'api/googlexads.html', 'init': { 'urlreport': 'campaigns', 'urlview': 'adgroups' } },
                    { 'translate': 'menu.googleads.keywords', 'view': 'api/googlexads.html', 'init': { 'urlreport': 'campaigns', 'urlview': 'keywords' } },
                    { 'translate': 'menu.googleads.ads', 'view': 'api/googlexads.html', 'init': { 'urlreport': 'campaigns', 'urlview': 'ads' } },
                    { 'translate': 'menu.googleads.conversions', 'view': 'api/googlexads.html', 'init': { 'urlreport': 'campaigns', 'urlview': 'conversions' } },
                ]
            },
            {
                'translate': 'menu.facebookads.facebookads',
                'types': [
                    { 'translate': 'menu.facebookads.all', 'view': 'api/facebookxads.html', 'init': { 'urlreport': 'campaigns', 'urlview': 'all' } },
                    { 'translate': 'menu.facebookads.adsets', 'view': 'api/facebookxads.html', 'init': { 'urlreport': 'campaigns', 'urlview': 'adsets' } },
                    { 'translate': 'menu.facebookads.ads', 'view': 'api/facebookxads.html', 'init': { 'urlreport': 'campaigns', 'urlview': 'ads' } },
                    { 'translate': 'menu.facebookads.keywords', 'view': 'api/facebookxads.html', 'init': { 'urlreport': 'campaigns', 'urlview': 'keywords' } },
                    { 'translate': 'menu.facebookads.age', 'view': 'api/facebookxads.html', 'init': { 'urlreport': 'campaigns', 'urlview': 'age' } },
                    { 'translate': 'menu.facebookads.gender', 'view': 'api/facebookxads.html', 'init': { 'urlreport': 'campaigns', 'urlview': 'gender' } },
                ]
            },
            {
                'translate': 'menu.facebookinsights.facebookinsights',
                'types': [
                    { 'translate': 'menu.facebookinsights.fans', 'view': 'api/facebookinsights.html', 'init': { 'urlreport': 'page', 'urlview': 'fans' } },
                    { 'translate': 'menu.facebookinsights.engagements', 'view': 'api/facebookinsights.html', 'init': { 'urlreport': 'page', 'urlview': 'engagements' } },
                    { 'translate': 'menu.facebookinsights.reach', 'view': 'api/facebookinsights.html', 'init': { 'urlreport': 'page', 'urlview': 'reach' } },
                    { 'translate': 'menu.facebookinsights.posts', 'view': 'api/facebookinsights.html', 'init': { 'urlreport': 'page', 'urlview': 'posts' } }
                ]
            },
            {
                'translate': 'menu.mybusiness.mybusiness',
                'types': [
                    { 'translate': 'menu.mybusiness.all', 'view': 'api/mybusiness.html', 'init': { 'urlreport': 'business', 'urlview': 'all' } },
                    { 'translate': 'menu.mybusiness.reviews', 'view': 'api/mybusiness.html', 'init': { 'urlreport': 'business', 'urlview': 'reviews' } },
                ]
            },
            {
                'translate': 'menu.planning',
                'types': [
                    { 'translate': 'menu.planning', 'view': 'planning/index.html', 'init': '' },
                ]
            },
  {
                'translate': 'menu.linkbuilding',
                'types': [
                    { 'translate': 'menu.linkbuilding', 'view': 'linkbuilding/assistant.html', 'init': '' },
                ]
            },
        ];
        var fnPage = {
            'new': function() {
                return {};
            },
            'type': function(o) {
                o.page.type = false;
                $timeout(function() {
                    o.page.type = o.type;
                    o.page.changetype = false;
                    fnReport.update();
                }, 500);
            }
        }
        var fnReport = {
            get: function() {
                $http.get('/rest/report/report.get', {
                    params: {
                        websiteid: h.siteId(),
                        report_id: $scope.report_id,
                    }
                }).then(function successCallback(res) {
                    console.log('ORIG DATE TS', res.data.download.date)
                    var date = new Date(res.data.download.date * 1000);
                    if(res.data.download.enddate){
                        console.log('END DATE TS', res.data.download.enddate)
                        var enddate = new Date(res.data.download.enddate * 1000);
                        var endts = new Date(enddate.getFullYear(), enddate.getMonth(), 0).getTime() / 1000;
                    } else {
                        var endts = new Date(date.getFullYear(), date.getMonth() + 1, 0).getTime() / 1000;
                    }
                    res.data.download.date = date;
                    $rootScope.reportdates = {
                        /* api */
                        'end': endts,
                        'start': new Date(date.getFullYear(), date.getMonth(), 1).getTime() / 1000,
                        /* planning */
                        'datestring': date.toLocaleString('default', { year: 'numeric', 'month': 'long' })
                    }
                    console.log('REPORTDATES', $rootScope.reportdates);
                    $scope.report = res.data;
                });
            },
            getsettings: function() {
                $http.get('/rest/report/settings.get', {
                    params: {
                        websiteid: h.siteId(),
                        report_id: $scope.report_id,
                    }
                }).then(function successCallback(res) {
                    $scope.settings = res.data;
                });
            },
            'addpage': function(index) {
                console.log(index, 'is index');
                $scope.report.pages = $scope.report.pages || [];
                $scope.report.pages.splice(index, 0, fnPage.new());
                $timeout(function() {
                    angular.element('html, body').animate({ scrollTop: angular.element('#page' + index).offset().top - 120 }, 400);
                }, 200);
            },
            'deletepage': function(index) {
                $scope.report.pages = $scope.report.pages || [];
                $scope.report.pages.splice(index, 1);
                fnReport.update();
            },
            'update': function(report) {
                report = $scope.report;
                                report.download = report.download || {};
                report.download.date = report.download.date || new Date();
                report.download.date = Math.round(report.download.date.getTime() / 1000)
                $http.post('/rest/report/report.update',
                    angular.extend({ websiteid: h.siteId() }, $scope.report)
                ).then(function successCallback(res) {
                    fnReport.get();
                });
            },
        }
        fnReport.get();
        fnReport.getsettings();
    }
]);
app.controller('reportpage', ['$scope', '$timeout', '$http', '$rootScope', '$controller', '$window', 'h',
    function($scope, $timeout, $http, $rootScope, $controller, $window, h) {
    }
]);
app.controller('coreapi', ['$scope', '$timeout', '$http', '$rootScope', '$filter', 'h',
    function ($scope, $timeout, $http, $rootScope, $filter, h) {
        $scope.charts = {};
        $scope.progresschart = {};
        $scope.viewfilters = {};
        var colorindex = 0;
        $scope.dateoptions = [
            { start: 'TODAY', end: 'TODAY', description: 'Today' },
            { start: 'YESTYERDAY', end: 'YESTYERDAY', description: 'Yesterday' },
            { start: '7DAYSAGO', end: 'TODAY', description: 'Past 7 days' },
            { start: '14DAYSAGO', end: 'TODAY', description: 'Past 14 days' },
            { start: '30DAYSAGO', end: 'TODAY', description: 'Past 30 days' },
            { start: '1YEARAGO', end: 'TODAY', description: 'Past year' },
            { start: 'THISMONTH', end: 'TODAY', description: 'This month' },
            { start: 'LASTMONTH', end: 'TODAY', description: 'Previous month' },
        ]
        $scope.compareoptions = [
            { 'compare': false, 'comparedescription': 'Do not compare' },
            { 'compare': 'PERIOD', 'comparedescription': 'Compare with previous period' },
            { 'compare': 'YEAR', 'comparedescription': 'Compare with previous year' },
        ]
        $scope.fnCustomDate = {
            'init': function () {
                var d = new Date()
                d.setMonth(d.getMonth() - 1);
                $scope.customdate = { 'start': d, 'end': new Date(), 'show': false }
            },
            'set': function () {
                console.log('------------------- AHHHHH ');
                $scope.customdate.show = false;
                $rootScope.reportdates.start = Math.round($scope.customdate.start.getTime() / 1000)
                $rootScope.reportdates.end = Math.round($scope.customdate.end.getTime() / 1000)
                $rootScope.reportdates.description = 'Custom';
                getReportData();
            }
        }
        $scope.fnCustomDate.init();
        $scope.table = {
            'curpage': 0,
            'itemsperpage': 20,
            'offset': 0,
            fnSetOffset: function () {
                this.offset = this.itemsperpage * (this.curpage - 1);
            }
        }
        if (!$rootScope.reportdates) {
            $rootScope.reportdates = { 'start': '30DAYSAGO', 'end': 'TODAY', 'description': 'Past 30 days', 'compare': false, 'comparedescription': 'Do not compare' };
        }
        $scope.fnDateSelection = function (reportdates) {
            $rootScope.reportdates.start = reportdates.start;
            $rootScope.reportdates.end = reportdates.end;
            $rootScope.reportdates.description = reportdates.description;
            getReportData();
        }
        $scope.fnCompareSelection = function (reportdates) {
            $rootScope.reportdates.compare = reportdates.compare;
            $rootScope.reportdates.comparedescription = reportdates.comparedescription;
            getReportData();
        }
        $scope.getCustomer = function () {
            if ($rootScope.user.site.role < 6) {
                $http.get('/rest/' + $scope.cfg.urlbase + '/getcustomer', {
                    params: {
                        action: 'getproperties',
                        websiteid: h.siteId(),
                    }
                }).then(function successCallback(res) {
                    $scope.customers = res.data;
                    $scope.fnModal('api/modal/' + $scope.cfg.urlbase + '.selectcustomer');
                });
            }
        }
        $scope.setCustomer = function (data) {
            $http.get('/rest/' + $scope.cfg.urlbase + '/setcustomer', {
                params: {
                    websiteid: h.siteId(),
                    customer: data
                }
            }).then(function successCallback(res) {
                getReportData();
            });
        }
        $scope.useApiGrant = function (apigrant) {
            $http.get('/rest/api-core/apigrants.set', {
                params: {
                    websiteid: h.siteId(),
                    'type': $scope.cfg.urlbase,
                    'grantid': apigrant.grantid,
                }
            }).then(function successCallback(res) {
                getReportData();
            });
        }
        $scope.fnOptions = function () {
            if ($scope.view.viewfilters) {
                $http.get('/rest/' + $scope.cfg.urlbase + '/getviewfilters', {
                    params: {
                        websiteid: h.siteId(),
                        viewfilters: $scope.view.viewfilters.join(',')
                    }
                }).then(function successCallback(res) {
                    $scope.viewfilteroptions = res.data.data
                });
            }
            if ($scope.cfg.switchclient) {
                $http.get('/rest/' + $scope.cfg.urlbase + '/getcustomer', {
                    params: {
                        action: 'getproperties',
                        websiteid: h.siteId(),
                    }
                }).then(function successCallback(res) {
                    $scope.customers = res.data;
                });
            }
            $scope.fnModal('api/modal/' + $scope.cfg.urlbase + '.options');
        }
        $scope.pullCustomer = function () {
            $http.get('/rest/' + $scope.cfg.urlbase + '/pullcustomer', {
                params: {
                    websiteid: h.siteId()
                }
            }).then(function successCallback(res) {
                getReportData();
            });
        }
        var _fnFetchData = function (i) {
            if ($scope.view[i]) {
                var vv = {};
                var metrics = ($scope.view[i].metrics) ? $scope.view[i].metrics : $scope.metrics;
                if ($scope.viewfilters) {
                    for (var y in $scope.viewfilters) {
                        vv[y] = $scope.viewfilters[y]['viewfilter'];
                    }
                }
                $http.get($scope.cfg.report_endpoint, {
                    params: {
                        websiteid: h.siteId(),
                        metrics: metrics.join(','),
                        dimension: $scope.view[i].dimension,
                        dimension2: $scope.view[i].dimension2,
                        report: $scope.view[i].report,
                        channel: $scope.view[i].channel,
                        context: $scope.view[i].context,
                        viewfilters: vv,
                        compare: $scope.view[i].compare || $rootScope.reportdates.compare,
                        allowcomp: $scope.view[i].allowcomp,
                        level: $scope.view[i].level,
                        endpoint: $scope.view[i].endpoint,
                        summary: $scope.view[i].summary,
                        breakdowns: $scope.view[i].breakdowns,
                        filterdimension: $scope.view[i].filterdimension,
                        filterexpression: $scope.view[i].filterexpression,
                        filteroperator: $scope.view[i].filteroperator,
                        sort: $scope.view[i].sort,
                        sortorder: $scope.view[i].sortorder,
                        start: ($scope.view[i].start) ? $scope.view[i].start : $rootScope.reportdates.start,
                        end: ($scope.view[i].end) ? $scope.view[i].end : $rootScope.reportdates.end,
                        limit: $scope.view[i].limit,
                        status: $scope.view[i].status,
                        campaignid: $scope.view[i].campaignid,
                        filter: $scope.view[i].filter,
                        campaign: $scope.view[i].campaign,
                        adgroup: $scope.view[i].adgroup,
                        network: $scope.view[i].network,
                        zeroimpressions: $scope.view[i].zeroimpressions,
                    }
                }).then(function successCallback(res) {
                    if ($scope.view[i].callback) {
                        $scope.view[i].callback(res.data);
                    }
                    if (res.data.error) {
                        $scope.fnModal('api/modal/global.norights');
                    } else if (res.data.action == 'connect') {
                        $scope.fnModal('api/modal/' + $scope.cfg.urlbase + '.connect');
                        $http.get('/rest/api-core/apigrants.get', {
                            params: {
                                websiteid: h.siteId(),
                                'type': $scope.cfg.urlbase,
                            }
                        }).then(function successCallback(res) {
                            if (res.data.data !== null) {
                                $scope.apigrants = res.data.data;
                            }
                        });
                        if (res.data.sets) {
                            for (var set in res.data.sets) {
                                $scope.analytics[set] = res.data.sets[set];
                                for (var y in $scope.charts) {
                                    if ($scope.charts[y].dataset == set) {
                                        fnMakeChart($scope.charts[y]);
                                    }
                                }
                            }
                            $scope.analytics[i] = { totals: res.data.totals };
                        } else {
                            $scope.analytics[i] = res.data;
                            for (var y in $scope.charts) {
                                if ($scope.charts[y].dataset == i) {
                                    fnMakeChart($scope.charts[y]);
                                }
                            }
                        }
                    } else if (res.data.action == 'getcustomer') {
                        $scope.getCustomer();
                    } else if (res.data.sets) {
                        for (var set in res.data.sets) {
                            $scope.analytics[set] = res.data.sets[set];
                            for (var y in $scope.charts) {
                                if ($scope.charts[y].dataset == set) {
                                    fnMakeChart($scope.charts[y]);
                                }
                            }
                        }
                        $scope.analytics[i] = { totals: res.data.totals };
                    } else {
                        $scope.analytics[i] = res.data;
                        for (var y in $scope.charts) {
                            if ($scope.charts[y].dataset == i) {
                                fnMakeChart($scope.charts[y]);
                            }
                        }
                    }
                }, function errorCallback() {
                    $scope.fnModal('api/modal/global.error');
                });
            }
        }
        var getReportData = function () {
            $scope.fnCloseModal();
            $scope.analytics = {};
            $scope.pagecharts = {};
            _fnFetchData('first');
            _fnFetchData('second');
            _fnFetchData('third');
            _fnFetchData('fourth');
        }
        var fnMakeChart = function (chart) {
            console.log(chart.dataset);
            var dataset = $scope.analytics[chart.dataset].data;
            var dimension = (chart.dimension) ? chart.dimension : ($scope.cfg.dimensionprefix + $scope.view[chart.dataset].dimension);
            var metric = (chart.metric) ? chart.metric : $scope.metric;
            $scope.progresschart[chart.chart] = false;
            if (chart['type'] == 'line') {
                _charts.fnLineChart(chart, dataset, dimension, metric);
            } else if (chart['type'] == 'bar') {
                _charts.fnBarChart(chart, dataset, dimension, metric);
            } else if (chart['type'] == 'pie') {
                _charts.fnPieChart(chart, dataset, dimension, metric);
            } else if (chart['type'] == 'linemulti') {
                _charts.fnLineChartMultiple(chart, dataset, dimension, metric);
            } else if (chart['type'] == 'bubble') {
                _charts.fnBubbleChart(chart, dataset, dimension, metric);
            } else if (chart['type'] == 'progress') {
                _charts.fnProgressChart(chart, dataset, dimension, metric);
            }
        }
        $scope.colors = ['#E91E63', '#3F51B5', '#00BCD4', '#8BC34A', '#FF9800', '#795548', '#607D8B', '#00CC00', '#0000CC', '#DDDDDD', '#999999', '#333333', '#990000']
        var _charts = {
            fnBubbleChart: function (chart, dataset, dimension, metric) {
                return false;
            },
            fnProgressChart: function (chart, dataset, dimension, metric) {
                $scope.pagecharts[chart.chart] = false
                var b = $filter('orderBy')(dataset, metric, $scope.order.reverse).slice(0, 5);
                $scope.progresschart[chart.chart] = b;
            },
            fnLineChart: function (chart, dataset, dimension, metric) {
                $scope.gloMetrics[metric] = $scope.gloMetrics[metric] || {};
                var datamerge = $scope.gloMetrics[metric].datemerge;
                var datesubstr = ($scope.cfg.dateformat == 'YYYYMMDD') ? [0, 4, 4, 6, 6, 8] : [0, 4, 5, 7, 8, 10];
                var data = {};
                // if (dataset.length > 62 && datamerge) {
                //     for (var i in dataset) {
                //         // todo date format YYYY-MM-DD vs YYYYMMDD
                //         var year = dataset[i][dimension].toString().substring(datesubstr[0], datesubstr[1]);
                //         var month = dataset[i][dimension].toString().substring(datesubstr[2], datesubstr[3]);
                //         var day = dataset[i][dimension].toString().substring(datesubstr[4], datesubstr[5]);
                //         var date = new Date(year, month - 1, day);
                //         onejan = new Date(date.getFullYear(), 0, 1);
                //         week = Math.ceil((((date - onejan) / 86400000) + onejan.getDay() + 1) / 7);
                //         var yw = year + '_' + week;
                //         if (data[yw]) {
                //             data[yw][metric] += dataset[i][metric];
                //             data[yw]['n'] += 1;
                //         } else {
                //             data[yw] = dataset[i];
                //             data[yw]['n'] = 1;
                //         }
                //     }
                //     // todo calc average
                //     dataset = $filter('orderBy')(Object.values(data), 'dimension', false);
                //     if (datamerge == 'avg') {
                //         dataset = dataset.map(function (c) {
                //             c[metric] = c[metric] / c['n'];
                //             return c;
                //         })
                //     }
                // }
                // A new function to merge data into 31-day buckets, starting from the last entry.
                if (dataset.length > 62 && datamerge) { // Condition changed to 31 for one bucket period.
                    // Assuming the dataset is sorted by date, with the most recent date at the end.
                    // If not sorted, you would need to find the maximum date first.
                    const lastEntry = dataset[dataset.length - 1];
                    const endDateYear = lastEntry[dimension].toString().substring(datesubstr[0], datesubstr[1]);
                    const endDateMonth = lastEntry[dimension].toString().substring(datesubstr[2], datesubstr[3]);
                    const endDateDay = lastEntry[dimension].toString().substring(datesubstr[4], datesubstr[5]);
                    // Set the anchor date to the end of the day of the last entry.
                    const anchorDate = new Date(endDateYear, endDateMonth - 1, endDateDay);
                    anchorDate.setHours(23, 59, 59, 999); // Use end of day to ensure the last day is included.
                    const data = {};
                    const MS_PER_DAY = 86400000; // Milliseconds in one day (24 * 60 * 60 * 1000)
                    let period = 7;
                    // Loop backwards from the end of the dataset.
                    for (let i = dataset.length - 1; i >= 0; i--) {
                        const item = dataset[i];
                        // Parse the date for the current item.
                        const year = item[dimension].toString().substring(datesubstr[0], datesubstr[1]);
                        const month = item[dimension].toString().substring(datesubstr[2], datesubstr[3]);
                        const day = item[dimension].toString().substring(datesubstr[4], datesubstr[5]);
                        const currentDate = new Date(year, month - 1, day);
                        // Calculate how many days ago this date was from our anchor date.
                        const daysDifference = (anchorDate.getTime() - currentDate.getTime()) / MS_PER_DAY;
                        // Determine the bucket index. Each bucket is a 31-day period.
                        // Math.floor(0 / 31) = 0, Math.floor(30.9 / 31) = 0, Math.floor(31 / 31) = 1
                        const bucketIndex = Math.floor(daysDifference / period);
                        // Create a representative date for the bucket's start day for a consistent key.
                        const bucketStartDate = new Date(anchorDate);
                        bucketStartDate.setDate(anchorDate.getDate() - (bucketIndex + 1) * period + 1);
                        // Use a clean 'YYYY-MM-DD' format for the key.
                        const bucketKey = bucketStartDate.toISOString().split('T')[0];
                        // Aggregate data into the bucket.
                        if (data[bucketKey]) {
                            data[bucketKey][metric] += item[metric];
                            data[bucketKey]['n'] += 1;
                        } else {
                            // Create a new entry for the bucket.
                            data[bucketKey] = { ...item }; // Copy item to avoid modifying original
                            data[bucketKey][dimension] = bucketKey; // Set the dimension to our bucket's start date
                            data[bucketKey]['n'] = 1;
                        }
                    }
                    // Convert the aggregated data object back to an array and sort it.
                    dataset = $filter('orderBy')(Object.values(data), dimension, false);
                    // If 'avg' is specified, calculate the average for each bucket.
                    if (datamerge === 'avg') {
                        dataset = dataset.map(function (c) {
                            c[metric] = c[metric] / c['n'];
                            return c;
                        });
                    }
                }
                $scope.pagecharts[chart.chart] = {
                    data: dataset,
                    type: 'serial',
                    theme: 'light',
                    marginLeft: 0,
                    marginRight: 0,
                    marginTop: 10,
                    fontFamily: 'Roboto',
                    categoryField: dimension,
                    rotate: false,
                    pathToImages: 'vendor/amchart/images/',
                    dataDateFormat: $scope.cfg.dateformat,
                    categoryAxis: {
                        gridPosition: "start",
                        parseDates: true,
                        gridThickness: 0
                    },
                    valueAxes: [{
                        position: "left",
                        axisAlpha: 0,
                        labelsEnabled: true,
                        dashLength: 4,
                        color: '#dedede',
                    }],
                    graphs: [{
                        balloonText: $filter('translate')('metrics.' + metric) + " 
 [[value]]",
                        "bullet": "round",
                        "bulletBorderAlpha": 1,
                        "bulletColor": "#FFFFFF",
                        "useLineColorForBulletBorder": true,
                        "fillAlphas": 0.2,
                        "lineThickness": 2,
                        "lineAlpha": 1,
                        "bulletSize": 7,
                        "connect": true,
                        "type": "smoothedLine",
                        "title": "Expenses",
                        "valueField": metric,
                        lineColor: $scope.colors[colorindex],
                    }],
                }
                colorindex += 1;
            },
            fnLineChartMultiple: function (chart, dataset, dimension, metric) {
                var d = [];
                var dimension2 = (chart.dimension2) ? chart.dimension2 : $scope.cfg.dimensionprefix + $scope.view[chart.dataset].dimension2;
                var datamerge = ($scope.gloMetrics[metric] || {}).datemerge;
                if (dataset && dataset.length > 62 && datamerge) {
                    var datesubstr = ($scope.cfg.dateformat == 'YYYYMMDD') ? [0, 4, 4, 6, 6, 8] : [0, 4, 5, 7, 8, 10];
                    var lastEntry = dataset[dataset.length - 1];
                    if (lastEntry) {
                        var lastYear = lastEntry[dimension].toString().substring(datesubstr[0], datesubstr[1]);
                        var lastMonth = lastEntry[dimension].toString().substring(datesubstr[2], datesubstr[3]);
                        var lastDay = lastEntry[dimension].toString().substring(datesubstr[4], datesubstr[5]);
                        var anchorDate = new Date(lastYear, lastMonth - 1, lastDay);
                        anchorDate.setHours(23, 59, 59, 999);
                        var MS_PER_DAY = 86400000;
                        var period = 7;
                        var bucketMap = {};
                        var formatBucketKey = function (dateObj) {
                            var year = dateObj.getFullYear();
                            var month = ('0' + (dateObj.getMonth() + 1)).slice(-2);
                            var day = ('0' + dateObj.getDate()).slice(-2);
                            if ($scope.cfg.dateformat === 'YYYYMMDD') {
                                return '' + year + month + day;
                            }
                            return year + '-' + month + '-' + day;
                        };
                        for (var idx = dataset.length - 1; idx >= 0; idx--) {
                            var row = dataset[idx];
                            var keyYear = row[dimension].toString().substring(datesubstr[0], datesubstr[1]);
                            var keyMonth = row[dimension].toString().substring(datesubstr[2], datesubstr[3]);
                            var keyDay = row[dimension].toString().substring(datesubstr[4], datesubstr[5]);
                            var currentDate = new Date(keyYear, keyMonth - 1, keyDay);
                            var daysDifference = (anchorDate.getTime() - currentDate.getTime()) / MS_PER_DAY;
                            var bucketIndex = Math.floor(daysDifference / period);
                            var bucketStart = new Date(anchorDate);
                            bucketStart.setDate(anchorDate.getDate() - (bucketIndex + 1) * period + 1);
                            var bucketKey = formatBucketKey(bucketStart);
                            var segment = row[dimension2];
                            if (!segment) {
                                continue;
                            }
                            bucketMap[bucketKey] = bucketMap[bucketKey] || {};
                            bucketMap[bucketKey][segment] = bucketMap[bucketKey][segment] || { sum: 0, count: 0 };
                            bucketMap[bucketKey][segment].sum += parseFloat(row[metric]) || 0;
                            bucketMap[bucketKey][segment].count += 1;
                        }
                        var mergedDataset = [];
                        var bucketKeys = Object.keys(bucketMap).sort();
                        for (var kIndex = 0; kIndex < bucketKeys.length; kIndex++) {
                            var bucketKey = bucketKeys[kIndex];
                            var segments = bucketMap[bucketKey];
                            for (var segmentName in segments) {
                                if (!segments.hasOwnProperty(segmentName)) {
                                    continue;
                                }
                                var entry = segments[segmentName];
                                var value = (datamerge === 'avg' && entry.count > 0) ? entry.sum / entry.count : entry.sum;
                                if (!isFinite(value)) {
                                    value = 0;
                                }
                                var mergedRow = {};
                                mergedRow[dimension] = bucketKey;
                                mergedRow[dimension2] = segmentName;
                                mergedRow[metric] = value;
                                mergedDataset.push(mergedRow);
                            }
                        }
                        dataset = mergedDataset;
                    }
                }
                if (!chart.graphs || !chart.graphs.length) {
                    var totalsByDimension2 = {};
                    dataset.forEach(function (row) {
                        var groupKey = row[dimension2];
                        if (!groupKey) {
                            return;
                        }
                        var value = parseFloat(row[metric]);
                        if (isNaN(value)) {
                            return;
                        }
                        totalsByDimension2[groupKey] = (totalsByDimension2[groupKey] || 0) + value;
                    });
                    chart.graphs = Object.keys(totalsByDimension2)
                        .map(function (key) {
                            return { name: key, total: totalsByDimension2[key] };
                        })
                        .sort(function (a, b) { return b.total - a.total; })
                        .slice(0, 5)
                        .map(function (item) { return item.name; });
                }
                for (var i in dataset) {
                    var row = dataset[i];
                    d[row[dimension]] = d[row[dimension]] || {};
                    d[row[dimension]].c = row[dimension];
                    if (chart.graphs) {
                        for (var y in chart.graphs) {
                            if (chart.graphs[y] == row[dimension2]) {
                                d[row[dimension]]['t' + chart.graphs[y]] = row[metric];
                            }
                        }
                    }
                }
                console.log('chart', chart);
                var b = [];
                Object.keys(d).sort().forEach(function (key) {
                    b.push(d[key]);
                });
                var graphs = [];
                for (var y in chart.graphs) {
                    // *** FIX: Changed 'var' to 'let' to correctly scope the variable for the closure ***
                    let segmentName = chart.graphs[y];
                    graphs.push({
                        balloonText: chart.graphs[y] + '
' + $filter('translate')('metrics.' + metric) + " [[value]]",
                        "bullet": "round",
                        "bulletBorderAlpha": 1,
                        "bulletColor": "#FFFFFF",
                        "useLineColorForBulletBorder": true,
                        "fillAlphas": 0,
                        "lineThickness": 2,
                        "lineAlpha": 1,
                        "bulletSize": 7,
                        "title": "Expenses",
                        "valueField": 't' + chart.graphs[y],
                        lineColor: $scope.colors[y],
                        stacked: false,
                        balloonFunction: function (item) {
                            var dateLabel = $filter('date')(item.category, 'yyyy-MM-dd');
                            var rawValue = item.values.value;
                            var formatted = $filter('useFilter')(
                                rawValue,
                                $scope.gloMetrics[metric].typefilter,
                                $scope.gloMetrics[metric].filtercomparator
                            );
                            var suffix = $scope.gloMetrics[metric].after || '';
                            return (
                                '' +
                                '
' + segmentName + '
' + // This will now use the correct segmentName
                                '
' + dateLabel + '
' +
                                '
' +
                                $filter('translate')('metrics.' + metric) +
                                ': ' + formatted + suffix + '' +
                                '
' +
                                '
position:[[position]]
ctr:[[ctr]]
 clicks:[[clicks]]
value:[[page]]",
                    "bullet": "circle",
                    "bulletBorderAlpha": 0.2,
                    "bulletAlpha": 0.8,
                    "lineAlpha": 0,
                    "fillAlphas": 0,
                    "valueField": "clicks",
                    "xField": "position",
                    "yField": "ctr",
                    "maxBulletSize": 40,
                    "colorField": "color"
                }],
            }
        }
        //add bubblechart to parent controller
        $controller('coreapi', { $scope: $scope });
        $scope.fnAddChart('fnBubbleChart', fnBubbleChart);
        $scope.init();
        // Start polling immediately if the initial state is pending or clustering
        if ($scope.analytics && $scope.analytics.second && ($scope.analytics.second.action === 'pending' || ($scope.analytics.second.data && ($scope.analytics.second.data.status === 'clustering' || $scope.analytics.second.data.status === 'pending')))) {
            $scope.startClusterPolling();
        }
    }
]);
app.controller('youtube', ['$scope', '$timeout', '$http', '$rootScope', '$controller', '$filter', 'h',
    function($scope, $timeout, $http, $rootScope, $controller, $filter, h) {
        $scope.cfg = {
            authurl: 'https://app.pageowl.app/rest/youtube/connect?site_id=' + h.siteId(),
            dateformat: "YYYY-MM-DD",
            dimensionprefix: '',
            urlbase: 'youtube',
            report_endpoint: '/rest/youtube/report',
        }
        $scope.gloMetrics = h.metrics('youtube');
      /*  $scope.gloMetrics = {
            commentCount: { name: 'Clicks', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
            subscriberCount: { name: 'Impressions', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
            videoCount: { name: 'Date', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
            viewCount: { name: 'Avg cost / Click', typefilter: 'number', filtercomparator: 0, 'datemerge': 'avg' },
            views: { name: 'Ctr', typefilter: 'number', filtercomparator: 0,  'datemerge': 'sum' },
            shares: { name: 'Conversions', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
            likes: { name: 'Cost', typefilter: 'number', filtercomparator: 0,  'datemerge': 'sum' },
            dislikes: { name: 'Cost / conversion', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
            comments: { name: 'Conversion rate', typefilter: 'number', filtercomparator: 0,  'datemerge': 'sum' },
            subscribersGained: { name: 'AbsoluteTopImpressionPercentage', typefilter: 'number', filtercomparator: 0,  'datemerge': 'sum' },
            subscribersLost: { name: 'Conversion value', typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
            estimatedMinutesWatched: { name: 'Zoekimpressie aandeel', typefilter: 'number', filtercomparator: 1,  'datemerge': 'sum' },
            annotationCloseRate: { name: 'Top Positie', typefilter: 'number', filtercomparator: 2, 'after': '%', 'datemerge': 'avg' },
            annotationClickThroughRate: { name: 'ROAS', typefilter: 'number', filtercomparator: 2, 'after': '%', 'datemerge': 'avg' },
            averageViewDuration: { name: 'ROAS', typefilter: 'secondsToHHmmss', filtercomparator: 0, 'datemerge': 'avg' },
        };
*/
        $scope.fnFormatAd = function(d) {
            return d.HeadlinePart1 + d.HeadlinePart2 + d.Description + d.CreativeDestinationUrl + d.CreativeFinalUrls;
        }
        $scope.reportconfig = {
            channel: {
                views: {
                    overview: {
                        name: 'Overview',
                        view: 'overview',
                        second: { dimension: 'Date', report: 'analytics', 'allowcomp': true },
                        third: { dimension: 'insightTrafficSourceType', report: 'analytics', metrics: ['views', 'estimatedMinutesWatched'] },
                        selectedmetric: 'views',
                        selectedmetrics: { 'Clicks': true, 'Impressions': true, 'Cost': true, 'AverageCpc': true, 'Ctr': true, 'Conversions': true, 'CostPerConversion': true, 'ConversionRate': true, 'AbsoluteTopImpressionPercentage': true, 'ConversionValue': true, 'SearchImpressionShare': true, 'roas': true },
                        metrics: ['views', 'shares', 'likes', 'dislikes', 'comments', 'subscribersGained', 'subscribersLost', 'estimatedMinutesWatched', 'annotationCloseRate', 'annotationClickThroughRate', 'averageViewDuration'],
                        //table: { dataset: 'second' },
                        panels: { dataset: 'second' },
                        charts: {
                            views: [{ 'chart': 'c1', 'name': 'views', type: 'line', dataset: 'second', date: true }, { 'chart': 'c2', 'name': 'Views / Source', 'metric':'views', type: 'bar', dataset: 'third' }],
                            shares: [{ 'chart': 'c1', 'name': 'Shares', type: 'line', dataset: 'second', date: true }, { 'chart': 'c2', 'name': 'Views / Source', 'metric':'views', type: 'bar', dataset: 'third' }],
                            likes: [{ 'chart': 'c1', 'name': 'Likes', type: 'line', dataset: 'second', date: true }, { 'chart': 'c2', 'name': 'Views / Source', 'metric':'views', type: 'bar', dataset: 'third' }],
                            dislikes: [{ 'chart': 'c1', 'name': 'Dislikes', type: 'line', dataset: 'second', date: true }, { 'chart': 'c2', 'name': 'Views / Source', 'metric':'views', type: 'bar', dataset: 'third' }],
                            comments: [{ 'chart': 'c1', 'name': 'Comments', type: 'line', dataset: 'second', date: true }, { 'chart': 'c2', 'name': 'Views / Source', 'metric':'views', type: 'bar', dataset: 'third' }],
                            subscribersGained: [{ 'chart': 'c1', 'name': 'Subscribers Gained', type: 'line', dataset: 'second', date: true }, { 'chart': 'c2', 'name': 'Views / Source', 'metric':'views', type: 'bar', dataset: 'third' }],
                            subscribersLost: [{ 'chart': 'c1', 'name': 'Subscribers Lost', type: 'line', dataset: 'second', date: true }, { 'chart': 'c2', 'name': 'Views / Source', 'metric':'views', type: 'bar', dataset: 'third' }],
                            estimatedMinutesWatched: [{ 'chart': 'c1', 'name': 'Minutes Watched', type: 'line', dataset: 'second', date: true }, { 'chart': 'c2', 'name': 'Views / Source', 'metric':'views', type: 'bar', dataset: 'third' }],
                            AbsoluteTopImpressionPercentage: [{ 'chart': 'c1', 'name': 'Average position', type: 'line', dataset: 'second', date: true }, { 'chart': 'c2', 'name': 'Views / Source', 'metric':'views', type: 'bar', dataset: 'third' }],
                            ConversionValue: [{ 'chart': 'c1', 'name': 'Conversion value', type: 'line', dataset: 'second', date: true },{ 'chart': 'c2', 'name': 'Views / Source', 'metric':'views', type: 'bar', dataset: 'third' }],
                        },
                    },  
                     anderekak: {
                        name: 'Overview',
                        view: 'anderekak',
                        first: { dimension: 'Date', report: 'channelstats' },
                        selectedmetric: 'views',
                        selectedmetrics: { 'Clicks': true, 'Impressions': true, 'Cost': true, 'AverageCpc': true, 'Ctr': true, 'Conversions': true, 'CostPerConversion': true, 'ConversionRate': true, 'AbsoluteTopImpressionPercentage': true, 'ConversionValue': true, 'SearchImpressionShare': true, 'roas': true },
                        metrics: ['commentCount', 'subscriberCount', 'videoCount', 'viewCount'],
                        //table: { dataset: 'second' },
                        panels: { dataset: 'second' },
                        charts: {
                            views: [{ 'chart': 'c1', 'name': 'views', type: 'line', dataset: 'second', date: true }, { 'chart': 'c2', 'name': 'Views / Source', 'metric':'views', type: 'bar', dataset: 'third' }],
                            shares: [{ 'chart': 'c1', 'name': 'Shares', type: 'line', dataset: 'second', date: true }, { 'chart': 'c2', 'name': 'Views / Source', 'metric':'views', type: 'bar', dataset: 'third' }],
                            likes: [{ 'chart': 'c1', 'name': 'Likes', type: 'line', dataset: 'second', date: true }, { 'chart': 'c2', 'name': 'Views / Source', 'metric':'views', type: 'bar', dataset: 'third' }],
                            dislikes: [{ 'chart': 'c1', 'name': 'Dislikes', type: 'line', dataset: 'second', date: true }, { 'chart': 'c2', 'name': 'Views / Source', 'metric':'views', type: 'bar', dataset: 'third' }],
                            comments: [{ 'chart': 'c1', 'name': 'Comments', type: 'line', dataset: 'second', date: true }, { 'chart': 'c2', 'name': 'Views / Source', 'metric':'views', type: 'bar', dataset: 'third' }],
                            subscribersGained: [{ 'chart': 'c1', 'name': 'Subscribers Gained', type: 'line', dataset: 'second', date: true }, { 'chart': 'c2', 'name': 'Views / Source', 'metric':'views', type: 'bar', dataset: 'third' }],
                            subscribersLost: [{ 'chart': 'c1', 'name': 'Subscribers Lost', type: 'line', dataset: 'second', date: true }, { 'chart': 'c2', 'name': 'Views / Source', 'metric':'views', type: 'bar', dataset: 'third' }],
                            estimatedMinutesWatched: [{ 'chart': 'c1', 'name': 'Minutes Watched', type: 'line', dataset: 'second', date: true }, { 'chart': 'c2', 'name': 'Views / Source', 'metric':'views', type: 'bar', dataset: 'third' }],
                            AbsoluteTopImpressionPercentage: [{ 'chart': 'c1', 'name': 'Average position', type: 'line', dataset: 'second', date: true }, { 'chart': 'c2', 'name': 'Views / Source', 'metric':'views', type: 'bar', dataset: 'third' }],
                            ConversionValue: [{ 'chart': 'c1', 'name': 'Conversion value', type: 'line', dataset: 'second', date: true },{ 'chart': 'c2', 'name': 'Views / Source', 'metric':'views', type: 'bar', dataset: 'third' }],
                        },
                    },
                    videos: {
                        name: 'Ad Groups',
                        view: 'videos',
                        first: { dimension: 'Date', report: 'videos' },
                        //second: { dimension: 'AverageCpm', sort: 'sessions', sortorder: 'DESCENDING', },
                        selectedmetric: 'Clicks',
                        metrics: ['Clicks'],
      
                    },
                },
            }
        }
        $controller('coreapi', { $scope: $scope });
        $scope.init();
    }
]);
app.controller('googleads', ['$scope', '$timeout', '$http', '$rootScope', '$controller', '$filter', 'h',
    function ($scope, $timeout, $http, $rootScope, $controller, $filter, h) {
        $scope.cfg = {
            authurl: 'https://app.marketingtracer.com/rest/googlexads/connect?websiteid=' + h.siteId(),
            dateformat: "YYYY-MM-DD",
            dimensionprefix: '',
            urlbase: 'googlexads',
            switchclient: true,
            report_endpoint: '/rest/googlexads/report',
        }
        if ($rootScope.user.reseller?.config?.authdomain) {
            $scope.cfg.authurl = 'https://' + $rootScope.user.reseller.config.authdomain + '/rest/googlexads/connect?websiteid=' + h.siteId();
        }
        $scope.gloMetrics = h.metrics('googlexads');
        /*  $scope.gloMetrics = {
              Clicks: { name: 'Clicks', typefilter: 'number', filtercomparator: 0  ,'datemerge':'sum'},
              Impressions: { name: 'Impressions', typefilter: 'number', filtercomparator: 0  ,'datemerge':'sum'},
              Date: { name: 'Date', typefilter: 'number', filtercomparator: 0  ,'datemerge':'sum'},
              AverageCpc: { name: 'Avg cost / Click', typefilter: 'number', filtercomparator: 2, 'before': '€'  ,'datemerge':'avg'},
              Ctr: { name: 'Ctr', typefilter: 'number', filtercomparator: 0, 'after': '%'  ,'datemerge':'avg'},
              Conversions: { name: 'Conversions', typefilter: 'number', filtercomparator: 0  ,'datemerge':'sum'},
              Cost: { name: 'Cost', typefilter: 'number', filtercomparator: 2, 'before': '€'  ,'datemerge':'sum'},
              CostPerConversion: { name: 'Cost / conversion', typefilter: 'number', filtercomparator: 2, 'before': '€'  ,'datemerge':'avg'},
              ConversionRate: { name: 'Conversion rate', typefilter: 'number', filtercomparator: 0, 'after': '%'  ,'datemerge':'avg'},
              AbsoluteTopImpressionPercentage: { name: 'AbsoluteTopImpressionPercentage', typefilter: 'number', filtercomparator: 0, 'after': '%'  ,'datemerge':'avg'},
              ConversionValue: { name: 'Conversion value', typefilter: 'number', filtercomparator: 0, 'before': '€'  ,'datemerge':'sum'},
              SearchImpressionShare: { name: 'Zoekimpressie aandeel', typefilter: 'number', filtercomparator: 2, 'after': '%'  ,'datemerge':'avg'},
              SearchAbsoluteTopImpressionShare: { name: 'Top Positie', typefilter: 'number', filtercomparator: 2, 'after': '%'  ,'datemerge':'avg'},
              roas: { name: 'ROAS', typefilter: 'number', filtercomparator: 2, 'after': '%'  ,'datemerge':'avg'},
          };*/
        $scope.fnFormatAd = function (d) {
            return d.HeadlinePart1 + d.HeadlinePart2 + d.Description + d.CreativeDestinationUrl + d.CreativeFinalUrls;
        }
        $scope.reportconfig = {
            campaigns: {
                views: {
                    all: {
                        name: 'Campaigns',
                        view: 'all',
                        first: { dimension: 'Date', report: 'ACCOUNT_PERFORMANCE_REPORT' },
                        second: { dimension: 'CampaignName', report: 'CAMPAIGN_PERFORMANCE_REPORT', 'allowcomp': true },
                        selectedmetric: 'Clicks',
                        selectedmetrics: { 'Clicks': true, 'Impressions': true, 'Cost': true, 'AverageCpc': true, 'Ctr': true, 'Conversions': true, 'CostPerConversion': true, 'ConversionRate': true, 'AbsoluteTopImpressionPercentage': true, 'ConversionValue': true, 'SearchImpressionShare': true, 'roas': true },
                        metrics: ['Clicks', 'Impressions', 'Cost', 'AverageCpc', 'Ctr', 'Conversions', 'CostPerConversion', 'ConversionRate', 'AbsoluteTopImpressionPercentage', 'ConversionValue', 'roas'],
                        table: { dataset: 'second' },
                        panels: { dataset: 'second' },
                        charts: {
                            Clicks: [{ 'chart': 'c1', 'name': 'Clicks', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Clicks / Campaign', type: 'progress', dataset: 'second' }],
                            Impressions: [{ 'chart': 'c1', 'name': 'Impressions', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Impressions / Campaign', type: 'progress', dataset: 'second' }],
                            Cost: [{ 'chart': 'c1', 'name': 'Kosten', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Sessions / Campaign', type: 'progress', dataset: 'second' }],
                            AverageCpc: [{ 'chart': 'c1', 'name': 'Avg cost / Click', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'CPC / Campaign', type: 'progress', dataset: 'second' }],
                            Ctr: [{ 'chart': 'c1', 'name': 'Ctr', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Ctr / Campaign', type: 'progress', dataset: 'second' }],
                            Conversions: [{ 'chart': 'c1', 'name': 'Conversies', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Conversies / Campaign', type: 'progress', dataset: 'second' }],
                            CostPerConversion: [{ 'chart': 'c1', 'name': 'Cost / conversion', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Cost / conversion / Campaign', type: 'progress', dataset: 'second' }],
                            ConversionRate: [{ 'chart': 'c1', 'name': 'Conversion rate', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Conversion rate / Campaign', type: 'progress', dataset: 'second' }],
                            AbsoluteTopImpressionPercentage: [{ 'chart': 'c1', 'name': 'Average position', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Average position / Campaign', type: 'progress', dataset: 'second' }],
                            ConversionValue: [{ 'chart': 'c1', 'name': 'Conversion value', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Conversion value / Campaign', type: 'progress', dataset: 'second' }],
                        },
                    },
                    adgroups: {
                        name: 'Ad Groups',
                        view: 'adgroups',
                        first: { dimension: 'Date', report: 'ACCOUNT_PERFORMANCE_REPORT' },
                        second: { dimension: 'AdGroupName', report: 'ADGROUP_PERFORMANCE_REPORT', 'allowcomp': true },
                        //second: { dimension: 'AverageCpm', sort: 'sessions', sortorder: 'DESCENDING', },
                        selectedmetric: 'Clicks',
                        selectedmetrics: { 'Clicks': true, 'Impressions': true, 'Cost': true, 'AverageCpc': true, 'Ctr': true, 'Conversions': true, 'CostPerConversion': true, 'ConversionRate': true, 'AbsoluteTopImpressionPercentage': true, 'ConversionValue': true, 'SearchImpressionShare': true, 'roas': true },
                        metrics: ['Clicks', 'Impressions', 'Cost', 'AverageCpc', 'Ctr', 'Conversions', 'CostPerConversion', 'ConversionRate', 'AbsoluteTopImpressionPercentage', 'ConversionValue', 'roas'],
                        table: { dataset: 'second' },
                        panels: { dataset: 'second' },
                        charts: {
                            Clicks: [{ 'chart': 'c1', 'name': 'Clicks', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Clicks / Adgroup', type: 'progress', dataset: 'second' }],
                            Impressions: [{ 'chart': 'c1', 'name': 'Impressions', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Impressions / Adgroup', type: 'progress', dataset: 'second' }],
                            Cost: [{ 'chart': 'c1', 'name': 'Kosten', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Sessions / Adgroup', type: 'progress', dataset: 'second' }],
                            AverageCpc: [{ 'chart': 'c1', 'name': 'Avg cost / Click', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'CPC / Adgroup', type: 'progress', dataset: 'second' }],
                            Ctr: [{ 'chart': 'c1', 'name': 'Ctr', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Ctr / Adgroup', type: 'progress', dataset: 'second' }],
                            Conversions: [{ 'chart': 'c1', 'name': 'Conversies', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Conversies / Adgroup', type: 'progress', dataset: 'second' }],
                            CostPerConversion: [{ 'chart': 'c1', 'name': 'Cost / conversion', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Cost / conversion / Adgroup', type: 'progress', dataset: 'second' }],
                            ConversionRate: [{ 'chart': 'c1', 'name': 'Conversion rate', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Conversion rate / Adgroup', type: 'progress', dataset: 'second' }],
                            AbsoluteTopImpressionPercentage: [{ 'chart': 'c1', 'name': 'Average position', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Average position / Adgroup', type: 'progress', dataset: 'second' }],
                            ConversionValue: [{ 'chart': 'c1', 'name': 'Conversion value', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Conversion value / Adgroup', type: 'progress', dataset: 'second' }],
                        },
                    },
                    keywords: {
                        name: 'Keywords',
                        view: 'keywords',
                        first: { dimension: 'Date', report: 'ACCOUNT_PERFORMANCE_REPORT' },
                        second: { dimension: 'Query', report: 'SEARCH_QUERY_PERFORMANCE_REPORT', 'allowcomp': true },
                        selectedmetric: 'Clicks',
                        selectedmetrics: { 'Clicks': true, 'Impressions': true, 'Cost': true, 'AverageCpc': true, 'Ctr': true, 'Conversions': true, 'CostPerConversion': true, 'ConversionRate': true, 'AbsoluteTopImpressionPercentage': true, 'ConversionValue': true, 'roas': true },
                        metrics: ['Clicks', 'Impressions', 'Cost', 'AverageCpc', 'Ctr', 'Conversions', 'CostPerConversion', 'ConversionRate', 'AbsoluteTopImpressionPercentage', 'ConversionValue', 'roas'],
                        table: { dataset: 'second' },
                        panels: { dataset: 'second' },
                        charts: {
                            Clicks: [{ 'chart': 'c1', 'name': 'Clicks', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Clicks / Keyword', type: 'bar', dataset: 'second' }],
                            Impressions: [{ 'chart': 'c1', 'name': 'Impressions', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Impressions / Keyword', type: 'bar', dataset: 'second' }],
                            Cost: [{ 'chart': 'c1', 'name': 'Kosten', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Sessions / Keyword', type: 'bar', dataset: 'second' }],
                            AverageCpc: [{ 'chart': 'c1', 'name': 'Avg cost / Click', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'CPC / Keyword', type: 'bar', dataset: 'second' }],
                            Ctr: [{ 'chart': 'c1', 'name': 'Ctr', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Ctr / Keyword', type: 'bar', dataset: 'second' }],
                            Conversions: [{ 'chart': 'c1', 'name': 'Conversies', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Conversies / Keyword', type: 'bar', dataset: 'second' }],
                            CostPerConversion: [{ 'chart': 'c1', 'name': 'Cost / conversion', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Cost / conversion / Keyword', type: 'bar', dataset: 'second' }],
                            ConversionRate: [{ 'chart': 'c1', 'name': 'Conversion rate', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Conversion rate / Keyword', type: 'bar', dataset: 'second' }],
                            AbsoluteTopImpressionPercentage: [{ 'chart': 'c1', 'name': 'Average position', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Average position / Keyword', type: 'bar', dataset: 'second' }],
                            ConversionValue: [{ 'chart': 'c1', 'name': 'Conversion value', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Conversion value / Keyword', type: 'bar', dataset: 'second' }],
                        },
                    },
                    // ads: {
                    //     name: 'Ads',
                    //     view: 'ads',
                    //     first: { dimension: 'Date', report: 'ACCOUNT_PERFORMANCE_REPORT', 'allowcomp': true },
                    //     second: { dimension: 'HeadlinePart1,HeadlinePart2,Description,CreativeDestinationUrl,CreativeFinalUrls', function: 'fnFormatAd', report: 'AD_PERFORMANCE_REPORT' },
                    //     selectedmetric: 'Clicks',
                    //     selectedmetrics: { 'Clicks': true, 'Impressions': true, 'Cost': true, 'AverageCpc': true, 'Ctr': true, 'Conversions': true, 'CostPerConversion': true, 'ConversionRate': true, 'AbsoluteTopImpressionPercentage': true, 'ConversionValue': true, 'roas': true },
                    //     metrics: ['Clicks', 'Impressions', 'Cost', 'AverageCpc', 'Ctr', 'Conversions', 'CostPerConversion', 'ConversionRate', 'AbsoluteTopImpressionPercentage', 'ConversionValue', 'roas'],
                    //     table: { dataset: 'second' },
                    //     panels: { dataset: 'second' },
                    //     charts: {
                    //         Clicks: [{ 'chart': 'c1', 'name': 'Clicks', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Clicks / Ad', type: 'bar', dataset: 'second' }],
                    //         Impressions: [{ 'chart': 'c1', 'name': 'Impressions', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Impressions / Ad', type: 'bar', dataset: 'second' }],
                    //         Cost: [{ 'chart': 'c1', 'name': 'Kosten', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Sessions / Ad', type: 'bar', dataset: 'second' }],
                    //         AverageCpc: [{ 'chart': 'c1', 'name': 'Avg cost / Click', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'CPC / Ad', type: 'bar', dataset: 'second' }],
                    //         Ctr: [{ 'chart': 'c1', 'name': 'Ctr', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Ctr / Ad', type: 'bar', dataset: 'second' }],
                    //         Conversions: [{ 'chart': 'c1', 'name': 'Conversies', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Conversies / Ad', type: 'bar', dataset: 'second' }],
                    //         CostPerConversion: [{ 'chart': 'c1', 'name': 'Cost / conversion', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Cost / conversion / Ad', type: 'bar', dataset: 'second' }],
                    //         ConversionRate: [{ 'chart': 'c1', 'name': 'Conversion rate', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Conversion rate / Ad', type: 'bar', dataset: 'second' }],
                    //         AbsoluteTopImpressionPercentage: [{ 'chart': 'c1', 'name': 'Average position', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Average position / Ad', type: 'bar', dataset: 'second' }],
                    //         ConversionValue: [{ 'chart': 'c1', 'name': 'Conversion value', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Conversion value / Ad', type: 'bar', dataset: 'second' }],
                    //     },
                    // },
                    // conversions: {
                    //     name: 'Conversions',
                    //     view: 'conversions',
                    //     first: { dimension: 'Date', report: 'ACCOUNT_PERFORMANCE_REPORT' },
                    //     second: { dimension: 'ConversionTypeName', report: 'ACCOUNT_PERFORMANCE_REPORT', 'allowcomp': true },
                    //     selectedmetric: 'Conversions',
                    //     selectedmetrics: { 'Conversions': true, 'ConversionValue': true },
                    //     //metrics: ['Conversions', 'CostPerConversion', 'ConversionRate', 'ConversionValue'],
                    //     metrics: ['Conversions','ConversionValue'],
                    //     table: { dataset: 'second' },
                    //     panels: { dataset: 'second' },
                    //     charts: {
                    //         Clicks: [{ 'chart': 'c1', 'name': 'Sessions', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Sessions / Channel', type: 'bar', dataset: 'second' }],
                    //         Impressions: [{ 'chart': 'c1', 'name': 'Sessions', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Sessions / Channel', type: 'bar', dataset: 'second' }],
                    //         Cost: [{ 'chart': 'c1', 'name': 'Sessions', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Sessions / Channel', type: 'bar', dataset: 'second' }],
                    //         AverageCpc: [{ 'chart': 'c1', 'name': 'Sessions', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Sessions / Channel', type: 'bar', dataset: 'second' }],
                    //         Ctr: [{ 'chart': 'c1', 'name': 'Sessions', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Sessions / Channel', type: 'bar', dataset: 'second' }],
                    //         Conversions: [{ 'chart': 'c1', 'name': 'Sessions', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Sessions / Channel', type: 'bar', dataset: 'second' }],
                    //         CostPerConversion: [{ 'chart': 'c1', 'name': 'Sessions', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Sessions / Channel', type: 'bar', dataset: 'second' }],
                    //         ConversionRate: [{ 'chart': 'c1', 'name': 'Sessions', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Sessions / Channel', type: 'bar', dataset: 'second' }],
                    //         AbsoluteTopImpressionPercentage: [{ 'chart': 'c1', 'name': 'Sessions', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Sessions / Channel', type: 'bar', dataset: 'second' }],
                    //         ConversionValue: [{ 'chart': 'c1', 'name': 'Sessions', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Sessions / Channel', type: 'bar', dataset: 'second' }],
                    //     },
                    // },
                },
            }
        }
        $controller('coreapi', { $scope: $scope });
        $scope.init();
    }
]);
app.controller('facebookads', ['$scope', '$timeout', '$http', '$rootScope', '$controller', '$filter', 'h',
    function($scope, $timeout, $http, $rootScope, $controller, $filter, h) {
        $scope.cfg = {
            authurl: 'https://app.marketingtracer.com/rest/facebookads/connect?websiteid=' + h.siteId(),
            dateformat: "YYYY-MM-DD",
            dimensionprefix: '',
            urlbase: 'facebookads',
            report_endpoint: '/rest/facebookads/report',
        }
        $scope.gloMetrics = h.metrics('facebookads');
        /*  $scope.gloMetrics = {
            clicks: { name: 'Klikken', typefilter: 'number', filtercomparator: 0  ,'datemerge':'sum'},
            impressions: { name: 'Impressies', typefilter: 'number', filtercomparator: 0  ,'datemerge':'sum'},
            cpc: { name: 'cpc', typefilter: 'number', filtercomparator: 2, 'before': '€'  ,'datemerge':'avg'},
            cpm: { name: 'cpm', typefilter: 'number', filtercomparator: 2, 'before': '€'  ,'datemerge':'avg'},
            ctr: { name: 'Ctr', typefilter: 'number', filtercomparator: 2, 'after': '%'  ,'datemerge':'avg'},
            Conversions: { name: 'Conversions', typefilter: 'number', filtercomparator: 0  ,'datemerge':'sum'},
            Cost: { name: 'Cost', typefilter: 'number', filtercomparator: 0, 'before': '€'  ,'datemerge':'sum'},
            CostPerConversion: { name: $filter('translate')('metrics.spend')+' / conversie', typefilter: 'number', filtercomparator: 0, 'before': '€'  ,'datemerge':'avg'},
            ConversionRate: { name: 'Conversie ratio', typefilter: 'number', filtercomparator: 0, 'after': '%'  ,'datemerge':'avg'},
            AveragePosition: { name: 'Gemiddelde positie', typefilter: 'number', filtercomparator: 0  ,'datemerge':'avg'},
            ConversionValue: { name: 'Totale conversiewaarde', typefilter: 'number', filtercomparator: 0, 'before': '€'  ,'datemerge':'sum'},
            relevance_score: { name: 'Relevantie Score', typefilter: 'number', filtercomparator: 0, hide: { 'panel': true }  ,'datemerge':'avg'},
            spend: { name: 'Kosten', typefilter: 'number', filtercomparator: 2, 'before': '€'  ,'datemerge':'sum'},
        };
*/
        $scope.reportconfig = {
            campaigns: {
                views: {
                    all: {
                        name: 'Campagnes',
                        view: 'all',
                        viewfilters: ['campaigns'],
                        first: { dimension: 'date', level: 'account', 'endpoint': 'insights' },
                        second: { dimension: 'campaign_name', level: 'campaign', 'endpoint': 'insights', 'summary': 'clicks,impressions,cpc,cpm', 'allowcomp': true },
                        selectedmetric: 'clicks',
                        selectedmetrics: { 'clicks': true, 'impressions': true, 'cpc': true, 'cpm': true },
                        metrics: ['clicks', 'impressions', 'cpc', 'cpm','conversion_values','conversions','cost_per_conversion','website_ctr','website_purchase_roas'],
                        table: { dataset: 'second' },
                        panels: { dataset: 'second' },
                        charts: {
                            clicks: [{ 'chart': 'c1', 'name': $filter('translate')('metrics.clicks') + ' / Day', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': $filter('translate')('metrics.clicks') + ' / Campaign', type: 'bar', dataset: 'second' }],
                            impressions: [{ 'chart': 'c1', 'name': $filter('translate')('metrics.impressions') + ' / Day', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': $filter('translate')('metrics.impressions') + ' / Campaign', type: 'bar', dataset: 'second' }],
                            cpc: [{ 'chart': 'c1', 'name': $filter('translate')('metrics.cpc') + ' / Day', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': $filter('translate')('metrics.cpc') + ' / Campaign', type: 'bar', dataset: 'second' }],
                            cpm: [{ 'chart': 'c1', 'name': $filter('translate')('metrics.cpm') + ' / Day', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': $filter('translate')('metrics.cpm') + ' / Campaign', type: 'bar', dataset: 'second' }],
                        },
                    },
                    adsets: {
                        name: 'Advertentie Sets',
                        view: 'adsets',
                        viewfilters: ['campaigns'],
                        first: { dimension: 'date', level: 'account', 'endpoint': 'insights', 'summary': 'clicks,impressions,cpc,cpm,spend,ctr', 'allowcomp': true },
                        second: { dimension: 'adset_name', level: 'adset', endpoint: 'insights' },
                        third: { dimension: 'date', level: 'account', 'endpoint': 'insights' },
                        selectedmetric: 'clicks',
                        selectedmetrics: { 'clicks': true, 'impressions': true, 'cpc': true, 'cpm': true, 'ctr': true, 'spend': true },
                        metrics: ['clicks', 'impressions', 'cpc', 'cpm', 'ctr', 'spend'],
                        table: { dataset: 'second' },
                        panels: { dataset: 'first' },
                        charts: {
                            clicks: [{ 'chart': 'c1', 'name': $filter('translate')('metrics.clicks') + ' / Day', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': $filter('translate')('metrics.clicks') + ' / ad set', type: 'bar', dataset: 'second' }],
                            impressions: [{ 'chart': 'c1', 'name': $filter('translate')('metrics.impressions') + ' / Day', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': $filter('translate')('metrics.impressions') + ' / ad set', type: 'bar', dataset: 'second' }],
                            cpc: [{ 'chart': 'c1', 'name': $filter('translate')('metrics.cpc') + ' / Day', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': $filter('translate')('metrics.cpc') + ' / ad set', type: 'bar', dataset: 'second' }],
                            cpm: [{ 'chart': 'c1', 'name': $filter('translate')('metrics.cpm') + ' / Day', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': $filter('translate')('metrics.cpm') + ' / ad set', type: 'bar', dataset: 'second' }],
                            ctr: [{ 'chart': 'c1', 'name': $filter('translate')('metrics.ctr') + ' / Day', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': $filter('translate')('metrics.ctr') + ' / ad set', type: 'bar', dataset: 'second' }],
                            spend: [{ 'chart': 'c1', 'name': $filter('translate')('metrics.spend') + ' / Day', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': $filter('translate')('metrics.spend') + ' / ad set', type: 'bar', dataset: 'second' }],
                        },
                    },
                    ads: {
                        name: 'Advertenties',
                        view: 'ads',
                        viewfilters: ['adsets', 'campaigns', 'ads'],
                        first: { dimension: 'date', level: 'account', 'endpoint': 'insights', 'summary': 'clicks,impressions,cpc,cpm,spend,ctr', 'allowcomp': true },
                        second: { dimension: 'ad_name', level: 'ad', endpoint: 'insights' },
                        selectedmetric: 'clicks',
                        selectedmetrics: { 'clicks': true, 'impressions': true, 'cpc': true, 'cpm': true, 'ctr': true, 'spend': true },
                        metrics: ['clicks', 'impressions', 'cpc', 'cpm', 'ctr', 'spend'],
                        table: { dataset: 'second' },
                        panels: { dataset: 'first' },
                        charts: {
                            clicks: [{ 'chart': 'c1', 'name': $filter('translate')('metrics.clicks') + ' / Day', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': $filter('translate')('metrics.clicks') + ' / ad', type: 'bar', dataset: 'second' }],
                            impressions: [{ 'chart': 'c1', 'name': $filter('translate')('metrics.impressions') + ' / Day', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': $filter('translate')('metrics.impressions') + ' / ad', type: 'bar', dataset: 'second' }],
                            cpc: [{ 'chart': 'c1', 'name': $filter('translate')('metrics.cpc') + ' / Day', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': $filter('translate')('metrics.cpc') + ' / ad', type: 'bar', dataset: 'second' }],
                            cpm: [{ 'chart': 'c1', 'name': $filter('translate')('metrics.cpm') + ' / Day', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': $filter('translate')('metrics.cpm') + ' / ad', type: 'bar', dataset: 'second' }],
                            ctr: [{ 'chart': 'c1', 'name': $filter('translate')('metrics.ctr') + ' / Day', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': $filter('translate')('metrics.ctr') + ' / ad', type: 'bar', dataset: 'second' }],
                            spend: [{ 'chart': 'c1', 'name': $filter('translate')('metrics.spend') + ' / Day', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': $filter('translate')('metrics.spend') + ' / ad', type: 'bar', dataset: 'second' }],
                        },
                    },
                    age: {
                        name: 'Leeftijd',
                        view: 'age',
                        viewfilters: ['adsets', 'campaigns', 'ads'],
                        first: { level: 'account', 'endpoint': 'insights', 'breakdowns': 'age', 'dimension': 'date', 'dimension2': 'age', 'summary': 'clicks,impressions,cpc,cpm', 'allowcomp': true },
                        second: { level: 'account', 'endpoint': 'insights', 'breakdowns': 'age', 'dimension': 'age' },
                        selectedmetric: 'clicks',
                        selectedmetrics: { 'clicks': true, 'impressions': true, 'cpc': true, 'cpm': true },
                        metrics: ['clicks', 'impressions', 'cpc', 'cpm'],
                        table: { dataset: 'second' },
                        panels: { dataset: 'first' },
                        charts: {
                            clicks: [{ 'chart': 'c1', 'name': 'Klikken, leeftijd en tijd', type: 'linemulti', dataset: 'first', date: true, 'graphs': ['18-24', '25-34', '35-44', '45-54', '55-64', '65+'] }, { 'chart': 'c2', 'name': $filter('translate')('metrics.clicks') + ' / age group', type: 'bar', dataset: 'second' }],
                            impressions: [{ 'chart': 'c1', 'name': 'Impressies,leeftijd en tijd', type: 'linemulti', dataset: 'first', date: true, 'graphs': ['18-24', '25-34', '35-44', '45-54', '55-64', '65+'] }, { 'chart': 'c2', 'name': $filter('translate')('metrics.impressions') + ' / age group', type: 'bar', dataset: 'second' }],
                            cpc: [{ 'chart': 'c1', 'name': 'CPC,leeftijd en tijd', type: 'linemulti', dataset: 'first', date: true, 'graphs': ['18-24', '25-34', '35-44', '45-54', '55-64', '65+'] }, { 'chart': 'c2', 'name': $filter('translate')('metrics.cpm') + ' / age group', type: 'bar', dataset: 'second' }],
                            cpm: [{ 'chart': 'c1', 'name': 'CPM,leeftijd en tijd', type: 'linemulti', dataset: 'first', date: true, 'graphs': ['18-24', '25-34', '35-44', '45-54', '55-64', '65+'] }, { 'chart': 'c2', 'name': $filter('translate')('metrics.cpc') + ' / age group', type: 'bar', dataset: 'second' }],
                        },
                    },
                    gender: {
                        name: 'Geslacht',
                        view: 'gender',
                        viewfilters: ['adsets', 'campaigns', 'ads'],
                        first: { level: 'account', 'endpoint': 'insights', 'breakdowns': 'gender', 'dimension': 'date', 'dimension2': 'gender', 'summary': 'clicks,impressions,cpc,cpm', 'allowcomp': true },
                        second: { level: 'account', 'endpoint': 'insights', 'breakdowns': 'gender', 'dimension': 'gender' },
                        selectedmetric: 'clicks',
                        selectedmetrics: { 'clicks': true, 'impressions': true, 'cpc': true, 'cpm': true },
                        metrics: ['clicks', 'impressions', 'cpc', 'cpm'],
                        table: { dataset: 'second' },
                        panels: { dataset: 'first' },
                        charts: {
                            clicks: [{ 'chart': 'c1', 'name': 'Klikken, geslacht per dag', type: 'linemulti', dataset: 'first', date: true, 'graphs': ['male', 'female'] }, { 'chart': 'c2', 'name': $filter('translate')('metrics.clicks') + ' / Gender', type: 'bar', dataset: 'second' }],
                            impressions: [{ 'chart': 'c1', 'name': 'Impressies, geslacht per dag', type: 'linemulti', dataset: 'first', date: true, 'graphs': ['male', 'female'] }, { 'chart': 'c2', 'name': $filter('translate')('metrics.impressions') + ' / Gender', type: 'bar', dataset: 'second' }],
                            cpc: [{ 'chart': 'c1', 'name': 'CPC, geslacht per dag', type: 'linemulti', dataset: 'first', date: true, 'graphs': ['male', 'female'] }, { 'chart': 'c2', 'name': $filter('translate')('metrics.cpc') + ' / Gender', type: 'bar', dataset: 'second' }],
                            cpm: [{ 'chart': 'c1', 'name': 'CPM, geslacht per dag', type: 'linemulti', dataset: 'first', date: true, 'graphs': ['male', 'female'] }, { 'chart': 'c2', 'name': $filter('translate')('metrics.cpm') + ' / Gender', type: 'bar', dataset: 'second' }],
                        },
                    },
                },
            },
        }
        $controller('coreapi', { $scope: $scope });
        $scope.init();
    }
]);
app.controller('facebookinsights', ['$scope', '$timeout', '$http', '$rootScope', '$controller', '$filter', 'h',
    function($scope, $timeout, $http, $rootScope, $controller, $filter, h) {
        $scope.cfg = {
            authurl: 'https://app.marketingtracer.com/rest/facebookinsights/connect?websiteid=' + h.siteId(),
            dateformat: "YYYY-MM-DD",
            dimensionprefix: '',
            urlbase: 'facebookinsights',
            report_endpoint: '/rest/facebookinsights/report',
        }
            $scope.gloMetrics = h.metrics('facebookinsights');
 /*       $scope.gloMetrics = {
            fans: { name: 'Fans', typefilter: 'number', filtercomparator: 0 },
            interacties: { name: 'Interactions', typefilter: 'number', filtercomparator: 0 },
            bereik: { name: 'Bereik', typefilter: 'number', filtercomparator: 0 },
           
        };*/
        //'page_fans','page_fans_country','page_fans_by_like_source','page_fans_gender_age'
        $scope.reportconfig = {
            page: {
                views: {
                    fans: {
                        name: 'Fans',
                        view: 'fans',
                        first: { 'report': 'timeline', 'endpoint': 'insights', 'dimension': 'date' },
                        second: { 'report': 'fans', 'endpoint': 'insights', 'dimension': 'date' },
                        selectedmetric: 'fans',
                        metrics: [],
                        charts: {
                            fans: [
                                { 'chart': 'c1', 'name': 'Total fans', type: 'line', dataset: 'page_fans_total', date: true, 'dimension': 'date', 'metric': 'change' },
                                { 'chart': 'c2', 'dimension2': 'type', 'name': 'Lost and new fans', type: 'linemulti', dataset: 'page_fans_delta', date: true, 'dimension': 'date', 'metric': 'change', 'graphs': ['page_fan_removes', 'page_fans_adds_paid', 'page_fans_adds_unpaid'] },
                                { 'chart': 'c3', 'name': 'Female fans / age ', type: 'bar', dataset: 'page_fans_female_age', 'dimension': 'key', 'metric': 'val' },
                                { 'chart': 'c4', 'name': 'Male fans / age ', type: 'bar', dataset: 'page_fans_male_age', 'dimension': 'key', 'metric': 'val' },
                                { 'chart': 'c5', 'name': 'Distribution Male and Female fans', type: 'pie', dataset: 'page_fans_age', 'dimension': 'key', 'metric': 'val' },
                            ],
                        },
                    },
                    engagements: {
                        name: 'Interactie',
                        view: 'engagements',
                        first: { 'report': 'timeline', 'endpoint': 'insights', 'dimension': 'date' },
                        second: { 'report': 'engagements', 'endpoint': 'insights', 'dimension': 'date' },
                        selectedmetric: 'interacties',
                        metrics: [],
                        charts: {
                            interacties: [
                                { 'chart': 'c1', 'dimension2': 'type', 'name': 'Total interactions / day', type: 'linemulti', dataset: 'engagements', date: true, 'dimension': 'date', 'metric': 'value', 'graphs': ['engagements'] },
                                { 'chart': 'c2', 'dimension2': 'type', 'name': 'Interactions / type', type: 'linemulti', dataset: 'engagements', date: true, 'dimension': 'date', 'metric': 'value', 'graphs': ['engagements_comments', 'engagements_likes', 'engagements_links', 'engagements_others'] },
                                { 'chart': 'c3', 'name': 'Female interactions / age ', type: 'bar', dataset: 'page_content_activity_female_age', 'dimension': 'key', 'metric': 'val' },
                                { 'chart': 'c4', 'name': 'Male interactions / age ', type: 'bar', dataset: 'page_content_activity_male_age', 'dimension': 'key', 'metric': 'val' },
                                { 'chart': 'c5', 'name': 'Interactions / age ', type: 'pie', dataset: 'page_content_activity_age', 'dimension': 'key', 'metric': 'val' },
                            ],
                        },
                    },
                    reach: {
                        name: 'Bereik',
                        view: 'reach',
                        first: { 'report': 'timeline', 'endpoint': 'insights', 'dimension': 'date' },
                        second: { 'report': 'reach', 'endpoint': 'insights', 'dimension': 'date' },
                        selectedmetric: 'bereik',
                        metrics: [],
                        charts: {
                            bereik: [
                                { 'chart': 'c1', 'name': 'Total bereik', type: 'line', dataset: 'page_impressions', date: true, 'dimension': 'date', 'metric': 'change' },
                                { 'chart': 'c2', 'dimension2': 'type', 'name': 'Bereik organisch en betaald', type: 'linemulti', dataset: 'page_impressions_type', date: true, 'dimension': 'date', 'metric': 'value', 'graphs': ['page_impressions_paid', 'page_impressions_organic'] },
                                { 'chart': 'c3', 'name': 'Female reach / age ', type: 'bar', dataset: 'page_impressions_female_age', 'dimension': 'key', 'metric': 'val' },
                                { 'chart': 'c4', 'name': 'Male reach / age ', type: 'bar', dataset: 'page_impressions_male_age', 'dimension': 'key', 'metric': 'val' },
                                { 'chart': 'c5', 'name': 'Reach / gender', type: 'pie', dataset: 'page_impressions_age', 'dimension': 'key', 'metric': 'val' },
                            ],
                        },
                    },
                    posts: {
                        name: 'Posts',
                        view: 'posts',
                        first: { 'report': 'posts' },
                        selectedmetric: 'posts',
                        metrics: [],
                        charts: {
                            
                        },
                    },
                },
            },
        }
        $controller('coreapi', { $scope: $scope });
        $scope.init();
    }
]);
app.controller('instagram', ['$scope', '$timeout', '$http', '$rootScope', '$controller', '$filter', 'h',
    function($scope, $timeout, $http, $rootScope, $controller, $filter, h) {
        $scope.cfg = {
            authurl: 'https://app.pageowl.app/rest/instagram/connect?websiteid=' + h.siteId(),
            dateformat: "YYYY-MM-DD",
            dimensionprefix: '',
            urlbase: 'instagram',
            report_endpoint: '/rest/instagram/report',
        }
        $scope.gloMetrics = h.metrics('instagram');
        /*$scope.gloMetrics = {
            impressions: { name: 'Fans', typefilter: 'number', filtercomparator: 0 },
            reach: { name: 'Interactions', typefilter: 'number', filtercomparator: 0 },
            follower_count: { name: 'Bereik', typefilter: 'number', filtercomparator: 0 },
            profile_views: { name: 'Bereik', typefilter: 'number', filtercomparator: 0 },
            website_clicks: { name: 'Bereik', typefilter: 'number', filtercomparator: 0 },
            email_contacts: { name: 'Bereik', typefilter: 'number', filtercomparator: 0 },
            get_directions_clicks: { name: 'Bereik', typefilter: 'number', filtercomparator: 0 },
            phone_call_clicks: { name: 'Bereik', typefilter: 'number', filtercomparator: 0 },
            text_message_clicks: { name: 'Bereik', typefilter: 'number', filtercomparator: 0 },
        };*/
        //'page_fans','page_fans_country','page_fans_by_like_source','page_fans_gender_age'
        $scope.reportconfig = {
            page: {
                views: {
                    insights: {
                        name: 'insights',
                        view: 'insights',
                        first: { 'report': 'timeline', 'endpoint': 'insights', 'dimension': 'date' },
                        //second: { 'report': 'fans', 'endpoint': 'insights', 'dimension': 'date' },
                        selectedmetric: 'impressions',
                        metrics: ['impressions', 'reach', 'follower_count'],
                                                panels: { dataset: 'first' },
                        charts: {
                            impressions: [
                                { 'chart': 'c1', 'name': 'Follower count', type: 'line', dataset: 'follower_count', date: true, 'dimension': 'date', 'metric': 'change' },
                                { 'chart': 'c2', 'name': 'Reach', type: 'line', dataset: 'reach', date: true, 'dimension': 'date', 'metric': 'change' },
                                { 'chart': 'c3', 'name': 'Impressions', type: 'line', dataset: 'impressions', date: true, 'dimension': 'date', 'metric': 'change' },
                            ],
                        },
                    },
                    engagements: {
                        name: 'Interactie',
                        view: 'engagements',
                        first: { 'report': 'timeline', 'endpoint': 'insights', 'dimension': 'date' },
                        //second: { 'report': 'engagements', 'endpoint': 'insights', 'dimension': 'date' },
                        selectedmetric: 'profile_views',
                        metrics: ['profile_views', 'website_clicks', 'email_contacts', 'get_directions_clicks', 'phone_call_clicks', 'text_message_clicks'],
                        panels: { dataset: 'first' },
                        charts: {
                            profile_views: [
                                { 'chart': 'c1', 'name': 'Profile views', type: 'line', dataset: 'profile_views', date: true, 'dimension': 'date', 'metric': 'change' },
                                { 'chart': 'c2', 'name': 'Website clicks', type: 'line', dataset: 'website_clicks', date: true, 'dimension': 'date', 'metric': 'change' },
                                { 'chart': 'c3', 'name': 'Email contacts', type: 'line', dataset: 'email_contacts', date: true, 'dimension': 'date', 'metric': 'change' },
                            ],
                        },
                    },
                    audience: {
                        name: 'Bereik',
                        view: 'audience',
                        //first: { 'report': 'timeline', 'endpoint': 'insights', 'dimension': 'date' },
                        second: { 'report': 'audience', 'endpoint': 'insights', 'dimension': 'date' },
                        selectedmetric: 'bereik',
                        metrics: [],
                        charts: {
                            bereik: [
                                { 'chart': 'c1', 'name': 'Female audience / age ', type: 'bar', dataset: 'audience_gender_female_age', 'dimension': 'key', 'metric': 'val' },
                                { 'chart': 'c2', 'name': 'Male audience / age ', type: 'bar', dataset: 'audience_gender_male_age', 'dimension': 'key', 'metric': 'val' },
                                { 'chart': 'c3', 'name': 'Gender', type: 'pie', dataset: 'audience_gender', 'dimension': 'type', 'metric': 'val' },
                            ],
                        },
                    },
                    posts: {
                        name: 'Posts',
                        view: 'posts',
                        first: { 'report': 'posts' },
                        selectedmetric: 'posts',
                        metrics: [],
                       
                    },
                    stories: {
                        name: 'Stories',
                        view: 'stories',
                        first: { 'report': 'stories' },
                        selectedmetric: 'stories',
                        metrics: [],
                      
                    },
                },
            },
        }
        $controller('coreapi', { $scope: $scope });
        $scope.init();
    }
]);
app.controller("linkedin", [
  "$scope",
  "$timeout",
  "$http",
  "$rootScope",
  "$controller",
  "$filter",
  "h",
  function ($scope, $timeout, $http, $rootScope, $controller, $filter, h) {
    $scope.cfg = {
      authurl: "https://app.pageowl.app/rest/linkedin/connect?websiteid=" + h.siteId(),
      dateformat: "YYYY-MM-DD",
      dimensionprefix: "",
      urlbase: "linkedin",
      report_endpoint: "/rest/linkedin/report",
    };
    $scope.gloMetrics = h.metrics("linkedin");
    // Added pageViews and uniqueVisitors to global metrics
    $scope.gloMetrics["pageViews"] = { typefilter: "number", filtercomparator: 0, datemerge: "sum" };
    $scope.gloMetrics["uniqueVisitors"] = { typefilter: "number", filtercomparator: 0, datemerge: "sum" };
    //'page_fans','page_fans_country','page_fans_by_like_source','page_fans_gender_age'
    $scope.reportconfig = {
      page: {
        views: {
          interactions: {
            name: "Interactions",
            view: "interactions",
            second: { dimension: "title", report: "followerstatistics-time" },
            third: { dimension: "title", report: "sharestatistics" },
            selectedmetric: "likeCount",
            metrics: ["likeCount", "shareCount", "engagement", "clickCount", "impressionCount", "commentCount"],
            panels: { dataset: "third" },
            charts: {
              likeCount: [
                { chart: "c0", name: "Likes / days", type: "line", dataset: "third", dimension: "date" },
                { chart: "c1", name: "New followers by type", type: "pie", dataset: "newfollowerdist", dimension: "key", metric: "val" },
                { chart: "c2", metric: "abc", dimension2: "type", name: "Lost and new followers", type: "linemulti", dataset: "newfollowerdelta", date: true, dimension: "date", metric: "value", graphs: ["Organic", "Paid"] },
              ],
              shareCount: [
                { chart: "c0", name: "Shares / Day", type: "line", dataset: "third", dimension: "date" },
                { chart: "c1", name: "New followers by type", type: "pie", dataset: "newfollowerdist", dimension: "key", metric: "val" },
                { chart: "c2", dimension2: "type", name: "Lost and new followers", type: "linemulti", dataset: "newfollowerdelta", date: true, dimension: "date", metric: "value", graphs: ["Organic", "Paid"] },
              ],
              engagement: [
                { chart: "c0", name: "Engagement / day", type: "line", dataset: "third", dimension: "date" },
                { chart: "c1", name: "New followers by type", type: "pie", dataset: "newfollowerdist", dimension: "key", metric: "val" },
                { chart: "c2", dimension2: "type", name: "Lost and new followers", type: "linemulti", dataset: "newfollowerdelta", date: true, dimension: "date", metric: "value", graphs: ["Organic", "Paid"] },
              ],
              clickCount: [
                { chart: "c0", name: "Clicks / day", type: "line", dataset: "third", dimension: "date" },
                { chart: "c1", name: "New followers by type", type: "pie", dataset: "newfollowerdist", dimension: "key", metric: "val" },
                { chart: "c2", dimension2: "type", name: "Lost and new followers", type: "linemulti", dataset: "newfollowerdelta", date: true, dimension: "date", metric: "value", graphs: ["Organic", "Paid"] },
              ],
              impressionCount: [
                { chart: "c0", name: "Impressions / day", type: "line", dataset: "third", dimension: "date" },
                { chart: "c1", name: "New followers by type", type: "pie", dataset: "newfollowerdist", dimension: "key", metric: "val" },
                { chart: "c2", dimension2: "type", name: "Lost and new followers", type: "linemulti", dataset: "newfollowerdelta", date: true, dimension: "date", metric: "value", graphs: ["Organic", "Paid"] },
              ],
              commentCount: [
                { chart: "c0", name: "Comments / day", type: "line", dataset: "third", dimension: "date" },
                { chart: "c1", name: "New followers by type", type: "pie", dataset: "newfollowerdist", dimension: "key", metric: "val" },
                { chart: "c2", dimension2: "type", name: "Lost and new followers", type: "linemulti", dataset: "newfollowerdelta", date: true, dimension: "date", metric: "value", graphs: ["Organic", "Paid"] },
              ],
            },
          },
          network: {
            name: "Network",
            view: "network",
            first: { dimension: "title", report: "networksize" },
            second: { dimension: "title", report: "followerstatistics" },
            selectedmetric: "val",
            metrics: ["val"],
            table: { dataset: "region" },
            charts: {
              val: [
                { chart: "c0", name: "Followers / Staff size", type: "bar", dataset: "staffcount", dimension: "key", metric: "val" },
                { chart: "c1", name: "Followers / Role", type: "pie", dataset: "seniority", dimension: "key", metric: "val" },
                { chart: "c2", name: "Followers / Country", type: "progress", dataset: "country", dimension: "key", metric: "val" },
                { chart: "c3", name: "Folowers / Industry", type: "progress", dataset: "industry", dimension: "key", metric: "val" },
                { chart: "c4", name: "Folowers / Function", type: "progress", dataset: "function", dimension: "key", metric: "val" },
              ],
            },
          },
          // NEW VIEW ADDED FOR VISITORS
          visitors: {
            hide: true,
            name: "Visitors",
            view: "visitors",
            first: { dimension: "title", report: "visitorstatistics" },
            selectedmetric: "val",
            metrics: ["pageViews", "uniqueVisitors"],
            panels: { dataset: "first" },
            table: { dataset: "country" },
            charts: {
              val: [
                { chart: "c0", name: "Visitors / Seniority", type: "pie", dataset: "seniority", dimension: "key", metric: "val" },
                { chart: "c1", name: "Visitors / Industry", type: "bar", dataset: "industry", dimension: "key", metric: "val" },
                { chart: "c2", name: "Visitors / Staff Size", type: "progress", dataset: "staffcount", dimension: "key", metric: "val" },
              ],
            },
          },
          posts: {
            name: "Posts",
            view: "posts",
            first: { dimension: "title", report: "posts" },
            selectedmetric: "Placeholder",
            dimension: "title",
            metrics: ["open_rate", "click_rate", "emails_sent", "unsubscribed", "bounces", "total_orders", "total_revenue"],
            panels: { dataset: "stats" },
            charts: {
              Placeholder: [
                { chart: "c0", name: "Emails sent", type: "line", dataset: "timeseries", metric: "emails_sent", dimension: "date" },
                { chart: "c1", name: "Emails opened", type: "line", dataset: "timeseries", metric: "unique_opens", dimension: "date" },
                { chart: "c2", name: "Clicks", type: "line", dataset: "timeseries", metric: "recipient_clicks", dimension: "date" },
              ],
            },
          },
          personalposts: {
            hide: true,
            name: "Personal Posts",
            view: "personalposts",
            hide: true,
            first: { dimension: "title", report: "personalposts" },
            selectedmetric: "Placeholder",
            dimension: "title",
            metrics: ["open_rate", "click_rate", "emails_sent", "unsubscribed", "bounces", "total_orders", "total_revenue"],
            panels: { dataset: "stats" },
            charts: {
              Placeholder: [
                { chart: "c0", name: "Emails sent", type: "line", dataset: "timeseries", metric: "emails_sent", dimension: "date" },
                { chart: "c1", name: "Emails opened", type: "line", dataset: "timeseries", metric: "unique_opens", dimension: "date" },
                { chart: "c2", name: "Clicks", type: "line", dataset: "timeseries", metric: "recipient_clicks", dimension: "date" },
              ],
            },
          },
        },
      },
    };
    $controller("coreapi", { $scope: $scope });
    $scope.init();
  },
]);
app.controller('linkedinxads', ['$scope', '$timeout', '$http', '$rootScope', '$controller', '$filter', 'h',
    function($scope, $timeout, $http, $rootScope, $controller, $filter, h) {
        $scope.cfg = {
            authurl: 'https://app.pageowl.app/rest/linkedinxads/connect?websiteid=' + h.siteId(),
            dateformat: "YYYY-MM-DD",
            dimensionprefix: '',
            urlbase: 'linkedinxads',
            report_endpoint: '/rest/linkedinxads/report',
        }
        $scope.gloMetrics = h.metrics('linkedinxads');
/*
        $scope.gloMetrics = {
            impressions: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
            clicks: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
            oneClickLeads: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
            costInLocalCurrency: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
            externalWebsiteConversions: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
            costInLocalCurrency: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
          
            networksize: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
            networksizeexternal: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
            networksizeinternal: { typefilter: 'number', filtercomparator: 0, 'datemerge': 'sum' },
        };
*/
        //'page_fans','page_fans_country','page_fans_by_like_source','page_fans_gender_age'
        $scope.reportconfig = {
            campaigns: {
                views: {
                    all: {
                        name: 'Campagnes',
                        view: 'all',
                        first: { dimension: 'date', report: 'campaigns-time' },
                        second: { dimension: 'pivotValues', report: 'campaigns-all' },
                        selectedmetric:  'impressions' ,
                        selectedmetrics: { 'impressions': true, 'clicks': true, 'oneClickLeads': true, 'costInLocalCurrency': true, 'externalWebsiteConversions': true },
                        metrics: ['impressions', 'clicks', 'oneClickLeads','costInLocalCurrency','externalWebsiteConversions'],
                        panels: { dataset: 'second' },
                        table: { dataset: 'second' },
                        charts: {
                            impressions: [{ 'chart': 'c1', 'name': $filter('translate')('metrics.impressions')+' / Day', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': $filter('translate')('metrics.impressions')+' / Campaign', type: 'bar', dataset: 'second' }],
                            clicks: [{ 'chart': 'c1', 'name': $filter('translate')('metrics.clicks')+' / Day', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': $filter('translate')('metrics.clicks')+' / Campaign', type: 'bar', dataset: 'second' }],
                            oneClickLeads: [{ 'chart': 'c1', 'name': $filter('translate')('metrics.clicks')+' / Day', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': $filter('translate')('metrics.clicks')+' / Campaign', type: 'bar', dataset: 'second' }],
                            costInLocalCurrency: [{ 'chart': 'c1', 'name': $filter('translate')('metrics.impressions')+' / Day', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': $filter('translate')('metrics.impressions')+' / Campaign', type: 'bar', dataset: 'second' }],
                            externalWebsiteConversions: [{ 'chart': 'c1', 'name': $filter('translate')('metrics.cpc')+' / Day', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': $filter('translate')('metrics.cpc')+' / Campaign', type: 'bar', dataset: 'second' }],
                            cpm: [{ 'chart': 'c1', 'name': $filter('translate')('metrics.cpm')+' / Day', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': $filter('translate')('metrics.cpm')+' / Campaign', type: 'bar', dataset: 'second' }],
                        },
                    },
                    network: {
                        name: 'Campagnes',
                        view: 'network',
                        //first: { dimension: 'title', 'report': 'networksize' },
                        second: { dimension: 'title', 'report': 'followerstatistics' },
                        selectedmetric: 'val',
                        metrics: ['val'],
                        table: { dataset: 'region' },
                        charts: {
                            val: [
                                { 'chart': 'c0', 'name': 'Followers / Staff size', type: 'bar', dataset: 'staffcount', 'dimension': 'key', 'metric': 'val' },
                                { 'chart': 'c1', 'name': 'Followers / Role', type: 'pie', dataset: 'seniority', 'dimension': 'key', 'metric': 'val' },
                                { 'chart': 'c2', 'name': 'Followers / Country', type: 'progress', dataset: 'country', 'dimension': 'key', 'metric': 'val' },
                                { 'chart': 'c3', 'name': 'Folowers / Industry', type: 'progress', dataset: 'industry', 'dimension': 'key', 'metric': 'val' },
                                { 'chart': 'c4', 'name': 'Folowers / Function', type: 'progress', dataset: 'function', 'dimension': 'key', 'metric': 'val' },
                            ],
                           
                        },
                    },
                    posts: {
                        name: 'Campagne',
                        view: 'posts',
                        first: { dimension: 'title', 'report': 'posts', },
                        selectedmetric: 'Placeholder',
                        dimension: 'title',
                        metrics: ['open_rate', 'click_rate', 'emails_sent', 'unsubscribed', 'bounces', 'total_orders', 'total_revenue'],
                        panels: { dataset: 'stats' },
                        charts: {
                            Placeholder: [
                                { 'chart': 'c0', 'name': 'Emails sent', type: 'line', dataset: 'timeseries', metric: 'emails_sent', dimension: 'date' },
                                { 'chart': 'c1', 'name': 'Emails opened', type: 'line', dataset: 'timeseries', metric: 'unique_opens', dimension: 'date' },
                                { 'chart': 'c2', 'name': 'Clicks', type: 'line', dataset: 'timeseries', metric: 'recipient_clicks', dimension: 'date' },
                            ],
                        },
                    },                    
                    personalposts: {
                                                hide: true,
                        name: 'Campagne',
                        view: 'personalposts',
                        hide: true,
                        first: { dimension: 'title', 'report': 'personalposts', },
                        selectedmetric: 'Placeholder',
                        dimension: 'title',
                        metrics: ['open_rate', 'click_rate', 'emails_sent', 'unsubscribed', 'bounces', 'total_orders', 'total_revenue'],
                        panels: { dataset: 'stats' },
                        charts: {
                            Placeholder: [
                                { 'chart': 'c0', 'name': 'Emails sent', type: 'line', dataset: 'timeseries', metric: 'emails_sent', dimension: 'date' },
                                { 'chart': 'c1', 'name': 'Emails opened', type: 'line', dataset: 'timeseries', metric: 'unique_opens', dimension: 'date' },
                                { 'chart': 'c2', 'name': 'Clicks', type: 'line', dataset: 'timeseries', metric: 'recipient_clicks', dimension: 'date' },
                            ],
                        },
                    },
                },
            },
        }
        $controller('coreapi', { $scope: $scope });
        $scope.init();
    }
]);
app.controller('mailchimp', ['$scope', '$timeout', '$http', '$rootScope', '$controller', '$filter', 'h',
    function($scope, $timeout, $http, $rootScope, $controller, $filter, h) {
        $scope.cfg = {
            authurl: 'https://app.marketingtracer.com/rest/mailchimp/connect?websiteid=' + h.siteId(),
            dateformat: "YYYY-MM-DD",
            dimensionprefix: '',
            urlbase: 'mailchimp',
            report_endpoint: '/rest/mailchimp/report',
        }
        $scope.gloMetrics = h.metrics('mailchimp');
/*
        $scope.gloMetrics = {
            Placeholder: { name: '', typefilter: 'number', filtercomparator: 0 },
            member_count: { name: 'Aanmeldingen', typefilter: 'number', filtercomparator: 0 },
            list_rating: { name: 'Rating', typefilter: 'number', filtercomparator: 0 },
            click_rate: { name: 'Klik Ratio', typefilter: 'number', filtercomparator: 0, 'after': '%' },
            open_rate: { name: 'Open Ratio', typefilter: 'number', filtercomparator: 0, 'after': '%' },
            emails_sent: { name: 'Email verstuurd', typefilter: 'number', filtercomparator: 0 },
            send_time: { name: 'Verstuurd op', typefilter: 'mcdate', filtercomparator: 0 },
            unsubscribed: { name: 'Afmeldingen', typefilter: 'number', filtercomparator: 0 },
            unsubscribe_count: { name: 'Afmeldingen', typefilter: 'number', filtercomparator: 0 },
            cleaned_count: { name: 'Verwijderd', typefilter: 'number', filtercomparator: 0 },
            bounces: { name: 'Bounce', typefilter: 'number', filtercomparator: 0 },
            total_orders: { name: 'Orders', typefilter: 'number', filtercomparator: 0 },
            recipient_clicks: { name: 'klikken', typefilter: 'number', filtercomparator: 0 },
            total_revenue: { name: 'Totale opbrangest', typefilter: 'number', filtercomparator: 0, 'after': '€' },
        };
*/
        //'page_fans','page_fans_country','page_fans_by_like_source','page_fans_gender_age'
        $scope.reportconfig = {
            mail: {
                views: {
                    campaigns: {
                        name: 'Campagnes',
                        view: 'campaigns',
                        second: { dimension: 'title', 'report': 'campaigns' },
                        selectedmetric: 'member_count',
                        dimension: 'title',
                        metrics: ['open_rate', 'click_rate', 'emails_sent', 'send_time', 'unsubscribed', 'bounces'],
                        table: { dataset: 'second' },
                        charts: {},
                    },
                    campaign: {
                        name: 'Campagne',
                        view: 'campaign',
                        hide: true,
                        first: { dimension: 'title', 'report': 'campaign.sent_to', filterexpression: $scope.urlfilter },
                        second: { dimension: 'title', 'report': 'campaign', filterexpression: $scope.urlfilter },
                        selectedmetric: 'Placeholder',
                        dimension: 'title',
                        metrics: ['open_rate', 'click_rate', 'emails_sent', 'unsubscribed', 'bounces', 'total_orders', 'total_revenue'],
                        panels: { dataset: 'stats' },
                        charts: {
                            Placeholder: [
                                { 'chart': 'c0', 'name': 'Emails sent', type: 'line', dataset: 'timeseries', metric: 'emails_sent', dimension: 'date' },
                                { 'chart': 'c1', 'name': 'Emails opened', type: 'line', dataset: 'timeseries', metric: 'unique_opens', dimension: 'date' },
                                { 'chart': 'c2', 'name': 'Clicks', type: 'line', dataset: 'timeseries', metric: 'recipient_clicks', dimension: 'date' },
                            ],
                        },
                    },
                    lists: {
                        name: 'Lijsten',
                        view: 'lists',
                        second: { dimension: 'name', 'report': 'lists' },
                        selectedmetric: 'member_count',
                        dimension: 'name',
                        metrics: ['member_count', 'click_rate', 'open_rate', 'list_rating'],
                        table: { dataset: 'second' },
                        charts: {},
                    },
                    list: {
                        name: 'List',
                        view: 'list',
                        hide: true,
                        first: { dimension: 'title', 'report': 'list', filterexpression: $scope.urlfilter },
                        second: { dimension: 'title', 'report': 'list.activity', filterexpression: $scope.urlfilter },
                        third: { dimension: 'title', 'report': 'list.members', filterexpression: $scope.urlfilter },
                        selectedmetric: 'Placeholder',
                        dimension: 'title',
                        metrics: ['open_rate', 'click_rate', 'member_count', 'unsubscribe_count', 'cleaned_count'],
                        panels: { dataset: 'first' },
                        charts: {
                            Placeholder: [
                                { 'chart': 'c0', 'name': 'Emails sent', type: 'line', dataset: 'second', metric: 'emails_sent', dimension: 'date' },
                                { 'chart': 'c1', 'name': 'Emails opened', type: 'line', dataset: 'second', metric: 'unique_opens', dimension: 'date' },
                                { 'chart': 'c2', 'name': 'Clicks', type: 'line', dataset: 'second', metric: 'recipient_clicks', dimension: 'date' },
                            ],
                        },
                    },
                },
            },
        }
        $controller('coreapi', { $scope: $scope });
        $scope.init();
    }
]);
app.controller('mybusiness', ['$scope', '$timeout', '$http', '$rootScope', '$controller', '$filter', 'h',
    function($scope, $timeout, $http, $rootScope, $controller, $filter, h) {
         $scope.cfg = {
            authurl: 'https://app.marketingtracer.com/rest/mybusiness/connect?websiteid=' + h.siteId(),
            dateformat: "YYYY-MM-DD",
            dimensionprefix: '',
            urlbase: 'mybusiness',
            report_endpoint: '/rest/mybusiness/report',
        }
        $scope.gloMetrics = h.metrics('mybusiness');
        
    /*    $scope.gloMetrics = {
            Placeholder: { name: '', typefilter: 'number', filtercomparator: 0 },
            QUERIES_DIRECT: { name: 'Directe zoekopdrachten', typefilter: 'number', filtercomparator: 0 },
            QUERIES_INDIRECT: { name: 'Indirecte zoekopdrachten', typefilter: 'number', filtercomparator: 0 },
            VIEWS_MAPS: { name: 'Google maps', typefilter: 'number', filtercomparator: 0 },
            VIEWS_SEARCH: { name: 'Google zoeken', typefilter: 'number', filtercomparator: 0 },
            QUERIES_DIRECT: { name: 'Bedrijf zoekopdacht', typefilter: 'number', filtercomparator: 0 },
            QUERIES_INDIRECT: { name: 'Categorie zoekopdracht', typefilter: 'number', filtercomparator: 0 },
            PHOTOS_VIEWS_MERCHANT: { name: 'Van eigenaars', typefilter: 'number', filtercomparator: 0 },
            PHOTOS_VIEWS_CUSTOMERS: { name: 'Van bezoekers', typefilter: 'number', filtercomparator: 0 },
            PHOTOS_COUNT_MERCHANT: { name: 'Van eigenaar', typefilter: 'number', filtercomparator: 0 },
            PHOTOS_COUNT_CUSTOMERS: { name: 'Van bezoekers', typefilter: 'number', filtercomparator: 0 },
            Date: { name: 'Datum', typefilter: 'number', filtercomparator: 0 },
            AverageCpc: { name: 'Gemiddelde kosten per klik', typefilter: 'number', filtercomparator: 2, 'before': '€' },
            Ctr: { name: 'Ctr', typefilter: 'number', filtercomparator: 0, 'after': '%' },
            Conversions: { name: 'Conversions', typefilter: 'number', filtercomparator: 0 },
            Cost: { name: 'Cost', typefilter: 'number', filtercomparator: 0, 'before': '€' },
            CostPerConversion: { name: 'Kosten per conversie', typefilter: 'number', filtercomparator: 0, 'before': '€' },
            ConversionRate: { name: 'Conversie ratio', typefilter: 'number', filtercomparator: 0, 'after': '%' },
            AveragePosition: { name: 'Gemiddelde positie', typefilter: 'number', filtercomparator: 1 },
            ConversionValue: { name: 'Totale conversiewaarde', typefilter: 'number', filtercomparator: 0, 'before': '€' },
        };
*/
        $scope.fnFormatAd = function(d) {
            return d.HeadlinePart1 + d.HeadlinePart2 + d.Description + d.CreativeDestinationUrl + d.CreativeFinalUrls;
        }
        $scope.reportconfig = {
            business: {
                views: {
                    all: {
                        name: 'Overzicht',
                        view: 'all',
                        first: { report: 'total' },
                        second: { report: 'daily' },
                        selectedmetric: 'Placeholder',
                        metrics: [],
                        table: { dataset: 'second' },
                        panels: { dataset: 'second' },
                        charts: {
                            Placeholder: [
                                { 'chart': 'c1', 'name': 'Search type', type: 'bar', dataset: 'queries', 'dimension': 'type', 'metric': 'queries' },
                                { 'chart': 'c2', 'name': 'Searches / day', type: 'pie', type: 'line', dataset: 'second', metric: 'QUERIES', dimension: 'date' },
                                { 'chart': 'c3', 'name': 'Impressions / type', type: 'bar', dataset: 'views', 'dimension': 'type', 'metric': 'views' },
                                { 'chart': 'c4', 'name': 'Impressions / day', type: 'pie', type: 'line', dataset: 'second', metric: 'VIEWS', dimension: 'date' },
                                { 'chart': 'c5', 'name': 'Available Photo\'s', type: 'pie', dataset: 'photocount', 'dimension': 'type', 'metric': 'photocount' },
                                { 'chart': 'c6', 'name': 'Photo Impressions', type: 'pie', dataset: 'photoview', 'dimension': 'type', 'metric': 'photoview' },
                                { 'chart': 'c7', 'name': 'Website clicks', type: 'pie', type: 'line', dataset: 'second', metric: 'ACTIONS_WEBSITE', dimension: 'date' },
                                { 'chart': 'c8', 'name': 'Phone contact', type: 'pie', type: 'line', dataset: 'second', metric: 'ACTIONS_PHONE', dimension: 'date' },
                                { 'chart': 'c9', 'name': 'Driving Directions', type: 'pie', type: 'line', dataset: 'second', metric: 'ACTIONS_DRIVING_DIRECTIONS', dimension: 'date' },
                            ],
                        },
                    },
                    reviews: {
                        name: 'Reviews',
                        view: 'reviews',
                        first: { report: 'reviews' },
                        selectedmetric: 'Placeholder',
                        metrics: [],
                        table: { dataset: 'second' },
                        panels: { dataset: 'second' },
                        charts: {
                            Placeholder: [
                                { 'chart': 'c1', 'name': 'Search type', type: 'bar', dataset: 'queries', 'dimension': 'type', 'metric': 'queries' },
                                { 'chart': 'c2', 'name': 'Zoekopdrachten / day', type: 'pie', type: 'line', dataset: 'second', metric: 'QUERIES', dimension: 'date' },
                                { 'chart': 'c3', 'name': 'Impressions / type', type: 'bar', dataset: 'views', 'dimension': 'type', 'metric': 'views' },
                                { 'chart': 'c4', 'name': 'Impressions / day', type: 'pie', type: 'line', dataset: 'second', metric: 'VIEWS', dimension: 'date' },
                                { 'chart': 'c5', 'name': 'Photo\'s', type: 'pie', dataset: 'photocount', 'dimension': 'type', 'metric': 'photocount' },
                                { 'chart': 'c6', 'name': 'Photo Impressions', type: 'pie', dataset: 'photoview', 'dimension': 'type', 'metric': 'photoview' },
                                { 'chart': 'c7', 'name': 'Website clicks', type: 'pie', type: 'line', dataset: 'second', metric: 'ACTIONS_WEBSITE', dimension: 'date' },
                                { 'chart': 'c8', 'name': 'Phone contact', type: 'pie', type: 'line', dataset: 'second', metric: 'ACTIONS_PHONE', dimension: 'date' },
                                { 'chart': 'c9', 'name': 'Driving Directions', type: 'pie', type: 'line', dataset: 'second', metric: 'ACTIONS_DRIVING_DIRECTIONS', dimension: 'date' },
                            ],
                        },
                    },
                },
            }
        }
        $controller('coreapi', { $scope: $scope });
        $scope.init();
    }
]);
/*
The current navigation is too literal. It names the data dimension, not the insight. We'll change it to be benefit-driven.
Current Text	Proposed Change	Why It's Better
Keywords	Keyword Opportunities	Focuses on the goal: finding new keyword targets.
Pages	Top Content	Highlights that these are the most important pages.
Country	Geographic Performance	Sounds more professional and comprehensive.
Device	Device Analytics	Aligns with industry-standard terminology.
Clusters	Topic Intelligence	Elevates the feature from a simple grouping to a strategic insight. This is the key change.
Gaps & Gains	Gaps & Gains	Clearly communicates finding new opportunities and plugging leaks.
*/
app.controller("hub", [
  "$scope",
  "$timeout",
  "$http",
  "$rootScope",
  "$controller",
  "$filter",
  "h",
  function ($scope, $timeout, $http, $rootScope, $controller, $filter, h) {
    $scope.cfg = {
      authurl: "https://app.marketingtracer.com/rest/searchconsole/connect?websiteid=" + h.siteId(),
      dateformat: "YYYY-MM-DD",
      dimensionprefix: "",
      urlbase: "hub",
      report_endpoint: "/rest/hub/report",
    };
    if ($rootScope.user.reseller?.config?.authdomain) {
      $scope.cfg.authurl = "https://" + $rootScope.user.reseller.config.authdomain + "/rest/searchconsole/connect?websiteid=" + h.siteId();
    }
    $scope.search = {
      updateFilter: function (query) {
        $scope.search.query = query;
      },
      query: "",
    };
    $scope.gloMetrics = {
      ...h.metrics("searchconsole"),
      ...h.metrics("analytics4"),
    };
    $scope.limit = 100;
    $scope.clusterProgress = 0;
    $scope.topicMode = "smart";
    $scope.clusterValue = { key: "none", hasValue: false };
    $scope.customTopic = {
      displayName: "",
      example_keywords: ["", "", ""],
      boost_terms: ["", ""],
    };
    $scope.customTopicSubmitting = false;
    $scope.customTopicMessages = {};
    $scope.setTopicMode = function (mode) {
      $scope.topicMode = mode;
    };
    $scope.resetCustomTopicForm = function (form) {
      $scope.customTopic = {
        displayName: "",
        example_keywords: ["", "", ""],
        boost_terms: ["", ""],
      };
      if (form) {
        form.$setPristine();
        form.$setUntouched();
      }
    };
    $scope.submitCustomTopic = function (form) {
      if (form && form.$invalid) {
        form.$setSubmitted();
        return;
      }
      var payload = {
        display_name: ($scope.customTopic.displayName || "").trim(),
        example_keywords: $scope.customTopic.example_keywords
          .map(function (keyword) {
            return (keyword || "").trim();
          })
          .filter(function (keyword) {
            return keyword.length > 0;
          }),
        boost_terms: $scope.customTopic.boost_terms
          .map(function (term) {
            return (term || "").trim();
          })
          .filter(function (term) {
            return term.length > 0;
          }),
      };
      if (!payload.display_name || payload.example_keywords.length < 3) {
        $scope.customTopicMessages = {
          error: "Provide a display name and at least three example keywords.",
        };
        if (form) {
          form.$setSubmitted();
        }
        return;
      }
      // If editing, add the cluster ID to the payload
      if ($scope.customTopic.customClusterId) {
        payload.custom_cluster_id = $scope.customTopic.customClusterId;
      }
      $scope.customTopicSubmitting = true;
      $scope.customTopicMessages = {};
      var endpoint = $scope.customTopic.customClusterId ? "/rest/searchconsole/cluster_custom_edit?websiteid=" + h.siteId() : "/rest/searchconsole/cluster_custom_add?websiteid=" + h.siteId();
      $http
        .post(endpoint, payload)
        .then(function (response) {
          $scope.customTopicMessages = {
            success: $scope.customTopic.customClusterId ? "Custom topic edited successfully." : "Custom topic saved successfully.",
          };
          $scope.resetCustomTopicForm(form);
          if (angular.isFunction($scope.getReportData)) {
            $scope.getReportData();
          }
        })
        .catch(function (error) {
          var message = error && error.data && error.data.message ? error.data.message : "Unable to save custom topic at this time.";
          $scope.customTopicMessages = {
            error: message,
          };
        })
        .finally(function () {
          $scope.customTopicSubmitting = false;
        });
    };
    $scope.fnEditCustomCluster = function (cluster) {
      // Load the cluster data into the form for editing
      if (cluster.example_keywords && Array.isArray(cluster.example_keywords)) {
        // Extract keyword strings from objects if they have keyword property
        var keywordStrings = cluster.example_keywords
          .map(function (kw) {
            return typeof kw === "object" && kw.keyword ? kw.keyword : typeof kw === "string" ? kw : "";
          });
        // Ensure at least 3 keywords (pad with empty strings if needed)
        while (keywordStrings.length < 3) {
          keywordStrings.push("");
        }
        $scope.customTopic.example_keywords = keywordStrings;
      }
      
      // Load boost terms if they exist
      if (cluster.boost_terms && Array.isArray(cluster.boost_terms)) {
        var boostTermStrings = cluster.boost_terms
          .map(function (bt) {
            return typeof bt === "object" && bt.term ? bt.term : typeof bt === "string" ? bt : "";
          });
        // Ensure at least 2 slots (pad with empty strings if needed)
        while (boostTermStrings.length < 2) {
          boostTermStrings.push("");
        }
        $scope.customTopic.boost_terms = boostTermStrings;
      } else {
        $scope.customTopic.boost_terms = ["", ""];
      }
      
      $scope.customTopic.displayName = cluster.cluster_name;
      $scope.customTopic.customClusterId = cluster.custom_cluster_id;
      // Scroll to form
      document.querySelector('[name="customTopicForm"]').scrollIntoView({ behavior: "smooth" });
    };
    $scope.fnAddKeywordField = function () {
      if (!$scope.customTopic.example_keywords) {
        $scope.customTopic.example_keywords = ["", "", ""];
      }
      $scope.customTopic.example_keywords.push("");
    };
    $scope.fnAddBoostTermField = function () {
      if (!$scope.customTopic.boost_terms) {
        $scope.customTopic.boost_terms = ["", "", ""];
      }
      $scope.customTopic.boost_terms.push("");
    };
    $scope.fnRemoveBoostTerm = function (index) {
      if ($scope.customTopic.boost_terms && index > 1 && index < $scope.customTopic.boost_terms.length) {
        $scope.customTopic.boost_terms.splice(index, 1);
      }
    };
    $scope.fnRemoveKeyword = function (index) {
      if ($scope.customTopic.example_keywords && index > 2 && index < $scope.customTopic.example_keywords.length) {
        $scope.customTopic.example_keywords.splice(index, 1);
      }
    };
    $scope.range = function (start, end) {
      var result = [];
      for (var i = start; i < end; i++) {
        result.push(i);
      }
      return result;
    };
    $scope.fnDeleteCustomCluster = function (cluster) {
      if (!confirm("Are you sure you want to delete this custom topic cluster? This action cannot be undone.")) {
        return;
      }
      $http
        .post("/rest/searchconsole/cluster_custom_remove?websiteid=" + h.siteId(), {
          custom_cluster_id: cluster.custom_cluster_id,
        })
        .then(function (response) {
          console.log("Cluster deleted successfully");
          if (angular.isFunction($scope.getReportData)) {
            $scope.getReportData();
          }
        })
        .catch(function (error) {
          var message = error && error.data && error.data.message ? error.data.message : "Unable to delete custom topic at this time.";
          alert("Error: " + message);
        });
    };
    $scope.fnMoveKeywordToCluster = function (keyword, targetCluster) {
      $http
        .post("/rest/searchconsole/cluster_custom_move_keyword?websiteid=" + h.siteId(), {
          keyword: keyword.query,
          from_cluster_id: $scope.currentCluster.custom_cluster_id,
          to_cluster_id: targetCluster.custom_cluster_id,
        })
        .then(function (response) {
          console.log("Keyword moved successfully");
          $scope.keywordMoveDropdown = null;
          if (angular.isFunction($scope.getReportData)) {
            $scope.getReportData();
          }
        })
        .catch(function (error) {
          var message = error && error.data && error.data.message ? error.data.message : "Unable to move keyword at this time.";
          alert("Error: " + message);
        });
    };
    $scope.topLandingPages = [];
    $scope.keywordDetailState = {};
    $scope.checkAccessToken = function (data) {
      if (data.action == "connect") {
        $scope.modaloverride = true;
        $scope.showConnectNudge = true;
      }
      $scope.cfg.urlbase = "searchconsole";
    };
    $scope.getClusterPendingState = function (data) {
      console.log("Cluster status check:", data);
      if (data?.data?.status && data?.data?.status !== "completed") {
        $scope.startClusterPolling();
      }
      // if($scope.clusterValueKey === "none") {
      //   $scope.hasRevenueContribution = false;
      // }
      // check if we have custom clusters
      var hasCustomClusters = data?.data?.custom_cluster_metrics && data.data.custom_cluster_metrics.length > 0;
      if (hasCustomClusters) {
        $scope.topicMode = "custom";
      }
      __getRevenueInfo(data);
    };
    $scope.getFilteredCluster = function (data) {
      console.log("Filtering cluster data:", data);
      if ($scope.urlfilter && data?.data?.cluster_metrics) {
        console.log("here");
        // ic cluster starts with custom
        if ($scope.urlfilter.startsWith("custom_")) {
          $scope.currentCluster = data.data.custom_cluster_metrics.filter((c) => c.cluster_id == $scope.urlfilter)?.[0];
          $scope.currentKeywords = data.data.keywords?.filter((k) => k.custom_cluster_id == $scope.urlfilter) || [];
        } else {
          $scope.currentCluster = data.data.cluster_metrics.filter((c) => c.cluster_id == $scope.urlfilter)?.[0];
          $scope.currentKeywords = data.data.keywords?.filter((k) => k.cluster_id == $scope.urlfilter) || [];
        }
        $scope.topLandingPages = $scope.buildTopLandingPages($scope.currentKeywords);
        $scope.keywordDetailState = {};
      }
      __getRevenueInfo(data);
    };
    var __getRevenueInfo = function (data) {
      // check if we have a Revenue Contribution anywhere?
      var hasRevenueContribution = false;
      if (data?.data?.cluster_metrics) {
        //hasRevenueContribution = data.data.cluster_metrics.some((metric) => metric.estimated_value_percent !== undefined && metric.estimated_value_percent > 0);
      }
      $scope.clusterValue.key = data?.data?.clusterValueKey ? data.data.clusterValueKey : "none";
      // Map the selected cluster value key to the appropriate metric fields
      var valueFieldMap = {
        "ecommerce-value": { value: "estimated_ecommerce_value", percent: "estimated_ecommerce_value_percent" },
        "goal-value": { value: "estimated_goal_value", percent: "estimated_goal_value_percent" },
        "goal-number": { value: "estimated_goal_number", percent: "estimated_goal_number_percent" },
        none: { value: null, percent: null },
      };
      $scope.selectedValueFields = valueFieldMap[$scope.clusterValue.key] || valueFieldMap["none"];
      // re-check hasRevenueContribution based on selected cluster value key
     // hasRevenueContribution = data.data.cluster_metrics.some((metric) => metric[$scope.selectedValueFields.value] !== undefined && metric[$scope.selectedValueFields.value] > 0);
      $scope.clusterValue.hasValue = hasRevenueContribution;
      /* OVERRIDE FOR NOW */
      $scope.clusterValue.hasValue = false;
      console.log("Selected cluster value key:", $scope.clusterValue.key);
      console.log("Selected value fields:", $scope.selectedValueFields);
      if(data.data?.custom_cluster_metrics_needsrefresh == true){
        $scope.clusterNeedsRefresh = true
      } else {
        $scope.clusterNeedsRefresh = false
      }
    };
    $scope.buildTopLandingPages = function (keywords) {
      if (!angular.isArray(keywords) || !keywords.length) {
        return [];
      }
      var aggregated = {};
      angular.forEach(keywords, function (keyword) {
        if (!keyword || !angular.isArray(keyword.urls)) {
          return;
        }
        angular.forEach(keyword.urls, function (urlInfo) {
          if (!urlInfo || !urlInfo.url) {
            return;
          }
          var key = urlInfo.url;
          if (!aggregated[key]) {
            aggregated[key] = {
              url: urlInfo.url,
              clicks: 0,
              estimatedValue: 0,
              keywords: [],
            };
          }
          aggregated[key].clicks += urlInfo.clicks || 0;
          aggregated[key].estimatedValue += urlInfo.estimatedValue || 0;
          if (keyword.query && aggregated[key].keywords.indexOf(keyword.query) === -1) {
            aggregated[key].keywords.push(keyword.query);
          }
        });
      });
      var rows = [];
      angular.forEach(aggregated, function (item) {
        rows.push({
          url: item.url,
          clicks: item.clicks,
          estimatedValue: item.estimatedValue,
          keywordCount: item.keywords.length,
          topKeyword: item.keywords[0] || "",
        });
      });
      rows.sort(function (a, b) {
        return (b.estimatedValue || 0) - (a.estimatedValue || 0);
      });
      return rows.slice(0, 20);
    };
    $scope.fnToggleKeywordDetails = function (keyword, $event) {
      if ($event) {
        $event.stopPropagation();
      }
      if (!keyword) {
        return;
      }
      var key = keyword.query || keyword._id || keyword.keyword_id;
      if (!key) {
        return;
      }
      $scope.keywordDetailState[key] = !$scope.keywordDetailState[key];
    };
    $scope.fnKeywordIsOpen = function (keyword) {
      if (!keyword) {
        return false;
      }
      var key = keyword.query || keyword._id || keyword.keyword_id;
      if (!key) {
        return false;
      }
      return !!$scope.keywordDetailState[key];
    };
    $scope.setAnalyticsConfig = function (data) {
      $scope.cfg.dateformat = "YYYYMMDD";
    };
    $scope.reportconfig = {
      v1: {
        views: {
          searchperformance: {
            name: "New, Lost and Opprotunities",
            view: "searchperformance",
            fullchart: true,
            /*timeline fallback */
            first: { dimension: "date", context: "searchconsole", report: "searchAnalytics", start: "1YEARAGO", callback: $scope.checkAccessToken, compare: "PERIOD" },
            /*  clusters */
            second: { dimension: "query", context: "searchconsole", report: "clusters", start: "60DAYSAGO", end: "TODAY", limit: $scope.limit, callback: $scope.getClusterPendingState },
            /* panels */
            third: { dimension: "date", context: "searchconsole", report: "searchAnalytics", compare: "PERIOD" },
            /* branded timeline */
            fourth: { dimension: "date", context: "searchconsole", report: "clusters_branded_timeline", dimension2: "label" },
            selectedmetric: "clicks",
            metrics: ["position", "clicks", "ctr", "impressions"],
            hide: false,
            panels: { dataset: "third" },
            selectedmetrics: { clicks: true, ctr: true, position: true, impressions: true },
            charts: {
              clicks: [
                { chart: "c1", name: "Clicks", type: "line", dataset: "first", date: true, stacked: true, active: true },
                { chart: "c2", name: "Branded vs Non Branded Clicks", type: "linemulti", dataset: "fourth", date: true, stacked: true, graphs: ["branded", "non_branded"] },
                { chart: "c3", name: "Click Intentions", type: "linemulti", dataset: "fourth", date: true, stacked: true, graphs: ["informational", "navigational", "transactional", "commercial"] },
              ],
              ctr: [
                { chart: "c1", name: "Ctr", type: "line", dataset: "first", date: true, active: true },
                { chart: "c2", name: "Branded vs Non Branded Ctr", type: "linemulti", dataset: "fourth", date: true, graphs: ["branded", "non_branded"] },
                { chart: "c3", name: "Ctr Intentions", type: "linemulti", dataset: "fourth", date: true, graphs: ["informational", "navigational", "transactional", "commercial"] },
              ],
              position: [
                { chart: "c1", name: "Position", type: "line", dataset: "first", date: true, active: true },
                { chart: "c2", name: "Branded vs Non Branded Position", type: "linemulti", dataset: "fourth", date: true, graphs: ["branded", "non_branded"] },
                { chart: "c3", name: "Position Intentions", type: "linemulti", dataset: "fourth", date: true, graphs: ["informational", "navigational", "transactional", "commercial"] },
              ],
              impressions: [
                { chart: "c1", name: "Impressions", type: "line", dataset: "first", date: true, active: true },
                { chart: "c2", name: "Branded vs Non Branded Impressions", type: "linemulti", dataset: "fourth", date: true, graphs: ["branded", "non_branded"] },
                { chart: "c3", name: "Impressions Intentions", type: "linemulti", dataset: "fourth", date: true, graphs: ["informational", "navigational", "transactional", "commercial"] },
              ],
            },
          },
          clusterperformance: {
            name: $scope.urlfilter,
            hide: true,
            view: "clusterperformance",
            first: { dimension: "date", context: "searchconsole", report: "searchAnalytics" },
            second: { dimension: "query", context: "searchconsole", report: "clusters", start: "60DAYSAGO", end: "TODAY", limit: $scope.limit, callback: $scope.getFilteredCluster },
            selectedmetric: "clicks",
            selectedmetrics: { clicks: true, ctr: true, position: true, impressions: true },
            metrics: ["position", "clicks", "ctr", "impressions"],
            //   charts: {
            //                         clicks: [{ 'chart': 'c1', 'name': 'Clicks', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Clicks per keyword', type: 'progress', dataset: 'third' }],
            //                         ctr: [{ 'chart': 'c1', 'name': 'Ctr', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Ctr per keyword', type: 'progress', dataset: 'third' }],
            //                         position: [{ 'chart': 'c1', 'name': 'Position', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Position per keyword', type: 'progress', dataset: 'third' }],
            //                         impressions: [{ 'chart': 'c1', 'name': 'Impressions', type: 'line', dataset: 'first', date: true }, { 'chart': 'c2', 'name': 'Impressions per keyword', type: 'progress', dataset: 'third' }],
            //                     },
          },
          searchengines: {
            name: "searchengines",
            view: "searchengines",
            hide: true,
            viewfilters: ["goals"],
            first: { context: "analytics", dimension: "date", dimension2: "sessionSource", channel: "Organic Search", callback: $scope.setAnalyticsConfig },
            second: { context: "analytics", dimension: "sessionSource", sort: "sessions", sortorder: "DESCENDING", allowcomp: true, channel: "Organic Search", callback: $scope.setAnalyticsConfig },
            selectedmetric: "sessions",
            selectedmetrics: { sessions: true, totalUsers: true, screenPageViews: true, screenPageViewsPerSession: true, averageSessionDuration: true, newUsers: true, bounceRate: true, bounceRate: true, eventCount: true, eventCountPerUser: true },
            metrics: ["sessions", "totalUsers", "screenPageViews", "screenPageViewsPerSession", "averageSessionDuration", "newUsers", "bounceRate", "eventCount", "eventCountPerUser"],
            table: { dataset: "second" },
            panels: { dataset: "second" },
            charts: {
              sessions: [
                { chart: "c1", name: "Sessions", type: "linemulti", dataset: "first", date: true },
                { chart: "c2", name: "Sessions / channel", type: "pie", dataset: "second" },
              ],
              totalUsers: [
                { chart: "c1", name: "Users", type: "linemulti", dataset: "first", date: true },
                { chart: "c2", name: "Users / channel", type: "pie", dataset: "second" },
              ],
              screenPageViews: [
                { chart: "c1", name: "Pagina weergaven", type: "linemulti", dataset: "first", date: true },
                { chart: "c2", name: "screenPageViews / channel", type: "pie", dataset: "second" },
              ],
              screenPageViewsPerSession: [
                { chart: "c1", name: "Pageviews per session", type: "linemulti", dataset: "first", date: true },
                { chart: "c2", name: "screenPageViewsPerSession per session /channel", type: "bar", dataset: "second" },
              ],
              averageSessionDuration: [
                { chart: "c1", name: "Average session duration", type: "linemulti", dataset: "first", date: true },
                { chart: "c2", name: "_", type: "bar", dataset: "second" },
              ],
              newUsers: [
                { chart: "c1", name: "Percentage new Sessions", type: "linemulti", dataset: "first", date: true },
                { chart: "c2", name: "_", type: "bar", dataset: "second" },
              ],
              bounceRate: [
                { chart: "c1", name: "Bounce ratio", type: "linemulti", dataset: "first", date: true },
                { chart: "c2", name: "_", type: "bar", dataset: "second" },
              ],
              eventCount: [
                { chart: "c1", name: "Goals", type: "linemulti", dataset: "first", date: true },
                { chart: "c2", name: "_", type: "pie", dataset: "second" },
              ],
              eventCountPerUser: [
                { chart: "c1", name: "Goalvalue", type: "linemulti", dataset: "first", date: true },
                { chart: "c2", name: "_", type: "pie", dataset: "second" },
              ],
            },
          },
          llmtraffic: {
            name: "llmtraffic",
            view: "llmtraffic",
            hide: true,
            viewfilters: ["goals"],
            first: { context: "analytics", dimension: "date", dimension2: "sessionSource", channel: "custom_llm", callback: $scope.setAnalyticsConfig },
            second: { context: "analytics", dimension: "sessionSource", sort: "sessions", sortorder: "DESCENDING", allowcomp: true, channel: "custom_llm", callback: $scope.setAnalyticsConfig },
            selectedmetric: "sessions",
            selectedmetrics: { sessions: true, totalUsers: true, screenPageViews: true, screenPageViewsPerSession: true, averageSessionDuration: true, newUsers: true, bounceRate: true, bounceRate: true, eventCount: true, eventCountPerUser: true },
            metrics: ["sessions", "totalUsers", "screenPageViews", "screenPageViewsPerSession", "averageSessionDuration", "newUsers", "bounceRate", "eventCount", "eventCountPerUser"],
            table: { dataset: "second" },
            panels: { dataset: "second" },
            charts: {
              sessions: [
                { chart: "c1", name: "Sessions", type: "linemulti", stacked: true, dataset: "first", date: true },
                { chart: "c2", name: "Sessions / channel", type: "pie", dataset: "second" },
              ],
              totalUsers: [
                { chart: "c1", name: "Users", type: "linemulti", stacked: true, dataset: "first", date: true },
                { chart: "c2", name: "Users / channel", type: "pie", dataset: "second" },
              ],
              screenPageViews: [
                { chart: "c1", name: "Pagina weergaven", type: "linemulti", stacked: true, dataset: "first", date: true },
                { chart: "c2", name: "screenPageViews / channel", type: "pie", dataset: "second" },
              ],
              screenPageViewsPerSession: [
                { chart: "c1", name: "Pageviews per session", type: "linemulti", stacked: true, dataset: "first", date: true },
                { chart: "c2", name: "screenPageViewsPerSession per session /channel", type: "bar", dataset: "second" },
              ],
              averageSessionDuration: [
                { chart: "c1", name: "Average session duration", type: "linemulti", stacked: true, dataset: "first", date: true },
                { chart: "c2", name: "_", type: "bar", dataset: "second" },
              ],
              newUsers: [
                { chart: "c1", name: "Percentage new Sessions", type: "linemulti", stacked: true, dataset: "first", date: true },
                { chart: "c2", name: "_", type: "bar", dataset: "second" },
              ],
              bounceRate: [
                { chart: "c1", name: "Bounce ratio", type: "linemulti", stacked: true, dataset: "first", date: true },
                { chart: "c2", name: "_", type: "bar", dataset: "second" },
              ],
              eventCount: [
                { chart: "c1", name: "Goals", type: "linemulti", stacked: true, dataset: "first", date: true },
                { chart: "c2", name: "_", type: "pie", dataset: "second" },
              ],
              eventCountPerUser: [
                { chart: "c1", name: "Goalvalue", type: "linemulti", stacked: true, dataset: "first", date: true },
                { chart: "c2", name: "_", type: "pie", dataset: "second" },
              ],
            },
          },
          info_and_roadmap: {
            name: "info_and_roadmap",
            view: "info_and_roadmap",
            hide: false,
            viewfilters: ["goals"],
            selectedmetrics: { sessions: true, totalUsers: true, screenPageViews: true, screenPageViewsPerSession: true, averageSessionDuration: true, newUsers: true, bounceRate: true, bounceRate: true, eventCount: true, eventCountPerUser: true },
            metrics: ["sessions", "totalUsers", "screenPageViews", "screenPageViewsPerSession", "averageSessionDuration", "newUsers", "bounceRate", "eventCount", "eventCountPerUser"],
          },
        },
      },
    };
    $scope.fnSetLimit = function (limit) {
      $scope.view.first.limit = limit;
      $scope.getReportData();
    };
    /* CLustering */
    $scope.fnStartClustering = function () {
      $scope.analytics.second = { action: "pending", data: { status: "pending" } };
      $http.get("/rest/searchconsole/cluster_create?websiteid=" + h.siteId()).then(function (response) {
        $scope.getReportData();
      });
    };
    $scope.fnStartCustomClustering = function () {
      $scope.clusterNeedsRefresh = false;
      $scope.analytics.second = { action: "pending", data: { status: "pending" } };
      $http.get("/rest/searchconsole/cluster_create_custom?websiteid=" + h.siteId()).then(function (response) {
        // refresh after 5 seconds to allow backend to start processing
        $timeout(function () {
          $scope.getReportData();
        }, 5000);
      });
    };
    $scope.fnUpdateClusterOptions = function () {
      console.log("About to update cluster options");
      console.log("$scope.clusterValue:", $scope.clusterValue);
      console.log("Full $scope:", $scope);
      $http
        .post("/rest/searchconsole/cluster_update_options", {
          websiteid: h.siteId(),
          clusterValueKey: $scope.clusterValue.key,
        })
        .then(function (response) {
          console.log("Cluster options updated:", response);
          // Optionally refresh data or show success message
          $scope.getReportData();
        });
    };
    // Poll cluster status every 10 seconds when action is pending
    $scope.startClusterPolling = function () {
      // Prevent multiple polling intervals
      if ($scope.clusterPollingInterval) {
        $timeout.cancel($scope.clusterPollingInterval);
      }
      console.log("Cluster polling started.");
      var poll = function () {
        $http
          .get("/rest/searchconsole/cluster_get_names?websiteid=" + h.siteId())
          .then(function (response) {
            if (response.data && response.data.data) {
              var status = response.data.data.status;
              // Ensure analytics.second and its data object exist
              $scope.analytics.second = $scope.analytics.second || {};
              $scope.analytics.second.data = $scope.analytics.second.data || {};
              // Update data on scope
              $scope.analytics.second.data.cluster_metrics = response.data.data.cluster_metrics;
              $scope.analytics.second.data.status = status;
              // Update progress: increment by 5 until 80%, then by 1, capped at 99
              if ($scope.clusterProgress < 80) {
                $scope.clusterProgress = Math.min($scope.clusterProgress + 5, 80);
              } else if ($scope.clusterProgress < 99) {
                $scope.clusterProgress = Math.min($scope.clusterProgress + 1, 99);
              }
              // If status is no longer clustering or pending, stop polling
              if (status === "completed") {
                $timeout.cancel($scope.clusterPollingInterval);
                $scope.clusterPollingInterval = null;
                console.log("Clustering complete. Polling stopped.");
                // call getReportData to refresh data
                $scope.getReportData();
              } else {
                // Otherwise, continue polling
                $scope.clusterPollingInterval = $timeout(poll, 10000);
              }
            }
          })
          .catch(function (error) {
            console.log("Error polling cluster status:", error);
            // Stop polling on error to prevent infinite loops
            $timeout.cancel($scope.clusterPollingInterval);
          });
      };
      // Start the first poll immediately
      poll();
    };
    $controller("coreapi", { $scope: $scope });
    $scope.init();
    // Start polling immediately if the initial state is pending or clustering
    if ($scope.analytics && $scope.analytics.second && ($scope.analytics.second.action === "pending" || ($scope.analytics.second.data && ($scope.analytics.second.data.status === "clustering" || $scope.analytics.second.data.status === "pending")))) {
      $scope.startClusterPolling();
    }
  },
]);
/**
     * Calculates a weighted visibility score for a given query.
     * @param {object} query - The query object from your database, now including a 'status' field.
     * @param {string} userDomain - The domain of the user's site.
     * @param {Array} providers - An array of all active providers.
     * @returns {object} - An object containing the score, status, and ranks.
     */
function calculateVisibilityScore(query, userDomain, providers) {
  // Directly use the status from the API.
  if (query.status === 'pending') {
    return {
      score: 0,
      status: 'Pending',
      ranks: {}
    };
  }
  // The rest of the logic only runs if the status is 'done'.
  const processed = {
    score: 0,
    status: 'Gap', // Default status for a 'done' query with no visibility
    ranks: {}
  };
  const getPointsForRank = (rank) => {
    if (rank === null) return 0;
    if (rank === 1) return 10;
    if (rank === 2) return 9.5;
    if (rank === 3) return 8.5;
    if (rank >= 4 && rank <= 5) return 8;
    if (rank >= 6 && rank <= 10) return 7;
    if (rank >= 11 && rank <= 15) return 6;
    return 0;
  };
  let totalPoints = 0;
  const cleanUserDomain = userDomain.replace(/^www\./, '');
  let latestHistory = {};
  (query.history || []).forEach(entry => {
    if (!latestHistory[entry.provider] || new Date(entry.date) > new Date(latestHistory[entry.provider].date)) {
      latestHistory[entry.provider] = entry;
    }
  });
  providers.forEach(provider => {
    const entry = latestHistory[provider];
    let rank = null;
    if (entry && entry.urls) {
      const foundIndex = entry.urls.findIndex(url => {
        try {
          const urlDomain = url.replace(/^https?:\/\//, '').split('/')[0].replace(/^www\./, '');
          return urlDomain === cleanUserDomain;
        } catch (e) { return false; }
      });
      if (foundIndex !== -1) {
        rank = foundIndex + 1;
      }
    }
    processed.ranks[provider] = rank;
    totalPoints += getPointsForRank(rank);
  });
  if (providers.length > 0) {
    processed.score = totalPoints / providers.length;
  }
  if (processed.score >= 7) {
    processed.status = 'Leading';
  } else if (processed.score >= 3) {
    processed.status = 'Visible';
  } else if (processed.score > 0) {
    processed.status = 'At Risk';
  }
  return processed;
}
app.controller("llmvisibility", [
  "$scope",
  "$http",
  "$rootScope",
  "$filter",
  "h",
  "$sce",
  function ($scope, $http, $rootScope, $filter, h, $sce) {
    $scope.queries = [];
    $scope.kpis = {
      overallVisibility: 0,
      queriesLeading: 0,
      visibilityTrend: 0, // Placeholder
      topCompetitor: "N/A",
      contentGaps: 0,
      queriesWithMentions: 0, // ++ ADD THIS
    };
    $scope.page = {
      newQuery: "",
      filter: {},
      sortType: "q",
      sortReverse: false,
      // New fields for add form
      newQueryExtraDomains: '',
      newQueryBrands: ''
    };
    // Add a new query to track (with error handling and multi-query split)
    $scope.fnAddQuery = function () {
      if (!$scope.page.newQuery || !$scope.page.newQuery.trim()) {
        return; // Don't add empty queries
      }
      if ($scope.page.isOverBudget) {
        $scope.page.error = "This query exceeds your available credits. Please adjust the providers or frequency.";
        return;
      }
      // If we're editing an existing query, perform update instead of add
      if ($scope.page.editing) {
        var updateQ = $scope.page.newQuery.trim();
        var extradomains = ($scope.page.newQueryExtraDomains || '').split(/[,\s]+/).map(function (d) { return (d || '').trim(); }).filter(Boolean);
        var brands = ($scope.page.newQueryBrands || '').split(/[,\s]+/).map(function (d) { return (d || '').trim(); }).filter(Boolean);
        $http.post('/rest/llmvisibility/update', {
          _id: $scope.page.editing,
          q: updateQ,
          websiteid: h.siteId(),
          extradomains: extradomains,
          brands: brands,
          providers: Object.keys($scope.page.newQueryProviders).filter(k => $scope.page.newQueryProviders[k]),
          frequency: $scope.page.newQueryFrequency
        }).then(function(res) {
          $scope.getQueries();
          $scope.fnCancelEdit();
        }, function(err) {
          var msg = (err.data && (err.data.error || err.data.message)) ? (err.data.error || err.data.message) : 'Failed to update query.';
          $scope.page.error = msg;
        });
        return;
      }
      // Split by comma or newline
      var queries = $scope.page.newQuery.split(/[\,\n]+/);
      var errorOccurred = false;
      $scope.page.error = null;
      // Prepare domains and brands
      var extradomains = ($scope.page.newQueryExtraDomains || '').split(/[,\s]+/).map(function (d) { return (d || '').trim(); }).filter(Boolean);
      var brands = ($scope.page.newQueryBrands || '').split(/[,\s]+/).map(function (d) { return (d || '').trim(); }).filter(Boolean);
      var addNext = function (index) {
        if (index >= queries.length) {
          $scope.fnCancelEdit(); // Reset form on completion
          return;
        }
        var query = queries[index].trim();
        if (!query) {
          addNext(index + 1);
          return;
        }
        $http.post("/rest/llmvisibility/add", {
          q: query,
          websiteid: h.siteId(),
          extradomains: extradomains,
          brands: brands,
          providers: Object.keys($scope.page.newQueryProviders).filter(k => $scope.page.newQueryProviders[k]),
          frequency: $scope.page.newQueryFrequency
        }).then(function successCallback(res) {
          $scope.getQueries();
          addNext(index + 1);
        }, function errorCallback(err) {
          var msg = (err.data && (err.data.error || err.data.message)) ? (err.data.error || err.data.message) : 'Failed to add query "' + query + '".';
          if (!errorOccurred) {
            $scope.page.error = msg;
            errorOccurred = true;
          }
          // Stop on first error
        });
      };
      addNext(0);
    };
    // Retrieve the list of all queries for the site
    $scope.getQueries = function () {
      $http
        .get("/rest/llmvisibility/list", {
          params: {
            websiteid: h.siteId(),
          },
        }) // site_id is handled by backend
        .then(function successCallback(res) {
          console.log("LLM Visibility Queries:", res.data);
          $scope.processData(res.data);
        });
    };
    // Remove a query
    $scope.fnRemoveQuery = function (query) {
      if (!confirm('Are you sure you want to remove this query?')) return;
      $http.post('/rest/llmvisibility/delete', {
        _id: query._id
      }).then(function () {
        $scope.getQueries();
      });
    };
    // // Edit a query (inline prompt -> update API)
    // $scope.fnEditQuery = function (query) {
    //   // Prevent editing pending queries that may be in-flight
    //   var newQ = prompt('Edit query', query.q);
    //   if (newQ === null) return; // user cancelled
    //   newQ = ('' + newQ).trim();
    //   if (!newQ) return alert('Query cannot be empty.');
    //   $http.post('/rest/llmvisibility/update', {
    //     _id: query._id,
    //     q: newQ
    //   }).then(function (res) {
    //     $scope.getQueries();
    //   }, function (err) {
    //     var msg = (err.data && (err.data.error || err.data.message)) ? (err.data.error || err.data.message) : 'Failed to update query.';
    //     alert(msg);
    //   });
    // };
    // Edit a query: populate the add form and set editing state
    $scope.fnEditQuery = function (query) {
     
      $scope.page.newQuery = query.q || '';
      // try multiple possible field names stored on the query object
      var existingExtra = query.extradomains || query.extraDomains || query.extra_domains || query.domains || '';
      var existingBrands = query.brands || query.brand || '';
      if (Array.isArray(existingExtra)) existingExtra = existingExtra.join(', ');
      if (Array.isArray(existingBrands)) existingBrands = existingBrands.join(', ');
      $scope.page.newQueryExtraDomains = existingExtra || '';
      $scope.page.newQueryBrands = existingBrands || '';
      
      // -- Populate new fields for editing --
      $scope.page.newQueryFrequency = query.frequency || 'weekly';
      // Reset providers, then set the ones from the query
      $scope.page.newQueryProviders = { google: false, openai: false, perplexity: false };
      if (query.providers && query.providers.length) {
        query.providers.forEach(p => {
          if ($scope.page.newQueryProviders.hasOwnProperty(p)) {
            $scope.page.newQueryProviders[p] = true;
          }
        });
      } else {
        // Default if not set
        $scope.page.newQueryProviders = { google: true, openai: true, perplexity: true };
      }
      $scope.page.editing = query._id;
      // focus the textarea
      setTimeout(function(){ try{ var el = document.querySelector('textarea[ng-model="page.newQuery"]'); if(el) el.focus(); }catch(e){} },50);
    };
    // Cancel editing and reset the add form
    $scope.fnCancelEdit = function() {
      $scope.page.editing = null;
      $scope.page.newQuery = '';
      $scope.page.newQueryExtraDomains = $rootScope.user && $rootScope.user.site ? $rootScope.user.site.domain.replace(/^www\./,'') : '';
      $scope.page.newQueryBrands = $rootScope.user && $rootScope.user.site && $rootScope.user.site.brand ? $rootScope.user.site.brand : '';
      $scope.page.error = null;
      // -- Reset new fields --
      $scope.page.newQueryProviders = { google: true, openai: true, perplexity: true };
      $scope.page.newQueryFrequency = 'weekly';
    };
    // Helper: Find the rank (1-based) of the user's domain in a list of URLs
    function findRankInUrls(urls, domain) {
      if (!Array.isArray(urls) || !domain) return null;
      for (var i = 0; i < urls.length; i++) {
        try {
          var urlDomain = urls[i].replace(/^https?:\/\//, '').split('/')[0].replace(/^www\./, '');
          if (urlDomain === domain.replace(/^www\./, '')) {
            return i + 1;
          }
        } catch (e) { }
      }
      return null;
    }
    // Helper: Extract domain from a URL
    function getDomainFromUrl(url) {
      if (!url) return null;
      try {
        return url.replace(/^https?:\/\//, '').split('/')[0].replace(/^www\./, '');
      } catch (e) { return null; }
    }
    // Main data processing function
    $scope.processData = function (data) {
        const userDomain = $rootScope.user.site.domain.replace(/^www\./, '');
        let totalVisibilityScore = 0;
        let leadingQueriesCount = 0;
        let contentGapsCount = 0;
        let allProvidersMap = {};
        
        // Note: The brand mention logic is kept here to ensure compatibility
        // if you have already implemented it.
        let queriesWithMentions = 0; 
        // ++ Variables for trend calculation
        let totalPastVisibilityScore = 0;
        let trendCalculableQueries = 0;
        // Competitor scoring system setup
        let competitorPoints = {};
        let competitorAppearances = {};
        const getPointsForRank = (rank) => {
            if (rank === null) return 0;
            if (rank === 1) return 10; if (rank === 2) return 8; if (rank === 3) return 7;
            if (rank >= 4 && rank <= 5) return 5; if (rank >= 6 && rank <= 10) return 3;
            if (rank >= 11 && rank <= 15) return 1; return 0;
        };
        const getDomainFromUrl = (url) => {
            if (!url) return null;
            try {
                return url.replace(/^https?:\/\//, '').split('/')[0].replace(/^www\./, '');
            } catch (e) { return null; }
        };
        // Determine all unique providers from the data
        data.forEach(function (query) {
            (query.history || []).forEach(function (entry) {
                allProvidersMap[entry.provider] = true;
            });
        });
        const allProviders = Object.keys(allProvidersMap).sort();
        $scope.allProviders = allProviders;
        // Process each query
        let visibleQueriesCount = 0;
        data.forEach(function (query) {
            // ++ Set defaults for existing queries without provider/frequency info ++
            if (!query.providers || query.providers.length === 0) {
                query.providers = allProviders;
            }
            if (!query.frequency) {
                query.frequency = 'weekly';
            }
            
            query.processed = calculateVisibilityScore(query, userDomain, allProviders);
            // Individual query sparkline logic (remains unchanged)
            let historyByDate = {};
            (query.history || []).forEach(function (entry) {
              if (!entry.date) return;
              var dateStr = entry.date.substr(0, 10);
              if (!historyByDate[dateStr]) historyByDate[dateStr] = [];
              var rank = null;
              if (entry.urls && entry.urls.length) {
                for (var i = 0; i < entry.urls.length; ++i) {
                  var urlDomain = entry.urls[i].replace(/^https?:\/\//, '').split('/')[0].replace(/^www\./, '');
                  if (urlDomain === userDomain) { rank = i + 1; break; }
                }
              }
              if (rank !== null) historyByDate[dateStr].push(rank);
            });
            var trendArr = [];
            Object.keys(historyByDate).forEach(function (d) {
              var arr = historyByDate[d];
              if (arr.length) {
                var avg = arr.reduce(function (a, b) { return a + b; }, 0) / arr.length;
                trendArr.push({ date: d, rank: avg });
              }
            });
            trendArr.sort(function (a, b) { return a.date.localeCompare(b.date); });
            if (trendArr.length > 1) {
              var minRank = Math.min.apply(null, trendArr.map(function (t) { return t.rank; }));
              var maxRank = Math.max.apply(null, trendArr.map(function (t) { return t.rank; }));
              if (minRank === maxRank) { minRank = 1; maxRank = minRank + 1; }
              var w = 60, h = 18, n = trendArr.length;
              query.trendline = trendArr.map(function (t, i) {
                var x = Math.round(i * (w / (n - 1)));
                var y = Math.round(h - ((t.rank - minRank) / (maxRank - minRank)) * h);
                return x + ',' + y;
              }).join(' ');
            } else {
              query.trendline = '';
            }
            // ++ START: NEW BRAND MENTION LOGIC ++
            query.processed.brandMentions = {}; // Object to store mentions by provider
            let queryHasAnyMention = false;
            const brandsToTrack = query.brands || [];
            if (brandsToTrack.length > 0) {
              let latestHistory = {};
              (query.history || []).forEach(function (entry) {
                if (!latestHistory[entry.provider] || new Date(entry.date) > new Date(latestHistory[entry.provider].date)) {
                  latestHistory[entry.provider] = entry;
                }
              });
              // Create a case-insensitive regex with word boundaries
              const brandRegex = new RegExp('\\b(' + brandsToTrack.join('|') + ')\\b', 'gi');
              for (const provider in latestHistory) {
                const entry = latestHistory[provider];
                if (entry.responseText && entry.responseText.match(brandRegex)) {
                  query.processed.brandMentions[provider] = true;
                  queryHasAnyMention = true;
                } else {
                  // Explicitly set to false if no mention is found for a provider with a response
                  if (entry.responseText) {
                      query.processed.brandMentions[provider] = false;
                  }
                }
              }
            }
            if (queryHasAnyMention) {
              queriesWithMentions++;
            }
            // ++ END: NEW BRAND MENTION LOGIC ++
            // Only count non-pending queries for KPIs and visibility
            if (query.status !== 'pending') {
                totalVisibilityScore += query.processed.score;
                visibleQueriesCount++;
                if (query.processed.status === "Leading") leadingQueriesCount++;
                else if (query.processed.status === "Gap") contentGapsCount++;
            }
            // ++ START: Overall Trend Calculation Logic ++
            if (query.history && query.history.length > 0) {
                let queryHistoryByDate = {};
                query.history.forEach(entry => {
                    const dateStr = entry.date.substr(0, 10);
                    if (!queryHistoryByDate[dateStr]) queryHistoryByDate[dateStr] = [];
                    queryHistoryByDate[dateStr].push(entry);
                });
                const sortedDates = Object.keys(queryHistoryByDate).sort();
                if (sortedDates.length > 1) {
                    const oldestDate = sortedDates[0];
                    let oldestLatestHistory = {};
                    queryHistoryByDate[oldestDate].forEach(entry => {
                        if (!oldestLatestHistory[entry.provider] || new Date(entry.date) > new Date(oldestLatestHistory[entry.provider].date)) {
                            oldestLatestHistory[entry.provider] = entry;
                        }
                    });
                    const pastQuery = { status: 'done', history: Object.values(oldestLatestHistory) };
                    const pastResult = calculateVisibilityScore(pastQuery, userDomain, allProviders);
                    totalPastVisibilityScore += pastResult.score;
                    trendCalculableQueries++;
                }
            }
            // ++ END: Overall Trend Calculation Logic ++
            // Competitor Logic (remains unchanged)
            let latestHistory = {};
            (query.history || []).forEach(function (entry) {
              if (!latestHistory[entry.provider] || new Date(entry.date) > new Date(latestHistory[entry.provider].date)) {
                latestHistory[entry.provider] = entry;
              }
            });
            for (const provider in latestHistory) {
              const entry = latestHistory[provider];
              const seenDomains = new Set();
              (entry.urls || []).forEach((url, index) => {
                const domain = getDomainFromUrl(url);
                if (domain && domain !== userDomain) {
                  if (!competitorPoints[domain]) {
                    competitorPoints[domain] = 0;
                    competitorAppearances[domain] = 0;
                  }
                  competitorPoints[domain] += getPointsForRank(index + 1);
                  if (!seenDomains.has(domain)) {
                    competitorAppearances[domain]++;
                    seenDomains.add(domain);
                  }
                }
              });
            }
        });
        // Final Competitor Score Calculation (remains unchanged)
        let topCompetitor = "N/A";
        let maxCompetitorScore = -1;
        for (const domain in competitorPoints) {
            const avgScore = competitorAppearances[domain] > 0 ? competitorPoints[domain] / competitorAppearances[domain] : 0;
            if (avgScore > maxCompetitorScore) {
                maxCompetitorScore = avgScore;
                topCompetitor = domain;
            }
        }
        // Calculate KPIs
        $scope.kpis.overallVisibility = visibleQueriesCount > 0 ? (totalVisibilityScore / visibleQueriesCount) : 0;
        $scope.kpis.queriesLeading = leadingQueriesCount;
        $scope.kpis.contentGaps = contentGapsCount;
        $scope.kpis.topCompetitor = topCompetitor;
        $scope.kpis.queriesWithMentions = queriesWithMentions;
        // ++ ADD FINAL TREND CALCULATION ++
        let visibilityTrend = 0;
        if (trendCalculableQueries > 0 && visibleQueriesCount > 0) {
            // Use the current average, not the sum for trendable queries
            const currentAverage = totalVisibilityScore / visibleQueriesCount; 
            const pastAverage = totalPastVisibilityScore / trendCalculableQueries;
            if (pastAverage > 0) {
                visibilityTrend = ((currentAverage - pastAverage) / pastAverage) * 100;
            } else if (currentAverage > 0) {
                visibilityTrend = 100; // From 0 to something positive is a 100% gain for our purposes
            }
        }
        $scope.kpis.visibilityTrend = visibilityTrend;
        $scope.queries = data;
    };
    // REVISED Toggle for details view
    $scope.fnQueryHistory = function (query) {
        query.active = !query.active;
        // Only process the data if we are opening the row for the first time
        if (query.active && !query.details) {
            const userDomain = $rootScope.user.site.domain.replace(/^www\./, '');
            const brandsToTrack = query.brands || [];
            
            // Setup for text highlighting
            const highlightTerms = [userDomain, ...brandsToTrack].filter(Boolean);
            const highlightRegex = new RegExp('\\b(' + highlightTerms.join('|') + ')\\b', 'gi');
            query.details = {
                responses: [],
                competitors: []
                // The separate brandSummary is no longer needed
            };
            const getPointsForRank = (rank) => {
                if (rank === null) return 0;
                if (rank === 1) return 10; if (rank === 2) return 8; if (rank === 3) return 7;
                if (rank >= 4 && rank <= 5) return 5; if (rank >= 6 && rank <= 10) return 3;
                if (rank >= 11 && rank <= 15) return 1; return 0;
            };
            let competitorPoints = {};
            let providerCount = 0;
            // Get the most recent entry for each provider
            let latestHistory = {};
            (query.history || []).forEach(function (entry) {
                if (!latestHistory[entry.provider] || new Date(entry.date) > new Date(latestHistory[entry.provider].date)) {
                    latestHistory[entry.provider] = entry;
                }
            });
            for (const provider in latestHistory) {
                providerCount++;
                const entry = latestHistory[provider];
                // 1. Prepare LLM Response Text (with highlighting)
                if (entry.responseText) {
                    let highlightedText = entry.responseText.replace(highlightRegex, `$&`);
                    highlightedText = highlightedText
                        .replace(/\*\*(.*?)\*\*/g, '$1')
                        .replace(/\*(.*?)\*/g, '$1')
                        .replace(/`([^`]+)`/g, '$1')
                        .replace(/\[(.*?)\]\((.*?)\)/g, '$1')
                        .replace(/\n{3,}/g, '\n\n');
                    // ++ START: NEW MENTION DETECTION LOGIC ++
                    let mentionedBrands = [];
                    if (brandsToTrack.length > 0) {
                        brandsToTrack.forEach(brand => {
                            const brandRegex = new RegExp('\\b' + brand + '\\b', 'gi');
                            if (brandRegex.test(entry.responseText)) {
                                mentionedBrands.push(brand);
                            }
                        });
                    }
                    // ++ END: NEW MENTION DETECTION LOGIC ++
                    query.details.responses.push({
                        provider: provider,
                        text: $sce.trustAsHtml(`${highlightedText}
`),
                        urls: entry.urls || [],
                        mentionedBrands: mentionedBrands // ++ ATTACH MENTIONED BRANDS
                    });
                }
                // 2. Calculate points for each competitor in this provider's list
                (entry.urls || []).forEach(function (url, index) {
                    const domain = getDomainFromUrl(url);
                    if (domain && domain !== userDomain) {
                        if (!competitorPoints[domain]) {
                            competitorPoints[domain] = 0;
                        }
                        competitorPoints[domain] += getPointsForRank(index + 1);
                    }
                });
            }
            
            // 3. Calculate final score for each competitor and sort
            for (const domain in competitorPoints) {
                query.details.competitors.push({
                    domain: domain,
                    score: providerCount > 0 ? competitorPoints[domain] / providerCount : 0
                });
            }
            query.details.competitors.sort((a, b) => b.score - a.score);
            // 4. Name clusters using AJAX calls to /name-single-cluster/
            query.details.clusterNames = {};
            const nameClusters = async () => {
                // Group keywords by cluster for naming
                const clustersForNaming = {};
                query.details.responses.forEach(response => {
                    if (response.urls && response.urls.length > 0) {
                        response.urls.forEach((url, index) => {
                            const keyword = url.replace(/^https?:\/\//, '').split('/')[0].replace(/^www\./, '');
                            // For now, we'll use a simple clustering approach or you can integrate with your clustering API
                            // This is a placeholder - you'll need to implement the actual clustering logic
                            const clusterId = Math.floor(Math.random() * 5); // Placeholder clustering
                            if (!clustersForNaming[clusterId]) {
                                clustersForNaming[clusterId] = [];
                            }
                            clustersForNaming[clusterId].push(keyword);
                        });
                    }
                });
                // Make AJAX calls for each cluster
                for (const [clusterId, keywords] of Object.entries(clustersForNaming)) {
                    try {
                        const response = await $http.post('http://135.125.202.210:8000/name-single-cluster/', {
                            keywords: keywords
                        });
                        query.details.clusterNames[clusterId] = response.data.name || `Cluster ${clusterId}`;
                    } catch (error) {
                        console.error('Error naming cluster', clusterId, error);
                        query.details.clusterNames[clusterId] = `Cluster ${clusterId}`;
                    }
                }
                
                // Trigger digest cycle to update UI
                $scope.$apply();
            };
            
            // Start naming clusters asynchronously
            nameClusters();
            // --- Render AmCharts historical chart ---
            // ... (existing AmCharts logic remains unchanged) ...
            setTimeout(function () {
              if (!window.AmCharts) return;
              var chartData = [];
              var providers = $scope.allProviders || [];
              var dateMap = {};
              (query.history || []).forEach(function (entry) {
                if (!entry.date) return;
                var dateStr = entry.date.substr(0, 10).replace(/-/g, '');
                dateMap[dateStr] = dateMap[dateStr] || { date: dateStr };
                var rank = null;
                if (entry.urls && entry.urls.length) {
                  for (var i = 0; i < entry.urls.length; ++i) {
                    var urlDomain = entry.urls[i].replace(/^https?:\/\//, '').split('/')[0].replace(/^www\./, '');
                    if (urlDomain === userDomain) {
                      rank = i + 1;
                      break;
                    }
                  }
                }
                dateMap[dateStr][entry.provider] = rank;
              });
              for (var d in dateMap) chartData.push(dateMap[d]);
              chartData.sort(function (a, b) { return a.date.localeCompare(b.date); });
              var graphs = (providers || []).map(function (provider, idx) {
                return {
                  balloonText: provider + ': [[value]]',
                  title: provider,
                  valueField: provider,
                  bullet: 'round',
                  bulletBorderAlpha: 1,
                  bulletColor: '#FFFFFF',
                  useLineColorForBulletBorder: true,
                  fillAlphas: 0,
                  lineThickness: 2,
                  lineAlpha: 1,
                  bulletSize: 7,
                  lineColor: h.colors ? h.colors()[idx % 6] : undefined
                };
              });
              AmCharts.makeChart('llm-history-chart-' + query._id, {
                type: 'serial', theme: 'light', marginLeft: 0, marginRight: 0, marginTop: 10, categoryField: 'date', rotate: false, dataDateFormat: 'YYYYMMDD',
                categoryAxis: { gridPosition: 'start', parseDates: true, labelRotation: 45 },
                valueAxes: [{ reversed: true, position: 'left', axisAlpha: 0, labelsEnabled: true, minimum: 1 }],
                graphs: graphs, dataProvider: chartData, legend: { position: 'bottom', enabled: true, useGraphSettings: true }
              });
            }, 0);
        }
    };
    // --- Credit & Budgeting ---
    $scope.providers = ['google', 'openai', 'perplexity'];
    $scope.frequencies = {
      'daily': { name: 'Daily', cost: 31 },
      'weekly': { name: 'Weekly', cost: 4 },
      'monthly': { name: 'Monthly', cost: 1 }
    };
    // Initialize new query options
    $scope.page.newQueryProviders = { google: true, openai: true, perplexity: true };
    $scope.page.newQueryFrequency = 'weekly';
    $scope.page.newQueryCost = 0;
    $scope.page.isOverBudget = false;
    $scope.page.currentUsage = 0;
    $scope.page.totalProjectedCost = 0;
    // Function to calculate cost
    $scope.calculateCost = function() {
      // Count the number of actual queries entered in the textarea
      var queryCount = 0;
      if ($scope.page.newQuery && $scope.page.newQuery.trim()) {
          // Split by comma or newline and filter out any empty strings
          queryCount = $scope.page.newQuery.split(/[\,\n]+/).filter(q => q.trim()).length;
      }
      // When editing, we are always dealing with a single query, so force count to 1
      if ($scope.page.editing) {
          queryCount = 1;
      }
      // 1. Calculate cost of the new/edited query batch
      var newQueryProvidersCount = Object.values($scope.page.newQueryProviders).filter(Boolean).length;
      var newQueryFrequencyCost = $scope.frequencies[$scope.page.newQueryFrequency] ? $scope.frequencies[$scope.page.newQueryFrequency].cost : 0;
      var newQueryCost = queryCount * newQueryProvidersCount * newQueryFrequencyCost;
      $scope.page.newQueryCost = newQueryCost;
      // 2. Calculate current usage from all existing queries
      var currentUsage = 0;
      ($scope.queries || []).forEach(function(q) {
          // If we are editing this query, its cost will be replaced by the new cost, so skip it here.
          if ($scope.page.editing && $scope.page.editing === q._id) {
              return;
          }
          var providerCount = (q.providers && q.providers.length) ? q.providers.length : $scope.allProviders.length;
          var frequencyCost = $scope.frequencies[q.frequency] ? $scope.frequencies[q.frequency].cost : $scope.frequencies['weekly'].cost;
          currentUsage += providerCount * frequencyCost;
      });
      $scope.page.currentUsage = currentUsage;
      // 3. Calculate total projected cost
      var totalProjectedCost = currentUsage + newQueryCost;
      $scope.page.totalProjectedCost = totalProjectedCost;
      // 4. Check against budget
      var availableCredits = ($rootScope.user && $rootScope.user.credits && $rootScope.user.credits.llm) ? $rootScope.user.credits.llm : 0;
      $scope.page.isOverBudget = totalProjectedCost > availableCredits;
    };
    // Watch for changes to recalculate cost
    $scope.$watch('page.newQueryProviders', $scope.calculateCost, true);
    $scope.$watch('page.newQueryFrequency', $scope.calculateCost);
    $scope.$watch('queries', $scope.calculateCost, true); // Recalculate if queries are added/deleted
    // Initial calculation
    $scope.calculateCost();
    // Initial load
    $scope.getQueries();
  },
]);
app.controller('keywordtool', ['$scope', '$http', '$rootScope', '$filter', '$location', 'h',
    function($scope, $http, $rootScope, $filter, $location, h) {
        $scope.suggest = { 'q': '', result: [] };
        $scope.order = {};
        $scope.fnOrder = function(field) {
            var reverse = (field == $scope.order.field) ? true : false;
            $scope.order = { 'field': field, 'reverse': reverse };
        }
        var lang = {
            "de": [
                { key: 'was', 'value': 'was ', 'type': 'vraag' },
                { key: 'was ist', 'value': 'was ist ', 'type': 'vraag' },
                { key: 'wie', 'value': 'wie ', 'type': 'vraag' },
                { key: 'wann', 'value': 'wann ', 'type': 'vraag' },
                { key: 'welche', 'value': 'welche ', 'type': 'vraag' },
                { key: 'warum', 'value': 'warum ', 'type': 'vraag' },
            ],
            "nl": [
                { key: 'wat', 'value': 'wat ', 'type': 'vraag' },
                { key: 'wat is', 'value': 'wat is ', 'type': 'vraag' },
                { key: 'hoe', 'value': 'hoe ', 'type': 'vraag' },
                { key: 'wanneer', 'value': 'wanneer ', 'type': 'vraag' },
                { key: 'welke', 'value': 'welke ', 'type': 'vraag' },
                { key: 'waarom', 'value': 'waarom ', 'type': 'vraag' },
            ],
            "en": [
                { key: 'what', 'value': 'what ', 'type': 'vraag' },
                { key: 'what is', 'value': 'what is ', 'type': 'vraag' },
                { key: 'how', 'value': 'how ', 'type': 'vraag' },
                { key: 'when', 'value': 'when ', 'type': 'vraag' },
                { key: 'which', 'value': 'which ', 'type': 'vraag' },
                { key: 'why', 'value': 'why ', 'type': 'vraag' },
            ]
        }
        var letters = [
            { key: 'a', 'value': ' a' },
            { key: 'b', 'value': ' b' },
            { key: 'c', 'value': ' c' },
            { key: 'd', 'value': ' d' },
            { key: 'e', 'value': ' e' },
            { key: 'f', 'value': ' f' },
            { key: 'g', 'value': ' g' },
            { key: 'h', 'value': ' h' },
            { key: 'i', 'value': ' i' },
            { key: 'j', 'value': ' j' },
            { key: 'k', 'value': ' k' },
            { key: 'l', 'value': ' l' },
            { key: 'm', 'value': ' m' },
            { key: 'n', 'value': ' n' },
            { key: 'o', 'value': ' o' },
            { key: 'p', 'value': ' p' },
            { key: 'q', 'value': ' q' },
            { key: 'r', 'value': ' r' },
            { key: 's', 'value': ' s' },
            { key: 't', 'value': ' t' },
            { key: 'u', 'value': ' u' },
            { key: 'v', 'value': ' v' },
            { key: 'w', 'value': ' w' },
            { key: 'x', 'value': ' x' },
            { key: 'y', 'value': ' y' },
            { key: 'z', 'value': ' z' },
        ]
        $scope.letters = lang[$rootScope.user.site.locale.lang].concat(letters);
        var current = { 'key': '', value: '' }
        $scope.fnTrackKeyword = function(kw) {
            $http.post('/rest/rank-tracker/add', {
                keywords: kw,
                websiteid: h.siteId()
            }).then(function successCallback(res) {
            });
        }
        $scope.fnExploreKeyword = function(q) {
            $scope.q = q;
            $scope.showsuggesties = true;
            $scope.suggest.result = [];
            current = { 'key': 'base', value: '' }
            $http.get('/rest/keywordtool/get', {
                params: {
                    q: $scope.q,
                    l: 'long',
                }
            }).then(function successCallback(res) {
                $scope.suggest.result['base'] = res.data;
            });
            $scope.kwplanner = false;
            var next = false;
            var go = false;
            var mbreak = true;
            $http.get('/rest/googlexads/keywordplanner', {
                params: {
                    q: $scope.q,
                    cc: $scope.user.site.locale.cc,
                    lc: $scope.user.site.locale.lc,
                }
            }).then(function successCallback(res) {
                $scope.kwplanner = res.data;
            });
            angular.forEach($scope.letters, function(value, key) {
                if (value.type == 'vraag') {
                    $http.get('/rest/keywordtool/get', {
                        params: {
                            q: value.value + $scope.q,
                            cc: $scope.user.site.locale.cc,
                            lc: $scope.user.site.locale.lc,
                        }
                    }).then(function successCallback(res) {
                        if (res.data[1]) {
                            $scope.suggest.result[value.key] = res.data;
                        }
                    });
                } else {
                    $http.get('/rest/keywordtool/get', {
                        params: {
                            q: $scope.q + value.value,
                            cc: $scope.user.site.locale.cc,
                            lc: $scope.user.site.locale.lc,
                        }
                    }).then(function successCallback(res) {
                        if (res.data[1]) {
                            $scope.suggest.result[value.key] = res.data;
                        }
                    });
                }
            });
        }
        $scope.fnDownload = function(text) {
            var text = '';
            for (var i in $scope.suggest.result) {
                var res = $scope.suggest.result[i];
                for (var y in res) {
                    var woord = res[y];
                    if (woord.check) {
                        console.log(woord);
                        text = text + woord.r + "\r\n";
                    }
                }
            }
            for (var i in $scope.kwplanner) {
                if ($scope.kwplanner[i].check) {
                    text = text + $scope.kwplanner[i].keyword + " (" + $scope.kwplanner[i].vol + "," + $scope.kwplanner[i].seo + "," + $scope.kwplanner[i].cpc + ")\r\n";
                }
            }
            var element = document.createElement('a');
            element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));
            element.setAttribute('download', 'zoekwoord suggesties voor ' + $scope.q + '.txt');
            element.style.display = 'none';
            document.body.appendChild(element);
            element.click();
            document.body.removeChild(element);
        }
    }
]);
app.controller('onpagestatus', ['$scope', '$timeout', '$http', '$rootScope', '$location', '$filter', 'h',
    function($scope, $timeout, $http, $rootScope, $location, $filter, h) {
        $scope.page = {};
        var _cb = {
            getstarted: function() {
                $scope.page.include = 'index.getstarted';
            },
            crawling: function() {
                $scope.page.crawling = true;
                $scope.page.include = 'index.list';
            },
            ready: function() {
                $scope.page.include = 'index.list';
            }
        }
        var timeout = 5000
        var getStatus = function() {
            if ($rootScope.onpagestatus && $rootScope.onpagestatus.data.status == 'done') {
                _cb[$rootScope.onpagestatus.cb]($rootScope.onpagestatus.data)
            } else {
                $http.get('/rest/onpage/status', {
                    params: {
                        websiteid: h.siteId(),
                    }
                }).then(function successCallback(res) {
                    $rootScope.onpagestatus = res.data;
                    _cb[res.data.cb](res.data);
                    if ($rootScope.onpagestatus && $rootScope.onpagestatus.data.status == 'crawling') {
                        $scope.$broadcast('refreshonpagelist');
                        $timeout.cancel($rootScope.to);
                        $rootScope.to = $timeout(function() {
                            timeout = timeout * 1.2;
                            getStatus();
                        }, timeout);
                    }
                });
            }
        }
        getStatus();
        $scope.fnCrawl = function() {
            $http.get('/rest/onpage/crawl', {
                params: {
                    websiteid: h.siteId(),
                }
            }).then(function successCallback(res) {
                $rootScope.onpagestatus.data.status = 'crawling';
                $timeout(function() {
                    getStatus();
                }, 2000);
                $location.path('/onpage-seo/all');
            });
        } 
         $scope.fnEmpty = function() {
            $http.get('/rest/onpage/empty', {
                params: {
                    websiteid: h.siteId(),
                }
            });
        }
    }
]);
app.filter('zeroplus', function() {
    return function(items, timingevent) {
        return items.reduce(function(acc, cur) {
            if (typeof cur.properties == 'object' && typeof cur.properties.timing == 'object' && cur.properties.timing[timingevent] > 0) {
                acc.push(cur);
            }
            return acc;
        }, []);
    };
});
app.controller('onpagelist', ['$scope', '$timeout', '$http', '$rootScope', '$filter', 'h',
    function($scope, $timeout, $http, $rootScope, $filter, h) {
        $scope.page = { 'curllabel': '', 'newurl': $rootScope.user.site.domain + '/' };
        $scope.page.table = {
            'curpage': 0,
            'itemsperpage': 34,
            'offset': 0,
            'rulefilter': 'all',
            'filter': {},
            'min': { 'opi': 100, 'score': 100 },
            'order': { 'k': 'url', 'r': false },
            'fnOrder': function(k, b) {
                this.order.r = (k == this.order.k) ? !this.order.r : b;
                this.order.k = k;
            },
            fnSetOffset: function() {
                this.offset = this.itemsperpage * (this.curpage - 1);
            },
            fnFilterProperty: function() {
                var pages = angular.copy($rootScope._pages);
                $scope.pages = $filter('filter')(pages, $scope.page.table.filter);
            }
        }
        $scope.fnPctChange = function(o, n) {
            if (n == 0) {
                return '0%';
            }
            var pct = ((n - o) / o) * 100;
            var npct = $filter('number')(pct, 2);
            if(!isFinite(npct)){
                npct = 100;
            }
            if (pct < 0) {
                return '' + npct + '%';
            }
            return '+ ' + npct + '%';r
        }
        $scope.fnNewLabel = function(label) {
            if ($scope.page.curlabel != label) {
                $scope.page.curlabel = label;
                return true;
            }
            return false;
        }
        // filter pages by rule
        $scope.fnFilterRule = function(ruleName) {
            $scope.page.table.fnOrder('properties.opi', true)
            var pages = angular.copy($rootScope._pages);
            pages = $filter('filter')(pages, $scope.page.table.filter);
            $scope.rule = $scope.onpage.rules[ruleName];
            $scope.pages = $filter('filter')(pages, function(v) { return (v.rules[ruleName] === false) });
            $scope.view = 'pages';
            var stats = { 'done': 0, 'open': 0, 'total': 0, 'pages': 0 };
            for (var i in pages) {
                if (typeof pages[i]['rules'][ruleName] != 'undefined') {
                    stats['pages']++;
                    stats['total']++;
                    stats['done'] = (pages[i]['rules'][ruleName]) ? stats['done'] + 1 : stats['done'];
                    stats['open'] = (pages[i]['rules'][ruleName]) ? stats['open'] : stats['open'] + 1;
                }
            }
            $scope.stats = stats;
        }
        var fnChanges = {
            init: function() {
                $http.get('/rest/onpage/changes', {
                    params: {
                        websiteid: h.siteId(),
                    }
                }).then(function successCallback(res) {
                    // filter in controller => data en url weergave
                    //$scope.changes = $filter('orderBy')(res.data.data,['-date','-url']);
                    $scope.changes = res.data.data;
                    $scope.page.table.fnOrder('date', true)
                    fnChart($rootScope._history, 'all');
                    fnChanges.stats();
                    fnChanges.group('date');
                });
            },
            stats: function() {
                var stats = [{ 'label': 'change', 'value': 0, 'color': '#808080' }, { 'label': 'done', 'value': 0, 'color': '#4caf50' }, { 'label': 'issue', 'value': 0, 'color': '#ff9800' }];
                var totals = {};
                for (var i in $scope.changes) {
                    if ($scope.changes[i].r === true) {
                        stats[1].value += 1;
                    } else if ($scope.changes[i].r === false) {
                        stats[2].value += 1;
                    } else {
                        stats[0].value += 1;
                    }
                    totals[$scope.changes[i].url] = totals[$scope.changes[i].url] + 1 || 1
                }
                // total changes etc per page
                $scope.page.totals = [];
                for (var i in totals) {
                    $scope.page.totals.push({ 'url': i, 'count': totals[i] })
                }
                $scope.page.totals = $filter('orderBy')($scope.page.totals, 'count', true).slice(0, 5);
                $scope.page.stats = stats;
                $scope.piechart = {
                    data: stats,
                    type: 'pie',
                    "precision": 0,
                    "decimalSeparator": ",",
                    "thousandsSeparator": ".",
                    legend: {
                        enabled: false,
                        position: 'right',
                        autoMargins: false,
                        marginRight: 100,
                    },
                    titleField: 'label',
                    valueField: 'value',
                    "colorField": "color",
                    labelRadius: 5,
                    radius: '42%',
                    innerRadius: '60%',
                    labelText: '[[label]]',
                }
            },
            group: function(key) {
                var groups = $scope.changes.reduce(function(acc, cur) {
                    acc[cur.date] = acc[cur.date] || { 'key': new Date(cur.date).toLocaleString('default', { year: 'numeric', 'month': 'long', day: 'numeric' }), 'letter': new Date(cur.date).toLocaleString('default', { 'month': 'short' }).charAt(0).toUpperCase(), 'items': [] };
                    acc[cur.date].items.push(cur);
                    return acc;
                }, {});
                $scope.groups = $filter('orderBy')(Object.values(groups), 'date', false);
            }
        }
        var fnSpeed = function(pages) {
            var t = {};
            var s = {};
            // min max
            pages.forEach(function(page, k) {
                if (typeof page.properties.timing != 'undefined' && page.properties.timing != null && page.properties.timing.ttfb) {
                    var _otiming = page.properties.timing;
                    delete _otiming.cls;
                    Object.keys(_otiming).forEach(function(timingevent, n) {
                        s[timingevent] = s[timingevent] || []
                        if (_otiming[timingevent] > 0) {
                            s[timingevent].push(_otiming[timingevent])
                        }
                    })
                }
            })
            for (timingevent in s) {
                var v = s[timingevent];
                var min = 0;
                var max = Math.max(...v);
                var step = Math.round((max - min) / 18);
                if (step == 0) {
                    step = 0.1;
                }
                var oinit = {}
                for (var i = min; i < max; i = i + step) {
                    oinit[Math.round(i / step) * step] = 0;
                }
                t[timingevent] = v.reduce(function(acc, cur) {
                    acc[Math.round(cur / step) * step] = acc[Math.round(cur / step) * step] + 1;
                    return acc;
                }, oinit)
            }
            // get events from keys
            $scope.timingevents = Object.keys(t);
            var colors = h.colors()
            // create charts
            $scope.charts = {};
            Object.keys(t).forEach(function(timingevent, k) {
                var data = Object.keys(t[timingevent]).map(function(a) {
                    return { 'timing': a, 'pages': t[timingevent][a] }
                })
                $scope.charts[timingevent] = {
                    data: data,
                    type: 'serial',
                    categoryField: 'timing',
                    rotate: false,
                    legend: {
                        enabled: false
                    },
                    categoryAxis: {
                        gridPosition: "start",
                        parseDates: false,
                        labelRotation: 0,
                        gridThickness: 0,
                        labelFunction: function(value, valueText, axis) { return value + 'ms' },
                    },
                    valueAxes: [{
                        position: "left",
                        axisAlpha: 0,
                        labelsEnabled: true,
                        dashLength: 4,
                        color: '#dedede',
                    }],
                    graphs: [{
                        fillColorsField: "color",
                        balloonText: "" + timingevent + "
[[category]]ms: 
[[value]] pages",
                        type: "column",
                        columnWidth: 0.90,
                        title: "Zoekwoord waarde",
                        valueField: 'pages',
                        fillAlphas: 1,
                        lineColor: colors[k],
                        autoColor: true,
                    }],
                }
            })
        }
        // calculare rules and scores
        var fnDuplicates = function(pages) {
            var duplicates = {};
            for (var i in pages) {
                for (var y in pages[i]['compare']) {
                    duplicates[y] = duplicates[y] || {};
                    duplicates[y][pages[i]['compare'][y]] = duplicates[y][pages[i]['compare'][y]] || { 'name': pages[i]['compare'][y], 'count': 0, 'pages': [] };
                    duplicates[y][pages[i]['compare'][y]].count++;
                    duplicates[y][pages[i]['compare'][y]].pages.push({ 'serps': pages[i].serps, 'url': pages[i].url, 'properties': pages[i].properties, '_id': pages[i]._id });
                }
            }
            // remove single counts in compare
            for (var i in duplicates) {
                for (var y in duplicates[i]) {
                    if (duplicates[i][y].count <= 1) {
                        delete duplicates[i][y];
                    }
                }
            }
            var x = {}
            for (var i in duplicates) {
                x[i] = Object.values(duplicates[i])
            }
            $scope.duplicates = x;
        }
        // assistent
        var fnAssistent = function(pages) {
            $http.get('/rest/onpage/weights').then(function successCallback(weights) {
                var issues = [];
                for (var i in pages) {
                    for (var y in pages[i]['rules']) {
                        if (!pages[i]['rules'][y]) {
                            if (pages[i]['properties']['pagerank'] && pages[i]['properties']['opi'] && weights.data[y]) {
                                issues.push({ 'help': false, 'page': pages[i], 'weight': parseFloat(weights.data[y]['f'] * (200 + pages[i]['properties']['pagerank']) * (200 + pages[i]['properties']['opi'])), 'rule': y, 'f': weights.data[y]['f'] })
                            }
                        }
                    }
                }
                $scope.issues = issues;
            });
        }
        // alerts
        $scope.oAlerts = {
            init: function() {
                $scope.page.notifications = 'pending';
                this.getSettings();
                $timeout(function() { $scope.oAlerts.firebase.init(); }, 4000)
            },
            firebase: {
                'config': {
                    apiKey: "AIzaSyAKgRy2MQF2OUPh-WpUYMWOU6M_XijIMxg",
                    authDomain: "marketingtracer-73fb0.firebaseapp.com",
                    databaseURL: "https://marketingtracer-73fb0.firebaseio.com",
                    projectId: "marketingtracer-73fb0",
                    storageBucket: "marketingtracer-73fb0.appspot.com",
                    messagingSenderId: "769511864713",
                    appId: "1:769511864713:web:340f1f811287abb766c958"
                },
                'init': function() {
                    firebase.initializeApp(this.config);
                    this.messaging = firebase.messaging();
                    this.messaging.usePublicVapidKey("BDRyazo-zYOixCGZOS-ZI87KPiGfDCCFr5J-GMvydQkBVXOU9RaV8dolUZt_9RT1ZXk2WQ54lwKulSXn-r_B3UY");
                    if (!("Notification" in window)) {
                        $scope.page.notifications = 'notenabled';
                    } else if (Notification.permission == "granted") {
                        this.getToken();
                    } else {
                        $scope.page.notifications = 'notgranted';
                    }
                },
                'getToken': function() {
                    this.messaging.getToken().then(function(token) {
                        $scope.token = token;
                        console.log($scope.alertnotifications);
                        if ($scope.alertnotifications.indexOf(token) > -1) {
                            $scope.page.notifications = 'granted';
                        } else {
                            $scope.page.notifications = 'available';
                        }
                        $scope.$apply();
                        console.log("token is : ", token)
                    })
                },
                unsubscribe: function() {
                    $scope.page.notifications = 'available';
                    $http.post('/rest/onpage/alertsettings.notifications.pull', {
                        websiteid: h.siteId(),
                        'token': $scope.token
                    });
                },
                subscribe: function() {
                    $scope.page.notifications = 'granted';
                    $http.post('/rest/onpage/alertsettings.notifications.save', {
                        websiteid: h.siteId(),
                        'token': $scope.token
                    });
                },
                'requestPermission': function() {
                    this.messaging
                        .requestPermission()
                        .then(function() {
                            console.log("Notification permission granted.");
                            $scope.page.notifications = 'granted';
                            $scope.$apply();
                            // get the token in the form of promise
                            return messaging.getToken()
                        })
                        .then(function(token) {
                            // console.log("token is : ", token)
                            $http.post('/rest/onpage/alertsettings.notifications.save', {
                                websiteid: h.siteId(),
                                'token': token
                            });
                        })
                        .catch(function(err) {
                            $scope.page.notifications = 'notenabled';
                            //console.log("Unable to get permission to notify.", err);
                        });
                    this.messaging.onMessage(function(payload) {
                        var notification = new Notification(payload.notification.title, payload.notification);
                        console.log("Message received. ", payload);
                    });
                },
            },
            getSettings: function() {
                // hardcoded ruleset
                $scope.alertrules = [
                    { 'rule': 'title_change' },
                    { 'rule': 'pfirst_change' },
                    { 'rule': 'metadescription_change' },
                    { 'rule': 'h1_change' },
                    { 'rule': 'title_removed' },
                    { 'rule': 'h1_removed' },
                    { 'rule': 'metadescription_removed' },
                    { 'rule': 'not_indexable' },
                    { 'rule': 'status_change' },
                    { 'rule': 'total_score_change' },
                    { 'rule': 'lighthouse_fail_change' },
                ];
                // users, names and settings
                $http.get('/rest/sites/get', {
                    params: {
                        'websiteid': h.siteId(),
                    }
                }).then(function successCallback(res) {
                    if (res.data._id) {
                        $scope.user.site.users = res.data.users;
                        $scope.user.site.names = res.data.names;
                        $scope.alertnotifications = res.data.alertnotifications || [];
                        $scope.alertsettings = angular.extend({
                            'title_change': { 'sens': 0, 'users': [], 'active': false },
                            'pfirst_change': { 'sens': 0, 'users': [], 'active': false },
                            'metadescription_change': { 'sens': 0, 'users': [], 'active': false },
                            'h1_change': { 'sens': 0, 'users': [], 'active': false },
                            'title_removed': { 'sens': 0, 'users': [], 'active': false },
                            'h1_removed': { 'sens': 0, 'users': [], 'active': false },
                            'metadescription_removed': { 'sens': 0, 'users': [], 'active': false },
                        }, res.data.alertsettings);
                    }
                });
            },
            saveSettings: function() {
                $http.post('/rest/onpage/alertsettings.save', {
                    websiteid: h.siteId(),
                    'alertsettings': $scope.alertsettings
                });
            },
            addUser: function(userid, rulename) {
                var count = 0;
                $scope.alertsettings[rulename].users = $scope.alertsettings[rulename].users || [];
                for (var i = 0; i < $scope.alertsettings[rulename].users.length; i++) {
                    if ($scope.alertsettings[rulename].users[i].$oid == userid.$oid) {
                        $scope.alertsettings[rulename].users.splice(i, 1);
                        count = count + 1;
                    }
                }
                if (count == 0) {
                    $scope.alertsettings[rulename].users.push(userid);
                }
                this.saveSettings();
            }
        }
        // calculare rules and scores
        var fnRules = function(pages) {
            var stats = { 'done': 0, 'open': 0, 'total': 0, 'pages': 0 };
            var rules = {};
            var compare = {};
            for (var i in pages) {
                stats['pages']++;
                for (var y in pages[i]['rules']) {
                    if ($scope.onpage.rules[y]) {
                        stats['total']++;
                        stats['done'] = (pages[i]['rules'][y]) ? stats['done'] + 1 : stats['done'];
                        stats['open'] = (pages[i]['rules'][y]) ? stats['open'] : stats['open'] + 1;
                        rules[y] = rules[y] || { 'done': 0, 'open': 0, 'total': 0 }
                        rules[y]['done'] = (pages[i]['rules'][y]) ? rules[y]['done'] + 1 : rules[y]['done'];
                        rules[y]['open'] = (pages[i]['rules'][y]) ? rules[y]['open'] : rules[y]['open'] + 1;
                        rules[y]['total']++;
                        rules[y]['name'] = y;
                    }
                }
            }
            $scope.rules = rules;
            $scope.stats = stats;
        }
        var fnChart = function(history, field) {
            $scope.chart = {
                data: history,
                type: 'serial',
                theme: 'light',
                marginLeft: 0,
                marginRight: 0,
                marginTop: 10,
                fontFamily: 'Roboto',
                categoryField: 'date',
                rotate: false,
                pathToImages: 'vendor/amchart/images/',
                dataDateFormat: 'YYYY-MM-DD',
                categoryAxis: {
                    gridPosition: "start",
                    parseDates: true,
                    gridThickness: 0
                },
                valueAxes: [{
                    position: "left",
                    axisAlpha: 0,
                    labelsEnabled: true,
                    dashLength: 4,
                    color: '#dedede',
                }],
                graphs: [{
                    balloonText: "[[key]] 
 [[value]]",
                    "bullet": "round",
                    "bulletBorderAlpha": 1,
                    "bulletColor": "#FFFFFF",
                    "useLineColorForBulletBorder": true,
                    "fillAlphas": 0,
                    "lineThickness": 2,
                    "lineAlpha": 1,
                    "bulletSize": 7,
                    "title": "Expenses",
                    "valueField": field,
                    lineColor: '#FFC107',
                }],
            }
        }
        var fnInit = function() {
            if ($scope.viewrule) {
                $scope.view = 'pages';
                fnChart($rootScope._history, $scope.viewrule);
                if ($scope.viewrule != 'all') {
                    $scope.fnFilterRule($scope.viewrule);
                } else {
                    // fuck, ach ja ...
                    var pages = angular.copy($rootScope._pages);
                    var stats = { 'done': 0, 'open': 0, 'total': 0, 'pages': 0 };
                    $scope.rule = { 'title': 'All pages', 'textfalse': 'View all pages and scores' }
                    var compare = {};
                    for (var i in pages) {
                        stats['pages']++;
                        for (var y in pages[i]['rules']) {
                            stats['total']++;
                            stats['done'] = (pages[i]['rules'][y]) ? stats['done'] + 1 : stats['done'];
                            stats['open'] = (pages[i]['rules'][y]) ? stats['open'] : stats['open'] + 1;
                        }
                    }
                    $scope.stats = stats;
                }
            } else if ($scope.viewrulelabel) {
                if ($scope.viewrulelabel == 'assistent') {
                    $scope.view = 'assistent';
                    fnAssistent($rootScope._pages);
                } else if ($scope.viewrulelabel == 'duplicates') {
                    $scope.view = 'duplicates';
                    fnDuplicates($rootScope._pages);
                } else if ($scope.viewrulelabel == 'alerts') {
                    $scope.view = 'alerts';
                    $scope.oAlerts.init();
                } else if ($scope.viewrulelabel == 'changes') {
                    $scope.view = 'changes';
                    fnChanges.init();
                } else if ($scope.viewrulelabel == 'speed') {
                    $scope.view = 'speed';
                    fnSpeed($rootScope._pages);
                } else {
                    $scope.view = 'rules';
                    if ($scope.viewrulelabel != 'all') {
                        var ret = {};
                        for (var i in $scope.onpage.rules) {
                            if ($scope.onpage.rules[i].label == $scope.viewrulelabel) {
                                ret[i] = $scope.onpage.rules[i];
                            }
                        }
                        $scope.onpage = { 'rules': ret, 'rulelabels': $scope.onpage.rulelabels };
                    }
                    fnRules($rootScope._pages);
                    fnChart($rootScope._history, $scope.viewrulelabel);
                }
            }
        }
        $scope.$on('refreshonpagelist', function(e) {
            fnIndexList();
        });
        $scope.fnStar = function(curpage){
            curpage.properties.star = (curpage.properties.star == 1)?0:1;;
            $http.post('/rest/onpage/page.save', {
                websiteid: h.siteId(),
                pageid: curpage._id.$oid,
                fields: { 'properties.star': curpage.properties.star }
            });
            //$http.post("/rest/rank-tracker/edit", angular.extend({ 'meta.star': !ranking.meta.star, fields: ['meta.star'] }, fnSingle.getParams(ranking))).then(function successCallback(res) { $scope.getKeywords(); })
        }
        // get list
        var fnIndexList = function() {
            $scope.page.table.fnOrder('properties.opi', true)
            //allways get rule list
            $http.get('/rest/onpage/rules', { 'params': { 'websiteid': h.siteId(), 'lang': $scope.user.site.locale.lang } }).then(function successCallback(res) {
                angular.forEach(res.data.rules, function(v, k) {
                    v.enabled = !v.disabled;
                })
                $scope.onpage = res.data;
                // get pages and historu of cache
                if ($rootScope._pages && $rootScope.onpagestatus.data.status == 'done') {
                    $scope.pages = angular.copy($rootScope._pages);
                    $scope.history = angular.copy($rootScope._history);
                    fnInit();
                } else {
                    $http.get('/rest/onpage/list', {
                        params: {
                            websiteid: h.siteId(),
                        }
                    }).then(function successCallback(res) {
                        $rootScope._pages = res.data.data;
                        $rootScope._history = res.data.history;
                        $scope.pages = angular.copy($rootScope._pages);
                        $scope.history = angular.copy($rootScope._history);
                        fnInit();
                    });
                }
            });
        }
        if ($scope.custominit) {
            $scope.viewrule = $scope.custominit.viewrule;
            $scope.viewrulelabel = $scope.custominit.viewrulelabel;
        };
        fnIndexList();
        $scope.fnScanByUrl = function() {
            $scope.fnGoto('/rest/onpage/page.create?websiteid=' + h.siteId() + '&url=' + $scope.page.newurl);
        }
    }
]);
app.controller('onpagescan', ['$scope', '$http', '$rootScope', '$filter', '$location', 'h',
    function($scope, $http, $rootScope, $filter, $location, h) {
        //page_id
        var _pages;
        $scope.page = { 'pending': true, 'overlay': {}, 'charts': {}, 'q': '' };
        var _cb = {
            'redir_back_to_index': function() {
                $location.path('/onpage-seo/all/all');
            },
        }
        $scope.fnPctChange = function(o, n) {
            if (!o) {
                return '';
            }
            if (n == 0) {
                return '0%';
            }
            var pct = ((n - o) / o) * 100;
            var npct = $filter('number')(pct, 2);
            if (pct < 0) {
                return '' + npct + '%';
            }
            return '+ ' + npct + '%';
        }
        $scope.fnScoreToColour = function(o){
             if (!o) {
                return '';
            }
            if (o < 50) {
                return ''+o+'%';
            } 
            if (o < 75) {
                return ''+o+'%';
            }
            
            return ''+o+'%';
        }
        /* perform scan*/
        var fn = {
            info: function(cb) {
                /* get ruleset */
                $http.get('/rest/onpage/rules', { 'params': { 'websiteid': h.siteId(), 'lang': $scope.user.site.locale.lang } }).then(function successCallback(res) {
                    angular.forEach(res.data.rules, function(v, k) {
                        v.enabled = !v.disabled;
                    })
                    $scope.onpage = res.data;
                    $http.get('/rest/onpage/page.info', {
                        params: {
                            websiteid: h.siteId(),
                            pageid: $scope.pageid,
                        }
                    }).then(function successCallback(res) {
                        $scope.pageinfo = res.data.data;
                        cb();
                    });
                });
            },
            scan: function(cb) {
                $http.get('/rest/onpage/page.scan', {
                    params: {
                        websiteid: h.siteId(),
                        pageid: $scope.pageid,
                    }
                }).then(function successCallback(res) {
                    $scope.page.pending = false;
                    $scope.scan = res.data.data;
                    $scope.scan.avg = { 'all': 0, 'technical': 0, 'content': 0, 'mobile': 0, 'indexability': 0, 'social': 0 }
                    var l = $scope.scan.history.length;
                    angular.forEach($scope.scan.history, function(value, key) {
                        $scope.scan.avg['all'] += value.all / l
                        $scope.scan.avg['technical'] += value.technical / l
                        $scope.scan.avg['content'] += value.content / l
                        $scope.scan.avg['mobile'] += value.mobile / l
                        $scope.scan.avg['indexability'] += value.indexability / l
                        $scope.scan.avg['social'] += value.social / l
                    });
                    $scope.fnDateChart('history', 'all', { data: res.data.data.history }, false)
                    cb();
                });
            },
            stats: function(rules) {
                var stats = {};
                for (var i in $scope.onpage['rules']) {
                    var rule = $scope.onpage['rules'][i];
                    if (rules[i]) {
                        stats[rule.label] = stats[rule.label] + 1 || 1;
                    }
                }
            },
            searchconsole(cb) {
                var addslash = true;
                $http.get('/rest/searchconsole/report', {
                    params: { websiteid: h.siteId(), 'opportunity':'true','dimension': 'query', 'start': '90DAYSAGO', 'end': 'TODAY', 'metrics': 'clicks,ctr,position,impressions', 'report': 'searchAnalytics', 'addslash': addslash, 'filterdimension': "page", 'filterexpression': $scope.pageinfo.serps.url, 'filteroperator': "equals", limit: 6000 }
                }).then(function successCallback(res) {
                    if (res.data.data.length > 0) {
                        $scope.searchconsolequeries = res.data;
                    } else {
                        addslash = false;
                        $http.get('/rest/searchconsole/report', {
                            params: { websiteid: h.siteId(), 'opportunity':'true','dimension': 'query', 'start': '90DAYSAGO', 'end': 'TODAY', 'metrics': 'clicks,ctr,position,impressions', 'report': 'searchAnalytics', 'addslash': addslash, 'filterdimension': "page", 'filterexpression': $scope.pageinfo.serps.url, 'filteroperator': "equals", limit: 6000 }
                        }).then(function successCallback(res) {
                            $scope.searchconsolequeries = res.data;
                        })
                    }
                    $http.get('/rest/searchconsole/report', {
                        params: { websiteid: h.siteId(), 'dimension': 'date', 'start': '90DAYSAGO', 'end': 'TODAY', 'metrics': 'clicks,ctr,position,impressions', 'report': 'searchAnalytics', 'addslash': addslash, 'filterdimension': "page", 'filterexpression': $scope.pageinfo.serps.url, 'filteroperator': "equals" }
                    }).then(function successCallback(res) {
                        if (res.data.data.length > 0) {
                            $scope.searchconsoledates = res.data;
                            $scope.fnDateChart('searchconsole', 'clicks', $scope.searchconsoledates, true);
                        }
                    })
                })
            },
            inlinks() {
                // make summary for inlinks ... shoudl I do this in rest ??
                var r = {}
                var data = []
                for (var i in $scope.pageinfo.inlinks.links) {
                    var t = $scope.pageinfo.inlinks.links[i];
                    r[t.anchor] = r[t.anchor] + 1 || 1;
                }
                for (var i in r) {
                    data.push({ 'anchor': i, 'n': r[i] });
                }
                fnPieChart('inlinks', 'anchor', 'n', data)
            },
            interceptions() {
                // make summary for interceptions ... shoudl I do this in rest ??
                var r = {}
                var data = []
                for (var i in $scope.scan.scan['response_interceptions']) {
                    var t = $scope.scan.scan['response_interceptions'][i];
                    t['content-length'] = parseInt((parseInt(t['content-length']) > 0) ? t['content-length'] : 0);
                    r[t['content-type']] = r[t['content-type']] + t['content-length'] || t['content-length'];
                }
                for (var i in r) {
                    data.push({ 'content-type': i, 'total': r[i] });
                }
                fnPieChart('interceptions', 'content-type', 'total', data)
            },
            analytics() {
                $http.get('/rest/analytics4/report', {
                    params: { websiteid: h.siteId(), 'dimension': 'date', 'start': '30DAYSAGO', 'end': 'TODAY', 'metrics': 'sessions,totalUsers,screenPageViews,screenPageViewsPerSession,averageSessionDuration,newUsers,bounceRate,eventCount,eventCountPerUser', 'path': $scope.pageinfo.url, 'sort': 'date', 'sortorder': "ASCENDING" }
                }).then(function successCallback(res) {
                    $scope.analyticsdates = res.data;
                    $scope.fnDateChart('analytics', 'sessions', $scope.analyticsdates, true);
                })
                $http.get('/rest/analytics4/report', {
                    params: { websiteid: h.siteId(), 'dimension': 'sessionDefaultChannelGrouping', 'start': '30DAYSAGO', 'end': 'TODAY', 'metrics': 'sessions,totalUsers,screenPageViews,screenPageViewsPerSession,averageSessionDuration,newUsers,bounceRate,eventCount,eventCountPerUser', 'path': $scope.pageinfo.url, 'sort': 'users', 'sortorder': "DESCENDING" }
                }).then(function successCallback(res) {
                    $scope.analyticschannels = res.data;
                })
            },
        }
        fn.info(
            function() {
                fn.stats($scope.pageinfo.rules);
                fn.analytics();
                fn.searchconsole();
                fn.inlinks();
            }
        );
        fn.scan(
            function() {
                fn.interceptions();
            }
        );
        var fnPieChart = function(name, field, value, data) {
            $scope.page.charts[name] = {
                data: data.slice(0, 9),
                type: 'pie',
                theme: 'light',
                marginLeft: 0,
                marginRight: 0,
                marginTop: 10,
                fontFamily: 'Roboto',
                categoryField: field,
                pathToImages: 'vendor/amchart/images/',
                "precision": 0,
                "decimalSeparator": ",",
                "thousandsSeparator": ".",
                legend: {
                    enabled: true,
                    position: 'right',
                    autoMargins: false,
                    marginRight: 100,
                },
                titleField: field,
                valueField: value,
                labelRadius: 5,
                radius: '42%',
                innerRadius: '60%',
                labelText: '[[title]]',
            }
        }
        $scope.fnDateChart = function(name, field, data, reverse) {
            data.field = field;
            data.reverse = reverse
            var opts = {
                'searchconsole': { 'clicks': true, 'ctr': true, 'position': false, 'impressions': true },
                'analytics': { 'users': true, 'pageviews': true, 'pageviewsPerSession': false, 'avgSessionDuration': true, 'percentNewSessions': true, 'bounceRate': true, 'goalCompletionsAll': true, 'goalValueAll': true },
                'history': { 'all': false }
            };
            var dateformats = { 'searchconsole': 'YYYY-MM-DD', 'analytics': 'YYYYMMDD', 'history': 'YYYY-MM-DD' };
            var datefields = { 'searchconsole': 'date', 'analytics': 'date', 'history': 'date' };
            var colors = { 'searchconsole': '#007bff', 'analytics': '#28a745', 'history': '#28a745' };
            datareverse = opts[name][field];
            var c = {
                data: data.data,
                type: 'serial',
                theme: 'light',
                marginLeft: 0,
                marginRight: 0,
                marginTop: 10,
                fontFamily: 'Roboto',
                categoryField: datefields[name],
                rotate: false,
                dataDateFormat: dateformats[name],
                categoryAxis: {
                    gridPosition: "start",
                    parseDates: true,
                    gridThickness: 0
                },
                valueAxes: [{
                    position: "left",
                    axisAlpha: 0,
                    labelsEnabled: true,
                    dashLength: 4,
                    color: '#dedede',
                }],
                graphs: [{
                    balloonText: " 
 [[value]]",
                    "bullet": "round",
                    "bulletBorderAlpha": 1,
                    "bulletColor": "#FFFFFF",
                    "useLineColorForBulletBorder": true,
                    "fillAlphas": 0,
                    "lineThickness": 2,
                    "lineAlpha": 1,
                    "bulletSize": 7,
                    "title": "Expenses",
                    "valueField": field,
                    lineColor: colors[name],
                }],
            }
            if (name == 'history') {
                c.autoMargins = false;
                c.marginLeft = 0;
                c.marginRight = 0;
                c.marginTop = 0;
                c.marginBottom = 0;
                c.valueAxes[0].gridAlpha = 0;
                c.valueAxes[0].axisAlpha = 0;
                c.valueAxes[0].color = '#ffffff';
                c.valueAxes[0].dashLength = 0;
                c.categoryAxis.gridAlpha = 0;
                c.categoryAxis.axisAlpha = 0;
            }
            $scope.page.charts[name] = c;
        }
        $scope.fnHide = function(type) {
            angular.element('#' + type).addClass('d-none');
        }
        $scope.fnExpose = function(bounds, type) {
            angular.element('#' + type).removeClass('d-none');
            if (bounds.h > 0) {
                var overlay = {}
                if (type == 'mobile') {
                    var width = document.getElementById(type).clientWidth;
                    var scale = 360 / width;
                } else {
                    var width = document.getElementById(type).clientWidth;
                    var scale = 1366 / width;
                }
                var scaledbounds = { l: bounds.l / scale, t: bounds.t / scale, w: bounds.w / scale, h: bounds.h / scale };
                overlay.c = { 'top': scaledbounds.t, 'left': scaledbounds.l, 'width': scaledbounds.w, 'height': scaledbounds.h }
                overlay.tl = { 'width': scaledbounds.l + scaledbounds.w / 2, 'height': scaledbounds.t }
                overlay.tr = { 'width': width - (scaledbounds.l + scaledbounds.w / 2), 'height': scaledbounds.t }
                overlay.bl = { 'width': scaledbounds.l + scaledbounds.w / 2, 'top': scaledbounds.t + scaledbounds.h }
                overlay.br = { 'width': width - (scaledbounds.l + scaledbounds.w / 2), 'top': scaledbounds.t + scaledbounds.h }
                overlay.lct = { 'width': scaledbounds.l, 'top': scaledbounds.t, 'height': scaledbounds.h / 2 }
                overlay.lcb = { 'width': scaledbounds.l, 'top': scaledbounds.t + scaledbounds.h / 2, 'height': scaledbounds.h / 2 }
                overlay.rct = { 'width': width - (scaledbounds.l + scaledbounds.w), 'top': scaledbounds.t, 'height': scaledbounds.h / 2 }
                overlay.rcb = { 'width': width - (scaledbounds.l + scaledbounds.w), 'top': scaledbounds.t + scaledbounds.h / 2, 'height': scaledbounds.h / 2 }
                $scope.page.overlay[type] = overlay;
                var scrolltop = ((bounds.t / scale) - 100 < 0) ? 0 : (bounds.t / scale - 100);
                angular.element('#' + type).stop(true, true).animate({ 'scrollTop': scrolltop + "px" }, 400)
            }
        }
        $scope.fnSaveRules = function() {
            var disabled_rules = Object.keys($scope.onpage.rules).reduce(function(acc,cur){
                if(!$scope.onpage.rules[cur].enabled){
                    acc[cur] = true;
                }
                return acc;
            },{});
            $http.post('/rest/onpage/rules.disabled.set', {
                'websiteid': h.siteId(),
                'disabled_rules': disabled_rules,
            }).then(function successCallback(res) {
                _cb[res.data.cb]();
            }); 
        }
        $scope.fnSavePage = function() {
            $http.post('/rest/onpage/page.save', {
                websiteid: h.siteId(),
                pageid: $scope.pageid,
                fields: { 'q': $scope.pageinfo.q, 'qneg': $scope.pageinfo.qneg }
            }).then(function successCallback(res) {
                _cb[res.data.cb]();
            });
        }
        $scope.fnDeletePage = function() {
            $http.post('/rest/onpage/page.delete', {
                websiteid: h.siteId(),
                pageid: $scope.pageid,
            }).then(function successCallback(res) {
                _cb[res.data.cb]();
            });
        }
    }
]);
app.controller('speedtest', ['$scope', '$http', '$rootScope', '$filter', '$window', 'h',
    function($scope, $http, $rootScope, $filter, $window, h) {
        var TARGET_TTFB = 64;
        $scope.speedtestpage = { 'state': 'init', 'url': $scope.pageinfo.url };
        $scope.t = { 'ttfb': 'TTFB', 'dns': 'DNS', 'dominteractive': 'DOM Interactive', 'domcontentloaded': 'DOM Content Loaded', 'onload': 'On Load', 'firstcontentfulfulpaint': 'FCP', 'largestcontentfulpaint': 'LCP', 'visualReady': 'visual Ready' };
        // no need to bind everything
        $scope.do = function(o, f) {
            speedtest[f]();
        }
        $scope.getColor = function(v) {
            return (v < 50) ? '#dc3545' : (v < 75) ? '#FF9800' : '#28a745';
        }
        //main
        var speedtest = {
            init: function() {
                if (!$scope.speedtest) {
                    $scope.speedtestpage.state = 'pending';
                    $http.get('https://pdfssl1.seoserver.nl/speedtest/scan.php', {
                        params: {
                            'url': $scope.speedtestpage.url,
                        }
                    }).then(function successCallback(response) {
                        if (response.data.error) {
                            $scope.speedtestpage.state = 'error';
                        } else {
                            $scope.speedtestpage.state = 'done';
                            $scope.speedtest = response.data;
                            $scope.speedtest.timeline = {};
                            $scope.speedtest.date = new Date();
                            speedtest._totaltimeTTFB();
                            speedtest._firstPage();
                            speedtest._createResourceTimelineFromEventInterest('BlockingJavaScript')
                            speedtest._createResourceTimelineFromEventInterest('nonBlockingJavaScript')
                            speedtest._createResourceTimelineFromEventInterest('BlockingCss')
                            speedtest._createResourceTimelineFromResourceInterest('ImageNotLazy')
                            speedtest._createResourceTimelineFromResourceInterest('IncorrectImageScale')
                            speedtest._createResourceTimelineFromResourceInterest('BlockingFont')
                            speedtest._createResourceTimelineFromResourceInterest('NotCacheAble')
                            speedtest._createResourceTimelineFromResourceInterest('NotCompressed')
                            speedtest._createResourceTimelineFromResourceInterest('NotHttp2')
                            speedtest._createFilmstrip()
                            // estimated savings
                            $scope.speedtest.timeline['NotCompressed'].est_saving *= .15 /*15% faster*/
                            $scope.speedtest.timeline['NotHttp2'].est_saving *= .36 /*36% faster*/
                            var scores = {
                                'firstcontentfulfulpaint': score.computeLogNormalScore(speedtest._getTimingByKey('firstcontentfulfulpaint'), 600, 2200),
                                'largestcontentfulpaint': score.computeLogNormalScore(speedtest._getTimingByKey('largestcontentfulpaint'), 800, 2600),
                                'visualReady': score.computeLogNormalScore(speedtest._getTimingByKey('visualReady'), 3000, 4000),
                                'totaltimeTTFB': score.computeLogNormalScore($scope.speedtest.timeline['totaltimeTTFB'].est_saving, 400, 600),
                                'NotHttp2': score.computeLogNormalScore($scope.speedtest.timeline['NotHttp2'].est_saving, 400, 600),
                                'firstPage': score.computeLogNormalScore($scope.speedtest.timeline['firstPage'].est_saving, 80, 160),
                                'BlockingJavaScript': score.computeLogNormalScore($scope.speedtest.timeline['BlockingJavaScript'].est_saving, 50, 100),
                                'nonBlockingJavaScript': score.computeLogNormalScore($scope.speedtest.timeline['nonBlockingJavaScript'].est_saving, 1000, 2000),
                                'BlockingCss': score.computeLogNormalScore($scope.speedtest.timeline['BlockingCss'].est_saving, 60, 120),
                                'BlockingFont': score.computeLogNormalScore($scope.speedtest.timeline['BlockingFont'].est_saving, 50, 100),
                                'ImageNotLazy': score.computeLogNormalScore($scope.speedtest.timeline['ImageNotLazy'].est_saving, 150, 300),
                                'IncorrectImageScale': score.computeLogNormalScore($scope.speedtest.timeline['ImageNotLazy'].est_saving, 150, 300),
                                'NotCompressed': score.computeLogNormalScore($scope.speedtest.timeline['NotCompressed'].est_saving, 150, 300),
                                'NotCacheAble': score.computeLogNormalScore($scope.speedtest.timeline['NotCacheAble'].est_saving, 150, 300),
                            }
                            $scope.scores = {
                                'total': Math.round((scores.firstPage + scores.firstcontentfulfulpaint + scores.largestcontentfulpaint + scores.visualReady + scores.NotHttp2 + scores.BlockingJavaScript + scores.BlockingCss + scores.BlockingFont) / 8),
                                'server': Math.round((scores.firstPage) / 1),
                                'paint': Math.round((scores.firstcontentfulfulpaint + scores.largestcontentfulpaint + scores.BlockingJavaScript + scores.BlockingCss + scores.BlockingFont) / 5),
                                'webflow': Math.round((scores.ImageNotLazy + scores.totaltimeTTFB + scores.NotCacheAble + scores.NotCompressed + scores.NotHttp2 + scores.nonBlockingJavaScript) / 6),
                                'part': scores
                            }
                            $scope.speedtestpage.state = 'done';
                        }
                    });
                }
            },
            _getTimingByKey: function(key) {
                return ($scope.speedtest.timing.filter(function(a) { return (a['name'] === key) })[0] || { 'ts': 0 }).ts;
            },
            _createFilmstrip: function() {
                var n = document.querySelector('#filmstrip').clientWidth / 55;
                $scope.filmstrip = [];
                // fake ts ergens in midden
                for (var i = 0; i < n; i++) {
                    var y = ($scope.speedtest.ts.last / n) * i;
                    var filmstrip = $scope.speedtest.filmstrip.reduce(function image(acc, cur) {
                        return ((Math.abs(cur.ts - y) < Math.abs(acc.ts - y)) && cur.ts < y) ? cur : acc;
                    })
                    $scope.filmstrip.push(filmstrip.args.snapshot);
                }
            },
            _firstPage: function() {
                var firstPage = $scope.speedtest.resources[0]
                firstPage.timing = firstPage.timing || { receiveHeadersEnd: TARGET_TTFB }
                var saving = (firstPage.timing.receiveHeadersEnd > TARGET_TTFB) ? firstPage.timing.receiveHeadersEnd - TARGET_TTFB : 0
                var timeline = {}
                timeline[firstPage.url] = { 'resources': [firstPage], 'totaltime': firstPage.timing.receiveHeadersEnd }
                $scope.speedtest.timeline['firstPage'] = { 'timeline': timeline, 'est_saving': saving, 'totaltime': firstPage.duration, 'ttfb': speedtest._getTimingByKey('ttfb') }
            },
            _totaltimeTTFB: function() {
                // calc ttfb if larger then good ttfp, deep copy resouces and overwrite duration
                var resourceclone = JSON.parse(JSON.stringify($scope.speedtest.resources));
                var cutoff = speedtest._getTimingByKey('visualReady');
                var ResourcesOfInterestUrls = resourceclone.reduce(function(acc, resource) {
                    resource.timing = resource.timing || { receiveHeadersEnd: TARGET_TTFB }
                    if (resource.timing.receiveHeadersEnd > TARGET_TTFB && resource.endTime < cutoff) {
                        resource.endTime = resource.startTime + resource.timing.receiveHeadersEnd - TARGET_TTFB
                        resource.duration = resource.timing.receiveHeadersEnd - TARGET_TTFB
                        acc.push(resource)
                    }
                    return acc;
                }, []);
                var timeline = ResourcesOfInterestUrls.reduce(function(a, b) {
                    a[b.url] = a[b.url] || { 'resources': [], 'totaltime': 0 }
                    return a;
                }, {})
                timeline = h.__mergeResources(timeline, ResourcesOfInterestUrls);
                $scope.speedtest.timeline['totaltimeTTFB'] = h.__createTimeLine(timeline);
            },
            _createResourceTimelineFromResourceInterest: function(Interest) {
                var ResourcesOfInterestUrls = $scope.speedtest.resources.filter(function(resource) {
                    return resource.interest.includes(Interest)
                });
                // create timeline from Resources
                var timeline = ResourcesOfInterestUrls.reduce(function(a, b) {
                    a[b.url] = a[b.url] || { 'resources': [], 'totaltime': 0 }
                    return a;
                }, {})
                timeline = h.__mergeResources(timeline, ResourcesOfInterestUrls);
                $scope.speedtest.timeline[Interest] = h.__createTimeLine(timeline);
            },
            _createResourceTimelineFromEventInterest: function(EventInterest) {
                var allEvents = $scope.speedtest.eventsOfInterest.filter(function(event) {
                    return event.interest[0] == EventInterest
                });
                // creat timeline from events
                var timeline = allEvents.reduce(function(a, b) {
                    a[b.url] = a[b.url] || { 'resources': [], 'totaltime': 0 }
                    a[b.url].resources.push(b);
                    return a;
                }, {})
                timeline = h.__mergeResources2(timeline, $scope.speedtest.resources);
                $scope.speedtest.timeline[EventInterest] = h.__createTimeLine(timeline)
            }
        }
        //helpers
        var h = {
            __mergeResources: function(timeline, allResources) {
                // merge resources to timeline, url must match and type not html
                angular.forEach(timeline, function(v, k) {
                    var myResources = Object.values(allResources).filter(function(e) {
                        return e.url == k;
                        //return e.url == k && e.mimeType != 'text/html';
                    })
                    timeline[k].resources = timeline[k].resources.concat(myResources);
                    timeline[k].totaltime = timeline[k].resources.reduce(function(acc, cur) { return acc + cur.duration }, 0);
                });
                return timeline;
            },
            __mergeResources2: function(timeline, allResources) {
                // merge resources to timeline, url must match and type not html
                angular.forEach(timeline, function(v, k) {
                    var myResources = Object.values(allResources).filter(function(e) {
                        //return e.url == k;
                        return e.url == k && e.mimeType != 'text/html';
                    })
                    timeline[k].resources = timeline[k].resources.concat(myResources);
                    timeline[k].totaltime = timeline[k].resources.reduce(function(acc, cur) { return acc + cur.duration }, 0);
                });
                return timeline;
            },
            __mergeTiming: function(aTiming) {
                // sort timing (needer for merge)
                aTiming = aTiming.sort(function(a, b) { return a[0] - b[0] })
                // merge overlapping time
                var mergedtime = aTiming.reduce(function(combined, next) {
                    if (!combined.length || combined[combined.length - 1][1] < next[0]) combined.push(next);
                    else {
                        var prev = combined.pop();
                        combined.push([prev[0], Math.max(prev[1], next[1])]);
                    }
                    return combined;
                }, []);
                // calculate total time
                var totaltime = mergedtime.reduce(function(a, b) {
                    return (a + b[1] - b[0]);
                }, 0);
                return totaltime;
            },
            __createTimeLine(timeline) {
                // fetch array of timings [[1,4],[2,3]] etc
                var aTiming = [];
                angular.forEach(timeline, function(v, url) {
                    var tmp = v.resources.reduce(function(a, b) {
                        a.push([b.startTime, b.endTime]);
                        return a;
                    }, []);
                    aTiming = aTiming.concat(tmp);
                });
                var est_saving = h.__mergeTiming(aTiming);
                return { 'timeline': timeline, 'est_saving': est_saving, 'n_timeranges': aTiming.length }
            },
        }
        //score
        var score = {
            computeLogNormalScore: function(measuredValue, diminishingReturnsValue, medianValue) {
                var distribution = this.getLogNormalDistribution(
                    medianValue,
                    diminishingReturnsValue
                );
                let score = distribution.computeComplementaryPercentile(measuredValue);
                score = Math.min(1, score);
                score = Math.max(0, score);
                return Math.round(score * 100);
            },
            erf: function(x) {
                var sign = Math.sign(x);
                x = Math.abs(x);
                var a1 = 0.254829592;
                var a2 = -0.284496736;
                var a3 = 1.421413741;
                var a4 = -1.453152027;
                var a5 = 1.061405429;
                var p = 0.3275911;
                var t = 1 / (1 + p * x);
                var y = t * (a1 + t * (a2 + t * (a3 + t * (a4 + t * a5))));
                return sign * (1 - y * Math.exp(-x * x));
            },
            getLogNormalDistribution: function(median, falloff) {
                var location = Math.log(median);
                // The "falloff" value specified the location of the smaller of the positive
                // roots of the third derivative of the log-normal CDF. Calculate the shape
                // parameter in terms of that value and the median.
                var logRatio = Math.log(falloff / median);
                var shape = Math.sqrt(1 - 3 * logRatio - Math.sqrt((logRatio - 3) * (logRatio - 3) - 8)) / 2;
                return {
                    computeComplementaryPercentile(x) {
                        var standardizedX = (Math.log(x) - location) / (Math.SQRT2 * shape);
                        return (1 - score.erf(standardizedX)) / 2;
                    },
                };
            }
        }
        //stupid resize
        angular.element($window).bind('resize', function() {
            speedtest._createFilmstrip();
            $scope.$apply()
        });
    }
]);
app.controller('planning', ['$scope', '$timeout', '$http', '$rootScope', '$filter', 'h',
    function($scope, $timeout, $http, $rootScope, $filter, h) {
        $scope.curtemplate = {};
        $scope.categorys = {};
        var aTemplateIds = [];
        // do
        $scope.do = function(obj, method, param) {
            if (obj == 'users') {
                return users[method](param);
            } else if (obj == 'taken') {
                return taken[method](param);
            } else if (obj == 'taak') {
                return taak[method](param);
            } else if (obj == 'fnTemplates') {
                return fnTemplates[method](param);
            }
        }
        var users = {
            userList: function() {
                $http.get('/rest/user/reseller.site.list', {
                    params: {
                        websiteid: h.siteId(),
                    }
                }).then(function successCallback(res) {
                    $scope.users = res.data;
                });
            },
            matchUser: function(UserId) {
                for (var i in $scope.users) {
                    if ($scope.users[i]._id.$oid == UserId) {
                        return $scope.users[i].name;
                    }
                }
                return '';
            }
        }
        var taken = {
            'data': { taken: [] },
            init: function() {
                $scope.datestring = ($rootScope.reportdates || { datestring: false }).datestring || new Date().toLocaleString('default', { year: 'numeric', 'month': 'long' })
                //tming could be wrong ... callback?
                users.userList();
                taken.getTaken();
            },
            setDateString: function(s) {
                $scope.datestring = s;
                taken.getStats();
            },
            fnReset: function(mtype) {
                console.log(mtype);
                var aantal = (mtype.type == 'taak') ? { 'aantal': 1 } : {};
                $scope.curtaak = angular.extend({ 'type': "taak", 'repeat': "", 'status': 'open', 'datum': new Date(), 'workflow': [{ 'uren': 0, 'user_id': $rootScope.user._id.$oid + "" }] }, mtype, aantal)
                console.log($scope.curtaak);
                /*  $scope.curtaak = { 'aantal': 1, 'type': "taak", 'repeat': "", 'status': 'open', 'datum': new Date(), 'workflow': [{ 'uren': 0, 'user_id': $rootScope.user._id.$oid + "" }] };
                 
                  if (mtype == 'workflow') {
                      $scope.curtaak = { 'type': "workflow", 'repeat': "", 'status': 'open', 'datum': new Date(), 'workflow': [{ 'uren': 0, 'user_id': $rootScope.user._id.$oid + "" }] };
                  } else {
                      $scope.curtaak = { 'aantal': 1, 'type': "taak", 'repeat': "", 'status': 'open', 'datum': new Date(), 'workflow': [{ 'uren': 0, 'user_id': $rootScope.user._id.$oid + "" }] };
                  }*/
            },
            getTaken: function() {
                $http.get("/rest/planning/planning.list", {
                    params: {
                        websiteid: h.siteId(),
                    }
                }).then(function successCallback(res) {
                    taken.data = res.data;
                    $scope.taken = taken.data.taken;
                    fnTemplates.init();
                });
            },
            getStats: function() {
                console.log('GET STATS');
                var categories = {};
                var overzicht = {};
                var urenPerUser = {};
                //loop planning 
                taken.data.taken.forEach(function(planning, k) {
                    //date conversion
                    planning.datum = new Date(planning.datum);
                    planning.datestring = planning.datum.toLocaleString('default', { year: 'numeric', 'month': 'long' })
                    //overichten aanmaken
                    overzicht[planning.datestring] = overzicht[planning.datestring] || { 'workflow': { 'open': 0, 'done': 0, 'active': 0 }, 'taak': { 'open': 0, 'done': 0 } }
                    // workflow
                    if (planning.type == 'workflow') {
                        planning.workflow.forEach(function(taak) {
                            // opverzicht[open|done] optellen
                            //er is een category
                            if (planning.template_id && aTemplateIds.indexOf(planning.template_id['$oid']) > -1) {
                                categories[planning.category] = { 'order': 1, 'name': planning.category, 'type': 'workflow' };
                                overzicht[planning.datestring][planning.category] = overzicht[planning.datestring][planning.category] || { 'open': 0, 'done': 0, 'active': 0 }
                                overzicht[planning.datestring][planning.category][planning.status] += (taak.uren * 1)
                            } else {
                                categories['workflow'] = { 'order': 2, 'name': 'workflow', 'type': 'workflow', 'translate': true };
                                overzicht[planning.datestring].workflow[planning.status] += (taak.uren * 1)
                                console.log(taak.uren);
                                console.log(planning.status);
                            }
                            if (planning.datestring == $scope.datestring) {
                                // user per user
                                urenPerUser[taak.user_id] = urenPerUser[taak.user_id] || 0
                                urenPerUser[taak.user_id] += (taak.status == 'done') ? taak.uren * 1 : 0;
                            }
                        });
                        // taak
                    } else {
                        // opverzicht[open|done] optellen
                        if (planning.template_id && aTemplateIds.indexOf(planning.template_id['$oid']) > -1) {
                            categories[planning.category] = { 'order': 1, 'name': planning.category, 'type': 'taak', 'translate': false };
                            overzicht[planning.datestring][planning.category] = overzicht[planning.datestring][planning.category] || { 'open': 0, 'done': 0 }
                            overzicht[planning.datestring][planning.category][planning.status] += (planning.aantal * 1)
                        } else {
                            categories['taak'] = { 'order': 2, 'name': 'taak', 'type': 'taak', 'translate': true };
                            overzicht[planning.datestring].taak[planning.status] += (planning.aantal * 1)
                        }
                    }
                });
                $scope.categories = Object.values(categories);
                $scope.overzicht = overzicht;
                charts.piechart(urenPerUser);
            }
        }
        var fnTemplates = {
            init: function() {
                fnTemplates.list();
            },
            list: function() {
                $http.get('/rest/planning/template.list', {
                    params: {
                        websiteid: h.siteId(),
                    }
                }).then(function successCallback(res) {
                    $scope.taaktemplates = res.data;
                    aTemplateIds = res.data.map(function(c) { return c.template_id['$oid'] });
                    taken.getStats();
                });
            },
            pre_edit: function() {
                $scope.fnModal('planning/modal.pre_edit');
            },
            create: function() {
                $http.post('/rest/planning/template.save', { 'template': $scope.curtemplate }).then(function successCallback(res) {
                    $scope.fnCloseModal();
                    fnTemplates.list();
                });
            },
            save: function(template) {
                $http.post('/rest/planning/template.save', { websiteid: h.siteId(), 'template': template }).then(function successCallback(res) {
                    $scope.fnCloseModal();
                    fnTemplates.list();
                });
            },
            delete: function(template) {
                $http.post('/rest/planning/template.delete', template).then(function successCallback(res) {
                    $scope.fnCloseModal();
                    fnTemplates.list();
                });
            },
        }
        var taak = {
            addWorkFlow: function() {
                $scope.curtaak.workflow.push({ user_id: $rootScope.user._id.$oid + "" });
            },
            removeWorkFlow: function(index) {
                $scope.curtaak.workflow.splice(index, 1);
            },
            useTemplate: function(curtaak) {
                $scope.curtaak = curtaak;
            },
            addCurtaak: function(taak) {
                $http.post('/rest/planning/planning.add', angular.extend($scope.curtaak, { websiteid: h.siteId(), })).then(function successCallback(res) {
                    taken.getTaken();
                });
            },
            updateCurtaak: function(taak) {
                $http.post('/rest/planning/planning.update', angular.extend($scope.curtaak, { websiteid: h.siteId(), })).then(function successCallback(res) {
                    taken.getTaken();
                });
            },
            editTaakStatus: function(taak) {
                taak.status = (taak.status == 'done') ? 'open' : 'done';
                $http.post('/rest/planning/planning.update', angular.extend(taak, { websiteid: h.siteId(), })).then(function successCallback(res) {
                    taken.getTaken();
                });
            },
            editTaak: function(taak) {
                $scope.curtaak = taak;
                $scope.fnModal('planning/modal.' + taak['type']);
            },
            setVoortgang: function([taak, index]) {
                $http.post('/rest/planning/planning.progress', { 'taak': taak, 'index': index, websiteid: h.siteId() }).then(function successCallback(res) {
                    taken.getTaken();
                });
            },
            removeCurtaak: function(taak) {
                $http.post('/rest/planning/planning.delete', angular.extend($scope.curtaak, { websiteid: h.siteId(), })).then(function successCallback(res) {
                    taken.getTaken();
                });
            },
        }
        var charts = {
            piechart: function(urenPerUser) {
                var colors = h.colors();
                // pie data zetten
                var piedata = Object.keys(urenPerUser).reduce(function(acc, cur, idx) {
                    acc.push({ "color": colors[idx], label: users.matchUser(cur), data: urenPerUser[cur] })
                    return acc;
                }, []);
                $scope.piechart = {
                    data: piedata,
                    type: 'pie',
                    marginLeft: 0,
                    marginRight: 0,
                    marginTop: 0,
                    categoryField: 'label',
                    colorField: 'color',
                    "precision": 0,
                    "decimalSeparator": ",",
                    "thousandsSeparator": ".",
                    titleField: 'label',
                    valueField: 'data',
                    labelRadius: 5,
                    radius: '42%',
                    innerRadius: '60%',
                    labelText: '[[title]]',
                }
            }
        }
        taken.init();
    }
]);
app.controller('reseller', ['$scope', '$timeout', '$http', '$rootScope', '$location', '$anchorScroll', '$filter', 'h',
    function($scope, $timeout, $http, $rootScope, $location, $anchorScroll, $filter, h) {
        $scope.page = {
            newadmin: {},
            resetpaymentwarning: false,
            testemail: $rootScope.user.email
        };
        $scope.adminroles = [
            { 'role': 2, 'name': 'administrator' },
            { 'role': 3, 'name': 'team member' },
        ]
        $scope.roles = [
            { 'role': 2, 'name': 'white label admin' },
            { 'role': 3, 'name': 'administrator' },
            //{ 'role': 4, 'name': 'site owner' },
            { 'role': 5, 'name': 'team member' },
            { 'role': 6, 'name': 'guest' },
        ]
        $scope.do = function(obj, method, param) {
            if (obj == 'fnReseller') {
                fnReseller[method](param);
            } else if (obj == 'fnPage') {
                fnPage[method](param);
            }
        }
        var fnReseller = {
            get: function() {
                $http.get('/rest/reseller/reseller.get.fromuser').then(function successCallback(res) {
                    if (res.data._id) {
                        $scope.page.tab = 'edit';
                        $scope.user.reseller = res.data;
                    } else {
                        $scope.page.tab = 'intro';
                    }
                });
                $http.get('/rest/locale/language.list').then(function successCallback(res) {
                    $scope.languages = res.data;
                });
                $http.get('/rest/locale/country.list').then(function successCallback(res) {
                    $scope.countries = res.data;
                });
                $http.get('/rest/global/tools.list').then(function successCallback(res) {
                    $scope.tools = res.data;
                });
            },
            'add': function() {
                $http.post('/rest/reseller/reseller.admin.add',
                    $scope.page.newadmin
                ).then(function successCallback(res) {
                    fnReseller.get();
                });
            },
            'testemail': function() {
                $http.post('/rest/reseller/reseller.email.test', { 'email': $scope.page.testemail });
            },
            'delete': function(admin) {
                $http.post('/rest/reseller/reseller.admin.delete',
                    admin
                ).then(function successCallback(res) {
                    fnReseller.get();
                });
            },
            'update': function(reseller) {
                $http.post('/rest/reseller/reseller.update',
                    $scope.user.reseller
                ).then(function successCallback(res) {
                    fnReseller.get();
                });
            },
            'invoice':function(key){
                $scope.fnGoto('http://pdf1.seoserver.nl/invoice/marketingtracer.php?reseller_id='+$scope.user.reseller._id.$oid+'&key='+key)
            },
            'resetbilling':function(){
                $http.post('/rest/pay/reseller.reset',
                    $scope.user.reseller
                ).then(function successCallback(res) {
                    fnReseller.get();
                });
            }
        }
        fnReseller.get();
    }
]);
app.controller('insights', ['$scope', '$timeout', '$http', '$rootScope', '$filter', 'h',
    function($scope, $timeout, $http, $rootScope, $filter, h) {
        var colorindex = 0;
        $scope.page = {
            tab: 'managers'
        }
        $scope.config = {
            analytics: {
                name: 'analytics visitors',
                dataset: 'analytics',
                metrickey: 'analytics',
                metrics: ['sessions', 'users', 'pageviews', 'pageviewsPerSession', 'avgSessionDuration', 'percentNewSessions', 'bounceRate', 'goalValueAll', 'goalConversionRateAll', 'goalCompletionsAll']
            },
            adwords: {
                name: 'adwords',
                dataset: 'adwords',
                metrickey: 'googlexads',
                metrics: ['Clicks', 'Impressions', 'Cost', 'AverageCpc', 'Ctr', 'Conversions', 'CostPerConversion', 'ConversionRate', 'ConversionValue', 'roas']
            },
            searchconsole: {
                name: 'searchconsole',
                dataset: 'searchconsole',
                metrickey: 'searchconsole',
                metrics: ['clicks', 'position', 'impressions', 'ctr']
            }
        };
        $scope.report = $scope.config[$scope.urlreport];
        $scope.gloMetrics = h.metrics($scope.report.metrickey);
        /* TEMP => RULES SHOULD BE FETCHED!!*/
        var _rules = [{
            'metric': 'avgSessionDuration',
            'comp': 'lt',
            'val': 70
        }, {
            'metric': 'bounceRate',
            'comp': 'gt',
            'val': 60
        }, {
            'metric': 'sessions',
            'comp': 'drop',
            'val': 30
        }];
        var rules = _rules.reduce((acc, item) => {
            acc[item.metric] = item;
            return acc;
        }, {});
        $scope.ruleopts = [{ v: 'gt', n: 'greater then (abs value)' },{ v: 'lt', n: 'less then (abs value)' },{ v: 'drop', n: 'drop (percentage)' },{ v: 'bump', n: 'increase (percentage)' }]
        $scope.rules = _rules;
        $scope.fnMatchesRule = function(metric, value, valueprev) {
            var rule = $scope.rules.find(function(o) { return o.metric === metric });
            if (rule) {
                console.log(rule);
                // less then abs value
                if (rule.comp == 'lt' && value < rule.val) {
                    return 'bg-warning'
                }
                if (rule.comp == 'gt' && value > rule.val) {
                    return 'bg-warning'
                }
                if (rule.comp == 'drop' && (((valueprev - value) / value) * 100) > rule.val) {
                    return 'bg-warning'
                }
                return 'bg-white rulepass';
            } else {
                return 'bg-white norule';
            }
        }
        // filter sites per user
        var fnFilterUser = function(id) {
            //var sites = angular.copy($scope.sites);
            sites = $scope.sites.filter(function(v) {
                for (var i in v.users) {
                    if (v.users[i].user_id.$oid == id.$oid) {
                        return true
                    }
                }
                return false;
            });
            return sites;
        }
        $scope.fnPctChange = function(o, n, reversesign) {
            if (n == 0) {
                return '0%';
            }
            var pct = ((n - o) / o) * 100;
            var npct = $filter('number')(pct, 2);
            if (reversesign) {
                if (pct < 0) {
                    return '' + npct + '%';
                }
                return '+ ' + npct + '%';
            }
            if (pct < 0) {
                return '' + npct + '%';
            }
            return '+ ' + npct + '%';
        }
        $http.get("/rest/insights/list", {
        }).then(function successCallback(res) {
            $scope.sites = res.data;
            $scope.avg = fnCalcAvg($scope.sites);
            // get chart data
            $http.get('/rest/reseller/insights.get').then(function successCallback(res) {
                $scope.insights = res.data[$scope.report.dataset];
                fnLineChart('c1', $scope.insights, 'date', $scope.report.metrics[0]);
                fnLineChart('c2', $scope.insights, 'date', $scope.report.metrics[1]);
            });
            // list users per reseller
            $http.get('/rest/reseller/users.list').then(function successCallback(res) {
                $scope.users = res.data;
                for (var i in $scope.users) {
                    $scope.users[i]['avg'] = fnCalcAvg(fnFilterUser($scope.users[i]._id));
                }
            });
        });
        $scope.fnSwitchMetric = function(metric) {
            fnLineChart('c2', $scope.insights, 'date', metric);
        }
        $scope.colors = ['#E91E63', '#3F51B5', '#00BCD4', '#8BC34A', '#FF9800', '#795548', '#607D8B', '#00CC00', '#0000CC', '#DDDDDD', '#999999', '#333333', '#990000']
        $scope.pagecharts = {};
        var fnLineChart = function(chart, dataset, dimension, metric) {
            $scope.pagecharts[chart] = {
                metric: metric,
                data: dataset,
                type: 'serial',
                theme: 'light',
                marginLeft: 0,
                marginRight: 0,
                marginTop: 10,
                fontFamily: 'Roboto',
                categoryField: dimension,
                rotate: false,
                pathToImages: 'vendor/amchart/images/',
                dataDateFormat: 'YYYYMMDD',
                categoryAxis: {
                    gridPosition: "start",
                    parseDates: true,
                    gridThickness: 0
                },
                valueAxes: [{
                    position: "left",
                    axisAlpha: 0,
                    labelsEnabled: true,
                    dashLength: 4,
                    color: '#dedede',
                }],
                graphs: [{
                    balloonText: $filter('translate')('metrics.' + metric) + " 
 [[value]]",
                    "bullet": "round",
                    "bulletBorderAlpha": 1,
                    "bulletColor": "#FFFFFF",
                    "useLineColorForBulletBorder": true,
                    "fillAlphas": 0.2,
                    "lineThickness": 2,
                    "lineAlpha": 1,
                    "bulletSize": 7,
                    "title": "Expenses",
                    "valueField": metric,
                    lineColor: $scope.colors[colorindex],
                }],
            }
            colorindex += 1;
        }
        var fnCalcAvg = function(sites) {
            var dataset = $scope.report.dataset;
            // CALCULATE AVERAGE
            return sites.reduce((acc, item) => {
                if (typeof item.insights[dataset] != 'undefined') {
                    for (var y in [0, 1]) {
                        if (typeof item.insights[dataset][y] != 'undefined') {
                            for (var i in item.insights[dataset][y]) {
                                if (typeof item.insights[dataset][y][i] != 'undefined') {
                                    acc[i] = acc[i] || [{ 'n': 0, 's': 0 }, { 'n': 0, 's': 0 }];
                                    acc[i][y].s = acc[i][y].s + item.insights[dataset][y][i];
                                    acc[i][y].n = acc[i][y].n + 1;
                                }
                            }
                        }
                    }
                }
                return acc;
            }, {});
        }
    }
]);