var metricesApi = {},
    path = require('path'),  
    cacheApi = require('./../../utils/semusi.cache.js'),
    common = require('./../../utils/common.js'),
    logger = require('../../../logger'),
    appsFlyer = require('./../../ref_plugins/appsflyer.js'),
    appSalar = require('./../../ref_plugins/appsalar.js'),
    fs = require('fs');
    request = require('request'),
    sys=require('sys');
    cheerio = require('cheerio'),
    uuid = require('uuid'),
    mail = require('./mail.js'),
    csvparse = require('csv'),
    stream = require('stream'),
    crypto = require('crypto'),
    es = require("event-stream"),
    CSV = require('csv-string'),
    AWS = require('aws-sdk'),
    _ = require("underscore"),
    async = require("async"),
    moment = require('moment'),
    validate = require('../../constants/constants'),
    semusiConfig = require('./../../config'),
    json2csv = require('./../../utils/json-2-csv.js'),
    semusiApi = {
        data: {
            events: require('../data/events.js')
        }
    };

(function (metricsApi) {
      //generate ObjectID for controllers
  metricesApi.getObjectId = function (params) {
    if(!params.qstring.app_id) {
        common.returnOutput(params, 'Not enough args');
    }
   let objectId = crypto.randomBytes(12).toString('hex');
   common.returnOutput(params, objectId);
} 

//Jounery functions start from here 
metricesApi.getJourneyList = function (params) {
    if(!params.qstring.app_id) {
        common.returnOutput(params, 'Not enough args');
    }
    common.db.collection('journeys_'+params.qstring.app_id).find({ deleted: false }).sort({ createdOn: -1 }).toArray(function(err,result){
    if(!err){
        common.returnOutput(params, result);
     }
     else{
        common.returnOutput(params, err);
     }  
    }
  )
}
metricesApi.deleteJourney = function (params) {
    let journey = {};
    journey.modifiedOn = common.getCurrentEpochTime();
    journey.deleted = true;
    common.db.collection('journeys_'+params.qstring.app_id).update({'_id':common.db.ObjectID(params.qstring.id)},  { $set: journey },function(err, deletedJourney) {
        if(!err)
        { logger.info("deleted journey successfully", deletedJourney);
        common.returnMessage(params, 200, 'Success');
        } else {
         logger.error("error in deletion", err);
        common.returnMessage(params, 500, 'Error updating referal');
        }

    })
}
metricesApi.getJourney = function (params) {
    common.db.collection('journeys_'+params.qstring.app_id).findOne({'_id':common.db.ObjectID(params.qstring.id)},function(err,result){
    if(!err)
      common.returnOutput(params, result);  
    });
}
metricesApi.updateJourney = function (params) {

    let argProps = {

        'startEvent':{'required':true,'type':'String'},
        'endEvent':{'required':true,'type':'String'},
        'journeyName':{'required':true,'type':'String', 'regex': validate.getRegex('name') },
        'journeyDescription':{'required':true,'type':'String', 'regex': validate.getRegex('name') },
        'platform':{'required':true,'type':'String', 'regex': validate.getRegex('name')},
        'period':{'required':false,'type':'String', 'regex': validate.getRegex('name')},
        'paths':{'required':false,'type':'Array'}

    }
    let obj = {};
    if (!(obj = common.validateArgs(JSON.parse(params.qstring.args), argProps))) {
       common.returnMessage(params, 422, 'Validation error');
       return false;
    }
    obj.modifiedOn = common.getCurrentEpochTime();
    common.db.collection('journeys_'+params.qstring.app_id).update({'_id':common.db.ObjectID(obj.id)},{$set: obj},function(err,result){
        if(!err || result){
        logger.info("updated journey successfully",result);
        common.returnOutput(params, result);
        }else{
            logger.error("error in updating journey",err);
            common.returnOutput(params, 'Failed to update journey');
            
        }  
    })
}
metricesApi.saveJourney = function (params) {
    let argProps = {

        'startEvent':{'required':true,'type':'String'},
        'endEvent':{'required':true,'type':'String'},
        'journeyName':{'required':true,'type':'String', 'regex': validate.getRegex('name') },
        'journeyDescription':{'required':true,'type':'String', 'regex': validate.getRegex('name') },
        'platform':{'required':true,'type':'String', 'regex': validate.getRegex('name')},
        'period':{'required':false,'type':'String', 'regex': validate.getRegex('name')},
        'paths':{'required':false,'type':'Array'},

  }
    let obj = {};

    if (!(obj = common.validateArgs(params.qstring.args || JSON.parse(params.req.body.args), argProps))) {
        common.returnMessage(params, 422, 'Validation error');
        return false;
    }
    obj.createdOn = common.getCurrentEpochTime();
    obj.modifiedOn = common.getCurrentEpochTime();
    obj.deleted = false;
    common.db.collection('journeys_'+params.qstring.app_id).insert(obj,function(err,result){
    if(err){
        logger.error("err occured in saving journey",err)    
    }    
    if(!err){
      logger.info('saved journey successfully', result);
      common.returnOutput(params, result); 
    } 
    })
}

metricesApi.savePushToken = function (params) {
    common.db.collection('usertoken_' + params.qstring.app_id).updateOne(
        { did: params.qstring.did }, 
        { $set: { 
            pushtoken: params.qstring.token,
            updatedAt: common.getCurrentEpochTime() 
        }},
        { upsert: true },  // If document doesn't exist, insert it
        (err, res) => {
            if (err) {
                logger.error("Error updating document:", err);
                common.returnOutput(params, 500, "Error");
            } else {
                common.returnOutput(params, 200, "Success");
            }
        }
    );
};

 

// get saveinstall data for install-data page
metricesApi.saveInstallData = function (params) {
    let args = params.qstring.args;
    if(args != null && args != undefined){
        let date = args.date.replace(/-/g, '_');
        let source = args.source;
        let campaign = args.campaign;
        let un = args.churn;
        let inn = args.acquisitions;
        let spend = args.spend;

        let obj = {"android":{[date]:{[source]:{[campaign]:{"un":un,"in":inn,'sp':spend}}}}};
        obj['app_id'] = args.appID;
        common.db.collection('campaign_aggregate').insert(obj,function(err,result){
            if(err){  
                logger.error(`err occured in saving journey => ${err}`);  
            }    
             if(!err)
              common.returnOutput(params, result);  
        })
    }else{
        common.returnOutput(params, {"msg":"args are missing"}); 
    }
}
// get getinstall data for aquisition page 
metricesApi.getInstallData = function (params) {
    let app_id = params.qstring.app_id;
    let args = params.qstring.args;
    if(app_id != null && app_id != undefined){
       
         // query on campaign aggregate collection
         common.db.collection('campaign_aggregate').find({ 'app_id': params.qstring.app_id}).toArray(function (error, result) {
            if (error) {
                logger.error(`campaign_aggregate error=> ${error}`);
                return common.returnOutput(params, []);
            }
            else {
                let resultData = [];
                let platforms = [];
                let sourcesList = [];
                let dataObj = [];
                if(args.platform != 'all'){
                    platforms.push(args.platform);
                }else{
                    platforms = ['android', 'ios', 'web'];
                }
                
                
                result.forEach(function (data) {
                    platforms.forEach(function (p) {
                        let cmpList = [];
                        if (data[p]) {
                            if(args.type == 'C'){
                                Object.keys(data[p]).forEach(function (date) {
                                    Object.keys(data[p][date]).forEach(function (source) {
                                        Object.keys(data[p][date][source]).forEach(function (cmp) {
                                            if (sourcesList.indexOf(cmp) == '-1') {
                                                sourcesList.push(cmp);
                                                let obj = {"cmp":cmp,"in":0,"un":0,"sp":0};
                                                dataObj.push(obj);
                                            }
                                            let index = sourcesList.indexOf(cmp);
                                            if (dataObj[index]['in'] == 0) {
                                                dataObj[index]['in'] = parseInt(data[p][date][source][cmp]['in']);
                                            } else {
                                                dataObj[index]['in'] += parseInt(data[p][date][source][cmp]['in']);
                                            }
                                            if (dataObj[index]['un'] == 0) {
                                                dataObj[index]['un'] = parseInt(data[p][date][source][cmp]['un']);
                                            } else {
                                                dataObj[index]['un'] += parseInt(data[p][date][source][cmp]['un']);
                                            }
                                            if (dataObj[index]['sp'] == 0) {
                                                dataObj[index]['sp'] = parseInt(data[p][date][source][cmp]['sp']);
                                            } else {
                                                dataObj[index]['sp'] += parseInt(data[p][date][source][cmp]['sp']);
                                            }
                                        }); 
                                    });
                                });
                            }else{
                                Object.keys(data[p]).forEach(function (date) {
                                    Object.keys(data[p][date]).forEach(function (source) {
                                        let install = 0; let uninstall = 0; let sp = 0;
                                            if (sourcesList.indexOf(source) == '-1') {
                                                sourcesList.push(source);
                                                let obj = {"cmp":source,"in":0,"un":0,"sp":0};
                                                dataObj.push(obj);
                                            }
                                            let index = sourcesList.indexOf(source);
                                            Object.keys(data[p][date][source]).forEach(function (cmp) {
                                                
                                            if (dataObj[index]['in'] == 0) {
                                                dataObj[index]['in'] = parseInt(data[p][date][source][cmp]['in']);
                                            } else {
                                                dataObj[index]['in'] += parseInt(data[p][date][source][cmp]['in']);
                                            }
                                            if (dataObj[index]['un'] == 0) {
                                                dataObj[index]['un'] = parseInt(data[p][date][source][cmp]['un']);
                                            } else {
                                                dataObj[index]['un'] += parseInt(data[p][date][source][cmp]['un']);
                                            }
                                            if (dataObj[index]['sp'] == 0) {
                                                dataObj[index]['sp'] = parseInt(data[p][date][source][cmp]['sp']);
                                            } else {
                                                dataObj[index]['sp'] += parseInt(data[p][date][source][cmp]['sp']);
                                            }

                                            });
                                    });
                                });
                            }
                            
                        }
                    });
                })
                resultData = dataObj;
                return common.returnOutput(params, resultData);
            }
        });
    }else{
        common.returnOutput(params, {"msg":"app_id  missing"}); 
    }
}

metricesApi.copyJourney  = function(params){
    if(params.qstring.id){
        common.db
          .collection("journeys_" + params.qstring.app_id)
          .findOne({ _id: common.db.ObjectID(params.qstring.id) }
          ,function(err, journey) {
            if(err){
              common.returnOutput(params, 500, "Error");
            }
            let copy = {};
          
              journey["journeyName"] = journey["journeyName"] + " copy "+ crypto.randomBytes(2).toString('hex');
              journey.createdOn = common.getCurrentEpochTime();
              journey.modifiedOn = common.getCurrentEpochTime();
              journey.deleted = false;
              journey._id = common.db.ObjectID();
              copy = journey;
              common.db
                .collection("journeys_" + params.qstring.app_id)
                .insert(copy, function(err, res) {
                  if (err) {
                    logger.error('error in journey copy', err);
                    common.returnOutput(params, 500, "Error");
                  } else {
                    logger.info('journey copied successfully', res);
                    common.returnOutput(params, 200, "Success");
                  }
                });
         
    
          });
    
        }
        else{
          common.returnMessage(params, 400, "Not enough args");
        }
} 
//Journey End
metricesApi.createReferal = function (params) {
            let argProps = {
                'referal_name':     { 'required': true, 'type': 'String' },
                'referal_keyname':     { 'required': false, 'type': 'String' },
                'isReferalDeleted':{'required':false,'type':'Boolean'},
                'isReferalConfigured':{'required':false,'type':'Boolean'},
                'createdOn':{'required':false,'type':'String'},
                'modifiedOn':{'required':false,'type':'String'}
            },
            referal = {};

        if (!(referal = common.validateArgs(params.qstring.args, argProps))) {
            common.returnMessage(params, 400, 'Not enough args');
            return false;
        }

        referal['createdAt'] = common.getCurrentEpochTime();
        common.db.collection('referals_'+params.qstring.app_id).insert(referal, function(err, tmpl) {
            referal._id = tmpl[0]._id;
            common.returnOutput(params, referal);
        });

};


metricesApi.deleteReferal = function (params) {
            let argProps = {
                'isReferalDeleted':{'required':false,'type':'Boolean'},
                'modifiedOn':{'required':false,'type':'String'}
            },
            updatedReferal = {};

        if (!(updatedReferal = common.validateArgs(params.qstring.args, argProps))) {
            common.returnMessage(params, 400, 'Not enough args');
            return false;
        }

        updatedReferal['updatedAt'] = common.getCurrentEpochTime();
        common.db.collection('referals_'+params.qstring.app_id).update({'_id': common.db.ObjectID(params.qstring.referal_id)}, {$set: updatedReferal}, {safe: true}, function(err, isOk) {
            if(!err)
            {
                common.db.collection('referals_'+params.qstring.app_id).findOne({'_id': common.db.ObjectID(params.qstring.referal_id)}, function(err, updatedReferal) {
                    if (updatedReferal && !err) {
                       common.returnMessage(params, 200, 'Success');
                    } else {
                        common.returnMessage(params, 500, 'Error updating referal');
                    }
                });
             }
        });

        return true;

};

metricesApi.getReferals=function(params) {

    common.db.collection('referals_'+ params.qstring.app_id).find({"isReferalDeleted":false}).toArray(function (err, result) {
        if (!result) {
            result = {};
        }

        common.returnOutput(params, result);
    });
};

metricesApi.getCSVLogs=function(params) {

    common.db.collection('csvlog_'+ params.qstring.app_id).find().toArray(function (err, result) {
        if (!result) {
            result = {};
        }

        common.returnOutput(params, result);
    });
};

metricesApi.getReferalMappings=function(params) {

    common.db.collection('referalmapping').find().maxTimeMS(semusiConfig.mongodb.maxTimeMS).toArray(function (err, result) {
        if (!result) {
            result = {};
        }

        common.returnOutput(params, result);
    });
};

metricesApi.processCSVFile=function(params) {
    let dateFormat;
    let fieldList;
    let delimiterChar;
    let appUser = {};
    let appUserArr = [];
    awsRegion = semusiConfig.AWS_REGION;

    let lineNr = 1;
    let result = {};
    let recordCounter = 0;
    let logFileId;
    let startIndex=params.filename.lastIndexOf('/');
    let logFile={
        referal_name:params.referal,
        file_name:params.filename.substr(startIndex+1),
        createdOn:common.getCurrentDate(),
        status: "Inprocess",
        records:0
    };
    
   common.db.collection('csvlog_'+params.app_id).save(logFile, function(err, logfile) {
    //logFileId = logfile.ops[0]._id;
        if(err){
            logger.error(`error=> ${err}`);
        }else{
            if(logfile){
                logFileId = logfile.ops[0]._id;
            s = fs.createReadStream(params.filename).pipe(es.split()).pipe(es.mapSync(function(line)
            {
         // pause the readstream
            s.pause();

            data = CSV.parse(line);
            if(lineNr == 1)
            {
                if(params.referal=="APPSFLYER"){
                        fieldList=appsFlyer.getFieldList(data);
                    }
                else if(params.referal=="APPSALAR"){
                    fieldList= appSalar.getFieldList(data);
                }
                else{
                    result.status="ERROR";
                    result.message="This referal data is not supported in our system.";
                    common.returnOutput(params, result);
                    return false;
                }
            }

            lineNr += 1;
            (function(){
                // process line here and call s.resume() when rdy
                //skip first line as it contains header only
                if(lineNr > 1)
                {
                    let tmpIUObj = {};
                    let dtEntry="";
                    let flag = 1;
                for (let j = 1; j < data.length; j++) {
                       let appUser = {
                            'app_id': params.app_id,
                            'app_key': params.app_key,
                            'api_key': params.api_key,
                            'metrics' : {"context":{"where" : {"location" : {"place" : "other"},"geo" : {}}},"_installer":"AppsFlyer"},
                            'moreInfo' : {}
                        };
                        appUser.metrics._ref = '';
                    for (let i = 0; i < fieldList.length; i++) {
                        if(fieldList[i][1] != -1){
                            switch(fieldList[i][0]){
                                case "Install Time":
                                    appUser.moreInfo.ls = (moment(new Date(data[j][fieldList[i][1]])).valueOf()/1000) ;
                                    appUser.metrics._tz=0;
                                    break;
                                case "Country Code":
                                    appUser.moreInfo.country=data[j][fieldList[i][1]];
                                    appUser.moreInfo.cc=data[j][fieldList[i][1]];
                                    appUser.moreInfo.region = '';
                                    break;
                                case "City":
                                    appUser.moreInfo.cty=data[j][fieldList[i][1]];
                                    break;
                                case "IMEI":
                                    appUser.moreInfo.imei=data[j][fieldList[i][1]];
                                    break;
                                case "Android Id":
                                    appUser.device_id = data[j][fieldList[i][1]];
                                    appUser.moreInfo.android_id=data[j][fieldList[i][1]];
                                 break;
                                case "IDFA":
                                case "Appsflyer Device Id":
                                    appUser.moreInfo.appsflyer_device_id=data[j][fieldList[i][1]];
                                    break;
                                case "Advertising Id":
                                    appUser.advertisingId = data[j][fieldList[i][1]];
                                break;
                                case "Campaign (c)":
                                    appUser.campaign = data[j][fieldList[i][1]];
                                    break;
                                case "Media Source (pid)":
                                    appUser.mediaSource = data[j][fieldList[i][1]];
                                    break;
                                case "App Version":
                                    appUser.metrics._app_version=data[j][fieldList[i][1]];
                                    break;
                                case "Device Type":
                                    appUser.metrics._device=data[j][fieldList[i][1]];
                                    break;
                                case "OS Version":
                                    appUser.metrics._os_version=data[j][fieldList[i][1]];
                                    appUser.metrics._os = params.platform;
                                    break;
                                case "Platform":
                                    appUser.metrics._os = params.platform;
                                    break;
                                case "Carrier":
                                    appUser.metrics._carrier=data[j][fieldList[i][1]];
                                    break;
                                case "IP":
                                    appUser.metrics.ip=data[j][fieldList[i][1]];
                                    break;
                                case "Operator":
                                    appUser.metrics.operator=data[j][fieldList[i][1]];
                                    break;
                                case "Click Time":
                                    appUser.timestamp = (moment(new Date(data[j][fieldList[i][1]])).valueOf()/1000) ;
                                    appUser.inittime = (moment(new Date(data[j][fieldList[i][1]])).valueOf()/1000) ;
                                    break;
                                default:
                                    /*appUser.qstring.metrics["_custom_"+fieldList[i][0]]=data[0][fieldList[i][1]];
                                    break; */
                            }
                        }
                    }
                    if(params.referal=="APPSFLYER" && appUser.metrics._carrier == ''){
                        appUser.metrics._carrier = appUser.metrics.operator;
                    }
                    if(params.referal=="APPSFLYER" && appUser.metrics._carrier == '' || appUser.metrics.operator == ''){
                        appUser.metrics._carrier = '';
                    }
                    if(params.referal=="APPSFLYER" && appUser.campaign !== ''){
                            appUser.metrics._ref +="%26utm_source="+appUser.campaign;
                        }
                    if(params.referal=="APPSFLYER" && appUser.mediaSource !== ''){
                        appUser.metrics._ref +="%26utm_medium="+appUser.mediaSource;
                    }
                    if(params.referal=="APPSFLYER" && (appUser.advertisingId == ''  || appUser.advertisingId == null )){
                        appUser.device_id = appUser.moreInfo.android_id;
                        //appUser.moreInfo.device_id = appUser.moreInfo.android_id;
                    }
                    if(params.referal == "APPSFLYER" && (appUser.moreInfo.android_id == '' || appUser.moreInfo.android_id == null)){
                        appUser.device_id = undefined;
                        //appUser.moreInfo.device_id = undefined;
                    }
                    appUser.metrics = JSON.stringify(appUser.metrics);
                    appUser.moreInfo = JSON.stringify(appUser.moreInfo);
                    appUser.logFileId = logFileId;
                    appUserArr.push(appUser);
                    recordCounter++;
                };
                }
                // resume the readstream
                s.resume();

            })();
    })
    .on('error', function(){
        logger.error(`Error while reading file => ${error}`);
    })
    .on('end', function(){
        //send to queue

            AWS.config.update({
                accessKeyId: semusiConfig.AWS_ACCESS_KEY_ID,
                secretAccessKey: semusiConfig.AWS_SECRET_KEY,
                region: awsRegion
              });

              sqs = new AWS.SQS();

                let queueUrl = '';
                if(semusiConfig.IsProduction == true)
                {
                    //queueUrl = semusiConfig.ProductionQueueDeviceImportUrl;
                }
                else
                {
                    queueUrl = semusiConfig.StagingQueueDeviceImportUrl;
                }
        let i = 1;
        appUserArr.forEach(function(appUserObj)
        {
            if(appUserArr[i] === 'undefined'){
                appUserArr.splice(i,1)
            }else{
                if(queueUrl)
                {
                 let queueObj = {};
                    //queueObj.appUserObj = appUserObj;
                    //queueObj.params = params;
                  let boxParams = {
                    MessageBody: JSON.stringify(appUserObj),
                    QueueUrl: queueUrl,
                    DelaySeconds: 0
                  };
                  sqs.sendMessage(boxParams, function (err, data) {
                    if (err) {
                        logger.error(`error sending msg to SQS => ${err} :: ${err.stack}`);
                    } // an error occurred
                    else {
                        logger.info('Victory, message sent ');
                    }
                  });
                }
            }
            i++;

        });


        //Upto this stage file processed success fully
        //main a log of uploaded file.
        let updatedAt = common.getCurrentEpochTime();
            common.db.collection('csvlog_'+params.app_id).update({'_id': logFileId}, {$set: {'status': 'Queued','records':recordCounter,'updatedAt':updatedAt}}, function(err, app) {
               result.status="OK";
                result.message="File Queued successfully.";
                common.returnOutput(params, result);
                return true;
            });
    })
    );
            }
        }
   });

};

//return the referral counts for a given time period
metricesApi.getReferralCounts=function(params)
{
    let argProps = {
                'startDate':{'required':true,'type':'Number'},
                'endDate':{'required':true,'type':'Number'},
                'type':{'required':true,'type':'String'},
                'metric':{'required':false,'type':'String'},
                'periodtype':{'required':true,'type':'String'}
            },
            referralMetrices = {};


    if (!(referralMetrices = common.validateArgs(params.qstring.args, argProps))) {
        common.returnMessage(params, 400, 'Not enough args');
        return false;
    }


    if(referralMetrices.type == "U")
    {
        let groupParam = { $group: {} };
        let _idObj = {};

        switch(referralMetrices.periodtype)
        {
            case "m":
               _idObj["oentry"] = "$oEntryMonth";
            break;
            case "d":
                _idObj["oentry"] = "$oEntryDayOfMonth";
            break;
            case "y":
                _idObj["oentry"] = "$oEntryYear";
            break;
            case "w":
                _idObj["oentry"] = "$oEntryWeekOfYear";
            break;
        }
         _idObj["refName"] = "$ref";
         _idObj["metric"] = "$" + referralMetrices.metric;

        groupParam.$group["_id"]= _idObj;
        groupParam.$group["subTotals"] = {};
        groupParam.$group["subTotals"]["$sum"] =  1;

        let metric = referralMetrices.metric;
        let project = { $project: {} };
        project.$project[referralMetrices.metric] = 1;
        project.$project["history"] = 1;
        project.$project["fs"] = 1;

        let project1= {$project:{}};
        project1.$project[referralMetrices.metric] = 1;
        project1.$project["fs"] = "$fs";
        project1.$project["originalEntry"] = "$fs";
        project1.$project["oEntryDate"] ={
                    "$add": [new Date(0), {
                        "$multiply": ["$fs", 1000]
                    }]
                };
        project1.$project["oEntrydayOfWeek"] = {
                "$dayOfWeek": {
                    "$add": [new Date(0), {
                        "$multiply": ["$fs", 1000]
                    }]
                }
            };
         project1.$project["oEntryYear"] = {
            "$year": {
                "$add": [new Date(0), {
                       "$multiply": ["$fs", 1000]
                   }]
            }
        };
        project1.$project["oEntryMonth"] = {
                "$month": {
                    "$add": [new Date(0), {
                        "$multiply": ["$fs", 1000]
                    }]
                }
            };
        project1.$project["oEntryDayOfMonth"] = {
                "$dayOfMonth": {
                    "$add": [new Date(0), {
                        "$multiply": ["$fs", 1000]
                    }]
                }
            };

        project1.$project["oEntryWeekOfYear"]={
                "$week": {
                    "$add": [new Date(0), {
                        "$multiply": ["$fs", 1000]
                    }]
                }
            };
        project1.$project["type"]="$history.type";
        project1.$project["ref"]= "$history.refname";
    }

    else if(referralMetrices.type == "I")
    {
        let project = { $project: {} };
        project.$project[referralMetrices.metric] = 1;
        project.$project["history"] = 1;
        project.$project["fs"] = 1;
        project.$project["did"] = 1;

        let project1 = { $project: {} };
        project1.$project[referralMetrices.metric] = 1;
        project1.$project["fs"] = 1;
        project1.$project["did"] = 1;
        project1.$project["dtEntry"] = "$history.dtEntry";
        project1.$project["type"] = "$history.type";
        project1.$project["refname"] = "$history.refname";

        let sortParams = { $sort: { "dtEntry": 1 } };

        let _idObj = {};
        _idObj["did"] =  "$did";
        _idObj["fs"] =  "$fs";
        _idObj["refname"] =  "$refname";
        _idObj["type"] =  "$type";
        _idObj["metric"] = "$" + referralMetrices.metric;

        let group1 = { $group: {} };
        group1.$group["_id"]= _idObj;
        group1.$group["dtEntry"]= { $first: "$dtEntry" };

        let project2= {$project:{}};
        project2.$project["did"] = "$_id.did";
        project2.$project[referralMetrices.metric] = "$_id." + referralMetrices.metric;
        project2.$project["fs"] = "$_id.fs";
        project2.$project["type"]="$_id.type";
        project2.$project["refname"]= "$_id.refname";
        project2.$project["dtEntry"] = 1;
        project2.$project["oEntryDate"] ={
                    "$add": [new Date(0), {
                        "$multiply": ["$_id.fs", 1000]
                    }]
                };
        project2.$project["oEntrydayOfWeek"] = {
                "$dayOfWeek": {
                    "$add": [new Date(0), {
                        "$multiply": ["$_id.fs", 1000]
                    }]
                }
            };
         project2.$project["oEntryYear"] = {
            "$year": {
                "$add": [new Date(0), {
                       "$multiply": ["$_id.fs", 1000]
                   }]
            }
        };
        project2.$project["oEntryMonth"] = {
                "$month": {
                    "$add": [new Date(0), {
                        "$multiply": ["$_id.fs", 1000]
                    }]
                }
            };
        project2.$project["oEntryDayOfMonth"] = {
                "$dayOfMonth": {
                    "$add": [new Date(0), {
                        "$multiply": ["$_id.fs", 1000]
                    }]
                }
            };

        project2.$project["oEntryWeekOfYear"]={
                "$week": {
                    "$add": [new Date(0), {
                        "$multiply": ["$_id.fs", 1000]
                    }]
                }
            };

        let group2 = { $group: {} };

        switch(referralMetrices.periodtype)
        {
            case "m":
               _idObj["oentry"] = "$oEntryMonth";
            break;
            case "d":
                _idObj["oentry"] = "$oEntryDayOfMonth";
            break;
            case "y":
                _idObj["oentry"] = "$oEntryYear";
            break;
            case "w":
                _idObj["oentry"] = "$oEntryWeekOfYear";
            break;
        }
         _idObj["refname"] = "$refname";
         _idObj["metric"] = "$_id.metric";

        group2.$group["_id"]= _idObj;
        group2.$group["subTotals"] = {};
        group2.$group["subTotals"]["$sum"] =  1;

    }


    if(referralMetrices.type == "I")
    {
         common.db.collection('app_users'+params.qstring.app_id).aggregate([
            {
                $match:{"fs":{$gte:referralMetrices.startDate,$lte:referralMetrices.endDate}
                    }
            },
            project,{$unwind:"$history"},
            {
                    $match:{"history.type":"I"}
            },
            project1,sortParams,
            group1,project2,group2,
            {
                $project:
                {
                    oEntry:"$_id.oentry",
                    refName:"$_id.refname",
                    metric:"$_id.metric",
                    subTotals:"$subTotals"
                }
            },
            {$sort :{oEntry:1}}], function(err, result) {
                if(!err)
                {
                    if(!result)
                    {
                        result = {};
                    }
                    common.returnOutput(params, result);

                }
                else
                {
                    logger.error(`error=> ${err}`);  
                }
            });


    }
    else if(referralMetrices.type == "U")
    {
          common.db.collection('app_users'+params.qstring.app_id).aggregate([
            {
                $match:{"fs":{$gte:referralMetrices.startDate,$lte:referralMetrices.endDate}
                    }
            },
            project, {$unwind:"$history"},
            project1,
            {
                $match:{"type":referralMetrices.type}
            },
                groupParam,
            {
                $project:
                {
                    oEntry:"$_id.oentry",
                    refName:"$_id.refName",
                    metric:"$_id.metric",
                    subTotals:"$subTotals"
                }
            },
            {$sort :{oEntry:1}}], function(err, result) {
                if(!err)
                {
                    if(!result)
                    {
                        result = {};
                    }
                    common.returnOutput(params, result);

                }
                else
                {
                    logger.error(`error=> ${err}`);  
                }
            });
    }



    //return true;
};


metricesApi.getCohortDataForInstalls=function(params){
     let argProps = {
                'startDate':{'required':true,'type':'Number'},
                'endDate':{'required':true,'type':'Number'},
                'startDateNew':{'required':true,'type':'String'},
                'endDateNew':{'required':true,'type':'String'},
                'metrices':{'required':false,'type':'Array'},
                'periodtype':{'required':true,'type':'String'}
            },
            cohortMetrices = {};
    if (!(cohortMetrices = common.validateArgs(params.qstring.args, argProps))) {
        common.returnMessage(params, 400, 'Not enough args');
        return false;
    }

    let array = [];
    let query = {}
    let tmpArray = [];

        common.fillInstallQueryObject(query, array, tmpArray, params.qstring.args.startDateNew, params.qstring.args.endDateNew, 'android', params.qstring.app_id);
        common.fillInstallQueryObject(query, array, tmpArray, params.qstring.args.startDateNew, params.qstring.args.endDateNew, 'ios', params.qstring.app_id);
        common.fillInstallQueryObject(query, array, tmpArray, params.qstring.args.startDateNew, params.qstring.args.endDateNew, 'web', params.qstring.app_id);
        common.db.collection('timely_dashboard').find({ _id: { $in: array } }, query).maxTimeMS(semusiConfig.mongodb.maxTimeMS).toArray(function (error, result) {
            if (!error) {
                let data = prepareCohortData(array, result, params.qstring.app_id, params.qstring.args.periodtype)
                common.returnOutput(params, data);
            }
            else {
                common.returnOutput(params, []);
            }
        });
    };


    let prepareCohortData = function (array, data, appid, periodtype) {
        let dataObj = {};
        let platforms = ['android', 'ios', 'web'];

        if(data.length > 0){
            if(periodtype == 'm' ){
                let sourcesList = [];
                let years = [];
                let months = [];

                data.forEach(function(keyObj){
                    let days = [];
                    platforms.forEach(function(value){
                        if(keyObj[value] != undefined){
                            if(array.indexOf(keyObj._id) != '-1'){
                                let dayKeys = Object.keys(keyObj[value]);
                                dayKeys.forEach(function(day){
                                    let elem = day;
                                    dayArray = day.split("_");

                                    let tObj = {y: dayArray[0], m: dayArray[1]};
                                    if(years.indexOf(tObj.y) == '-1'){
                                        years.push(tObj.y);
                                        dataObj[tObj.y] = {};
                                    }
                                    if(months.indexOf(tObj.m) == '-1'){
                                        months.push(tObj.m);
                                        dataObj[tObj.y][tObj.m] = {};
                                    }
                                    day = dayArray[2];
                                    if(days.indexOf(day) == '-1' ){
                                        days.push(day);
                                        dataObj[tObj.y][tObj.m][day] = {'in':0,'un':0};
                                    }

                                    if(keyObj[value][elem] && keyObj[value][elem]['cohort']){
                                            let keys = Object.keys(keyObj[value][elem]['cohort']);
                                            keys.forEach(function(val){
                                                if(dataObj[tObj.y][tObj.m][day] != undefined){
                                                    if( val == 'in'){
                                                        dataObj[tObj.y][tObj.m][day]['in'] = dataObj[tObj.y][tObj.m][day]['in']+keyObj[value][elem]['cohort'][val];
                                                    }
                                                    else if(val == 'o'){
                                                        dataObj[tObj.y][tObj.m][day]['un'] = dataObj[tObj.y][tObj.m][day]['un']+keyObj[value][elem]['cohort'][val];
                                                    }

                                                    else if(!isNaN(val)){
                                                        let actualDate = common.getDateFromDate(day+"-"+tObj.m+'-'+tObj.y, val);
                                                        if(actualDate){
                                                            let dateArray = actualDate.split('-');
                                                            dateArray[1] = parseInt(dateArray[1]);
                                                            dateArray[0] = parseInt(dateArray[0]);

                                                            // days difference uninstalls
                                                            if(dataObj[dateArray[2]] && dataObj[dateArray[2]][dateArray[1]]){
                                                                if(dataObj[dateArray[2]][dateArray[1]][dateArray[0]]){
                                                                    if(dataObj[dateArray[2]][dateArray[1]][dateArray[0]][parseInt(dateArray[0])+parseInt(val)] == undefined){
                                                                        dataObj[dateArray[2]][dateArray[1]][dateArray[0]][parseInt(dateArray[0])+parseInt(val)] = keyObj[value][elem]['cohort'][val];
                                                                    }
                                                                    else{
                                                                        dataObj[dateArray[2]][dateArray[1]][dateArray[0]][parseInt(dateArray[0])+parseInt(val)] += keyObj[value][elem]['cohort'][val];
                                                                    }
                                                                }
                                                                else if(dataObj[dateArray[2]] && dataObj[dateArray[2]][dateArray[1]]){
                                                                    days.push(dateArray[0].toString());
                                                                    dataObj[dateArray[2]][dateArray[1]][dateArray[0]] = {'in':0,'un':0};
                                                                    if(dataObj[dateArray[2]][dateArray[1]][dateArray[0]][parseInt(dateArray[0])+parseInt(val)] == undefined){
                                                                        dataObj[dateArray[2]][dateArray[1]][dateArray[0]][parseInt(dateArray[0])+parseInt(val)] = keyObj[value][elem]['cohort'][val];
                                                                    }
                                                                    else{
                                                                        dataObj[dateArray[2]][dateArray[1]][dateArray[0]][parseInt(dateArray[0])+parseInt(val)] += keyObj[value][elem]['cohort'][val];
                                                                    }
                                                                }
                                                            }
                                                        }
                                                    }
                                                }
                                            });
                                    }
                                });
                            }
                        }
                    });
                });
            }
            else if(periodtype != 'w'){
                let sourcesList = [];
                let years = [];
                let months = [];

                data.forEach(function(keyObj){
                    let days = [];
                    platforms.forEach(function(value){
                        if(keyObj[value] != undefined){
                            if(array.indexOf(keyObj._id) != '-1'){
                                let dayKeys = Object.keys(keyObj[value]);
                                dayKeys.forEach(function(day){
                                    let elem = day;
                                    dayArray = day.split("_");

                                    let tObj = {y: dayArray[0], m: dayArray[1]};
                                    if(years.indexOf(tObj.y) == '-1'){
                                        years.push(tObj.y);
                                        dataObj[tObj.y] = {};
                                    }
                                    if(months.indexOf(tObj.m) == '-1'){
                                        months.push(tObj.m);
                                        dataObj[tObj.y][tObj.m] = {};
                                    }
                                    day = dayArray[2];
                                    if(days.indexOf(day) == '-1' ){
                                        days.push(day);
                                        dataObj[tObj.y][tObj.m][day] = {'in':0,'un':0};
                                    }

                                    if(keyObj[value][elem]){
                                        let keys = Object.keys(keyObj[value][elem]['cohort']);
                                        keys.forEach(function(val){
                                            if(dataObj[tObj.y][tObj.m][day] != undefined){

                                                if( val == 'in' || val == 'ri'){
                                                    dataObj[tObj.y][tObj.m][day]['in'] = dataObj[tObj.y][tObj.m][day]['in']+keyObj[value][elem]['cohort'][val];
                                                }
                                                else if(val == 'o'){
                                                    dataObj[tObj.y][tObj.m][day]['un'] = dataObj[tObj.y][tObj.m][day]['un']+keyObj[value][elem]['cohort'][val];
                                                }

                                                else if(!isNaN(val)){
                                                    let actualDate = common.getDateFromDate(day+"-"+tObj.m+'-'+tObj.y, val);
                                                    if(actualDate){
                                                        let dateArray = actualDate.split('-');
                                                        dateArray[1] = parseInt(dateArray[1]);
                                                        dateArray[0] = parseInt(dateArray[0]);

                                                        // days difference uninstalls
                                                        if(dataObj[dateArray[2]] && dataObj[dateArray[2]][dateArray[1]]){
                                                            if(dataObj[dateArray[2]][dateArray[1]][dateArray[0]]){
                                                                if(dataObj[dateArray[2]][dateArray[1]][dateArray[0]][val] == undefined){
                                                                    dataObj[dateArray[2]][dateArray[1]][dateArray[0]][val] = keyObj[value][elem]['cohort'][val];
                                                                }
                                                                else{
                                                                    dataObj[dateArray[2]][dateArray[1]][dateArray[0]][val] += keyObj[value][elem]['cohort'][val];
                                                                }
                                                            }
                                                            else if(dataObj[dateArray[2]] && dataObj[dateArray[2]][dateArray[1]]){
                                                                days.push(dateArray[0].toString());
                                                                dataObj[dateArray[2]][dateArray[1]][dateArray[0]] = {'in':0,'un':0};
                                                                if(dataObj[dateArray[2]][dateArray[1]][dateArray[0]][val] == undefined){
                                                                    dataObj[dateArray[2]][dateArray[1]][dateArray[0]][val] = keyObj[value][elem]['cohort'][val];
                                                                }
                                                                else{
                                                                    dataObj[dateArray[2]][dateArray[1]][dateArray[0]][val] += keyObj[value][elem]['cohort'][val];
                                                                }
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                        });
                                    }
                                });
                            }
                        }
                    });
                });
            }else if(periodtype == 'w' ){
                let weeks = [];
                let years = [];
                platforms.forEach(function(value){
                    data.forEach(function(keyObj){
                        if(keyObj[value] != undefined){
                            if(array.indexOf(keyObj._id) != '-1'){
                                let tObj = getYearMonth(appid, keyObj._id);
                                if(years.indexOf(tObj.y) == '-1'){
                                    years.push(tObj.y);
                                    dataObj[tObj.y] = {};
                                }

                                let dayKeys = Object.keys(keyObj[value]);
                                dayKeys.forEach(function(day){
                                    let elem = day;
                                    day = day.split("_");
                                    day = day[2];
                                    if(keyObj[value][elem]){

                                        let week = moment(day+'-'+tObj.m+'-'+tObj.y, 'DD-MM-YYYY').week();
                                        //week -= 1;
                                        if(weeks.indexOf(week) == '-1' ){
                                            weeks.push(week);
                                            dataObj[tObj.y][week] = {'in':0,'un':0};
                                        }

                                        let keys = Object.keys(keyObj[value][elem]['cohort']);
                                        keys.forEach(function(val){
                                            if( val == 'in' || val == 'ri'){
                                                dataObj[tObj.y][week]['in'] = dataObj[tObj.y][week]['in']+keyObj[value][elem]['cohort'][val];
                                            }
                                            else if(val == 'o'){
                                                dataObj[tObj.y][week]['un'] = dataObj[tObj.y][week]['un']+keyObj[value][elem]['cohort'][val];
                                            }
                                            if(!isNaN(val)){
                                                let actualDate = common.getDateFromDate(day+"-"+tObj.m+'-'+tObj.y, val);
                                                if(actualDate){
                                                    let dateArray = actualDate.split('-');
                                                    let newDate = dateArray[2]+'-'+dateArray[1]+'-'+dateArray[0]
                                                    let tweek = moment(newDate.toString(),'YYYY-M-D', true).week();
                                                    let cDate = tObj.y+"-"+tObj.m+'-'+day;
                                                    let cweek = moment(cDate.toString(),'YYYY-M-D', true).week();

                                                    if(tObj.y > parseInt(dateArray[2])){
                                                        let tmpweek = moment("31-12-"+parseInt(dateArray[2]),"DD-MM-YYYY").week();
                                                        let d = tmpweek - tweek;
                                                        let diff = cweek+d;
                                                    }
                                                    else{
                                                        let diff = cweek-tweek;
                                                    }
                                                    diff = (diff == 0)? 'un' : diff;

                                                    if(dataObj[tObj.y][tweek]){
                                                        if(dataObj[tObj.y][tweek][diff] == undefined){
                                                            dataObj[tObj.y][tweek][diff] = keyObj[value][elem]['cohort'][val];
                                                        }
                                                        else{
                                                            dataObj[tObj.y][tweek][diff] += keyObj[value][elem]['cohort'][val];
                                                        }
                                                    }
                                                    else if(dataObj[parseInt(dateArray[2])] && dataObj[parseInt(dateArray[2])][tweek]){
                                                        if(dataObj[parseInt(dateArray[2])][tweek][diff] == undefined){
                                                            dataObj[parseInt(dateArray[2])][tweek][diff] = keyObj[value][elem]['cohort'][val];
                                                        }
                                                        else{
                                                            dataObj[parseInt(dateArray[2])][tweek][diff] += keyObj[value][elem]['cohort'][val];
                                                        }
                                                    }
                                                    else if(dataObj[tObj.y][tweek] == undefined){
                                                        // check week
                                                        if(weeks.indexOf(tweek) == '-1' ){
                                                            weeks.push(tweek);
                                                            dataObj[tObj.y][tweek] = {'in':0,'un':0};
                                                        }

                                                        if(dataObj[tObj.y][tweek]){
                                                            if(dataObj[tObj.y][tweek][diff] == undefined){
                                                                dataObj[tObj.y][tweek][diff] = keyObj[value][elem]['cohort'][val];
                                                            }
                                                            else{
                                                                dataObj[tObj.y][tweek][diff] += keyObj[value][elem]['cohort'][val];
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                        });
                                    }
                                });
                            }
                        }
                    });
                });
            }
        }
        return dataObj;
    }

let getYearMonth = function (appId, id){
    id = id.replace(appId,'');
    let obj = {y: id.substr(0, 4), m: id.substr(4) };
    return obj;
}

/*returnAppStats = function (params,index,total,stats){
    if(index == total){
        common.returnOutput(params,stats);
    }
}*/

    metricesApi.getAppStats = function (params) {
        let stats = [];
        let index = 1;
        if (params.app_ids.length == 0) {
            common.returnOutput(params, stats);
            return false
        }
        let query = {};
        let array = [];
        let current = [];
        common.db.collection('timely_dashboard').find({}, { "android.totalIn": 1, "android.totalUn": 1, "ios.totalIn": 1, "ios.totalUn": 1, "web.totalIn": 1, "web.totalUn": 1, "_id": 1 }).maxTimeMS(semusiConfig.mongodb.maxTimeMS).toArray(function (error, result) {
            if (!error) {
                let data = prepareAppsInstallUninstallCount(result);
                 result = { data: data, appIds: params.app_ids }
                common.returnOutput(params, result);
            } else {
                logger.error(`error=> ${error}`);  
            }
        });
    };

    function prepareAppsInstallUninstallCount(data) {
        if (data.length > 0) {
            let dataObj = {};
            let mainObj = {};
            let results = [];
            let platforms = ['android', 'ios', 'web'];
            let tempArr = [];
            let appid
            platforms.forEach(function (value) {
                dataObj[value] = [];
                data.forEach(function (keyObj) {
                    if (keyObj[value] != undefined) {
                        let yearRange = keyObj._id.slice(24, 28);
                        if (yearRange > 2016 && yearRange < 2050) {

                        appid = getAppId(keyObj._id);
                        if (tempArr.indexOf(appid) == -1) {
                            tempArr.push(appid);
                            mainObj[appid] = { 'androidInstallTotal': 0, 'iosInstallTotal': 0, 'webInstallTotal': 0, 'androidUnInstallTotal': 0, 'iosUnInstallTotal': 0, 'webUnInstallTotal': 0 };
                        }

                        if (value.toLowerCase() == 'android') {
                            if (keyObj[value].totalIn != undefined) {
                                mainObj[appid].androidInstallTotal += keyObj[value].totalIn;
                            }
                            if (keyObj[value].totalUn != undefined) {
                                mainObj[appid].androidUnInstallTotal += keyObj[value].totalUn;
                            }
                        } else if (value.toLowerCase() == 'ios') {
                            if (keyObj[value].totalIn != undefined) {
                                mainObj[appid].iosInstallTotal += keyObj[value].totalIn;
                            }
                            if (keyObj[value].totalUn != undefined) {
                                mainObj[appid].iosUnInstallTotal += keyObj[value].totalUn;
                            }
                        }
                        else if (value.toLowerCase() == 'web') {
                            if (keyObj[value].totalIn != undefined) {
                                mainObj[appid].webInstallTotal += keyObj[value].totalIn;
                            }
                            if (keyObj[value].totalUn != undefined) {
                                mainObj[appid].webUnInstallTotal += keyObj[value].totalUn;
                            }
                        }
                      }
                    }
                });
            });
            return mainObj;
        } else {
            return mainObj;
        }
    };

    function getAppId(appId) {
        let strshortened = appId.slice(0, 24);
        return strshortened;
    }

    //This API fetchs:
    //1.Total installs(new+repeat) for given current and previous periods
    //2.Total uninstalls for given current and previous periods
    metricesApi.getDashboardTotalStats = function (params) {
        let installData = {};
        let argProps = {
            'startDate_C': { 'required': true, 'type': 'Number' },
            'endDate_C': { 'required': true, 'type': 'Number' },
            'startDate_P': { 'required': true, 'type': 'Number' },
            'endDate_P': { 'required': true, 'type': 'Number' },
            'startDate_CNew': { 'required': true, 'type': 'String' },
            'endDate_CNew': { 'required': true, 'type': 'String' },
            'startDate_PNew': { 'required': true, 'type': 'String' },
            'endDate_PNew': { 'required': true, 'type': 'String' }
        }, dateRange = {};
        if (!(dateRange = common.validateArgs(params.qstring.args, argProps))) {
            common.returnMessage(params, 400, 'Not enough args');
            return false;
        }

        let query = {};
        let current = [];
        let array = [];
        let previous = [];


        common.fillInstallQueryObject(query, array, current, dateRange.startDate_CNew, dateRange.endDate_CNew, 'android', params.qstring.app_id);
        common.fillInstallQueryObject(query, array, current, dateRange.startDate_CNew, dateRange.endDate_CNew, 'ios', params.qstring.app_id);
        common.fillInstallQueryObject(query, array, current, dateRange.startDate_CNew, dateRange.endDate_CNew, 'web', params.qstring.app_id);

        common.fillInstallQueryObject(query, array, previous, dateRange.startDate_PNew, dateRange.endDate_PNew, 'android', params.qstring.app_id);
        common.fillInstallQueryObject(query, array, previous, dateRange.startDate_PNew, dateRange.endDate_PNew, 'ios', params.qstring.app_id);
        common.fillInstallQueryObject(query, array, previous, dateRange.startDate_PNew, dateRange.endDate_PNew, 'web', params.qstring.app_id);

        common.db.collection('timely_dashboard').find({ _id: { $in: array } }, query).maxTimeMS(semusiConfig.mongodb.maxTimeMS).toArray(function (error, result) {
            if (!error) {
                let res = prepareTimelyDashboardData(current, previous, result);
                let av = prepareTimelyAvData(result);
                let data = { current: res.c, previous: res.p, appversion: av};
                common.returnOutput(params, data);
            }
            else {
                let data = { current: { androidTotal: 0, iosTotal: 0, webTotal: 0, totalUninstall: 0, totalUniqueInstall: 0, totalUniqueUninstall: 0 }, previous: { androidTotal: 0, iosTotal: 0, webTotal: 0, totalUninstall: 0 } };
                common.returnOutput(params, data);
            }
        });
    };

    /* function for app version char on dashbaord */
    function prepareTimelyAvData(data) {
        if (data.length > 0) {
            let dataArray = {};
            let sourcesList = [];
            let platforms = ['android', 'ios', 'web'];
            platforms.forEach(function (value) {
                dataArray[value] = [];
                sourcesList = [];
                data.forEach(function (keyObj) {
                    if (keyObj[value] != undefined) {
                        // get time keys
                        let dayKeys = Object.keys(keyObj[value]);
                        dayKeys.forEach(function (day) {
                            let elem = day;
                            if (keyObj[value][elem]) {
                                // get hours keys
                                let hoursKeys = Object.keys(keyObj[value][elem]);
                                hoursKeys.forEach(function (hour) {
                                    if (hour != 'cohort' && keyObj[value][elem][hour]) {
                                        // get pv keys
                                        let pvKeys = Object.keys(keyObj[value][elem][hour]);
                                        pvKeys.forEach(function (pv) {
                                            if (keyObj[value][elem][hour][pv]) {
                                                let avKeys = Object.keys(keyObj[value][elem][hour][pv]);
                                                avKeys.forEach(function (av) {
                                                    if (keyObj[value][elem][hour][pv][av]) {
                                                        //av = av.replace (/\_/g, ".");
                                                        if (sourcesList.indexOf(av) == '-1') {
                                                            sourcesList.push(av);
                                                            dataArray[value].push({ x:av, value: 0 })
                                                        }
                                                        let index = sourcesList.indexOf(av);
                                                        let sourceKeys = Object.keys(keyObj[value][elem][hour][pv][av]);
                                                        sourceKeys.forEach(function (source) {
                                                            let countries = Object.keys(keyObj[value][elem][hour][pv][av][source]);
                                                            countries.forEach(function (country) {
                                                                if (keyObj[value][elem][hour][pv][av][source][country]) {
                                                                    let citys = Object.keys(keyObj[value][elem][hour][pv][av][source][country]);
                                                                    citys.forEach(function (city) {
                                                                        let keys = Object.keys(keyObj[value][elem][hour][pv][av][source][country][city]);
                                                                        keys.forEach(function (val) {
                                                                            if (val == 'in' || val == 'ri') {
                                                                                dataArray[value][index].value += keyObj[value][elem][hour][pv][av][source][country][city][val];
                                                                            }
                                                                        });
                                                                    });
                                                                }
                                                            });
                                                        });
                                                    }
                                                });
                                            }
                                        });
                                    }
                                });
                            }
                        });

                    }
                });
            });
            return dataArray;
        }else{
            return 0;
        }
        
    }
     /* function for app device data char on insight page */
    metricesApi.getDeviceTotalStats = function (params) {
        let installData = {};
        if (params.qstring.app_id == null && params.qstring.app_id == undefined) {
            common.returnMessage(params, 400, 'Not enough args');
            return false;
        }
        common.db.collection('timely_deviceinfo').find({ _id: params.qstring.app_id }).maxTimeMS(semusiConfig.mongodb.maxTimeMS).toArray(function (error, result) {
            if (!error) {
                let devicedata = prepareTimelyDeviceData(result);
                common.db.collection('timely_appversioninfo').find({ _id: params.qstring.app_id }).maxTimeMS(semusiConfig.mongodb.maxTimeMS).toArray(function (error, av) {
                    if (!error) {
                        let avdata = prepareTimelyDeviceData(av);
                        let data = { devicedata: devicedata, avdata:avdata };
                        common.returnOutput(params, data);
                    } 
                    else {
                        let data = [];
                        common.returnOutput(params, data);
                    }
                });
            } 
            else {
                let data = [];
                common.returnOutput(params, data);
            }
        });
    };

    /* function for app version char on dashbaord */ 
    function prepareTimelyDeviceData(data) {
        if (data.length > 0) {
            let dataArray = {};
            let sourcesList = [];
            let platforms = ['Android', 'IOS', 'web'];
            platforms.forEach(function (value) {
                dataArray[value] = [];
                sourcesList = [];
                data.forEach(function (keyObj) {
                    if (keyObj[value] != undefined) {
                        // get time keys
                        let dayKeys = Object.keys(keyObj[value]);
                        dayKeys.forEach(function (day) {
                            let elem = day;
                            if (keyObj[value][elem]) {
                                let daysKeys = Object.keys(keyObj[value][elem]);
                                daysKeys.forEach(function (make) {
                                    if (sourcesList.indexOf(make) == '-1') {
                                        sourcesList.push(make);
                                        dataArray[value].push({ x:make, value: 0 })
                                    }
                                    let index = sourcesList.indexOf(make);
                                    let sourceKeys = Object.keys(keyObj[value][elem][make]);
                                    sourceKeys.forEach(function (modal) {
                                        dataArray[value][index].value += keyObj[value][elem][make][modal];
                                    });

                                });
                            }
                        });

                    }
                });
            });
            return dataArray;
        }else{
            return 0;
        }
        
    }

    function prepareSourceWishInstallAndUninstall(data, type, platformSelect) {
        let dataArray = [];
        if (data.length > 0) {

            let sourcesList = [];
            let platforms = ['android', 'ios', 'web'];

            platforms.forEach(function (value) {
                //sourcesList = [];
                if (platformSelect == value || platformSelect == 'all') {
                    data.forEach(function (keyObj) {
                        if (keyObj[value] != undefined) {
                            // get time keys
                            let dayKeys = Object.keys(keyObj[value]);
                            dayKeys.forEach(function (day) {
                                let elem = day;
                                if (keyObj[value][elem]) {
                                    // get hours keys
                                    let hoursKeys = Object.keys(keyObj[value][elem]);
                                    hoursKeys.forEach(function (hour) {
                                        if (hour != 'cohort' && keyObj[value][elem][hour]) {
                                            // get pv keys
                                            let pvKeys = Object.keys(keyObj[value][elem][hour]);
                                            pvKeys.forEach(function (pv) {
                                                if (keyObj[value][elem][hour][pv]) {
                                                    let avKeys = Object.keys(keyObj[value][elem][hour][pv]);
                                                    avKeys.forEach(function (av) {
                                                        if (keyObj[value][elem][hour][pv][av]) {
                                                            let sourceKeys = Object.keys(keyObj[value][elem][hour][pv][av]);
                                                            sourceKeys.forEach(function (source) {
                                                                //source = (source == 'None')? 'self':source;
                                                                if (sourcesList.indexOf(source) == '-1') {
                                                                    sourcesList.push(source);
                                                                    dataArray.push({ p: value, t: type, ref: source, avgcpi: 0, insUnique: 0, insTotal: 0, unUnique: 0, unTotal: 0 })
                                                                }
                                                                let index = sourcesList.indexOf(source);
                                                                let countries = Object.keys(keyObj[value][elem][hour][pv][av][source]);
                                                                countries.forEach(function (country) {
                                                                    if (keyObj[value][elem][hour][pv][av][source][country]) {
                                                                        let citys = Object.keys(keyObj[value][elem][hour][pv][av][source][country]);
                                                                        citys.forEach(function (city) {
                                                                            let keys = Object.keys(keyObj[value][elem][hour][pv][av][source][country][city]);
                                                                            keys.forEach(function (val) {
                                                                                if (val == 'in' || val == 'ri' || val == 'un' || val == 'ru') {
                                                                                    if (val == 'in') {
                                                                                        dataArray[index].insUnique += keyObj[value][elem][hour][pv][av][source][country][city][val];
                                                                                        dataArray[index].insTotal += keyObj[value][elem][hour][pv][av][source][country][city][val];
                                                                                    } else if (val == 'ri') {
                                                                                        dataArray[index].insTotal += keyObj[value][elem][hour][pv][av][source][country][city][val];
                                                                                    } else if (val == 'un') {
                                                                                        dataArray[index].unUnique += keyObj[value][elem][hour][pv][av][source][country][city][val];
                                                                                        dataArray[index].unTotal += keyObj[value][elem][hour][pv][av][source][country][city][val];
                                                                                    } else if (val == 'ru') {
                                                                                        dataArray[index].unTotal += keyObj[value][elem][hour][pv][av][source][country][city][val];
                                                                                    }
                                                                                }
                                                                                if (val == 'cpi') {
                                                                                    dataArray[index].avgcpi += keyObj[value][elem][hour][pv][av][source][country][city][val];
                                                                                }
                                                                            });
                                                                        });
                                                                    }
                                                                });
                                                            });
                                                        }
                                                    });
                                                }
                                            });
                                        }
                                    });
                                }
                            });

                        }
                    });
                }
            });

        }
        return dataArray;

    }

    let processDownloadCSVData = function (params, data, type) {
        let csvData = '';
        if (data) {
            if (type == 'I') {
                csvData = "Source,Avg CPI,New Installs,Repeat Installs,Total";
                data.forEach(function (value) {
                    if (value.t == "I") {
                        if (value.insTotal > 0) {
                            csvData += "\r\n" + value.ref + "," + value.avgcpi + "," + value.insUnique + "," + (value.insTotal - value.insUnique) + "," + value.insTotal;
                        }
                    }
                });
            } else if (type == 'BOTH') {
                csvData = "Avg CPI,Installs,Source,UnInstalls,Percentage";
                data.forEach(function (value) {
                    if (value.t == "BOTH") {
                        let p = 0 + "%";
                        if (value.unTotal > 0 && value.insTotal > 0) {
                            p = parseFloat(value.unTotal / value.insTotal * 100).toFixed(2) + "%"
                        }
                        if (value.insTotal > 0 || value.unTotal > 0) {
                            csvData += "\r\n" + value.avgcpi + "," + value.insUnique + "(" + value.insTotal + ")," + value.ref + "," + value.unUnique + "(" + value.unTotal + ")," + p;
                        }
                    }
                });
            }
        }
        common.returnCSV(params, csvData);
    }

    function prepareTimelyDashboardData(array, previous, data) {
        if (data.length > 0) {
            let totalUniqueInstall = 0;
            let totalUniqueUninstall = 0;
            let totalUninstall = 0;
            let androidTotal = 0;
            let iosTotal = 0;
            let webTotal = 0;
            let ptotalUninstall = 0;
            let pandroidTotal = 0;
            let piosTotal = 0;
            let pwebTotal = 0;
            let pandroidUninstall = 0;
            let piosUninstall = 0;
            let pwebUninstall = 0;
            let androidTotalU = 0;
            let iosTotalU = 0;
            let webTotalU = 0;
            let totalUninstallss = 0;
            let dataObj = {};
            let sourcesList = [];
            let platformList = [];
            let platforms = ['android', 'ios', 'web'];
            platforms.forEach(function (value) {
                dataObj[value] = [];
                sourcesList = [];
                data.forEach(function (keyObj) {
                    if (keyObj[value] != undefined) {
                        // get time keys
                        let dayKeys = Object.keys(keyObj[value]);
                        dayKeys.forEach(function (day) {
                            let elem = day;
                            if (keyObj[value][elem]) {
                                // get hours keys
                                let hoursKeys = Object.keys(keyObj[value][elem]);
                                hoursKeys.forEach(function (hour) {
                                    if (hour != 'cohort' && keyObj[value][elem][hour]) {
                                        // get pv keys
                                        let pvKeys = Object.keys(keyObj[value][elem][hour]);
                                        pvKeys.forEach(function (pv) {
                                            if (keyObj[value][elem][hour][pv]) {
                                                let avKeys = Object.keys(keyObj[value][elem][hour][pv]);
                                                avKeys.forEach(function (av) {
                                                    if (keyObj[value][elem][hour][pv][av]) {
                                                        let sourceKeys = Object.keys(keyObj[value][elem][hour][pv][av]);
                                                        sourceKeys.forEach(function (source) {
                                                            //source = (source == 'None')? 'self':source;
                                                            if (sourcesList.indexOf(source) == '-1') {
                                                                sourcesList.push(source);
                                                                let obj = {};
                                                                obj[source] = {};
                                                                dataObj[value].push(obj);
                                                            }
                                                            let index = sourcesList.indexOf(source);
                                                            let countries = Object.keys(keyObj[value][elem][hour][pv][av][source]);
                                                            countries.forEach(function (country) {
                                                                if (keyObj[value][elem][hour][pv][av][source][country]) {
                                                                    let citys = Object.keys(keyObj[value][elem][hour][pv][av][source][country]);
                                                                    citys.forEach(function (city) {
                                                                        let keys = Object.keys(keyObj[value][elem][hour][pv][av][source][country][city]);
                                                                        keys.forEach(function (val) {
                                                                            if (val == 'in' || val == 'ri' || val == 'un' || val == 'ru') {
                                                                                if (previous.indexOf(elem) != -1) {
                                                                                    if (value.toLowerCase() == 'android' && (val == 'in' || val == 'ri')) {
                                                                                        pandroidTotal += keyObj[value][elem][hour][pv][av][source][country][city][val];
                                                                                    }
                                                                                    // ios totol install
                                                                                    if (value.toLowerCase() == 'ios' && (val == 'in' || val == 'ri')) {
                                                                                        piosTotal += keyObj[value][elem][hour][pv][av][source][country][city][val];
                                                                                    }
                                                                                    // web total install
                                                                                    if (value.toLowerCase() == 'web' && (val == 'in' || val == 'ri')) {
                                                                                        pwebTotal += keyObj[value][elem][hour][pv][av][source][country][city][val];
                                                                                    }
                                                                                      //android total unistall
                                                                                      if (value.toLowerCase() == 'android' && (val == 'un' || val == 'ru')) {
                                                                                        pandroidUninstall += keyObj[value][elem][hour][pv][av][source][country][city][val];
                                                                                    }

                                                                                    //ios total uninstall
                                                                                    if (value.toLowerCase() == 'ios' && (val == 'un' || val == 'ru')) {
                                                                                        piosUninstall += keyObj[value][elem][hour][pv][av][source][country][city][val];
                                                                                    }

                                                                                    //web total uninstall
                                                                                    if (value.toLowerCase() == 'web' && (val == 'un' || val == 'ru')) {
                                                                                        pwebUninstall += keyObj[value][elem][hour][pv][av][source][country][city][val];
                                                                                    }

                                                                                    // total uninstall
                                                                                    if (val == 'un' || val == 'ru') {
                                                                                        ptotalUninstall += keyObj[value][elem][hour][pv][av][source][country][city][val];
                                                                                    }
                                                                                }
                                                                                else {
                                                                                    if (dataObj[value][index][source][val] == undefined || dataObj[value][index][source][val] == null) {
                                                                                        dataObj[value][index][source][val] = keyObj[value][elem][hour][pv][av][source][country][city][val];
                                                                                    } else {
                                                                                        dataObj[value][index][source][val] += keyObj[value][elem][hour][pv][av][source][country][city][val];
                                                                                    }
                                                                                    // android totol install
                                                                                    if (value.toLowerCase() == 'android' && (val == 'in' || val == 'ri')) {
                                                                                        androidTotal += keyObj[value][elem][hour][pv][av][source][country][city][val];
                                                                                    }
                                                                                    // ios totol install
                                                                                    else if (value.toLowerCase() == 'ios' && (val == 'in' || val == 'ri')) {
                                                                                        iosTotal += keyObj[value][elem][hour][pv][av][source][country][city][val];
                                                                                    }
                                                                                    // web total install
                                                                                    else if (value.toLowerCase() == 'web' && (val == 'in' || val == 'ri')) {
                                                                                        webTotal += keyObj[value][elem][hour][pv][av][source][country][city][val];
                                                                                    }
                                                                                     //android total uninstall
                                                                                     if (value.toLowerCase() == 'android' && (val == 'un' || val == 'ru')) {
                                                                                        androidTotalU += keyObj[value][elem][hour][pv][av][source][country][city][val];
                                                                                     }
                                                                                    //ios total uninstall
                                                                                    if (value.toLowerCase() == 'ios' && (val == 'un' || val == 'ru')) {
                                                                                        iosTotalU += keyObj[value][elem][hour][pv][av][source][country][city][val];
                                                                                    }
                                                                                    //web total uninstall
                                                                                    if (value.toLowerCase() == 'web' && (val == 'un' || val == 'ru')) {
                                                                                        webTotalU += keyObj[value][elem][hour][pv][av][source][country][city][val];
                                                                                    }
                                                                                    // total uninstall
                                                                                    if (val == 'un' || val == 'ru') {
                                                                                        totalUninstall += keyObj[value][elem][hour][pv][av][source][country][city][val];
                                                                                    }
                                                                                    // unique installs
                                                                                    if (val == 'in') {
                                                                                        totalUniqueInstall += keyObj[value][elem][hour][pv][av][source][country][city][val];
                                                                                    }
                                                                                    // unique uninstall
                                                                                    if (val == 'un') {
                                                                                        totalUniqueUninstall += keyObj[value][elem][hour][pv][av][source][country][city][val];
                                                                                    }
                                                                                }
                                                                            }
                                                                            else if (val == 'cpi') {
                                                                                if (dataObj[value][index][source][val] == undefined) {
                                                                                    dataObj[value][index][source][val] = keyObj[value][elem][hour][pv][av][source][country][city][val];
                                                                                } else {
                                                                                    dataObj[value][index][source][val] += keyObj[value][elem][hour][pv][av][source][country][city][val];
                                                                                }
                                                                            }
                                                                        });
                                                                    });
                                                                }
                                                            });
                                                        });
                                                    }
                                                });
                                            }
                                        });
                                    }
                                });
                            }
                        });

                    }
                });
            });

            let c = { all: dataObj, androidTotal: androidTotal, iosTotal: iosTotal, webTotal: webTotal, androidTotalU: androidTotalU, iosTotalU: iosTotalU, webTotalU: webTotalU,totalUninstall: totalUninstall, totalUniqueInstall: totalUniqueInstall, totalUniqueUninstall: totalUniqueUninstall };
            let p = { androidTotal: pandroidTotal, iosTotal: piosTotal, webTotal: pwebTotal, androidU: pandroidUninstall, iosU: piosUninstall, webU: pwebUninstall,totalUninstall: ptotalUninstall };
            let mainObj = { c: c, p: p }
            return mainObj;
        }
        let mainObj = { current: { androidTotal: 0, iosTotal: 0, webTotal: 0, totalUninstall: 0, totalUniqueInstall: 0, totalUniqueUninstall: 0 }, previous: { androidTotal: 0, iosTotal: 0, webTotal: 0, totalUninstall: 0 } };
        return mainObj;
    }


    metricesApi.getCampaignStats = function (params) {
        let argProps = {
            'startDate_C': { 'required': true, 'type': 'Number' },
            'endDate_C': { 'required': true, 'type': 'Number' },
            'startDate_P': { 'required': true, 'type': 'Number' },
            'endDate_P': { 'required': true, 'type': 'Number' },
            'startDate_CNew': { 'required': true, 'type': 'String' },
            'endDate_CNew': { 'required': true, 'type': 'String' },
            'startDate_PNew': { 'required': true, 'type': 'String' },
            'endDate_PNew': { 'required': true, 'type': 'String' }
        }, dateRange = {};
        if (!(dateRange = common.validateArgs(params.qstring.args, argProps))) {
            common.returnMessage(params, 400, 'Not enough args');
            return false;
        }

        // define global variable that store query and iteration for prepare data for frontend
        let query = {};
        let array = [];
        // prepare query for get campaign data with selected date
        common.fillEventQueryObject(query, array, dateRange.startDate_CNew, dateRange.endDate_CNew, 'android', params.qstring.app_id);
        common.fillEventQueryObject(query, array, dateRange.startDate_CNew, dateRange.endDate_CNew, 'ios', params.qstring.app_id);
        common.fillEventQueryObject(query, array, dateRange.startDate_CNew, dateRange.endDate_CNew, 'web', params.qstring.app_id);


        // query on campaign aggregate collection
        common.db.collection('campaign_aggregate').find({ '_id': common.db.ObjectID(params.qstring.app_id) }, query).toArray(function (error, result) {
            if (error) {
                logger.error(`campaign_aggregate error => ${error}`);
                return common.returnOutput(params, []);
            }
            else {
                let resultData = { 'android': [], 'ios': [], 'web': [] };
                if (result) {
                    let platforms = ['android', 'ios', 'web'];
                    result.forEach(function (data) {
                        platforms.forEach(function (p) {
                            let sourceList = [];
                            if (data[p]) {
                                Object.keys(data[p]).forEach(function (date) {
                                    Object.keys(data[p][date]).forEach(function (source) {
                                        if (sourceList.indexOf(source) >= 0) {
                                            insKey = sourceList.indexOf(source);
                                        } else {
                                            let obj = {};
                                            obj[source] = { 'in': 0, 'ri': 0, 'un': 0, 'ru': 0, 'cpi': 0 };
                                            resultData[p].push(obj);
                                            insKey = resultData[p].length - 1;
                                            sourceList.push(source);
                                        }

                                        if (data[p][date][source]['in'])
                                            resultData[p][insKey][source]['in'] += data[p][date][source]['in'];
                                        if (data[p][date][source]['ri'])
                                            resultData[p][insKey][source]['ri'] += data[p][date][source]['ri'];
                                        if (data[p][date][source]['un'])
                                            resultData[p][insKey][source]['un'] += data[p][date][source]['un'];
                                        if (data[p][date][source]['ru'])
                                            resultData[p][insKey][source]['ru'] += data[p][date][source]['ru'];
                                        if (data[p][date][source]['cpi'])
                                            resultData[p][insKey][source]['cpi'] += data[p][date][source]['cpi'];
                                    });
                                });
                            }
                        });
                    })
                }
                return common.returnOutput(params, resultData);
            }
        });

    }

    //This function returns active users.
    /*metricesApi.getActiveUsers = function(params){
        let match = {"active":true};
        common.db.collection('app_users'+params.qstring.app_id).aggregate([
                {$match: {"active":true}},
                { $project :  {
                        date:{
                        "$add": [new Date(0), {"$multiply": ["$ls", 1000]}]
                        }
                    }
                },
                {$project :  {
                        day:{ $dayOfMonth:"$date"},
                        month:{ $month:"$date"},
                        year:{ $year:"$date"},
                    }
                },
                {$group : { _id : {"d":"$day","m":"$month","y":"$year"} , total : { $sum : 1 } } },
                {$project: {"d":"$_id.d","m":"$_id.m","y":"$_id.y",total:1,"_id":0}}
    
            ],function(err,totalUsers){
                if(!err && totalUsers.length > 0){
                    let date = moment().date();
                    let month = moment().month()+1;
                    let year = moment().year();
                    let users = 0;
                    let dau = 0;
                    let mau = 0;
                    totalUsers.forEach(function(val,key){
                        users = users+val.total;
                        if(val.m == month && val.y == year){
                            mau = mau+val.total;
                        }
                        if(val.d == date && val.m == month && val.y == year){
                            dau += val.total;
                        }
                    });
    
                    common.returnOutput(params,{totalUsers:users,dau:dau,mau:mau,hasdata:true});
                }else{
                    common.returnOutput(params,{users:0,hasdata:false});
                }
        });
    };*/

    //[This method is deprocated now]
    //This API is used in installs and uninstalls page to provide different data groupings based on the group param passed from the UI.
    //type parameter controls, "Installs/Uninstalls" return output
    //getprevious when true, returns previous range data set.
    //regained when true, returns regained user count for the current date range.
    metricesApi.getInstallUnistallStatsByParam1 = function (params) {
        let installData = {};
        let argProps = {
            'startDate_C': { 'required': true, 'type': 'Number' },
            'endDate_C': { 'required': true, 'type': 'Number' },
            'startDate_P': { 'required': true, 'type': 'Number' },
            'endDate_P': { 'required': true, 'type': 'Number' },
            'groupParam': { 'required': true, 'type': 'JSON' },
            'getPrevious': { 'required': true, 'type': 'Boolean' },
            'type': { 'required': true, 'type': 'String' },
            'regained': { 'required': false, 'type': 'Boolean' },

        }, dateRange = {};
        if (!(dateRange = common.validateArgs(params.qstring.args, argProps))) {
            common.returnMessage(params, 400, 'Not enough args');
            return false;
        }
        let currentMatch = {}


        if (dateRange.type == "I" || dateRange.type == "U") {
            currentMatch = {
                "history.dtEntry": { $gte: parseInt(dateRange.startDate_C), $lte: parseInt(dateRange.endDate_C) },
                "history.type": dateRange.type
            }
        }
        else {
            currentMatch = {
                "history.dtEntry": { $gte: parseInt(dateRange.startDate_C), $lte: parseInt(dateRange.endDate_C) },
            }
        }
        common.db.collection('app_users' + params.qstring.app_id).aggregate([
            { $unwind: "$history" },
            {
                $project: {
                    date: {
                        "$add": [new Date(0), { "$multiply": ["$history.dtEntry", 1000] }]
                    },
                    "history.type": 1,
                    "history.isnew": 1,
                    "history.dtEntry": 1,
                    "history.refname": 1,
                    "p": { $toLower: "$p" },
                    "pv": { $toLower: "$pv" },
                    "cty": 1,
                    "cc": 1,
                    "av": 1
                }
            },
            { $match: currentMatch },
            {
                $project: {
                    day: { $dayOfMonth: "$date" },
                    month: { $month: "$date" },
                    year: { $year: "$date" },
                    hour: { $hour: "$date" },
                    "history.type": 1,
                    "history.isnew": 1,
                    "history.dtEntry": 1,
                    "history.refname": 1,
                    "p": 1,
                    "pv": 1,
                    "cty": 1,
                    "cc": 1,
                    "av": 1
                }

            },
            { $group: { _id: dateRange.groupParam, total: { $sum: 1 } } },
            { $sort: { total: -1 } }

        ],
        {maxTimeMS:semusiConfig.mongodb.maxTimeMS}
            , function (err, currentInstalls) {
                installData.current = currentInstalls;
                if (dateRange.getPrevious) {
                    common.db.collection('app_users' + params.qstring.app_id).aggregate([
                        { $unwind: "$history" },
                        { $match: { "history.type": dateRange.type, "history.dtEntry": { $gte: parseInt(dateRange.startDate_P), $lte: parseInt(dateRange.endDate_P) } } },
                        { $group: { _id: dateRange.groupParam, total: { $sum: 1 } } },
                        { $sort: { total: -1 } }

                    ]
                        , function (err, previousInstalls) {
                            installData.previous = previousInstalls;

                            //Check if this API needs to return regained users.
                            if (dateRange.regained) {
                                //Regained User: Any user who has uninstalled and installs again any number of times, the count should be only 1 towards regained.
                                common.db.collection('app_users' + params.qstring.app_id).aggregate([
                                    {
                                        $project: {
                                            did: 1,
                                            history: 1,
                                            "historyItems": { "$size": { "$ifNull": ["$history", []] } }
                                        }
                                    },
                                    { $match: { "history.dtEntry": { $gte: parseInt(dateRange.startDate_C), $lte: parseInt(dateRange.endDate_C) }, "historyItems": { $gt: 2 } } },
                                    { $unwind: "$history" },
                                    { $group: { "_id": { did: "$did" }, "history": { $last: "$history" } } },
                                    { $project: { _id: 1, history: "$history" } },
                                    { $match: { "history.type": "I" } }

                                ]
                                    , function (err, regainedUsers) {
                                        installData.regainedusers = regainedUsers.length;
                                        common.returnOutput(params, installData);
                                    });
                            }
                            else {
                                common.returnOutput(params, installData);
                            }
                        });
                }
                else {
                    //Check if this API needs to return regained users.
                    if (dateRange.regained) {
                        //Regained User:Any user who has uninstalled and installs again any number of times, the count should be only 1 towards regained.
                        common.db.collection('app_users' + params.qstring.app_id).aggregate([
                            {
                                $project: {
                                    did: 1,
                                    history: 1,
                                    "historyItems": { "$size": { "$ifNull": ["$history", []] } }
                                }
                            },
                            { $match: { "history.dtEntry": { $gte: parseInt(dateRange.startDate_C), $lte: parseInt(dateRange.endDate_C) }, "historyItems": { $gt: 2 } } },
                            { $unwind: "$history" },
                            { $group: { "_id": { did: "$did" }, "history": { $last: "$history" } } },
                            { $project: { _id: 1, history: "$history" } },
                            { $match: { "history.type": "I" } }

                        ]
                            , function (err, regainedUsers) {
                                installData.regainedusers = regainedUsers.length;
                                common.returnOutput(params, installData);
                            });
                    }
                    else {
                        common.returnOutput(params, installData);
                    }
                }

            });

    };

   //THis function returns install uninstall stats, grouped on various parameters as required by the front end UI.
   metricesApi.getInstallUnistallStatsByParam = function (params) {
    let installData = {};
    let argProps = {
        'startDate_C': { 'required': true, 'type': 'Number' },
        'endDate_C': { 'required': true, 'type': 'Number' },
        'startDate_P': { 'required': true, 'type': 'Number' },
        'endDate_P': { 'required': true, 'type': 'Number' },
        'startDate_CNew': { 'required': true, 'type': 'String' },
        'endDate_CNew': { 'required': true, 'type': 'String' },
        'startDate_PNew': { 'required': true, 'type': 'String' },
        'endDate_PNew': { 'required': true, 'type': 'String' },
        'type': { 'required': true, 'type': 'String' },
        'downloadFlag': { 'required': false, 'type': 'Boolean' },
        'downloadData': { 'required': false, 'type': 'String' },
        'platform': { 'required': false, 'type': 'String' }

    }, dateRange = {};
    if (!(dateRange = common.validateArgs(params.qstring.args, argProps))) {
        common.returnMessage(params, 400, 'Not enough args');
        return false;
    }

    let current = [];
    let previous = [];
    let array = [];
    let query = {}
    common.fillInstallQueryObject(query, array, current, dateRange.startDate_CNew, dateRange.endDate_CNew, 'android', params.qstring.app_id);
    common.fillInstallQueryObject(query, array, current, dateRange.startDate_CNew, dateRange.endDate_CNew, 'ios', params.qstring.app_id);
    common.fillInstallQueryObject(query, array, current, dateRange.startDate_CNew, dateRange.endDate_CNew, 'web', params.qstring.app_id);

    common.fillInstallQueryObject(query, array, previous, dateRange.startDate_PNew, dateRange.endDate_PNew, 'android', params.qstring.app_id);
    common.fillInstallQueryObject(query, array, previous, dateRange.startDate_PNew, dateRange.endDate_PNew, 'ios', params.qstring.app_id);
    common.fillInstallQueryObject(query, array, previous, dateRange.startDate_PNew, dateRange.endDate_PNew, 'web', params.qstring.app_id);

    common.db.collection('timely_dashboard').find({ _id: { $in: array } }, query).maxTimeMS(semusiConfig.mongodb.maxTimeMS).toArray(function (error, result) {
        if (!error) {
            if (dateRange.type == "I") {
                let data = prepareInstallData(result, current, previous, params.qstring.app_id, dateRange.downloadFlag );
                if (dateRange.downloadFlag == true) {
                    processDownloadInstallUninstallCSV(params, data, dateRange.downloadData, dateRange.platform, dateRange.type);
                }
                else {
                    data.appversion =  prepareTimelyAvData(result);
                    common.returnOutput(params, data);
                }
            }
            else if (dateRange.type == "U") {
                let data = prepareUninstallData(result, current, previous, params.qstring.app_id);
                if (dateRange.downloadFlag == true) {
                    processDownloadInstallUninstallCSV(params, data, dateRange.downloadData, dateRange.platform, dateRange.type);
                }
                else {
                    data.appversion =  prepareTimelyAvData(result);
                    common.returnOutput(params, data);
                }
            }
        }
        else {
            common.returnOutput(params, []);
        }
    });
};
    metricesApi.getInstallUnistallStatsByParamOld = function (params) {
        let installData = {};
        let argProps = {
            'startDate_C': { 'required': true, 'type': 'Number' },
            'endDate_C': { 'required': true, 'type': 'Number' },
            'startDate_P': { 'required': true, 'type': 'Number' },
            'endDate_P': { 'required': true, 'type': 'Number' },
            'type': { 'required': true, 'type': 'String' },
            'downloadFlag': { 'required': false, 'type': 'Boolean' },
            'downloadData': { 'required': false, 'type': 'String' },
            'platform': { 'required': false, 'type': 'String' }

        }, dateRange = {};
        if (!(dateRange = common.validateArgs(params.qstring.args, argProps))) {
            common.returnMessage(params, 400, 'Not enough args');
            return false;
        }
        let currentMatch = {}


        if (dateRange.type == "I" || dateRange.type == "U") {
            currentMatch = {
                "history.dtEntry": { $gte: parseInt(dateRange.startDate_P), $lte: parseInt(dateRange.endDate_C) },
                "history.type": dateRange.type
            }
        }
        else {
            currentMatch = {
                "history.dtEntry": { $gte: parseInt(dateRange.startDate_P), $lte: parseInt(dateRange.endDate_C) },
            }
        }

        common.db.collection('app_users' + params.qstring.app_id).aggregate([
            //common.db.collection('app_users55d57203ec8d936962000004').aggregate([
            { $match: currentMatch },
            { $unwind: "$history" },
            { $match: currentMatch },
            {
                $project: {
                    date: {
                        "$add": [new Date(0), { "$multiply": ["$history.dtEntry", 1000] }]
                    },
                    "history.type": 1,
                    "history.isnew": 1,
                    "history.dtEntry": 1,
                    "history.refname": 1,
                    "p": { $toLower: "$p" },
                    "pv": { $toLower: "$pv" },
                    "cty": 1,
                    "cc": 1,
                    "av": 1,
                    "s": { $cond: { if: { $lt: ["$history.dtEntry", dateRange.startDate_C] }, then: "p", else: "c" } }
                }
            },
            {
                $project: {
                    day: { $dayOfMonth: "$date" },
                    month: { $month: "$date" },
                    year: { $year: "$date" },
                    hour: { $hour: "$date" },
                    "history.type": 1,
                    "history.isnew": 1,
                    "history.dtEntry": 1,
                    "history.refname": 1,
                    "p": 1,
                    "pv": 1,
                    "cty": 1,
                    "cc": 1,
                    "av": 1,
                    "s": 1
                }

            },
            { $group: { _id: { "p": "$p", "pv": "$pv", "av": "$av", "cty": "$cty", "cc": "$cc", "d": "$day", "isnew": "$history.isnew", "h": "$hour", "t": "$history.type", "s": "$s" }, total: { $sum: 1 } } },
            { $project: { "p": "$_id.p", "pv": "$_id.pv", "av": "$_id.av", "cty": "$_id.cty", "cc": "$_id.cc", "d": "$_id.d", "h": "$_id.h", "isnew": "$_id.isnew", "t": "$_id.t", "s": "$_id.s", total: 1, "_id": 0 } },
            { $sort: { s: 1, total: -1 } }

        ], function (err, data) {
            let result = {};
            if (dateRange.type == "U") {
                result.appversions = getPlatformAndAppVersionWiseData(data);
                result.platforms = getPlatformWiseData(data);
                result.totals = getNewAndRepeatTotals(data);
                result.cities = getCityWiseData(data);
                result.countries = getCountryWiseData(data);
                result.days = getPlatformAndDayWiseData(data);
                result.hours = getPlatformAndHourWiseData(data);
            }
            else if (dateRange.type == "I") {
                result.cities = getCityWiseData(data);
                result.countries = getCountryWiseData(data);
                result.versions = getPlatformAndVersionWiseData(data);
                result.days = getPlatformAndDayWiseData(data);
                result.hours = getPlatformAndHourWiseData(data);
            }
            if (dateRange.downloadFlag == true) {
                processDownloadData(params, result, dateRange.downloadData, dateRange.type, dateRange.platform);
            }
            else {
                common.returnOutput(params, result);
            }
        });
    };

    metricesApi.getInstallUnistallStatsBySourceOld = function (params) {
        let installData = {};
        let argProps = {
            'startDate_C': { 'required': true, 'type': 'Number' },
            'endDate_C': { 'required': true, 'type': 'Number' },
            'type': { 'required': true, 'type': 'String' },
            'downloadFlag': { 'required': false, 'type': 'Boolean' },
            'downloadData': { 'required': false, 'type': 'String' },
            'platform': { 'required': false, 'type': 'String' },


        }, dateRange = {};
        if (!(dateRange = common.validateArgs(params.qstring.args, argProps))) {
            common.returnMessage(params, 400, 'Not enough args');
            return false;
        }
        let currentMatch = {}


        if (dateRange.type == "I" || dateRange.type == "U") {
            currentMatch = {
                "history.dtEntry": { $gte: parseInt(dateRange.startDate_C), $lte: parseInt(dateRange.endDate_C) },
                "history.type": dateRange.type
            }
        }
        else {
            currentMatch = {
                "history.dtEntry": { $gte: parseInt(dateRange.startDate_C), $lte: parseInt(dateRange.endDate_C) },
            }
        }

        common.db.collection('app_users' + params.qstring.app_id).aggregate([
            //common.db.collection('app_users55d57203ec8d936962000004').aggregate([
            { $match: currentMatch },
            { $unwind: "$history" },
            { $match: currentMatch },
            {
                $project: {
                    "history.type": 1,
                    "history.isnew": 1,
                    "history.dtEntry": 1,
                    "history.refname": 1,
                    "history.cpi": 1,
                    "p": { $toLower: "$p" },

                }
            },
            { $group: { _id: { "p": "$p", "isnew": "$history.isnew", "t": "$history.type", "ref": "$history.refname" }, total: { $sum: 1 }, avgcpi: { $avg: "$history.cpi" } } },
            { $project: { "p": "$_id.p", "isnew": "$_id.isnew", "t": "$_id.t", "ref": "$_id.ref", total: 1, avgcpi: 1, "_id": 0 } },
            { $sort: { total: -1 } }

        ],
        {maxTimeMS:semusiConfig.mongodb.maxTimeMS}, 
        function (err, data) {
            let result = {};

            result.installs = getSourceWiseInstallsUninstalls(data);
            if (dateRange.downloadFlag == true) {
                processDownloadData(params, result, dateRange.downloadData, dateRange.type, dateRange.platform);
            }
            else {
                common.returnOutput(params, result);
            }

        });
    };

    let processDownloadInstallUninstallCSV = function (params, data, downloadData, platform, type) {
        if (downloadData == "versions") {
            let csvData = "Platform,Total";
            let dataArray = [];
            let tmpOs = [];
            data.osversionWiseData_currentData.forEach(function (item) {
                if (item.s == "c" && (item.p == platform || platform == "all")) {
                    if (tmpOs.indexOf(item.pv) == -1) {
                        tmpOs.push(item.pv);
                        dataArray.push({ p: item.p, pv: item.pv, total: 0 });
                    }
                    let index = tmpOs.indexOf(item.pv);
                    dataArray[index].total += item.total;
                }
            });

            tmpOs = [];

            dataArray.forEach(function (item) {
                csvData += "\r\n" + common.toFirstUpper(item.p) + " " + item.pv.replace(/a/g, "").replace(/i/g, "").replace(/:/g, ".") + "," + item.total;
            });

            common.returnCSV(params, csvData);
        } else if (downloadData == "cities") {
            let csvData = "City,Total";
            let dataArray = [];
            let tmpOs = [];
            data.cityWiseData_currentData.forEach(function (item) {
                if (item.s == "c") {
                    if (tmpOs.indexOf(item.cty) == -1) {
                        tmpOs.push(item.cty);
                        dataArray.push({ cty: item.cty, total: 0 });
                    }
                    let index = tmpOs.indexOf(item.cty);
                    dataArray[index].total += item.total;
                }
            });

            tmpOs = [];
            dataArray.forEach(function (item) {
                csvData += "\r\n" + common.sanitizeString(item.cty) + "," + item.total;
            });
            common.returnCSV(params, csvData);
        }
        else if (downloadData == "countries") {
            let csvData = "Country,Total";
            let dataArray = [];
            let tmpOs = [];
            data.countryWiseData_currentData.forEach(function (item) {
                if (item.s == "c") {
                    if (tmpOs.indexOf(item.cc) == -1) {
                        tmpOs.push(item.cc);
                        dataArray.push({ cc: item.cc, total: 0 });
                    }
                    let index = tmpOs.indexOf(item.cc);
                    dataArray[index].total += item.total;
                }
            });

            tmpOs = [];
            dataArray.forEach(function (item) {
                csvData += "\r\n" + common.sanitizeString(item.cc )+ "," + item.total;
            });
            common.returnCSV(params, csvData);
        }
        else if (downloadData == "days") {
            let csvData;
            if (type == "I") {
                csvData = "Day,Platform,"+common.sanitizeString('New Installs')+","+common.sanitizeString('Repeat Installs')+",Total";
                let dataArray = [];
                let tmpOs = [];
                data.dayWiseData_newData.forEach(function (item) {
                    if (item.s == "c" && (item.p == platform || platform == 'all')) {
                        if (tmpOs.indexOf(item.d) == -1) {
                            tmpOs.push(item.d);
                            dataArray.push({ d: parseInt(item.d), p: item.p, n: 0, r: 0, total: 0 });
                        }
                        let index = tmpOs.indexOf(item.d);
                        if (item.isnew == true) {
                            dataArray[index].n += item.total;
                            dataArray[index].total += item.total;
                        }
                    }
                });

                data.dayWiseData_repeatData.forEach(function (item) {
                    if (item.s == "c" && (item.p == platform || platform == 'all')) {
                        if (tmpOs.indexOf(item.d) == -1) {
                            tmpOs.push(item.d);
                            dataArray.push({ d: parseInt(item.d), p: item.p, n: 0, r: 0, total: 0 });
                        }
                        let index = tmpOs.indexOf(item.d);
                        if (item.isnew == false) {
                            dataArray[index].r += item.total;
                            dataArray[index].total += item.total;
                        }
                    }
                });

                tmpOs = [];
                  // Sort the array using the comparison function
                dataArray.sort(function(a, b){return a.d - b.d});  
                dataArray.forEach(function (item) {
                    csvData += "\r\n" + item.d + "," + common.toFirstUpper(item.p) + "," + item.n + "," + item.r + "," + item.total;
                });
            }
            else {
                csvData = "Day,Platform,"+common.sanitizeString('New UnInstalls')+","+common.sanitizeString('Repeat UnInstalls')+",Total";
                let dataArray = [];
                let tmpOs = [];
                data.dayWiseData_newData.forEach(function (item) {
                    if (item.s == "c" && (item.p == platform || platform == 'all')) {
                        if (tmpOs.indexOf(item.d) == -1) {
                            tmpOs.push(item.d);
                            dataArray.push({ d: parseInt(item.d), p: item.p, n: 0, r: 0, total: 0 });
                        }
                        let index = tmpOs.indexOf(item.d);
                        if (item.isnew == true) {
                            dataArray[index].n += item.total;
                            dataArray[index].total += item.total;
                        }
                    }
                });

                data.dayWiseData_repeatData.forEach(function (item) {
                    if (item.s == "c" && (item.p == platform || platform == 'all')) {
                        if (tmpOs.indexOf(item.d) == -1) {
                            tmpOs.push(item.d);
                            dataArray.push({ d: parseInt(item.d), p: item.p, n: 0, r: 0, total: 0 });
                        }
                        let index = tmpOs.indexOf(item.d);
                        if (item.isnew == false) {
                            dataArray[index].r += item.total;
                            dataArray[index].total += item.total;
                        }
                    }
                });

                tmpOs = [];
                  // Sort the array using the comparison function
                dataArray.sort(function(a, b){return a.d - b.d});  
                dataArray.forEach(function (item) {
                    csvData += "\r\n" + item.d + "," + common.toFirstUpper(item.p) + "," + item.n + "," + item.r + "," + item.total;
                });
            }

            common.returnCSV(params, csvData);
        }
        else if (downloadData == "hours") {
            let csvData;
            if (type == "I") {
                csvData = "Hour,Platform,"+common.sanitizeString('New Installs')+","+common.sanitizeString('Repeat Installs')+",Total";
                let dataArray = [];
                let tmpOs = [];
                data.timeWiseData_newData.forEach(function (item) {
                    if (item.s == "c" && (item.p == platform || platform == 'all')) {
                        if (tmpOs.indexOf(item.h) == -1) {
                            tmpOs.push(item.h);
                            dataArray.push({ h: parseInt(item.h), p: item.p, n: 0, r: 0, total: 0 });
                        }
                        let index = tmpOs.indexOf(item.h);
                        if (item.isnew == true) {
                            dataArray[index].n += item.total;
                            dataArray[index].total += item.total;
                        }
                    }
                });

                data.timeWiseData_repeatData.forEach(function (item) {
                    if (item.s == "c" && (item.p == platform || platform == 'all')) {
                        if (tmpOs.indexOf(item.h) == -1) {
                            tmpOs.push(item.h);
                            dataArray.push({ h: parseInt(item.h), p: item.p, n: 0, r: 0, total: 0 });
                        }
                        let index = tmpOs.indexOf(item.h);
                        if (item.isnew == false) {
                            dataArray[index].r += item.total;
                            dataArray[index].total += item.total;
                        }
                    }
                });

                tmpOs = [];
                  // Sort the array using the comparison function
                  dataArray.sort(function(a, b){return a.h - b.h});                    
                dataArray.forEach(function (item) {
                    csvData += "\r\n" + item.h + "," + common.toFirstUpper(item.p) + "," + item.n + "," + item.r + "," + item.total;
                });
            }
            else {
                csvData = "Hour,Platform,"+common.sanitizeString('New UnInstalls')+","+common.sanitizeString('Repeat UnInstalls')+",Total";
                let dataArray = [];
                let tmpOs = [];
                data.timeWiseData_newData.forEach(function (item) {
                    if (item.s == "c" && (item.p == platform || platform == 'all')) {
                        if (tmpOs.indexOf(item.h) == -1) {
                            tmpOs.push(item.h);
                            dataArray.push({ h: parseInt(item.h), p: item.p, n: 0, r: 0, total: 0 });
                        }
                        let index = tmpOs.indexOf(item.h);
                        if (item.isnew == true) {
                            dataArray[index].n += item.total;
                            dataArray[index].total += item.total;
                        }
                    }
                });

                data.timeWiseData_repeatData.forEach(function (item) {
                    if (item.s == "c" && (item.p == platform || platform == 'all')) {
                        if (tmpOs.indexOf(item.h) == -1) {
                            tmpOs.push(item.h);
                            dataArray.push({ h: parseInt(item.h), p: item.p, n: 0, r: 0, total: 0 });
                        }
                        let index = tmpOs.indexOf(item.h);
                        if (item.isnew == false) {
                            dataArray[index].r += item.total;
                            dataArray[index].total += item.total;
                        }
                    }
                });

                tmpOs = [];
                  // Sort the array using the comparison function
                  dataArray.sort(function(a, b){return a.h - b.h});  
                dataArray.forEach(function (item) {
                    csvData += "\r\n" + item.h + "," + common.toFirstUpper(item.p) + "," + item.n + "," + item.r + "," + item.total;
                });
            }

            common.returnCSV(params, csvData);
        }
        else if (downloadData == "appversions") {
            let csvData = "Platform,App Version,Total";
            let dataArray = [];
            let tmpOs = [];
            data.appversionWiseData_currentData.forEach(function (item) {
                if (item.s == "c" && (item.p == platform || platform == "all")) {
                    if (tmpOs.indexOf(item.av) == -1) {
                        tmpOs.push(item.av);
                        dataArray.push({ p: item.p, av: item.av, total: 0 });
                    }
                    let index = tmpOs.indexOf(item.av);
                    dataArray[index].total += item.total;
                }
            });

            tmpOs = [];
            dataArray.forEach(function (item) {
                csvData += "\r\n" + common.toFirstUpper(item.p) + "," + item.av.replace(/a/g, "").replace(/i/g, "").replace(/:/g, ".") + "," + item.total;
            });

            common.returnCSV(params, csvData);
        }
    }

    let prepareInstallData = function (data, current, previous, appId, downloadFlag) {
        let cityWiseData_currentData = [];
        let cityWiseData_previousData = [];
        let countryWiseData_currentData = [];
        let countryWiseData_previousData = [];
        // os version variables
        let osversionWiseData_currentData = [];
        let osversionWiseData_previousData = [];
        // time variables
        let timeWiseData_newData = [];
        let timeWiseData_repeatData = [];
        // day variables
        let dayWiseData_newData = [];
        let dayWiseData_repeatData = [];

        if (data.length > 0) {
            let platforms = ['android', 'ios', 'web'];
            data.forEach(function (dataObj) {
                let tmpObj = common.getYearMonth(appId, dataObj._id);
                platforms.forEach(function (value) {
                    if (dataObj[value] != undefined) {
                        let dayKeys = Object.keys(dataObj[value]);
                        dayKeys.forEach(function (elem) {
                            if (dataObj[value][elem]) {
                                let day = elem.split("_");
                                day = day[2];
                                let tmpDate = tmpObj.y + "-" + tmpObj.m + "-" + day;
                                let installDay = {};
                                installDay['d'] = day;
                                installDay['s'] = 'c';
                                installDay['isnew'] = true;
                                installDay['p'] = value;
                                installDay['total'] = 0;

                                let repeatDay = {};
                                repeatDay['d'] = day;
                                repeatDay['s'] = 'c';
                                repeatDay['isnew'] = false;
                                repeatDay['p'] = value;
                                repeatDay['total'] = 0;

                                // get hours keys
                                let hoursKeys = Object.keys(dataObj[value][elem]);
                                hoursKeys.forEach(function (hour) {
                                    if (hour != 'cohort' && dataObj[value][elem][hour]) {
                                        let installTime = {};
                                        installTime['h'] = hour;
                                        installTime['s'] = 'c';
                                        installTime['isnew'] = true;
                                        installTime['p'] = value;
                                        installTime['total'] = 0;

                                        let repeatTime = {};
                                        repeatTime['h'] = hour;
                                        repeatTime['s'] = 'c';
                                        repeatTime['isnew'] = false;
                                        repeatTime['p'] = value;
                                        repeatTime['total'] = 0;

                                        // get pv keys
                                        let pvKeys = Object.keys(dataObj[value][elem][hour]);
                                        pvKeys.forEach(function (pv) {
                                            if (dataObj[value][elem][hour][pv]) {
                                                let installPv = {};
                                                installPv['s'] = 'c';
                                                installPv['pv'] = pv.replace(/\_/g, ".");
                                                installPv['p'] = value;
                                                installPv['total'] = 0;

                                                let repeatPv = {};
                                                repeatPv['s'] = 'p';
                                                repeatPv['pv'] = pv.replace(/\_/g, ".");
                                                repeatPv['p'] = value;
                                                repeatPv['total'] = 0;

                                                let avKeys = Object.keys(dataObj[value][elem][hour][pv]);
                                                avKeys.forEach(function (av) {
                                                    if (dataObj[value][elem][hour][pv][av]) {
                                                        let sourceKeys = Object.keys(dataObj[value][elem][hour][pv][av]);
                                                        sourceKeys.forEach(function (source) {
                                                            let countries = Object.keys(dataObj[value][elem][hour][pv][av][source]);
                                                            countries.forEach(function (country) {
                                                                let currentCountry = {};
                                                                currentCountry['s'] = 'c';
                                                                currentCountry['cc'] = country;
                                                                currentCountry['total'] = 0;
                                                                let previousCountry = {};
                                                                previousCountry['s'] = 'p';
                                                                previousCountry['cc'] = country;
                                                                previousCountry['total'] = 0;
                                                                let citys = Object.keys(dataObj[value][elem][hour][pv][av][source][country]);
                                                                citys.forEach(function (city) {
                                                                    let currentCity = {};
                                                                    currentCity['s'] = 'c';
                                                                    currentCity['cty'] = city;
                                                                    currentCity['total'] = 0;
                                                                    let previousCity = {};
                                                                    previousCity['s'] = 'p';
                                                                    previousCity['cty'] = city;
                                                                    previousCity['total'] = 0;
                                                                    let keys = Object.keys(dataObj[value][elem][hour][pv][av][source][country][city]);
                                                                    keys.forEach(function (val) {
                                                                        if (previous.indexOf(elem) != -1) {
                                                                            if (val == 'in' || val == 'ri') {
                                                                                previousCity['total'] += dataObj[value][elem][hour][pv][av][source][country][city][val];
                                                                                previousCountry['total'] += dataObj[value][elem][hour][pv][av][source][country][city][val];
                                                                                repeatPv['total'] += dataObj[value][elem][hour][pv][av][source][country][city][val];
                                                                            }
                                                                        } else {
                                                                            // unique installs
                                                                            if (val == 'in' || val == 'ri') {
                                                                                currentCity['total'] += dataObj[value][elem][hour][pv][av][source][country][city][val];
                                                                                installPv['total'] += dataObj[value][elem][hour][pv][av][source][country][city][val];
                                                                                currentCountry['total'] += dataObj[value][elem][hour][pv][av][source][country][city][val];
                                                                            }
                                                                            if (val == 'ri') {
                                                                                repeatDay['total'] += dataObj[value][elem][hour][pv][av][source][country][city][val];
                                                                                repeatTime['total'] += dataObj[value][elem][hour][pv][av][source][country][city][val];
                                                                            }
                                                                            if (val == 'in') {
                                                                                installDay['total'] += dataObj[value][elem][hour][pv][av][source][country][city][val];
                                                                                installTime['total'] += dataObj[value][elem][hour][pv][av][source][country][city][val];
                                                                            }
                                                                        }
                                                                    });
                                                                    if (currentCity['total'] > 0) {
                                                                        cityWiseData_currentData.push(currentCity);
                                                                    }

                                                                    if (previousCity['total'] > 0) {
                                                                        cityWiseData_previousData.push(previousCity);
                                                                    }
                                                                });

                                                                if (currentCountry['total'] > 0) {
                                                                    countryWiseData_currentData.push(currentCountry);
                                                                }
                                                                if (previousCountry['total'] > 0) {
                                                                    countryWiseData_previousData.push(previousCountry);
                                                                }
                                                            });
                                                        });
                                                    }
                                                });

                                                if (installPv['total'] > 0) {
                                                    osversionWiseData_currentData.push(installPv);
                                                }

                                                if (repeatPv['total'] > 0) {
                                                    osversionWiseData_previousData.push(repeatPv);
                                                }
                                            }
                                        });

                                        if (installTime['total'] > 0) {
                                            timeWiseData_newData.push(installTime);
                                        }

                                        if (repeatTime['total'] > 0) {
                                            timeWiseData_repeatData.push(repeatTime);
                                        }
                                    }
                                });

                                if (installDay['total'] > 0) {
                                    dayWiseData_newData.push(installDay);
                                }
                                if (repeatDay['total'] > 0) {
                                    dayWiseData_repeatData.push(repeatDay);
                                }
                            }
                        });
                    }
                });
            });
        }

        let obj = {
            cityWiseData_currentData: cityWiseData_currentData,
            cityWiseData_previousData: cityWiseData_previousData,
            countryWiseData_currentData: countryWiseData_currentData,
            countryWiseData_previousData: countryWiseData_previousData,
            osversionWiseData_currentData: osversionWiseData_currentData,
            osversionWiseData_previousData: osversionWiseData_previousData,
            timeWiseData_newData: timeWiseData_newData,
            timeWiseData_repeatData: timeWiseData_repeatData,
            dayWiseData_newData: dayWiseData_newData,
            dayWiseData_repeatData: dayWiseData_repeatData
        }
        if (downloadFlag){
            return obj;
        }
        else{
            /***Start with frontend logic ***/

            let cityWiseData ={currentData:[],previousData:[]};
            let countryWiseData ={currentData:[],previousData:[]};
            let osversionWiseData ={currentData:[],previousData:[]};
            let timeWiseData = {newdata:[],repeatData:[]};
            let dayWiseData = {newdata:[],repeatData:[]};


            cityWiseData.currentData= obj.cityWiseData_currentData;
            cityWiseData.previousData= obj.cityWiseData_previousData;
            countryWiseData.currentData=obj.countryWiseData_currentData;
            countryWiseData.previousData=obj.countryWiseData_previousData;
            // os version variables
            osversionWiseData.currentData=obj.osversionWiseData_currentData;
            osversionWiseData.previousData=obj.osversionWiseData_previousData;
            // time variables
            timeWiseData.newData=obj.timeWiseData_newData;
            timeWiseData.repeatData=obj.timeWiseData_repeatData;
            // day variables
            dayWiseData.newData=obj.dayWiseData_newData;
            dayWiseData.repeatData=obj.dayWiseData_repeatData;

            let populateTopCity =  populateTopCityData(cityWiseData.currentData,cityWiseData.previousData);
            let populateTopOSVersion = populateTopOSVersionData(osversionWiseData.currentData,osversionWiseData.previousData);
            let populateTopCountry = populateTopCountryData( countryWiseData.currentData,countryWiseData.previousData);

            let finalobj = {
                cityWiseData: populateTopCity,
                countryWiseData: populateTopCountry,
                osversionWiseData: populateTopOSVersion,
                timeWiseData: timeWiseData,
                dayWiseData:dayWiseData,
            }
            return finalobj;
        }

    }

        //This method populates UI with city data.
    let populateTopCityData = function(currentData,previousData){
                currentData =  currentData;
                previousData = previousData;
                let data=[];
                let ctyArr = [];
                if(currentData && currentData.length>0){
                    let result=_.groupBy(currentData,"cty");
                    let keys = Object.keys(result)
                    let data=[];
                    let i = 0;
                    keys.forEach(function(item){
                        let totalCity = 0;
                        result[item].forEach(function(city){
                            totalCity += city.total;
                        })
                        data[i]=[];
                        data[i][0] = (item) ? item : "NA";
                        data[i][1] = totalCity;
                        data[i][2] = 0
                        i++;
                    })
                }
                data = data.filter(function(n){ return n != undefined });
                //If we have current period data, then calculate previous period data for the same
                for(let i = 0; i < data.length; i++){
                    for(let x=0;x<previousData.length; x++) {
                        if(previousData[x].cty == data[i][0] || (previousData[x].cty == undefined && data[i][0]=="NA") ){
                            data[i][2] += previousData[x].total;
                        }
                    }
                };
             data.sort(function(a, b) {
                return b[1] - a[1];
             });
             return data;  
        }


      //This method populates app version wise data on UI.
      let populateTopOSVersionData = function(currentData, previousData) {
        let result;
        if (currentData && currentData.length > 0) {
        //let result=_.groupBy(currentData,"cc");
            result = _.groupBy(currentData, function(value) {
                return value.p + ' ' + value.pv;
            });
        }
        return { OScurrentData: result, OSpreviousData: previousData };
    }


  let populateTopCountryData = function(currentData,previousData){

    currentData = currentData;
    previousData = previousData;
    let data=[];
    if(currentData && currentData.length>0){
        let result=_.groupBy(currentData,"cc");
        let keys = Object.keys(result)
        let data=[];
        let i = 0;
        keys.forEach(function(item){
            let totalCc = 0;
            result[item].forEach(function(city){
                totalCc += city.total;
            })
            data[i]=[];
            data[i][0] = (item) ? item : "NA";
            data[i][1] = totalCc;
            data[i][2] = 0
            i++;
        })
     
    }
    data = data.filter(function(n){ return n != undefined });
    //If we have current period data, then calculate previous period data for the same
    for(let i = 0; i < data.length; i++){
        for(let x=0;x<previousData.length; x++) {
            if(previousData[x].cc == data[i][0] || (previousData[x].cc == undefined && data[i][0]=="NA") ){
                data[i][2] += previousData[x].total;
            }
        }
    };
    data.sort(function(a, b) {
        return b[1] - a[1];
    });
    return data;

}

    let prepareUninstallData = function (data, current, previous, appId) {
        let populateUninstalls = {};
        // location variable
        let cityWiseData_currentData = [];
        let cityWiseData_previousData = [];
        let countryWiseData_currentData = [];
        let countryWiseData_previousData = [];
        // os version variables
        let appversionWiseData_currentData = [];
        let appversionWiseData_previousData = [];
        // time variables
        let timeWiseData_newData = [];
        let timeWiseData_repeatData = [];
        // day variables
        let dayWiseData_newData = [];
        let dayWiseData_repeatData = [];

        let androidTotalUninstalls = 0;
        let androidUniqueUninstalls = 0;
        let iosTotalUninstalls = 0;
        let iosUniqueUninstalls = 0;
        let webTotalUninstalls = 0;
        let webUniqueUninstalls = 0;
        let totalUn = 0;

        if (data.length > 0) {
            let totalUniqueInstall = 0;
            let totalUniqueUninstall = 0;
            let totalUninstall = 0;
            let androidTotalUninstalls = 0;
            let iosTotal = 0;
            let webTotal = 0;

            let dataObj = {};
            let sourcesList = [];
            let platformList = [];
            let platforms = ['android', 'ios', 'web'];

            platforms.forEach(function (value) {
                dataObj[value] = [];
                sourcesList = [];
                data.forEach(function (keyObj) {
                    if (keyObj[value] != undefined) {
                        let tmpObj = common.getYearMonth(appId, keyObj._id);
                        let dayKeys = Object.keys(keyObj[value]);
                        dayKeys.forEach(function (elem) {
                            let day = elem.split("_");
                            day = day[2];
                            if (keyObj[value][elem]) {
                                let tmpDate = tmpObj.y + "-" + tmpObj.m + "-" + day;
                                let uninstallDay = {};
                                uninstallDay['d'] = day;
                                uninstallDay['s'] = 'c';
                                uninstallDay['isnew'] = true;
                                uninstallDay['p'] = value;
                                uninstallDay['total'] = 0;

                                let repeatDay = {};
                                repeatDay['d'] = day;
                                repeatDay['s'] = 'c';
                                repeatDay['isnew'] = false;
                                repeatDay['p'] = value;
                                repeatDay['total'] = 0;
                                // get hours keys
                                let hoursKeys = Object.keys(keyObj[value][elem]);
                                hoursKeys.forEach(function (hour) {
                                    if (hour != 'cohort' && keyObj[value][elem][hour]) {
                                        let uninstallTime = {};
                                        uninstallTime['h'] = hour;
                                        uninstallTime['s'] = 'c';
                                        uninstallTime['isnew'] = true;
                                        uninstallTime['p'] = value;
                                        uninstallTime['total'] = 0;

                                        let repeatTime = {};
                                        repeatTime['h'] = hour;
                                        repeatTime['s'] = 'c';
                                        repeatTime['isnew'] = false;
                                        repeatTime['p'] = value;
                                        repeatTime['total'] = 0;
                                        // get pv keys
                                        let pvKeys = Object.keys(keyObj[value][elem][hour]);
                                        pvKeys.forEach(function (pv) {
                                            if (keyObj[value][elem][hour][pv]) {
                                                let avKeys = Object.keys(keyObj[value][elem][hour][pv]);
                                                avKeys.forEach(function (av) {
                                                    if (keyObj[value][elem][hour][pv][av]) {
                                                        let uninstallAv = {};
                                                        uninstallAv['s'] = 'c';
                                                        uninstallAv['av'] = av.replace(/\_/g, ".");
                                                        uninstallAv['p'] = value;
                                                        uninstallAv['total'] = 0;
                                                        let repeatAv = {};
                                                        repeatAv['s'] = 'p';
                                                        repeatAv['av'] = av.replace(/\_/g, ".");
                                                        repeatAv['p'] = value;
                                                        repeatAv['total'] = 0;
                                                        let sourceKeys = Object.keys(keyObj[value][elem][hour][pv][av]);
                                                        sourceKeys.forEach(function (source) {
                                                            //source = (source == 'None')? 'self':source;
                                                            if (sourcesList.indexOf(source) == '-1') {
                                                                sourcesList.push(source);
                                                                let obj = {};
                                                                obj[source] = {};
                                                                dataObj[value].push(obj);
                                                            }
                                                            let index = sourcesList.indexOf(source);
                                                            let countries = Object.keys(keyObj[value][elem][hour][pv][av][source]);
                                                            countries.forEach(function (country) {
                                                                if (keyObj[value][elem][hour][pv][av][source][country]) {
                                                                    let currentCountry = {};
                                                                    currentCountry['s'] = 'c';
                                                                    currentCountry['cc'] = country;
                                                                    currentCountry['total'] = 0;
                                                                    let previousCountry = {};
                                                                    previousCountry['s'] = 'p';
                                                                    previousCountry['cc'] = country;
                                                                    previousCountry['total'] = 0;
                                                                    let citys = Object.keys(keyObj[value][elem][hour][pv][av][source][country]);
                                                                    citys.forEach(function (city) {
                                                                        let currentCity = {};
                                                                        currentCity['s'] = 'c';
                                                                        currentCity['cty'] = city;
                                                                        currentCity['total'] = 0;
                                                                        let previousCity = {};
                                                                        previousCity['s'] = 'p';
                                                                        previousCity['cty'] = city;
                                                                        previousCity['total'] = 0;
                                                                        let keys = Object.keys(keyObj[value][elem][hour][pv][av][source][country][city]);
                                                                        keys.forEach(function (val) {

                                                                    if(previous.indexOf(elem) != -1){
                                                                        if(val == 'un' || val == 'ru'){
                                                                            previousCity['total'] += keyObj[value][elem][hour][pv][av][source][country][city][val];
                                                                            previousCountry['total'] += keyObj[value][elem][hour][pv][av][source][country][city][val];
                                                                            repeatAv['total'] += keyObj[value][elem][hour][pv][av][source][country][city][val];
                                                                        }
                                                                    }else{
                                                                        if(value == 'android'){
                                                                            if(val == 'un' || val == 'ru'){
                                                                                androidTotalUninstalls += keyObj[value][elem][hour][pv][av][source][country][city][val];
                                                                            }
                                                                            if(val == 'un'){
                                                                                androidUniqueUninstalls += keyObj[value][elem][hour][pv][av][source][country][city][val];
                                                                            }
                                                                        } else if(value == 'ios'){
                                                                            if(val == 'un' || val == 'ru'){
                                                                                iosTotalUninstalls += keyObj[value][elem][hour][pv][av][source][country][city][val];
                                                                            }
                                                                            if(val == 'un'){
                                                                                iosUniqueUninstalls += keyObj[value][elem][hour][pv][av][source][country][city][val];
                                                                            }
                                                                        }

                                                                                if (val == 'un') {
                                                                                    uninstallTime['total'] += keyObj[value][elem][hour][pv][av][source][country][city][val];
                                                                                    uninstallDay['total'] += keyObj[value][elem][hour][pv][av][source][country][city][val];
                                                                                }
                                                                                else if (val == 'ru') {
                                                                                    repeatTime['total'] += keyObj[value][elem][hour][pv][av][source][country][city][val];
                                                                                    repeatDay['total'] += keyObj[value][elem][hour][pv][av][source][country][city][val];
                                                                                }
                                                                                // unique installs
                                                                                if (val == 'un' || val == 'ru') {
                                                                                    currentCity['total'] += keyObj[value][elem][hour][pv][av][source][country][city][val];
                                                                                    uninstallAv['total'] += keyObj[value][elem][hour][pv][av][source][country][city][val];
                                                                                    currentCountry['total'] += keyObj[value][elem][hour][pv][av][source][country][city][val];
                                                                                }
                                                                            }
                                                                        });

                                                                if(currentCity['total'] > 0){
                                                                    cityWiseData_currentData.push(currentCity);
                                                                }
                                                                if(previousCity['total'] > 0){
                                                                    cityWiseData_previousData.push(previousCity);
                                                                }
                                                                });

                                                                if(currentCountry['total'] > 0){
                                                                 countryWiseData_currentData.push(currentCountry);
                                                                }
                                                                if(previousCountry['total'] > 0){
                                                                     countryWiseData_previousData.push(previousCountry);
                                                                }
                                                            }
                                                        });
                                                    });
                                                    if(uninstallAv['total'] > 0){
                                                        appversionWiseData_currentData.push(uninstallAv);
                                                    }
                                                    if(repeatAv['total'] > 0){
                                                        appversionWiseData_previousData.push(repeatAv);
                                                    }
                                                }
                                            });
                                        }
                                    });
                                    if(uninstallTime['total'] > 0){
                                        timeWiseData_newData.push(uninstallTime);
                                    }
                                    if(repeatTime['total'] > 0){
                                        timeWiseData_repeatData.push(repeatTime);
                                    }
                                }
                            });
                            if(uninstallDay['total'] > 0){
                                dayWiseData_newData.push(uninstallDay);
                            }
                            if(repeatDay['total'] > 0){
                                dayWiseData_repeatData.push(repeatDay);
                            }
                        }
                    });

                }
            });
        });
    }

        let obj = {
            cityWiseData_currentData: cityWiseData_currentData,
            cityWiseData_previousData: cityWiseData_previousData,
            countryWiseData_currentData: countryWiseData_currentData,
            countryWiseData_previousData: countryWiseData_previousData,
            appversionWiseData_currentData: appversionWiseData_currentData,
            appversionWiseData_previousData: appversionWiseData_previousData,
            timeWiseData_newData: timeWiseData_newData,
            timeWiseData_repeatData: timeWiseData_repeatData,
            dayWiseData_newData: dayWiseData_newData,
            dayWiseData_repeatData: dayWiseData_repeatData,
            populateUninstalls: {
                androidTotalUninstalls: androidTotalUninstalls,
                androidUniqueUninstalls: androidUniqueUninstalls,
                iosTotalUninstalls: iosTotalUninstalls,
                iosUniqueUninstalls: iosUniqueUninstalls,
                webTotalUninstalls: webTotalUninstalls,
                webUniqueUninstalls: webUniqueUninstalls
            }
        };
        return obj;

    }

//THis function returns install uninstall stats, grouped on various parameters as required by the front end UI.
metricesApi.getInstallUnistallLocation = function(params){
    let installData={};
    let argProps = {
                'startDate_C':{'required':true,'type':'Number'},
                'endDate_C':{'required':true,'type':'Number'},
                'startDate_P':{'required':true,'type':'Number'},
                'endDate_P':{'required':true,'type':'Number'},
                'type':{'required':true,'type':'String'},
                'downloadFlag':{'required':false,'type':'Boolean'},
                'downloadData':{'required':false,'type':'String'},
                'platform':{'required':false,'type':'String'}

            },dateRange={};
    if (!(dateRange = common.validateArgs(params.qstring.args, argProps))) {
        common.returnMessage(params, 400, 'Not enough args');
        return false;
    }

    let currentMatch ={}
    if(dateRange.type == "I" || dateRange.type == "U"){
        currentMatch = {
            "history.dtEntry":{$gte:parseInt(dateRange.startDate_P),$lte:parseInt(dateRange.endDate_C)},
            "history.type":dateRange.type
        }
    }
    else{
        currentMatch = {
            "history.dtEntry":{$gte:parseInt(dateRange.startDate_P),$lte:parseInt(dateRange.endDate_C)},
        }
    }

    common.db.collection('app_users'+params.qstring.app_id).aggregate([
    {$match: currentMatch},
    {$unwind : "$history" },
    {$match: currentMatch},
    { $project :  {
            date:{
            "$add": [new Date(0), {"$multiply": ["$history.dtEntry", 1000]}]
            },
            "history.type":1,
            "history.isnew":1,
            "history.dtEntry":1,
            "history.refname":1,
            "p":{ $toLower: "$p" },
            "pv":{ $toLower: "$pv" },
            "cty":1,
            "cc" :1,
            "av": 1,
            "s":{$cond:{if: {$lt:["$history.dtEntry",dateRange.startDate_C] }, then :"p", else:"c"}}
        }
    },
    {
        $project :  {
        day:{ $dayOfMonth:"$date"},
        month:{ $month:"$date"},
        year:{ $year:"$date"},
        hour:{ $hour:"$date"},
        "history.type":1,
        "history.isnew":1,
        "history.dtEntry":1,
        "history.refname":1,
        "p":1,
        "pv":1,
        "cty":1,
        "cc" :1,
        "av" :1,
        "s":1
        }

    },
    {$group : { _id : {"p":"$p","pv":"$pv","av":"$av","cty":"$cty","cc":"$cc","d":"$day","isnew":"$history.isnew","h":"$hour","t":"$history.type","s":"$s"} , total : { $sum : 1 } } },
    {$project: {"p":"$_id.p","pv":"$_id.pv","av":"$_id.av","cty":"$_id.cty","cc":"$_id.cc","d":"$_id.d","h":"$_id.h","isnew":"$_id.isnew","t":"$_id.t","s":"$_id.s",total:1,"_id":0}},
    { $sort : {s:1,total : -1 } }

  ],function(err,data){
        let result={};
        if(dateRange.type=="U"){
            result.appversions = getPlatformAndAppVersionWiseData(data);
            result.platforms = getPlatformWiseData(data);
            result.totals = getNewAndRepeatTotals(data);
            result.cities = getCityWiseData(data);
            result.countries = getCountryWiseData(data);
            result.days = getPlatformAndDayWiseData(data);
            result.hours = getPlatformAndHourWiseData(data);
        }
        else if(dateRange.type=="I"){
            result.cities = getCityWiseData(data);
            result.countries = getCountryWiseData(data);
            result.versions = getPlatformAndVersionWiseData(data);
            result.days = getPlatformAndDayWiseData(data);
            result.hours = getPlatformAndHourWiseData(data);
        }
        if(dateRange.downloadFlag==true){
            processDownloadData(params,result,dateRange.downloadData,dateRange.type,dateRange.platform);
        }
        else{
            common.returnOutput(params,result);
        }
  });
};

metricesApi.getInstallUnistallStatsBySource = function(params){
    let installData={};
    let argProps = {
                'startDate_C':{'required':true,'type':'Number'},
                'endDate_C':{'required':true,'type':'Number'},
                'startDate_CNew':{'required':true,'type':'String'},
                'endDate_CNew':{'required':true,'type':'String'},
                'type':{'required':true,'type':'String'},
                'downloadFlag':{'required':false,'type':'Boolean'},
                'downloadData':{'required':false,'type':'String'} ,
                'platform':{'required':false,'type':'String'} ,


        }, dateRange = {};
        if (!(dateRange = common.validateArgs(params.qstring.args, argProps))) {
            common.returnMessage(params, 400, 'Not enough args');
            return false;
        }

        let array = [];
        let current = [];
        let query = {}

        common.fillInstallQueryObject(query, array, current, dateRange.startDate_CNew, dateRange.endDate_CNew, 'android', params.qstring.app_id);
        common.fillInstallQueryObject(query, array, current, dateRange.startDate_CNew, dateRange.endDate_CNew, 'ios', params.qstring.app_id);
        common.fillInstallQueryObject(query, array, current, dateRange.startDate_CNew, dateRange.endDate_CNew, 'web', params.qstring.app_id);
        common.db.collection('timely_dashboard').find({ _id: { $in: array } }, query).maxTimeMS(semusiConfig.mongodb.maxTimeMS).toArray(function (error, result) {
            if (!error) {
                if (dateRange.downloadFlag == true) {
                    let data = prepareSourceWishInstallAndUninstall(result, dateRange.type, dateRange.platform);
                    processDownloadCSVData(params, data, dateRange.type, dateRange.platform);
                }
                else {
                    let installs = prepareTimelyDashboardData(current, [], result);
                    let data = (installs.c && installs.c.all) ? { installs: installs.c.all } : { installs: {} };
                    common.returnOutput(params, data);
                }
            }
            else {
                logger.error(`error => ${error}`);
                let data = { installs: {} };
                common.returnOutput(params, data);
            }
        });
    };

//This API returns regained users.
//Regained User: Any user who has uninstalled and installs again any number of times, the count should be only 1 towards regained.
metricesApi.getRegainedUsers = function(params){
    let argProps = {
                'startDate_C':{'required':true,'type':'Number'},
                'endDate_C':{'required':true,'type':'Number'},
            },dateRange={};
    if (!(dateRange = common.validateArgs(params.qstring.args, argProps))) {
        common.returnMessage(params, 400, 'Not enough args');
        return false;
    }

    common.db.collection('app_users'+params.qstring.app_id).aggregate([
        {$project: {
                    p:1,
                    did: 1,
                    history:1,
                    "historyItems": { "$size": { "$ifNull": [ "$history", [] ] }}
                    }
         },
        {$match: {"history.dtEntry":{$gte:parseInt(dateRange.startDate_C),$lte:parseInt(dateRange.endDate_C)},"historyItems": {$gt:2} }},
        {$unwind:"$history"},
        {$group:{"_id":{did:"$did",p:"$p"},"history":{$last:"$history"}}},
        {$project : {_id:1,history:"$history"}},
        {$match :{"history.type":"I"}},
        {$group :{"_id": {p:"$_id.p"}, total : { $sum : 1 } } },
        {$project : {p:"$_id.p", total:1,_id:0} }

    ],
    {maxTimeMS:semusiConfig.mongodb.maxTimeMS},
    function(err,regainedUsers){
        common.returnOutput(params,{regainedUsers : regainedUsers});
    });
};
//This function returns users at Risk,
metricesApi.getUsersAtRisk = function(params){
    if(params.qstring.app_id){
        metricesApi.checkDefaultAtRiskSegments(params.qstring.app_id, function(err, result){
            if(!err && result){
                common.db.collection('audiencesegment_'+params.qstring.app_id).find({"name":"AtRisk Users"},{"range":1,"name":1}).toArray(function(err, audiencesegments) {
                    if (!err && audiencesegments) {
                        common.returnMessage(params, 200, audiencesegments);
                    } else {
                        common.returnMessage(params, 200, 'No Segments Found');
                    }
                });
            }
            else{
                common.returnMessage(params, 200, 'No default Segments Found');
            }
        });
    }else{
        common.returnOutput(params,{"usersAtRisk":0});
    }
}

metricesApi.checkDefaultAtRiskSegments = function(appId, callback){
    common.db.collection('audiencesegment_'+appId).find({"name": "AtRisk Users"}).toArray(function(err, audiencesegments) {
        if (!err && audiencesegments) {
            if(audiencesegments.length > 0 ){ // return callback if default aud segments exists
                callback(err, true);
            }
            else{ // insert default aud segments
                let segmentObj = {"name":"AtRisk Users","description":"At Risk Users","range":0,"type": "system","segmentinfo":{"who":[{"operand":"ls","operator":"days","value":30,"category":"App Usage","attr":"","since":"","segmentOperator":""}],"q":"","what":[],"where":[],"when":[]}};
                common.db.collection('audiencesegment_'+appId).insert(segmentObj, function(err, result) {
                    if(err){
                        callback(false);
                    }
                    else{
                         callback(true);
                    }
                });
            }
        } else {
            callback(err, null);
        }
    });
}

metricesApi.downloadData = function(params){
    let csvData;
    if(params.qstring.type=="I"){
        csvData="Install_time,First_seen,Last_seen,Did,Utm_source,Platform,Carrier,Country,City";
    }
    else{
        csvData="Uninstall_time,First_seen,Last_seen,Did,Utm_source,Platform,Carrier,Country,City";
    }

    common.db.collection('app_users'+params.qstring.app_id).aggregate([
            {$unwind:"$history"},
            {$match: { "history.type": params.qstring.type,"history.dtEntry":{$gte:parseInt(params.qstring.startDate),$lte:parseInt(params.qstring.endDate)} }},
            {$project:{"history.dtEntry":1,"fs":1,"ls":1,"did":1,"history.refname":1,"p":1,"c":1,"cc":1,"cty":1}},
            {$sort: {"history.dtEntry": -1}}
          ]
        ,function(err,result){
            if(err){
                logger.error(`error => ${err}`);
                common.returnOutput(params,{"result":"Download data exceeds data limit size, please try with smaller dataset."});
                return false;
            }
            if(!err){
                result.forEach(function(item){
                    csvData+="\r\n"+common.getEpochToDateWithTimeF(item.history.dtEntry)+","+common.getEpochToDateWithTime(item.fs)+","+common.getEpochToDateWithTime(item.ls)+","+item.did+","+item.history.refname+","+item.p+","+item.c+","+item.cc+","+item.cty;
                });
            }

        common.returnCSV(params,csvData.replace('undefined',''));

    });
};

metricesApi.downloadDataCustom = function(params){
    let argProps = {
                'filter':{'required':true,'type':'JSON'},
            },filterObj={};

    if (!(filterObj = common.validateArgs(params.qstring.args, argProps))) {
        common.returnMessage(params, 400, 'Not enough args');
        return false;
    }

    let csvData, csvArray=[];
    let match={"history.type": params.qstring.type};

    if(params.qstring.type=="I"){
        csvData="install_time,first_seen,last_seen,did,utm_source,platform,carrier,device,country,city,app_version,os_version,utm_medium,utm_campaign,cpi,campaignname,Attribution";
    }
    else{
        csvData="uninstall_time,first_seen,last_seen,did,utm_source,platform,carrier,device,country,city,app_version,os_version,utm_medium,utm_campaign,cpi,last_event,# of Sessions,total_session_time,last_known_location,average_session_time,email_id,Attribution";
    }

    // get some extra column for epic cricket
    if(params.qstring.app_id == '583293316940eec96800559f'){
        csvData="install_time,first_seen,last_seen,did,utm_source,platform,carrier,device,country,city,app_version,os_version,utm_medium,utm_campaign,cpi,last_event,# of Sessions,total_session_time,average_session";
    }

    if(filterObj.filter.all!=true){
        if(filterObj.filter.dateRange){
            match["history.dtEntry"] = {$gte:filterObj.filter.dateRange.sd,$lte:filterObj.filter.dateRange.ed};
        }
        if(filterObj.filter.sessionRange){
            match.sc={};
            match['sc'][filterObj.filter.sessionRange.op] = filterObj.filter.sessionRange.value;
        }
        if(filterObj.filter.durationRange){
            match.tsd={};
            match['tsd'][filterObj.filter.durationRange.op] = filterObj.filter.durationRange.value;
        }
    }

    let QueryData = [ {$match:match}, {$unwind:"$history"}, {$project:{"_id":0,"history.dtEntry":1,"history.fr":1,"history.type":1,"history.isnew":1,"fs":1,"ls":1,"did":1,"history.refname":1,"p":1,"c":1,"d":1,"cc":1,"cty":1,"le":1,"av":1,"pv":1,"_custom_UserId":1 }}, {$sort: {"history.dtEntry": -1}}, {$out : "randomAggregates"+params.qstring.app_id} ];
    common.db.collection('app_users'+params.qstring.app_id).aggregate([ {$match:match}, {$unwind:"$history"}, {$project:{"_id":0,"history.dtEntry":1,"history.fr":1,"history.type":1,"history.isnew":1,"fs":1,"ls":1,"did":1,"history.refname":1,"p":1,"c":1,"d":1,"cc":1,"cty":1,"le":1,"av":1,"pv":1,"_custom_UserId":1 ,"attrname":1,"cname":1}}, {$sort: {"history.dtEntry": -1}}, {$out : "randomAggregates"+params.qstring.app_id} ],
          {allowDiskUse: true}, function(err,result){
              if(err){
                logger.error(`error => ${err}`);
                  common.returnOutput(params,{"result":"Something Went Wrong! Please drop an email to csm@appice.io"});
                  return false;
              }
              else{
                  common.db.collection("randomAggregates"+params.qstring.app_id).find({}).toArray(function(err,result){
                      if(err){
                        logger.error(`error => ${err}`);
                          common.returnOutput(params,{"result":"Download data exceeds data limit size, please try with smaller dataset."});
                          return false;
                      }
                      if(!err){
                          result.forEach(function(item, indexNo){
                              if(item.did){
                                  let eventKey = '';
                                  let utm_medium = '';
                                  let utm_campaign = '';
                                  let cpi = '';
                                  let lkc = '';
                                  let email_id = '';
                                  let ast_duration = 0;

                                  if(params.qstring.type=="I"){
                                      eventKey = eventKey ;
                                      let session_count = '';
                                      let total_session_time = '';
                                      lkc = '';
                                      let ast = '';
                                      email_id = '';
                                  }
                                  else{
                                      eventKey = (item.le) ? item.le.k : "NA";
                                      let session_count = item.sc;
                                      let total_session_time = item.tsd;

                                      if(item.le != undefined && item.le.c != undefined && item.le.c.where != undefined && item.le.c.where.location != undefined && item.le.c.where.location.place != undefined){
                                          lkc = item.le.c.where.location.place;
                                      }else{
                                          lkc = '';
                                      }

                                      email_id = '';
                                      if(item.alias != undefined){
                                          email_id = item.alias;
                                      }

                                      let ast = 0;
                                      if(item.sc != undefined && item.tsd != undefined){
                                          let currentTotal = parseFloat((item.tsd/item.sc)).toFixed(2);
                                          if(currentTotal>=0){
                                              let mins = parseInt(currentTotal/60);
                                              let seconds = parseInt(currentTotal-(mins*60));
                                              ast = mins+' Mins '+seconds+' secs'
                                          }
                                      }
                                  }

                                  let isnew = (item.history.isnew)? "New":"Repeat";
                                  item.history.refname = (item.history.refname == 'self')? 'Organic': item.history.refname;

                                  if(filterObj.filter.all == true){
                                      let carrier = (item.c) ? item.c.replace(/\,/g, " ") :"NA";
                                      if(params.qstring.type=="I") {
                                          let tmpObj = {
                                               Device_Id: item.did,
                                              Install_Time: common.getEpochToDateWithTime(item.history.dtEntry),
                                              First_Seen: common.getEpochToDateWithTime(item.fs),
                                              Last_Seen: common.getEpochToDateWithTime(item.ls),
                                              Platform: item.p,
                                              Carrier: carrier,
                                              Device: item.d,
                                              Country: item.cc,
                                              City: item.cty,
                                              App_Version: item.av,
                                              OS_Version: item.pv,
                                              Install_Type: isnew,
                                              Source: item.history.refname,
                                              Cpi: cpi,
                                              campaign_Name : item.cname,
                                              Attribution : item.attrname
                                          };

                                          if(item._custom_UserId){
                                            tmpObj = Object.assign({Customer_Id: item._custom_UserId}, tmpObj);
                                          }
                                          // check utm source or utm campaign details
                                          if (item.history.fr) {
                                              metricesApi.parseUtmSource(item.history.fr, tmpObj);
                                          }
                                          csvArray.push(tmpObj);
                                      }
                                      else{
                                          let tmpObj = {
                                               Device_Id: item.did,
                                              Uninstall_Time: common.getEpochToDateWithTime(item.history.dtEntry),
                                              First_Seen: common.getEpochToDateWithTime(item.fs),
                                              Last_Seen: common.getEpochToDateWithTime(item.ls),
                                              Platform: item.p,
                                              Carrier: carrier,
                                              Device: item.d,
                                              Country: item.cc,
                                              City: item.cty,
                                              App_Version: item.av,
                                              OS_Version: item.pv,
                                              Last_Event: eventKey,
                                            //   Session_Count: session_count,
                                            //   Total_Session_time: total_session_time,
                                            //   Session_Count: session_count,
                                              Last_Known_Location: lkc,
                                              Email_Id: email_id,
                                            //   Avg_Session: ast,
                                              Source: item.history.refname,
                                              Cpi: cpi,
                                              campaign_Name : item.cname,
                                              Attribution : item.attrname
                                          };

                                          if(item._custom_UserId){
                                            tmpObj = Object.assign({Customer_Id: item._custom_UserId}, tmpObj);
                                          }

                                          // check utm source or utm campaign details
                                          if (item.history.fr) {
                                              metricesApi.parseUtmSource(item.history.fr, tmpObj);
                                          }
                                          csvArray.push(tmpObj);
                                      }

                                  }else{
                                      if(filterObj.filter.dateRange.dates.indexOf(moment(item.history.dtEntry*1000).format('YYYY-MM-DD')) != -1){
                                          let carrier = (item.c) ? item.c.replace(/\,/g, " ") :"NA";
                                          if(params.qstring.type=="I") {
                                              let tmpObj = {
                                                   Device_Id: item.did,
                                                  Install_Time: common.getEpochToDateWithTime(item.history.dtEntry),
                                                  First_Seen: common.getEpochToDateWithTime(item.fs),
                                                  Last_Seen: common.getEpochToDateWithTime(item.ls),
                                                  Platform: item.p,
                                                  Carrier: carrier,
                                                  Device: item.d,
                                                  Country: item.cc,
                                                  City: item.cty,
                                                  App_Version: item.av,
                                                  OS_Version: item.pv,
                                                  Install_Type: isnew,
                                                  Source: item.history.refname,
                                                  Cpi: cpi,
                                                  campaign_Name : item.cname,
                                                  Attribution : item.attrname
                                              };

                                              if(item._custom_UserId){
                                                tmpObj = Object.assign({Customer_Id: item._custom_UserId}, tmpObj);
                                              }

                                              // check utm source or utm campaign details
                                              if (item.history.fr) {
                                                  metricesApi.parseUtmSource(item.history.fr, tmpObj);
                                              }
                                              csvArray.push(tmpObj);
                                          }
                                          else{
                                              let tmpObj = {
                                                    Device_Id: item.did,
                                                  Uninstall_Time: common.getEpochToDateWithTime(item.history.dtEntry),
                                                  First_Seen: common.getEpochToDateWithTime(item.fs),
                                                  Last_Seen: common.getEpochToDateWithTime(item.ls),
                                                  Platform: item.p,
                                                  Carrier: carrier,
                                                  Device: item.d,
                                                  Country: item.cc,
                                                  City: item.cty,
                                                  App_Version: item.av,
                                                  OS_Version: item.pv,
                                                  Last_Event: eventKey,
                                                  Session_Count: session_count,
                                                  Total_Session_Time: total_session_time,
                                                  Session_Count: session_count,
                                                  Last_Known_Location: lkc,
                                                  Email_Id: email_id,
                                                  AvgSession: ast,
                                                  Source: item.history.refname,
                                                  Cpi: cpi,
                                                  campaign_Name : item.cname,
                                                  Attribution : item.attrname
                                              };

                                              if(item._custom_UserId){
                                                tmpObj = Object.assign({Customer_Id: item._custom_UserId}, tmpObj);
                                              }
                                              
                                              // check utm source or utm campaign details
                                              if (item.history.fr) {
                                                  metricesApi.parseUtmSource(item.history.fr, tmpObj);
                                              }
                                              csvArray.push(tmpObj);
                                          }
                                      }
                                  }
                              }
                          });
                      }
                      
         
              // Function to make query for newUsers & churn exports
              function buildMainQuery(app_id, isChurn, dateRange) {
                let sd = dateRange ? dateRange.sd : undefined ;
                let ed = dateRange ? dateRange.ed : undefined ;
                let timeColumn = isChurn ? 'Uninstall_Time' : 'Install_Time';
                let mainQuery = {};
                if (dateRange) {
                   mainQuery = `SELECT did  AS \"''\"Device_ID\"''\", _custom_UserId AS \"''\"Customer_ID\"''\",TO_CHAR(to_timestamp((history->0->>''dtEntry'')::bigint),''Mon DD, YYYY HH12:MI:SS AM'') AS \"''\"${timeColumn}\"''\", TO_CHAR(to_timestamp(fs), ''Mon DD, YYYY HH12:MI:SS AM'') AS \"''\"First_Seen\"''\", TO_CHAR(to_timestamp(ls), ''Mon DD, YYYY HH12:MI:SS AM'') AS \"''\"Last_Seen\"''\", p AS \"''\"Platform\"''\", c AS \"''\"Carrier\"''\", d AS \"''\"Device\"''\", cc AS \"''\"Country\"''\", cty AS \"''\"City\"''\", av AS \"''\"App_Version\"''\", pv AS \"''\"OS_Version\"''\",history->0->>''refname'' AS \"''\"Source\"''\",CASE WHEN history->0->>''isnew'' = ''true'' THEN ''New'' WHEN history->0->>''isnew'' = ''false'' THEN ''Old'' ELSE history->0->>''isnew''END AS  \"''\"Install_Type\"''\" FROM app_users_${app_id} WHERE fs BETWEEN ${sd} AND ${ed} ORDER BY to_timestamp(fs::bigint) DESC`;
                }else{
                   mainQuery = `SELECT did  AS \"''\"Device_ID\"''\", _custom_UserId AS \"''\"Customer_ID\"''\",TO_CHAR(to_timestamp((history->0->>''dtEntry'')::bigint),''Mon DD, YYYY HH12:MI:SS AM'') AS \"''\"${timeColumn}\"''\", TO_CHAR(to_timestamp(fs), ''Mon DD, YYYY HH12:MI:SS AM'') AS \"''\"First_Seen\"''\", TO_CHAR(to_timestamp(ls), ''Mon DD, YYYY HH12:MI:SS AM'') AS \"''\"Last_Seen\"''\", p AS \"''\"Platform\"''\", c AS \"''\"Carrier\"''\", d AS \"''\"Device\"''\", cc AS \"''\"Country\"''\", cty AS \"''\"City\"''\", av AS \"''\"App_Version\"''\", pv AS \"''\"OS_Version\"''\",history->0->>''refname'' AS \"''\"Source\"''\",CASE WHEN history->0->>''isnew'' = ''true'' THEN ''New'' WHEN history->0->>''isnew'' = ''false'' THEN ''Old'' ELSE history->0->>''isnew'' END AS  \"''\"Install_Type\"''\" FROM app_users_${app_id} ORDER BY to_timestamp(fs::bigint) DESC`;
                }
                return mainQuery
            }

                    let app_id = params.app_id.toString();
                    let isChurn = params.qstring.type !== 'I';
                    let dateRange = params.qstring.args.filter.dateRange;
                    let type = isChurn ? 'Churn' : 'NewUser';
                    let filename = `${type}Exports_${moment().format('MMMM Do YYYY,h:mm:ss a').replace(' ', '_')}`;
                    let mainQuery = buildMainQuery(app_id, isChurn, dateRange);

                    let jobs = {
                      app_id: params.app_id.toString(),
                      filename: filename,
                      deleted: false,
                      status: "initiated",
                      exportjobbaseurl: "",
                      exportjobentityurl: "",
                      processeddate: "",
                      email: params.member.email,
                      createdOn: common.getCurrentEpochTime(),
                      modifiedOn: common.getCurrentEpochTime(),
                      query: mainQuery
                    };
                  
                     // Insert data into MongoDB 
   
                     const insertMongoDB = () => {
                       return new Promise((resolve, reject) => {
                         common.db.collection('exportjobs_' + params.qstring.app_id).insertOne(jobs, (err, res) => {
                           if (err) {
                             common.returnOutput(params, 500, "Error"); // Return error response here
                             reject("Error");
                           } else {
                             common.returnOutput(params, 200, "Success"); // Return success response
                             resolve(); // Resolve the Promise to continue with the next step
                           }
                         });
                       });
                     };
                  
                    //Execute the PostgreSQL query
                    const executePostgreSQLQuery = () => {
                      let app_id = params.app_id.toString();
                      let payloadStatusTableName = "jobexportdatastatus_" + app_id;
                      const jobId = uuid.v4();
  
                      let main_Query = {};
  
                      main_Query.q = jobs.query;
                      main_Query.email = jobs.email;
                      main_Query.serviceType = isChurn ? "appice-churn" : "appice-newUser";
                      main_Query.mid = jobs._id;
  
                      let insQuery = `
                      INSERT INTO ${payloadStatusTableName} (jobid, status)
                      VALUES ('${jobId}', 'unprocessed');
                    
                      INSERT INTO exportdata_${app_id} (jobid, payload)
                      VALUES ('${jobId}', '${JSON.stringify(main_Query)}');
                    `;
                      return psqlUtils.runQuery(insQuery);
                    };
                  
                    insertMongoDB()
                      .then(() => {
                        return executePostgreSQLQuery();
                      })
                      .then((s) => {
                        logger.info(`s==> ${s}`);
                      })
                      .catch((err) => {
                        // This catch block will handle errors from both MongoDB and PostgreSQL queries
                        logger.error(`err${err}`);
                      });
                    });
              }
          });
};

metricesApi.parseUtmSource = function(utmData, tmpObj){
    utmData = utmData.split('&');
    utmData.forEach(function(pair) {
        pair = pair.split('=');
        if(
            pair[0] == 'utm_source' ||
            pair[0] == 'utm_medium' ||
            pair[0] == 'utm_campaign' ||
            pair[0] == 'utm_content' ||
            pair[0] == 'utm_term' ||
            pair[0] == 'member_id'
        ) {
            tmpObj[pair[0]] = (pair[1] == '(not set)') ? 'self' : pair[1];
        }
    });

    return;
}

metricesApi.getAppUsers = function(params){
    let argProps = {
                'childAppId':{'required':true,'type':'String'},
                'type':{'required':true,'type':'String'},
                'startDate':{'required':true,'type':'Number'},
                'endDate':{'required':true,'type':'Number'},
                'customVars':{'required':false,'type':'Array'},
                'ignoreChildId':{'required':false,'type':'Boolean'},
            },filterObj={};

    if (!(filterObj = common.validateArgs(params.qstring.args, argProps))) {
        common.returnMessage(params, 400, 'Not enough args');
        return false;
    }


    //construct match.
    let match={"history.type": filterObj.type};
    match["history.dtEntry"] = {$gte:filterObj.startDate,$lte:filterObj.endDate};
    if(filterObj.ignoreChildId == undefined || filterObj.ignoreChildId==false){
        match["childAppId"] = filterObj.childAppId;
    }

    let project = {"Install Date":"$history.dtEntry","First Seen":"$fs","Last Seen":"$ls","Device ID":"$did","Source":"$history.refname","Platform":"$p","Carrier":"$c","Device":"$d","Country":"$cc","City":"$cty"};
    //Add custom vars to project
    if(filterObj.customVars && filterObj.customVars.length>0){
        filterObj.customVars.forEach(function(item){
            project[item]="$_custom_"+item;
        });
    }
    if(filterObj.ignoreChildId==true){
        project['GCM Id'] = "$gcmid";
    }
    common.db.collection('app_users'+params.qstring.app_id).aggregate([
            {$match: match},
            {$unwind:"$history"},
            {$match: match},
            {$project:project},
            {$sort: {"history.dtEntry": -1}}
        ],function(err,result){
            if(err){
                logger.error(`error => ${err}`);
                common.returnMessage(params,400,"Error while fetching data, you can try with smaller date range.");
                return false;
            }
            if(!err){
                common.returnOutput(params,result);
            }
    });
};


metricesApi.getActiveUserSessionStats = function(params){

    let sessionData={};
    let customSessionData = {};
    let argProps = {
        'startDate_C':{'required':true,'type':'Number'},
        'endDate_C':{'required':true,'type':'Number'},
        'startDate_P':{'required':true,'type':'Number'},
        'endDate_P':{'required':true,'type':'Number'},
        'startDate_CNew':{'required':true,'type':'String'},
        'endDate_CNew':{'required':true,'type':'String'},
        'startDate_PNew':{'required':true,'type':'String'},
        'endDate_PNew':{'required':true,'type':'String'}
    },dateRange={};

    if (!(dateRange = common.validateArgs(params.qstring.args, argProps))) {
        common.returnMessage(params, 400, 'Not enough args');
        return false;
    }

    try{
        cacheApi.getKey("app_id"+params.qstring.app_id,function(err,cacheResult){
            if(!err && cacheResult != null){
                cacheResult = JSON.parse(cacheResult)
                if(cacheResult.name){
                    let array = [];
                    let current = [];
                    let previous = []
                    let query = {};
                    common.fillAppsQueryObject(query, params.qstring.app_id, cacheResult.name, array, current, dateRange.startDate_CNew, dateRange.endDate_CNew, 'android');
                    common.fillAppsQueryObject(query, params.qstring.app_id, cacheResult.name, array, current, dateRange.startDate_CNew, dateRange.endDate_CNew, 'ios');
                    common.fillAppsQueryObject(query, params.qstring.app_id, cacheResult.name, array, current, dateRange.startDate_CNew, dateRange.endDate_CNew, 'web');
                    common.fillAppsQueryObject(query, params.qstring.app_id, cacheResult.name, array, previous, dateRange.startDate_PNew, dateRange.endDate_PNew, 'android');
                    common.fillAppsQueryObject(query, params.qstring.app_id, cacheResult.name, array, previous, dateRange.startDate_PNew, dateRange.endDate_PNew, 'ios');
                    common.fillAppsQueryObject(query, params.qstring.app_id, cacheResult.name, array, previous, dateRange.startDate_PNew, dateRange.endDate_PNew, 'web');
                    logger.info(`array  => ${array}::: query ${query}`);
                    common.db.collection('timely_users_session').find({_id:{$in:array}}, query).toArray(function(error, result){
                        if(!error){
                            logger.info(`data from session stats before ${result}`);
                            let data = common.prepareSessionData(result, true, current, previous);
                            logger.info(`data from session stats ${data}`);
                            common.returnOutput(params,data);
                        }else{
                            logger.error(`optimise data error => ${error}`);
                            common.returnOutput(params,{});
                        }
                    });
                }
                else{
                    common.returnOutput(params,{});
                }
            }
            else{
                logger.error(`cache error => ${err}`);
                let data = {};
                common.returnOutput(params,data);
            }
        });
    }
    catch(err){
        logger.error(`cache error => ${err}`);
        let data = {};
        common.returnOutput(params,data);
    }
};

populateAverageUsersChunk = function(currentData,previousData,platform){
      let currentTotal =0;
      let previousTotal =0;
      let row = {
        "five_plus":0,
        "three_to_five":0,
        "one_to_three":0,
        "half_to_one":0,
        "less_than_thirtysec":0
      };

      //let platform = $("#ddlPlatform").val();
      let total_tsd = 0;
      let total_sc = 0;

      currentData.forEach(function(item){
          if(item.p && (item.p.toLowerCase() == platform || platform=="all")){
            if(item.tsd<10000 && item.tsd>0){
              if(item.tsd/60>5){
                  row.five_plus++;
              }
              else if(item.tsd/60>3 && item.tsd/60<=5){
                  row.three_to_five++;
              }
              else if(item.tsd/60>=1 && item.tsd/60<=3){
                  row.one_to_three++;
              }
              else if(item.tsd/60>=.5 && item.tsd/60<=1){
                  row.half_to_one++;
              }
              else{
                  row.less_than_thirtysec++;
              }
              if(item.tsd){
                total_tsd = total_tsd +item.tsd;
              }
              if(item.sc){
                total_sc = total_sc +item.sc;
              }
            }
          }
      });
      currentTotal = parseFloat((total_tsd/total_sc)).toFixed(2);

      total_tsd = 0;
      total_sc = 0;
      previousData.forEach(function(item){
          if(item.p && (item.p.toLowerCase() == platform || platform=="all")){
              if(item.tsd && item.tsd<10000 && item.tsd>0){
                total_tsd = total_tsd +item.tsd;
              }
              if(item.sc){
                total_sc = total_sc +item.sc;
              }
          }
      });
      if(total_tsd==0 && total_sc==0){
        previousTotal=0;
      }
      else{
        previousTotal = parseFloat((total_tsd/total_sc)).toFixed(2);
      }
      return averageUserChunk = {row:row,currentTotal:currentTotal,previousTotal:previousTotal}
  }
populateActiveUsersChunk = function(currentData,previousData,platform){
      let currentTotal =0;
      let previousTotal =0;
      let acitveUserChunk = {};
      let row = {
        "ten_plus":0,
        "eight_to_ten":0,
        "six_to_eight":0,
        "two_to_five":0,
        "one":0
      };
      currentData.forEach(function(item){
          if(item.p && (item.p.toLowerCase() == platform || platform=="all")){
              if(item.sc>10){
                  row.ten_plus++;
              }
              else if(item.sc>8 && item.sc<=10){
                  row.eight_to_ten++;
              }
              else if(item.sc>=6 && item.sc<=8){
                  row.six_to_eight++;
              }
              else if(item.sc>=2 && item.sc<=5){
                  row.two_to_five++;
              }
              else{
                  row.one++;
              }
           currentTotal++;
          }
      });

      previousData.forEach(function(item){
          if(item.p && (item.p.toLowerCase() == platform || platform=="all")){
              previousTotal++;
          }
      });
      return acitveUserChunk = {row:row,currentTotal:currentTotal,previousTotal:previousTotal}
}

metricesApi.getActiveUserSessionStatsDashboard = function(params){
    let sessionData={};
    let argProps = {
        'startDate_C':{'required':true,'type':'Number'},
        'endDate_C':{'required':true,'type':'Number'},
        'startDate_P':{'required':true,'type':'Number'},
        'endDate_P':{'required':true,'type':'Number'},

    },dateRange={};

    if (!(dateRange = common.validateArgs(params.qstring.args, argProps))) {
        common.returnMessage(params, 400, 'Not enough args');
        return false;
    }

    common.db.collection('app_users'+params.qstring.app_id).aggregate(
        [
            {$match: {"ls":{$gte:parseInt(dateRange.startDate_C),$lte:parseInt(dateRange.endDate_C)},"active":true}},{$project:{did:1,sc:1,tsd:1,p:1}}
        ]
        ,function(err,userSessions1){
            sessionData.current = userSessions1;
            common.returnOutput(params,sessionData);
        }
    );
};

metricesApi.getActiveUserTimelySessions = function(params){
    let sessionData={
        current : [],
        previous : [],
        currentTotal:0
    };
    
    let argProps = {
        'startDate_C':{'required':true,'type':'Number'},
        'endDate_C':{'required':true,'type':'Number'},
        'startDate_P':{'required':true,'type':'Number'},
        'endDate_P':{'required':true,'type':'Number'},
        'startDate_CNew':{'required':true,'type':'String'},
        'endDate_CNew':{'required':true,'type':'String'},
        'startDate_PNew':{'required':true,'type':'String'},
        'endDate_PNew':{'required':true,'type':'String'}
    },dateRange={};

        if (!(dateRange = common.validateArgs(params.qstring.args, argProps))) {
            common.returnMessage(params, 400, 'Not enough args');
            return false;
        }

        let $current = {}
        let $currentSearchFilter = [];
        common.fillTimeObjectQuery($current, $currentSearchFilter, dateRange.startDate_CNew, dateRange.endDate_CNew, 'android');
        common.fillTimeObjectQuery($current, $currentSearchFilter, dateRange.startDate_CNew, dateRange.endDate_CNew, 'ios');
        common.fillTimeObjectQuery($current, $currentSearchFilter, dateRange.startDate_CNew, dateRange.endDate_CNew, 'web');

        let $previousSearchFilter = [];
        common.fillTimeObjectQuery($current, $previousSearchFilter, dateRange.startDate_PNew, dateRange.endDate_PNew, 'android');
        common.fillTimeObjectQuery($current, $previousSearchFilter, dateRange.startDate_PNew, dateRange.endDate_PNew, 'ios');
        common.fillTimeObjectQuery($current, $previousSearchFilter, dateRange.startDate_PNew, dateRange.endDate_PNew, 'web');

        // get active users form optimise collection
        $current['android_active_users'] = 1;
        $current['ios_active_users'] = 1;
        $current['web_active_users'] = 1;
        // run query
        common.db.collection('timely_sessions').find({ _id: common.db.ObjectID(params.qstring.app_id) }, $current).maxTimeMS(semusiConfig.mongodb.maxTimeMS).toArray(function (err, result) {
            if (!err) {
                if (result.length > 0) {
                    // get active users
                    //sessionData.activeUsers  = parseInt((result[0] && result[0].android_active_users)? result[0].android_active_users : 0);
                    //sessionData.activeUsers  += parseInt((result[0] && result[0].ios_active_users)? result[0].ios_active_users : 0);
                    // remove active users key
                    if (result[0] && result[0].android_active_users) {
                        delete result[0].android_active_users;
                    }
                    if (result[0] && result[0].ios_active_users) {
                        delete result[0].ios_active_users;
                    }
                    if (result[0] && result[0].web_active_users) {
                        delete result[0].web_active_users;
                    }
                     // get engagement or session
                     let filter_ = params.qstring.filter_;
                     let data = metricesApi.timelySessionWithTimeAndPlace(result, $currentSearchFilter, false, dateRange.endDate_C, filter_);
                     sessionData.current = data.currentSession;
                     sessionData.currentTotal = data.currentTotal;
                     sessionData.previous = metricesApi.timelySessionWithTimeAndPlace(result, $previousSearchFilter, true, dateRange.endDate_P,filter_);
                     
                    // get active users
                        common.db.collection('timely_sessions').find({_id:common.db.ObjectID(params.qstring.app_id)},{android_active_users:1, ios_active_users:1, web_active_users:1}).toArray(function(err, result){
                            if(!err){
                                let obj = {android:0, ios:0};
                                if(result){
                                    obj.android = (result[0]['android_active_users'])? result[0]['android_active_users']:0;
                                    obj.ios = (result[0]['ios_active_users'])? result[0]['ios_active_users']:0;
                                    obj.web = (result[0]['web_active_users'])? result[0]['web_active_users']:0;
                                }
                                sessionData.activeUsers  = parseInt(obj.android) + parseInt(obj.ios) + parseInt(obj.web);
                                sessionData.androidUsers = parseInt(obj.android);
                                sessionData.iosUsers = parseInt(obj.ios);
                                sessionData.webUsers = parseInt(obj.web);
                                let totalCountInSessions = (sessionData.current && sessionData.current[0] != undefined) ? sessionData.current[0].android : undefined;
                                if(totalCountInSessions == undefined){
                                    totalCountInSessions = (sessionData.current && sessionData.current[0] != undefined) ? sessionData.current[0].web : undefined;
                                }
                                let timeType = [ "morning", "afternoon", "evening", "night", "midnight"];
                                let totalCurrentCount= 0;
                                if(totalCountInSessions && totalCountInSessions.length != 0){
                                    for (let i = 0 ; i < totalCountInSessions.length; i++) {
                                        getOtherCount = totalCountInSessions[i][timeType[i]];
                                        totalCurrentCount = (getOtherCount && getOtherCount.other) ? totalCurrentCount + getOtherCount.other : totalCurrentCount + 0 ;                           
                                    }
                                }
                                sessionData.totalCurrentCount = totalCurrentCount ;
                                logger.info(`🚀 ~ file: metrices.js ~ line 3973 ~ common.db.collection ~ totalCurrentCount =>  ${totalCurrentCount}`)
                                common.returnOutput(params, sessionData);
                            }
                            else{
                                sessionData.activeUsers = 0;
                                common.returnOutput(params, sessionData);
                            }
                        });
                }
                else {
                    common.returnOutput(params, sessionData);
                }
            }
            else {
                common.returnOutput(params, sessionData);
            }
        });
    }

metricesApi.getDauWauMau = function(params){
    let argProps = {
        'startDate_C':{'required':true,'type':'Number'},
        'endDate_C':{'required':true,'type':'Number'},
        'startDate_P':{'required':true,'type':'Number'},
        'endDate_P':{'required':true,'type':'Number'},
        'startDate_CNew':{'required':true,'type':'String'},
        'endDate_CNew':{'required':true,'type':'String'},
        'startDate_PNew':{'required':true,'type':'String'},
        'endDate_PNew':{'required':true,'type':'String'}
    },dateRange={};

    if (!(dateRange = common.validateArgs(params.qstring.args, argProps))) {
        common.returnMessage(params, 400, 'Not enough args');
        return false;
    }

    // get current month dau and mau
    metricesApi.getActiveUserDauAndMau(params,function(err, monthData){
        if(err){
            logger.error(`error => ${err}`);
        }
        else{
            common.returnOutput(params,monthData);
        }
    });
}

    // get current month dau, mau and active users count
    metricesApi.getActiveUserDauAndMau = function (params, callback) {
        let query = {}
        common.fillDauMauObjectQuery(query, false, params);
        common.db.collection('timely_sessions').find({ _id: common.db.ObjectID(params.qstring.app_id) }, query).maxTimeMS(semusiConfig.mongodb.maxTimeMS).toArray(function (err, result) {
            if (!err) {
                let obj = { dau: 0, mau: 0, wau: 0, daywisedau: [], activeCmp:0, totalCmp:0 };
                if (result) {
                    if (result) {
                        // let counter = 0;
                        let counter = Math.floor((Date.UTC(new Date(params.qstring.args.endDate_CNew).getFullYear(), new Date(params.qstring.args.endDate_CNew).getMonth(), new Date(params.qstring.args.endDate_CNew).getDate()) - Date.UTC(new Date(params.qstring.args.startDate_CNew).getFullYear(), new Date(params.qstring.args.startDate_CNew).getMonth(), new Date(params.qstring.args.startDate_CNew).getDate()) ) /(1000 * 60 * 60 * 24)) + 1
                        let mcounter=1;
                        let c = [];
                        let wc = [];
                        //let wcounter = parseInt(moment(params.qstring.args.endDate_CNew).diff(moment(params.qstring.args.startDate_CNew), 'week'))+1;
                        let startDate_C_Wau = params.qstring.args.startDate_CNew; 
                        let noOfDays = Math.floor((Date.UTC(new Date(params.qstring.args.endDate_CNew).getFullYear(), new Date(params.qstring.args.endDate_CNew).getMonth(), new Date(params.qstring.args.endDate_CNew).getDate()) - Date.UTC(new Date(startDate_C_Wau).getFullYear(), new Date(startDate_C_Wau).getMonth(), new Date(startDate_C_Wau).getDate()) ) /(1000 * 60 * 60 * 24))+1;
                        let wcounter = Math.ceil(noOfDays/7);
                        if(new Date(startDate_C_Wau).getDate != 0){
                            startDate_C_Wau = new Date(startDate_C_Wau).getDate() - new Date(params.qstring.args.startDate_CNew).getDay();
                            startDate_C_Wau =  new Date(new Date(params.qstring.args.startDate_CNew).setDate(startDate_C_Wau)).toUTCString();
                            noOfDays = Math.floor((Date.UTC(new Date(params.qstring.args.endDate_CNew).getFullYear(), new Date(params.qstring.args.endDate_CNew).getMonth(), new Date(params.qstring.args.endDate_CNew).getDate()) - Date.UTC(new Date(startDate_C_Wau).getFullYear(), new Date(startDate_C_Wau).getMonth(), new Date(startDate_C_Wau).getDate()) ) /(1000 * 60 * 60 * 24))+1;
                            wcounter = Math.ceil(noOfDays/7);
                        }
    
    
                        let startDate = new Date(params.qstring.args.startDate_CNew.split('-').join(',')); // month number for start date
                        let startDateWeek = startDate.getWeek();
                        let endDate = new Date(params.qstring.args.endDate_CNew.split('-').join(',')); // month number for start date
                        let endDateWeek = endDate.getWeek();
                        if(endDateWeek < startDateWeek){
                            endDateWeek = endDateWeek+52;
                        }
                        // let wcounter = (parseInt(endDateWeek) - parseInt(startDateWeek));
                        let plist = ['android', 'ios', 'web'];
                        
                        result.forEach(function (data) {
                            plist.forEach(function (p) {
                                if (data[p]) {
                
                                    // calculate avg dau
                                    let startDate_C = params.qstring.args.startDate_CNew;
                                    let endDate_C = moment(params.qstring.args.endDate_CNew)
                                      .add(1, "days")
                                      .format("YYYY-MM-DD");
                                    d = new Date(startDate_C);
                                    let day = d.getDay(), diff = d.getDate() - day + (day == 0 ? -6:1); // adjust when day is sunday
                                    // let startDateObj = new Date(d.setDate(diff));
                                    // // let startDate_C_Wau = moment(new Date(startDateObj.setDate(startDateObj.getDate() - startDateObj.getDay()))).format('YYYY-MM-DD');
                                   
                                
                                    while (moment(startDate_C).valueOf() < moment(endDate_C).valueOf()) {
                                        if (data[p] && data[p][moment(startDate_C).format('YYYY')] &&
                                            data[p][moment(startDate_C).format('YYYY')][moment(startDate_C).format('M')] &&
                                            data[p][moment(startDate_C).format('YYYY')][moment(startDate_C).format('M')][moment(startDate_C).format('D')]) {
                                            // add DAU
                                            if (data[p][moment(startDate_C).format('YYYY')][moment(startDate_C).format('M')][moment(startDate_C).format('D')]['dau']) {
                                               
                                                // counter++;
                                                let dauDate =  moment(startDate_C).format('M') +"_"+ moment(startDate_C).format('D');
                                       
                                                /* add daywisedau for get date wise DAU for dashboard line chart */
                                                obj.daywisedau.push([dauDate , data[p][moment(startDate_C).format('YYYY')][moment(startDate_C).format('M')][moment(startDate_C).format('D')]['dau'] ]);
                                                obj.dau += data[p][moment(startDate_C).format('YYYY')][moment(startDate_C).format('M')][moment(startDate_C).format('D')]['dau'];
                                              }
                                        }
                                        
                                        startDate_C = moment(startDate_C).add(1, 'days').format('YYYY-MM-DD');
                                         
                                    }
    
    
                                       /// WAU calculate section
    
                                        //Check if sunday=0
        
                                          wc.push(startDate_C_Wau);
                                          wc.push(endDate_C);
                                          while (
                                            moment(startDate_C_Wau).valueOf() <
                                            moment(endDate_C).valueOf()
                                          ) {
                                            if (
                                              data[p] &&
                                              data[p][moment(startDate_C_Wau).format("YYYY")] &&
                                              data[p][moment(startDate_C_Wau).format("YYYY")][
                                                moment(startDate_C_Wau).format("M")
                                              ] &&
                                              data[p][moment(startDate_C_Wau).format("YYYY")][
                                                moment(startDate_C_Wau).format("M")
                                              ][moment(startDate_C_Wau).format("D")]
                                            ) {
                                              // add WAU
                                              if (
                                                data[p][moment(startDate_C_Wau).format("YYYY")][
                                                  moment(startDate_C_Wau).format("M")
                                                ][moment(startDate_C_Wau).format("D")]["wau"]
                                              ) {
                                                obj.wau +=
                                                  data[p][moment(startDate_C_Wau).format("YYYY")][
                                                    moment(startDate_C_Wau).format("M")
                                                  ][moment(startDate_C_Wau).format("D")]["wau"];
                                              wc.push(data[p][moment(startDate_C_Wau).format("YYYY")][
                                                moment(startDate_C_Wau).format("M")
                                              ][moment(startDate_C_Wau).format("D")]["wau"]);
                                              obj.wcount = wc;
    
                                              }
                                            }
                                            startDate_C_Wau = moment(startDate_C_Wau)
                                              .add(1, "days")
                                              .format("YYYY-MM-DD");
                                          }
                                      
                       
    
                        // calculate mau
    
                        endDate_C = params.qstring.args.endDate_C * 1000;
                        let start = params.qstring.args.startDate_CNew;
                        let end = params.qstring.args.endDate_CNew;
                        
                       //except this month/today/yesterday/last 7 days
                       if(Math.floor((Date.UTC(new Date(params.qstring.args.endDate_CNew).getFullYear(), new Date(params.qstring.args.endDate_CNew).getMonth(), new Date(params.qstring.args.endDate_CNew).getDate()) - Date.UTC(new Date(params.qstring.args.startDate_CNew).getFullYear(), new Date(params.qstring.args.startDate_CNew).getMonth(), new Date(params.qstring.args.startDate_CNew).getDate()) ) /(1000 * 60 * 60 * 24)) >=29 ){
                           //make start date to 1st date of month
                           let startDate_C = params.qstring.args.startDate_CNew;
                           let firstDay = new Date(new Date(startDate_C).getFullYear(), new Date(startDate_C).getMonth(), 1).getDate();
                           let firstMonth = new Date(new Date(startDate_C).getFullYear(), new Date(startDate_C).getMonth(), 1).getMonth();
                           let firstYear = new Date(new Date(startDate_C).getFullYear(), new Date(startDate_C).getMonth(), 1).getFullYear();
                           //getting start date from start of month
                     
                          startDate_C = new Date(`${firstMonth+1}/${firstDay}/${firstYear}`).valueOf();
                          
                           //calculating month counter
                           if(new Date(startDate_C).getMonth() == new Date(endDate_C).getMonth()){
                               mcounter=1;
    
                           }
                           else{
                               mcounter = (new Date(endDate_C).getFullYear() - new Date(startDate_C).getFullYear()) * 12;
                               mcounter -= new Date(startDate_C).getMonth();
                               mcounter += new Date(endDate_C).getMonth();
                               mcounter = mcounter <= 0 ? 0 : mcounter+1;
                           }
                           c.push(startDate_C);
                           c.push(endDate_C)
                           while (moment(startDate_C).valueOf() <= moment(endDate_C).valueOf()) {
                               if (data[p] && data[p][moment(startDate_C).format('YYYY')] &&
                                   data[p][moment(startDate_C).format('YYYY')][moment(startDate_C).format('M')] &&
                                   data[p][moment(startDate_C).format('YYYY')][moment(startDate_C).format('M')][moment(startDate_C).format('D')]) {
    
                                   // add MAU
                                   if (data[p][moment(startDate_C).format('YYYY')][moment(startDate_C).format('M')][moment(startDate_C).format('D')]['mau']) {
                                       obj.mau += data[p][moment(startDate_C).format('YYYY')][moment(startDate_C).format('M')][moment(startDate_C).format('D')]['mau'];
                                       c.push(data[p][moment(startDate_C).format('YYYY')][moment(startDate_C).format('M')][moment(startDate_C).format('D')]['mau']);
                                       obj.count = c;
                                   }
                               }
    
                               startDate_C = moment(startDate_C).add(1, 'days'); 
                               
                           }
                           
                       }
                         
                       //start date and end date are of same month //custom month case
                       
                       else if (new Date(start).getMonth() == new Date(end).getMonth() && new Date().getMonth() > new Date(end).getMonth() && new Date(start).getDate() != new Date(end).getDate()){  
                        start = common.adjustStartDate(start);
                        obj.st = start;
                        let yyyy = new Date(end).getFullYear();
                        obj.yyyy = yyyy;
                        let mm = new Date(end).getMonth();
                        obj.mm = mm;
                        let dd = new Date(yyyy,mm+1 ,0).getDate();
                        obj.dd = dd;
                        end = new Date(`${mm+1}/${dd}/${yyyy}`).valueOf();
                        obj.ed = end;
                           c.push(start);
                           c.push(end)
                           while (moment(start).valueOf() <= moment(end).valueOf()) {
                               if (data[p] && data[p][moment(start).format('YYYY')] &&
                                   data[p][moment(start).format('YYYY')][moment(start).format('M')] &&
                                   data[p][moment(start).format('YYYY')][moment(start).format('M')][moment(start).format('D')]) {
    
                                   // add MAU
                                   if (data[p][moment(start).format('YYYY')][moment(start).format('M')][moment(start).format('D')]['mau']) {
                                       obj.mau += data[p][moment(start).format('YYYY')][moment(start).format('M')][moment(start).format('D')]['mau'];
                                       c.push(data[p][moment(start).format('YYYY')][moment(start).format('M')][moment(start).format('D')]['mau']);
                                       obj.count = c;
                                   }
                               }
    
                               start = moment(start).add(1, 'days'); 
                               
                           }
                         
                       }
    
                       //For other default case
                       else{
                        //if start date end date same //this month case
                        if(new Date(start).getMonth() === new Date(end).getMonth()){ 
                            startDate_C = common.adjustStartDate(start);
                            obj.s = startDate_C;
                            obj.e = endDate_C;
                            c.push(startDate_C);
                            c.push(endDate_C)

                            while (moment(startDate_C).valueOf() <= moment(endDate_C).valueOf()) {
                                if (data[p] && data[p][moment(startDate_C).format('YYYY')] &&
                                    data[p][moment(startDate_C).format('YYYY')][moment(startDate_C).format('M')] &&
                                    data[p][moment(startDate_C).format('YYYY')][moment(startDate_C).format('M')][moment(startDate_C).format('D')]) {
         
                                    // add MAU
                                    if (data[p][moment(startDate_C).format('YYYY')][moment(startDate_C).format('M')][moment(startDate_C).format('D')]['mau']) {
                                        obj.mau += data[p][moment(startDate_C).format('YYYY')][moment(startDate_C).format('M')][moment(startDate_C).format('D')]['mau'];
                                        c.push(data[p][moment(startDate_C).format('YYYY')][moment(startDate_C).format('M')][moment(startDate_C).format('D')]['mau']);
                                        obj.count = c;
                                    }
                                }
         
                                startDate_C = moment(startDate_C).add(1, 'days'); 
                                
                            }
                        }
                        //else default last 30 days case
                        else{
                           mcounter=2;
                       
                           let startDate_C = moment(endDate_C).subtract(30, 'days').valueOf();
                           let firstDay = new Date(new Date(startDate_C).getFullYear(), new Date(startDate_C).getMonth(), 1).getDate();
                           let firstMonth = new Date(new Date(startDate_C).getFullYear(), new Date(startDate_C).getMonth(), 1).getMonth();
                           let firstYear = new Date(new Date(startDate_C).getFullYear(), new Date(startDate_C).getMonth(), 1).getFullYear();
                           //getting start date from start of month
                                 
                           startDate_C = new Date(`${firstMonth+1}/${firstDay}/${firstYear}`).valueOf();
                           
                           c.push(startDate_C);
                           c.push(endDate_C);
                           while (moment(startDate_C).valueOf() <= moment(endDate_C).valueOf()) {
                           if (data[p] && data[p][moment(startDate_C).format('YYYY')] &&
                               data[p][moment(startDate_C).format('YYYY')][moment(startDate_C).format('M')] &&
                               data[p][moment(startDate_C).format('YYYY')][moment(startDate_C).format('M')][moment(startDate_C).format('D')]) {
    
                               // add MAU
                               if (data[p][moment(startDate_C).format('YYYY')][moment(startDate_C).format('M')][moment(startDate_C).format('D')]['mau']) {
                                   obj.mau += data[p][moment(startDate_C).format('YYYY')][moment(startDate_C).format('M')][moment(startDate_C).format('D')]['mau'];
                                   c.push(data[p][moment(startDate_C).format('YYYY')][moment(startDate_C).format('M')][moment(startDate_C).format('D')]['mau']);
                                   obj.count = c;
                               }
                           }
    
                           startDate_C = moment(startDate_C).add(1, 'days'); 
                           
                           }
                        }
                           
                   
                          }
    
                        }
                      })
    
                    });
                      
                     
                        if (obj.dau > 0 && obj.dau > counter && counter > 0 ) {
                            obj.dau = obj.dau / counter;
                        }
    
                        if (obj.wau > 0 && obj.wau > wcounter && wcounter > 0) {
                            obj.wau = obj.wau / wcounter;
                        }
                        if(mcounter>0 && obj.mau>0 && obj.mau > mcounter){
                          obj.mau = obj.mau/mcounter;
                        }
                    }
                    
                }
                common.db.collection('campaign_statsdata_'+ params.qstring.app_id).find({"st":{"$in" : ["ACTIVE", "PENDING"]}}).count(function (err, result) {
                    if (!result) {
                        result = 0;
                    }
                    obj.activeCmp = result;
                    common.db.collection('campaign_statsdata_'+ params.qstring.app_id).find({ isdelete: false, $or: [{"st": "ACTIVE"}, {"st": "DRAFT"}, {"st": "PAST"},] }).count(function (err,totCmp) {
                        if (!totCmp) {
                            totCmp= 0;
                        }
                        obj.totalCmp =totCmp;
                        callback(null, obj);
                    });
                });
            }
            else {
                callback(err, null);
            }
        });
    }   
    
    
      // get current month dau, mau and active users count
      metricesApi.getActiveUserDauAndMauWithPlatforms = function(params) {
        let platform = params.qstring.platform_;
        let argProps = {
            startDate_CNew: {
              required: true,
              type: "String"
            },
            endDate_CNew: {
              required: true,
              type: "String"
            }
          },
          dateRange = {},
          query = {};
    
        if (!(dateRange = common.validateArgs(params.qstring.args, argProps))) {
          common.returnMessage(params, 400, "Not enough args");
          return false;
        }
    
        // prepare query for get DAU, WAU and MAU data
        //common.fillDauMauObjectQueryWithPlatforms(query, params);
        common.fillDauMauObjectQuery(query, false, params);
        // run query on optimise collection
        logger.info(`query ==>  ${query}`);
        common.db
          .collection("timely_sessions")
          .find(
            {
              _id: common.db.ObjectID(params.qstring.app_id)
            },
            query
          )
          .toArray(function(err, result) {
            // if not get any error
            if (!err) {
              // prepare data object
              let obj = {
                android: {
                  dau: 0,
                  mau: 0,
                  wau: 0,
                  daywisedau: []
                },
                ios: {
                  dau: 0,
                  mau: 0,
                  wau: 0,
                  daywisedau: []
                },
                web: {
                  dau: 0,
                  mau: 0,
                  wau: 0,
                  daywisedau: []
                }
              };
    
              if (result) {
                let currentEpoch = common.getCurrentEpochTime();

                if (result) {
                    let counter = Math.floor((Date.UTC(new Date(params.qstring.args.endDate_CNew).getFullYear(), new Date(params.qstring.args.endDate_CNew).getMonth(), new Date(params.qstring.args.endDate_CNew).getDate()) - Date.UTC(new Date(params.qstring.args.startDate_CNew).getFullYear(), new Date(params.qstring.args.startDate_CNew).getMonth(), new Date(params.qstring.args.startDate_CNew).getDate()) ) /(1000 * 60 * 60 * 24)) + 1
                    let mcounter = 1;
                    let wtimes = 0;
                    let wc = [];
                    let startDate_C_Wau = params.qstring.args.startDate_CNew; 
                    let noOfDays = Math.floor((Date.UTC(new Date(params.qstring.args.endDate_CNew).getFullYear(), new Date(params.qstring.args.endDate_CNew).getMonth(), new Date(params.qstring.args.endDate_CNew).getDate()) - Date.UTC(new Date(startDate_C_Wau).getFullYear(), new Date(startDate_C_Wau).getMonth(), new Date(startDate_C_Wau).getDate()) ) /(1000 * 60 * 60 * 24))+1;
                    let wcounter = Math.ceil(noOfDays/7);
                    if(new Date(startDate_C_Wau).getDate() != 0){
                        startDate_C_Wau = new Date(startDate_C_Wau).getDate() - new Date(params.qstring.args.startDate_CNew).getDay();
                        startDate_C_Wau =  new Date(new Date(params.qstring.args.startDate_CNew).setDate(startDate_C_Wau)).toUTCString();
                        noOfDays = Math.floor((Date.UTC(new Date(params.qstring.args.endDate_CNew).getFullYear(), new Date(params.qstring.args.endDate_CNew).getMonth(), new Date(params.qstring.args.endDate_CNew).getDate()) - Date.UTC(new Date(startDate_C_Wau).getFullYear(), new Date(startDate_C_Wau).getMonth(), new Date(startDate_C_Wau).getDate()) ) /(1000 * 60 * 60 * 24))+1;
                        wcounter = Math.ceil(noOfDays/7);
                    }              
                    //let wcounter = parseInt(moment(params.qstring.args.endDate_CNew).diff(moment(params.qstring.args.startDate_CNew), 'week'))+1;
                    let startDate = new Date(
                      params.qstring.args.startDate_CNew.split("-").join(",")
                    ); // month number for start date
                    let startDateWeek = startDate.getWeek();
                    let endDate = new Date(
                      params.qstring.args.endDate_CNew.split("-").join(",")
                    ); // month number for start date
                    let endDateWeek = endDate.getWeek();
                    if (endDateWeek < startDateWeek) {
                      endDateWeek = endDateWeek + 52;
                    }
                  
                    obj.result = {
                      wcounter: wcounter,
                      endDateWeek: endDateWeek,
                      endDate: endDate,
                      startDate: startDate,
                      startDateWeek: startDateWeek
                    };
                    let plist = ["android", "ios", "web"];
      
                    result.forEach(function(data) {
                      plist.forEach(function(p) {
                        if (data[p]) {
      
                       startDate_C_Wau = params.qstring.args.startDate_CNew; 
                      if(new Date(startDate_C_Wau).getDate() != 0){
                        startDate_C_Wau = new Date(startDate_C_Wau).getDate() - new Date(params.qstring.args.startDate_CNew).getDay();
                        startDate_C_Wau =  new Date(new Date(params.qstring.args.startDate_CNew).setDate(startDate_C_Wau)).toUTCString();
                      }             
                          // counter = 0;
                          // calculate avg dau
                          let startDate_C = params.qstring.args.startDate_CNew;
                          let endDate_C = moment(params.qstring.args.endDate_CNew).add(1, "days")
                            .format("YYYY-MM-DD");
                          d = new Date(startDate_C);
                          let day = d.getDay(),
                            diff = d.getDate() - day + (day == 0 ? -6 : 1); // adjust when day is sunday
                         
                      
                          while (
                            moment(startDate_C).valueOf() <
                            moment(endDate_C).valueOf()
                          ) {
                            if (
                              data[p] &&
                              data[p][moment(startDate_C).format("YYYY")] &&
                              data[p][moment(startDate_C).format("YYYY")][
                                moment(startDate_C).format("M")
                              ] &&
                              data[p][moment(startDate_C).format("YYYY")][
                                moment(startDate_C).format("M")
                              ][moment(startDate_C).format("D")]
                            ) {
                              // add DAU
                              if (
                                data[p][moment(startDate_C).format("YYYY")][
                                  moment(startDate_C).format("M")
                                ][moment(startDate_C).format("D")]["dau"]
                              ) {
                                // counter++;
                                let dauDate =
                                  moment(startDate_C).format("D") +
                                  "_" +
                                  moment(startDate_C).format("M");
                                obj[p].daywisedau.push([
                                  dauDate,
                                  data[p][moment(startDate_C).format("YYYY")][
                                    moment(startDate_C).format("M")
                                  ][moment(startDate_C).format("D")]["dau"]
                                ]);
                                obj[p].dau +=
                                  data[p][moment(startDate_C).format("YYYY")][
                                    moment(startDate_C).format("M")
                                  ][moment(startDate_C).format("D")]["dau"];
                              }
                            }
                            startDate_C = moment(startDate_C)
                              .add(1, "days")
                              .format("YYYY-MM-DD");
                          }
                          /// WAU calculate section
                          wc.push(startDate_C_Wau);
                          wc.push(endDate_C);
                          while (
                            moment(startDate_C_Wau).valueOf() <
                            moment(endDate_C).valueOf()
                          ) {
                            if (
                              data[p] &&
                              data[p][moment(startDate_C_Wau).format("YYYY")] &&
                              data[p][moment(startDate_C_Wau).format("YYYY")][
                                moment(startDate_C_Wau).format("M")
                              ] &&
                              data[p][moment(startDate_C_Wau).format("YYYY")][
                                moment(startDate_C_Wau).format("M")
                              ][moment(startDate_C_Wau).format("D")]
                            ) {
                              // add WAU
                              if (
                                data[p][moment(startDate_C_Wau).format("YYYY")][
                                  moment(startDate_C_Wau).format("M")
                                ][moment(startDate_C_Wau).format("D")]["wau"]
                              ) {
                                obj[p].wau +=
                                  data[p][moment(startDate_C_Wau).format("YYYY")][
                                    moment(startDate_C_Wau).format("M")
                                  ][moment(startDate_C_Wau).format("D")]["wau"];
      
                                  wc.push(data[p][moment(startDate_C_Wau).format("YYYY")][
                                    moment(startDate_C_Wau).format("M")
                                  ][moment(startDate_C_Wau).format("D")]["wau"]);
                                  obj.wcount = wc;  
                              }
                            }
                            startDate_C_Wau = moment(startDate_C_Wau)
                              .add(1, "days")
                              .format("YYYY-MM-DD");
                              wtimes+=1;
                          }
      
                          // calculate mau
      
                          endDate_C = params.qstring.args.endDate_C * 1000;
                          let start = params.qstring.args.startDate_CNew;
                          let end = params.qstring.args.endDate_CNew;
                       
                         //Condition - except this month/today/yesterday/last 7 days
                         if(Math.floor((Date.UTC(new Date(params.qstring.args.endDate_CNew).getFullYear(), new Date(params.qstring.args.endDate_CNew).getMonth(), new Date(params.qstring.args.endDate_CNew).getDate()) - Date.UTC(new Date(params.qstring.args.startDate_CNew).getFullYear(), new Date(params.qstring.args.startDate_CNew).getMonth(), new Date(params.qstring.args.startDate_CNew).getDate()) ) /(1000 * 60 * 60 * 24)) >=29 ){
                             //make start date to 1st date of month
                             let startDate_C = params.qstring.args.startDate_CNew;
                             startDate_C = common.adjustStartDate(startDate_C);
                          
                             //calculating month counter
                             if(new Date(startDate_C).getMonth() == new Date(endDate_C).getMonth()){
                                 mcounter=1;
      
                             }
                             else{
                                 mcounter = (new Date(endDate_C).getFullYear() - new Date(startDate_C).getFullYear()) * 12;
                                 mcounter -= new Date(startDate_C).getMonth();
                                 mcounter += new Date(endDate_C).getMonth();
                                 mcounter = mcounter <= 0 ? 0 : mcounter+1;
                             }
                 
                             while (moment(startDate_C).valueOf() <= moment(endDate_C).valueOf()) {
                                 if (data[p] && data[p][moment(startDate_C).format('YYYY')] &&
                                     data[p][moment(startDate_C).format('YYYY')][moment(startDate_C).format('M')] &&
                                     data[p][moment(startDate_C).format('YYYY')][moment(startDate_C).format('M')][moment(startDate_C).format('D')]) {
      
                                     // add MAU
                                     if (data[p][moment(startDate_C).format('YYYY')][moment(startDate_C).format('M')][moment(startDate_C).format('D')]['mau']) {
                                         obj[p].mau += data[p][moment(startDate_C).format('YYYY')][moment(startDate_C).format('M')][moment(startDate_C).format('D')]['mau'];
                                      
                                     }
                                 }
      
                                 startDate_C = moment(startDate_C).add(1, 'days'); 
                             
                             }
                             
                         }
                           
                         //start date and end date are of same month //this month case
                         
                         else if (new Date(start).getMonth() == new Date(end).getMonth() && new Date().getMonth() > new Date(end).getMonth() && new Date(start).getDate() != new Date(end).getDate()){  
                          start = common.adjustStartDate(start);
                          
                          let yyyy = new Date(end).getFullYear();
                          let mm = new Date(end).getMonth();
                          let dd = new Date(yyyy,mm ,0).getDate();
                          end = new Date(`${mm}/${dd}/${yyyy}`).valueOf();
  
                             while (moment(start).valueOf() <= moment(end).valueOf()) {
                                 if (data[p] && data[p][moment(start).format('YYYY')] &&
                                     data[p][moment(start).format('YYYY')][moment(start).format('M')] &&
                                     data[p][moment(start).format('YYYY')][moment(start).format('M')][moment(start).format('D')]) {
      
                                     // add MAU
                                     if (data[p][moment(start).format('YYYY')][moment(start).format('M')][moment(start).format('D')]['mau']) {
                                      obj[p].mau += data[p][moment(start).format('YYYY')][moment(start).format('M')][moment(start).format('D')]['mau'];
                              
                                     }
                                 }
      
                                 start = moment(start).add(1, 'days'); 
                                
                             }
                           
                         }
      
                         //For other cases default last 30 days
                         else{
                       
                          //if start date end date same //this month case
                          if(new Date(start).getMonth() === new Date(end).getMonth()){
                          
                              startDate_C = common.adjustStartDate(start);
                            
                              while (moment(startDate_C).valueOf() <= moment(endDate_C).valueOf()) {
                                  if (data[p] && data[p][moment(startDate_C).format('YYYY')] &&
                                      data[p][moment(startDate_C).format('YYYY')][moment(startDate_C).format('M')] &&
                                      data[p][moment(startDate_C).format('YYYY')][moment(startDate_C).format('M')][moment(startDate_C).format('D')]) {
           
                                      // add MAU
                                      if (data[p][moment(startDate_C).format('YYYY')][moment(startDate_C).format('M')][moment(startDate_C).format('D')]['mau']) {
                                       obj[p].mau += data[p][moment(startDate_C).format('YYYY')][moment(startDate_C).format('M')][moment(startDate_C).format('D')]['mau'];
                                       
                                      }
                                  }
           
                                  startDate_C = moment(startDate_C).add(1, 'days'); 
                               
                                   }
                          }
                       else{
                      
                          mcounter=2;
                          let startDate_C = moment(endDate_C).subtract(30, 'days').valueOf();
                          startDate_C = common.adjustStartDate(startDate_C);
                       
                          while (moment(startDate_C).valueOf() <= moment(endDate_C).valueOf()) {
                          if (data[p] && data[p][moment(startDate_C).format('YYYY')] &&
                              data[p][moment(startDate_C).format('YYYY')][moment(startDate_C).format('M')] &&
                              data[p][moment(startDate_C).format('YYYY')][moment(startDate_C).format('M')][moment(startDate_C).format('D')]) {
   
                              // add MAU
                              if (data[p][moment(startDate_C).format('YYYY')][moment(startDate_C).format('M')][moment(startDate_C).format('D')]['mau']) {
                               obj[p].mau += data[p][moment(startDate_C).format('YYYY')][moment(startDate_C).format('M')][moment(startDate_C).format('D')]['mau'];
                               
                              }
                          }
   
                          startDate_C = moment(startDate_C).add(1, 'days'); 
                       
                           }
                         }
                        }
                       }
                        if (obj[p].dau > 0 && obj[p].dau > counter && counter > 0) {
                          obj[p].dau = obj[p].dau / counter;
                        }
      
                        if (obj[p].wau > 0 && obj[p].wau > wcounter && wcounter > 0) {
                          obj[p].wau = obj[p].wau / wcounter;
                        }
                        if (obj[p].mau > 0 && obj[p].mau > mcounter && mcounter > 0) {
                          obj[p].mau = obj[p].mau / mcounter;
                        }
                      });
                    });
                  }

                // Added the activeCamp key based on platform "web" , "ios" , "android"
                if (platform == "ios" || platform == "android") {
                    common.db.collection('campaign_statsdata_' + params.qstring.app_id).find({
                        "st": { "$in": ["ACTIVE", "PENDING"] },
                        "type": { "$nin": ["WEB_PUSH", "WEB_POPUP"] }
                    }).count(function(err, result) {
                        if (err) {
                            logger.error(err);
                        } else {
                            obj.activeCamp = result;
                
                            common.db.collection('campaigns_' + params.qstring.app_id).find({
                                d: false,
                                $or: [
                                    {"st": "ACTIVE"},
                                    {"st": "DRAFT"},
                                    {"st": "PAST"},
                                    {"st": "PENDING"}
                                ],
                                // Exclude ==>> "WEB_PUSH" and "WEB_POPUP" types from the count
                                "t": { "$nin": ["WEB_PUSH", "WEB_POPUP"] }
                            }).count(function(err, totCmp) {
                                if (err) {
                                    logger.error(err);
                                } else {
                                    obj.totalCmp = totCmp;
                                    common.returnOutput(params, obj);
                                }
                            });
                        }
                    });
                }
                 else if (platform == "web") {
                    common.db.collection('campaign_statsdata_' + params.qstring.app_id).count({
                        "st": { "$in": ["ACTIVE", "PENDING"] },
                        "type": { "$in": ["WEB_PUSH", "WEB_POPUP"] }
                    }, function(err, count) {
                        if (err) {
                            logger.error(err);
                        } else {
                            obj.activeCamp = count;
                            common.db.collection('campaigns_' + params.qstring.app_id).find({
                                d: false,
                                $or: [
                                    {"st": "ACTIVE"},
                                    {"st": "DRAFT"},
                                    {"st": "PAST"},
                                    {"st": "PENDING"}
                                ],
                                // Include ==> only "WEB_PUSH" and "WEB_POPUP" types in the count
                                "t": { "$in": ["WEB_PUSH", "WEB_POPUP"] }
                            }).count(function(err, count) {
                                if (err) {
                                    logger.error(err);
                                } else {
                                    obj.totalCmp = count;
                                    common.returnOutput(params, obj);
                                }
                            });
                            
                        }
                    });
                } else {
                    common.db.collection('campaign_statsdata_' + params.qstring.app_id).count({
                        "st": { "$in": ["ACTIVE", "PENDING"] }
                    }, function(err, count) {
                        if (err) {
                            logger.error(err);
                        } else {
                            obj.activeCamp = count;
                            common.returnOutput(params, obj);
                        }
                    });
                }
            } else {
                common.returnOutput(params, obj);
            }
        } else {
            logger.error(err);
            common.returnMessage(params, 500, "Internal Server Error");
        }
    });
};
    /**
     * @author Pranay P.
     * @param {*}
     * @description this function VALIDATES above written business logic function for DAU, WAU, MAU
     */
    metricesApi.getDauWauMauWithPlatform = function (params) {
        try {
            let argProps = {
                'startDate_C':{'required':true,'type':'Number'},
                'endDate_C':{'required':true,'type':'Number'},
                'startDate_P':{'required':true,'type':'Number'},
                'endDate_P':{'required':true,'type':'Number'},
                'startDate_CNew':{'required':true,'type':'String'},
                'endDate_CNew':{'required':true,'type':'String'},
                'startDate_PNew':{'required':true,'type':'String'},
                'endDate_PNew':{'required':true,'type':'String'}
            },dateRange={};
    
            if (!(dateRange = common.validateArgs(params.qstring.args, argProps))) {
                common.returnMessage(params, 400, 'Not enough args');
                return false;
            }    
            metricesApi.getActiveUserDauAndMauWithPlatforms(params);   
        } catch (error) {
            logger.error(`error => ${error}`);
            return false;
        }
    }


    metricesApi.timelySessionWithTimeAndPlace = function(data, filterArray, isPrevious, currentDateEpoch, filter_){
        let filter = filter_;
        let currentObject = {}
        let currentSession  = [];
        let previousSession = {};
        let tempPlatform    = '';
        //isPrevious          = (isPrevious)? isPrevious : false;
        data                = data[0];
        let timesList       = [];
        let counter         = -1;
        let currentTotal = 0;
        let previousTotal = 0;
    
        filterArray.forEach(function(value){
    
            if(value.p){
                if(data.hasOwnProperty(value.p)){
                    let platform = value.p;
                    if( tempPlatform != platform ){
                        timesList       = [];
                        tempPlatform = platform;
                        counter++;
                        // manage previous session data
                        previousSession[platform] = 0;
                        // manage current session data
                        let tmp = {};
                        tmp[platform] = [];
                        currentSession.push(tmp);
                    }
                    if(data[platform].hasOwnProperty(value.y)){
                        if(data[platform][value.y].hasOwnProperty(value.m)){
                            if(data[platform][value.y][value.m].hasOwnProperty(value.d)){
                                let dataObj = data[platform][value.y][value.m][value.d];
                                if(dataObj){
                                    let timeList = Object.keys(dataObj); // take out times from object keys
                                    timeList.forEach(function(timeName){ // times loop
                                        if( timeName != 'total' && timeName !='dau' && timeName !='mau' && timeName !='wau'){ // time not be equal total
    
                                            if( timesList.indexOf(timeName) === -1){ // check time exists into array or not
                                                timesList.push(timeName); // push time into array
                                                let obj = {}; // create new object
                                                obj[timeName] = {}; // add dynamic time as key in object and init new object on time
                                                currentSession[counter][platform].push(obj); // push into current session array
                                            }
                                            let index = timesList.indexOf(timeName);  // get current time position in array
                                            let places = Object.keys(dataObj[timeName]); // take out places list from object
                                            places.forEach(function(place){ // places loop
                                                if( place != 'total' ){ // place not be equal total\
                                                    if(isPrevious){
                                                        previousSession[platform] += dataObj[timeName][place];
                                                        previousTotal += dataObj[timeName][place];
                                                    }
                                                    else{
                                                        //when web data is not available
                                                        if(data.web == undefined && filter == "web"){
                                                            currentTotal = 0;
                                                        }else{
                                                            currentTotal += dataObj[timeName][place];
                                                            if( currentSession[counter][platform][index] ){
                                                                if( currentSession[counter][platform][index][timeName] != undefined ){
                                                                    if( currentSession[counter][platform][index][timeName][place] == undefined){
                                                                        currentSession[counter][platform][index][timeName][place] = dataObj[timeName][place]; // calculate current session total
                                                                    }
                                                                    else{
                                                                        currentSession[counter][platform][index][timeName][place] += dataObj[timeName][place]; // calculate current session total
                                                                    }
                                                                }
                                                            }
                                                        }
                                                    
                                                    }
                                                }
                                            }); // end places loop
                                        }
                                    }); // end times loop
                                }
                            }
                        }
                    }
                }
            }
        });
    
        if(isPrevious){
            previousSession['previousTotal'] = previousTotal;
            return previousSession;
        }
        else{
            currentObject = {currentSession:currentSession, currentTotal:currentTotal}
            return currentObject;
        }
    }

metricesApi.getActiveUserInterests = function(params){
    if(common.config.intetestAppsList.indexOf(params.qstring.app_id) >= 0){
    common.db.collection('interests_aggregates').findOne({_id:common.db.ObjectID(params.qstring.app_id)}, {_id:0}, function(err, interests){
    if(err){
        logger.error(`interests_aggregates error => ${err}`);
    }
    else{
    let userInterests = [];
    if(Reflect.ownKeys(interests)){
    Reflect.ownKeys(interests).forEach( platform => {
    Reflect.ownKeys(interests[platform]).forEach( interest => {
    userInterests.push({
    _id:{
    Interests:interest
    },
    total:interests[platform][interest],
    interest:interest
    });
    });
    });
    common.returnOutput(params,userInterests);
    }
    else{
    common.returnOutput(params,userInterests);
    }
    }
    });
    }
    else{
    common.db.collection('app_users'+params.qstring.app_id).aggregate([
    {$match: { "active": true}},
    {$project:{"did":1,"Interests":"$Interests"}},
    {$unwind:"$Interests"},
    { $group : { _id : {Interests:"$Interests"}, total : { $sum : 1 } } },
    {$project: {"interest":"$_id.Interests",total:1}}
    ],
    {maxTimeMS:semusiConfig.mongodb.maxTimeMS},
    function(err,userInterests){
    common.returnOutput(params,userInterests);
    }
    );
    }
    };

    metricesApi.getActiveUserDemographics = function(params){

       /* if(common.config.notInGenericQueue.indexOf(params.qstring.app_id) >= 0){
             common.db.collection('app_users'+params.qstring.app_id).aggregate([
                 {$match:{"active":true}},
                 {$project:{"did":1, "p":1,"gender":1}},
                 {$group : { _id : {p:"$p", gender:"$gender"}, total : { $sum : 1 } } },
                 {$project: {"p":"$_id.p","gender":"$_id.gender",total:1}}
                 ]
                 ,function(err,userDemographics){
                     common.returnOutput(params,userDemographics);
                 }
             );
         } */
         //else{
             common.db.collection('active_users_aggregates').find({_id:common.db.ObjectID(params.qstring.app_id)}).toArray(function(err, result){
                 if(!err){
                     let obj = {
                         android:[],
                         ios:[]
                     };
     
                     if(result){
                         // defind android property
                         obj.android = [{
                             gender:'M',
                             p:'Android',
                             total:0
                         },{
                             gender:'F',
                             p:'Android',
                             total:0
                         },{
                             p:'Android',
                             total:0
                         }];
     
                         // defind ios property
                         obj.ios = [{
                             gender:'M',
                             p:'IOS',
                             total:0
                         },{
                             gender:'F',
                             p:'IOS',
                             total:0
                         },{
                             p:'IOS',
                             total:0
                         }];
     
                         // get android active users data
                         if(result[0]['android'] && result[0]['android']['M']){
                             obj.android[0].total = result[0]['android']['M'];
                         }
                         if(result[0]['android'] && result[0]['android']['F']){
                             obj.android[1].total = result[0]['android']['F'];
                         }
                         if(result[0]['android'] && result[0]['android']['unknown']){
                             obj.android[2].total = result[0]['android']['unknown'];
                         }
     
                         // get ios active users data
                         if(result[0]['ios'] && result[0]['ios']['M']){
                             obj.ios[0].total = result[0]['ios']['M'];
                         }
                         if(result[0]['ios'] && result[0]['ios']['F']){
                             obj.ios[1].total = result[0]['ios']['F'];
                         }
                         if(result[0]['ios'] && result[0]['ios']['unknown']){
                             obj.ios[2].total = result[0]['ios']['unknown'];
                         }
                     }
                     common.returnOutput(params, [...obj.android, ...obj.ios]);
                 }
                 else{
                     common.returnOutput(params, []);
                 }
             });
         //}
     };

//This function returns active users with X number of competing apps
metricesApi.getActiveUserCompetingAppStats = function(params){
    if(common.config.intetestAppsList.indexOf(params.qstring.app_id) >= 0){
        let competingApps = [];
        common.db.collection('competing_aggregates').findOne({_id:common.db.ObjectID(params.qstring.app_id)},function(error, result){
            if(error){
                logger.error(`error => ${error}`);
                common.returnOutput(params, competingApps);
            }
            else{
                if(result.android && result.android.ctr){
                    Reflect.ownKeys(result.android.ctr).forEach(ctr =>{
                        competingApps.push({
                            _id:{
                                ctr:ctr
                            },
                            total:result.android.ctr[ctr],
                            ctr:ctr
                        });
                    })
                }
                common.returnOutput(params, competingApps);
            }
        });
    }
    else{
        common.db.collection('app_users'+params.qstring.app_id).aggregate([
            {$match: { "active": true}},
            {$project:{"capps":"$competingapps.apps","did":1}},
            {$unwind :"$capps"},
            {$match :{"capps.state":"I"}},
            {$group:{"_id":"$did","capps":{"$addToSet":"$capps"}}},
            {$project:{did:1,"capps": { "$size": { "$ifNull": [ "$capps", [] ] }}}},
            {$group: { _id: {"ctr":"$capps"}, total: {$sum: 1}}},
            {$project:{ctr:"$_id.ctr",total:1}}
            ], 
            {maxTimeMS:semusiConfig.mongodb.maxTimeMS}, 
            function(err,result){
                if(result){
                    common.returnOutput(params,result);
                }
                else{
                    common.returnOutput(params,[]);
                }
        });
    }
};

    //Private functions
    function sum(numbers) {
        return _.reduce(numbers, function(result, current) {
            return result + parseFloat(current);
        }, 0);
    }
    function getCityWiseData(data){

        result = _.chain(data).groupBy("s").map(function(state, s) {
                return _.chain(state).groupBy("cty").map(function(value1, cty) {
                        return {
                            s:s,
                            cty: cty,
                            total: sum(_.pluck(value1, "total"))
                        }
                    }).value();
                }).value();


        //Combine the results to a single array for readability and UI manipluation purpose
        let finalResult=[];
        result.forEach(function(stateGroup){
            finalResult = finalResult.concat(stateGroup);
        });


        return finalResult;
    }
    function getCountryWiseData(data){
        result = _.chain(data).groupBy("s").map(function(state, s) {
                return _.chain(state).groupBy("cc").map(function(value1, cc) {
                        return {
                            s:s,
                            cc: cc,
                            total: sum(_.pluck(value1, "total"))
                        }
                    }).value();
                }).value();
        //Combine the results to a single array for readability and UI manipluation purpose
        let finalResult=[];
        result.forEach(function(stateGroup){
            finalResult = finalResult.concat(stateGroup);
        });


        return finalResult;
    }
    function getPlatformAndVersionWiseData(data){
        result = _.chain(data).groupBy("s").map(function(state, s) {
            return _.chain(state).groupBy("p").map(function(value, p) {
                return _.chain(value).groupBy("pv").map(function(value1, pv) {
                        return {
                            s:s,
                            p: p,
                            pv: pv,
                            total: sum(_.pluck(value1, "total"))
                        }
                    }).value();
                }).value();
            }).value();
        //Combine the results to a single array for readability and UI manipluation purpose
        let finalResult=[];
        result.forEach(function(stateGroup){
            stateGroup.forEach(function(platformGroup){
                finalResult = finalResult.concat(platformGroup);
            });
        });

        return finalResult;
    }
    function getPlatformAndAppVersionWiseData(data){
        result = _.chain(data).groupBy("s").map(function(state, s) {
            return _.chain(state).groupBy("p").map(function(value, p) {
                return _.chain(value).groupBy("av").map(function(value1, av) {
                        return {
                            s:s,
                            p: p,
                            av: av,
                            total: sum(_.pluck(value1, "total"))
                        }
                    }).value();
                }).value();
            }).value();
        //Combine the results to a single array for readability and UI manipluation purpose
        let finalResult=[];
        result.forEach(function(stateGroup){
            stateGroup.forEach(function(platformGroup){
                finalResult = finalResult.concat(platformGroup);
            });
        });

        return finalResult;
    }
    function getPlatformAndDayWiseData(data){
       result = _.chain(data).groupBy("s").map(function(state, s) {
            return _.chain(state).groupBy("isnew").map(function(isnew, isn) {
                return _.chain(isnew).groupBy("p").map(function(value, p) {
                    return _.chain(value).groupBy("d").map(function(value1, d) {
                            return {
                                s:s,
                                isnew:isn,
                                p: p,
                                d: d,
                                total: sum(_.pluck(value1, "total"))
                            }
                        }).value();
                    }).value();
                }).value();

            }).value();
        let finalResult=[];
        result.forEach(function(stateGroup){
            stateGroup.forEach(function(isnewGroup){
                isnewGroup.forEach(function(platformGroup){
                    finalResult = finalResult.concat(platformGroup);
                });
            });
        });
        return finalResult;
    }
    function getPlatformAndHourWiseData(data){
        result = _.chain(data).groupBy("s").map(function(state, s) {
            return _.chain(state).groupBy("isnew").map(function(isnew, isn) {
                return _.chain(isnew).groupBy("p").map(function(value, p) {
                    return _.chain(value).groupBy("h").map(function(value1, h) {
                            return {
                                s:s,
                                isnew:isn,
                                p: p,
                                h: h,
                                total: sum(_.pluck(value1, "total"))
                            }
                        }).value();
                    }).value();
                }).value();

            }).value();
        let finalResult=[];
        result.forEach(function(stateGroup){
            stateGroup.forEach(function(isnewGroup){
                isnewGroup.forEach(function(platformGroup){
                    finalResult = finalResult.concat(platformGroup);
                });
            });
        });


        return finalResult;
    }
    function getPlatformWiseData(data){
        result = _.chain(data).groupBy("s").map(function(state, s) {
                return _.chain(state).groupBy("p").map(function(value, p) {
                        return {
                            s:s,
                            p: p,
                            total: sum(_.pluck(value, "total"))
                        }
                    }).value();
                }).value();

        let finalResult=[];
        result.forEach(function(stateGroup){
            stateGroup.forEach(function(platformGroup){
                finalResult = finalResult.concat(platformGroup);
            });
        });
        return finalResult;
    }
    function getPlatformAndTypeWiseData(data){
        result = _.chain(data).groupBy("s").map(function(state, s) {
            return _.chain(state).groupBy("t").map(function(type, t) {
                return _.chain(type).groupBy("p").map(function(value, p) {
                        return {
                            s:s,
                            t:t,
                            p: p,
                            total: sum(_.pluck(value, "total"))

                        }
                    }).value();
                }).value();
            }).value();

        let finalResult=[];
        result.forEach(function(stateGroup){
            stateGroup.forEach(function(typeGroup){
                typeGroup.forEach(function(platformGroup){
                    finalResult = finalResult.concat(platformGroup);
                });
            })
        });
        return finalResult;
    }
    function getNewAndRepeatTotals(data){
        result = _.chain(data).groupBy("s").map(function(state, s) {
                return _.chain(state).groupBy("isnew").map(function(value, isn) {
                    return _.chain(value).groupBy("p").map(function(value1, p) {
                        return {
                            s:s,
                            isnew: isn,
                            p:p,
                            total: sum(_.pluck(value1, "total"))
                        }
                    }).value();
                }).value();
                }).value();

        let finalResult=[];
        result.forEach(function(stateGroup){
            stateGroup.forEach(function(isnewGroup){
                isnewGroup.forEach(function(platformGroup){
                    finalResult = finalResult.concat(platformGroup);
                });
            });
        });
        return finalResult;
    }
    function getSourceWiseInstallsUninstalls(data){
        result = _.chain(data).groupBy("t").map(function(type, t) {
                return _.chain(type).groupBy("p").map(function(platform, p) {
                    return _.chain(platform).groupBy("isnew").map(function(isnew, isn) {
                        return _.chain(isnew).groupBy("ref").map(function(ref, r) {
                            return {
                                t:t,
                                isnew: isn,
                                p:p,
                                ref:r,
                                total: sum(_.pluck(ref, "total")),
                                avgcpi: _.pluck(ref,"avgcpi")[0]
                            }
                        }).value();
                    }).value();
                }).value();
            }).value();

        let finalResult=[];
        result.forEach(function(typeGroup){
            typeGroup.forEach(function(platformGroup){
                platformGroup.forEach(function(isnewGroup){
                    isnewGroup.forEach(function(refGroup){
                        finalResult = finalResult.concat(refGroup);
                    });
                });
            });
        });
        return finalResult;
    }

    function getSourceWiseInstallsUninstallsWithPreviousData(data){
        result = _.chain(data).groupBy("s").map(function(state, s) {
            return _.chain(state).groupBy("t").map(function(type, t) {
                return _.chain(type).groupBy("p").map(function(platform, p) {
                    return _.chain(platform).groupBy("isnew").map(function(isnew, isn) {
                        return _.chain(isnew).groupBy("ref").map(function(ref, r) {
                            return {
                                t:t,
                                isnew: isn,
                                p:p,
                                ref:r,
                                s:s,
                                total: sum(_.pluck(ref, "total")),
                                avgcpi:_.pluck(ref,"avgcpi")[0]
                            }
                        }).value();
                    }).value();
                }).value();
            }).value();
        }).value();
        let finalResult=[];
        result.forEach(function(stateGroup){
            stateGroup.forEach(function(typeGroup){
                typeGroup.forEach(function(platformGroup){
                    platformGroup.forEach(function(isnewGroup){
                        isnewGroup.forEach(function(refGroup){
                            finalResult = finalResult.concat(refGroup);
                        });
                    });
                });
            });
        });
        return finalResult;
    }

    function processDownloadData(params,data,downloadData,type,platform){
        if(downloadData == "cities"){
            let csvData = "City,Total";
            data.cities.forEach(function(item){
                if(item.s=="c"){
                    csvData+="\r\n"+item.cty+","+item.total;
                }

            });
            common.returnCSV(params,csvData);
        }
        else if(downloadData == "countries"){
            let csvData = "Country,Total";
            data.countries.forEach(function(item){
                if(item.s=="c"){
                    csvData+="\r\n"+item.cc+","+item.total;
                }

            });
            common.returnCSV(params,csvData);
        }
        else if(downloadData == "versions"){
            let csvData = "Platform,Total";
            data.versions.forEach(function(item){
                if(item.s=="c" &&  (item.p==platform || platform=="all")){
                    csvData+="\r\n"+common.toFirstUpper(item.p)+" "+item.pv.replace(/a/g,"").replace(/i/g,"").replace(/:/g,".")+","+item.total;
                }

            });
            common.returnCSV(params,csvData);
        }
        else if(downloadData == "appversions"){
            let csvData = "Platform,App Version,Total";
            data.appversions.forEach(function(item){
                if(item.s=="c" && (item.p==platform || platform=="all")){
                    csvData+="\r\n"+common.toFirstUpper(item.p)+","+ item.av.replace(/a/g,"").replace(/i/g,"").replace(/:/g,".")+","+item.total;
                }

            });
            common.returnCSV(params,csvData);
        }
        else if(downloadData == "days"){
            let csvData;
            if(type=="I"){
                csvData = "Day,Platform,New Installs,Repeat Installs,Total";
            }
            else{
                csvData = "Day,Platform,New UnInstalls,Repeat UnInstalls,Total";
            }

            let groupedData = _.groupBy(data.days, function(d) {
                return d.p+d.d;
            });

            let keys = Object.keys(groupedData);
            keys.forEach(function(key){
                let n=0;
                let r=0;
                let t=0;
                let p="";
                let d="";
                groupedData[key].forEach(function(item){
                    if(item.p==platform || platform=='all'){
                        if(item.s=="c"){
                            if(item.isnew=="true"){
                                n+=item.total;
                            }
                            else if(item.isnew=="false"){
                                r+=item.total;
                            }
                        }
                        p=item.p;
                        d=item.d;
                    }
                });
                t=n+r;
                if(p==platform || platform=='all'){
                    csvData+="\r\n"+d+","+ common.toFirstUpper(p)+","+ n +","+r+","+t;
                }
            });
            common.returnCSV(params,csvData);
        }
        else if(downloadData == "hours"){
            let csvData;
            if(type=="I"){
                csvData = "Hour,Platform,New Installs,Repeat Installs,Total";
            }
            else{
                csvData = "Hour,Platform,New UnInstalls,Repeat UnInstalls,Total";
            }
            let groupedData = _.groupBy(data.hours, function(d) {
                return d.p+d.h;
            });

            let keys = Object.keys(groupedData);
            keys.forEach(function(key){
                let n=0;
                let r=0;
                let t=0;
                let p="";
                let h="";
                groupedData[key].forEach(function(item){
                    if(item.p==platform || platform=='all'){
                        if(item.s=="c"){
                            if(item.isnew=="true"){
                                n+=item.total;
                            }
                            else if(item.isnew=="false"){
                                r+=item.total;
                            }
                        }
                        p=item.p;
                        h=item.h;
                    }
                });
                t=n+r;
                if(p==platform || platform=='all'){
                    csvData+="\r\n"+h+","+ common.toFirstUpper(p)+","+ n +","+r+","+t;
                }
            });

            common.returnCSV(params,csvData);
        }
        else if(downloadData == "sources"){
            let csvData = "";
            let groupedData =  _.groupBy(data.installs, function(d) {
                return d.ref;
            });

            let sources = Object.keys(groupedData);
            if(type=="I"){
                csvData = "Source,Avg CPI,New Installs,Repeat Installs,Total";
                sources.forEach(function(source){
                    let n=0;
                    let r=0;
                    let t=0;
                    let avgcpi=0;
                    groupedData[source].forEach(function(item){
                        if(item.isnew=="true" && (item.p==platform || platform=='all')){
                            n+=item.total;
                        }
                        else if(item.isnew=="false" && (item.p==platform || platform=='all')){
                            r+=item.total;
                        }
                        avgcpi=item.avgcpi;
                    });
                    t=n+r;
                    if(t>0){
                        csvData+="\r\n"+source+","+avgcpi+","+ n +","+r+","+t;
                    }
                });
            }
            else if(type=="BOTH"){
                csvData = "Avg CPI,Installs,Source,UnInstalls,Percentage";
                sources.forEach(function(source){
                    let i=0;
                    let u=0;
                    let t=0;
                    let p = 0;

                    groupedData[source].forEach(function(item){
                        if(item.t=="I" && (item.p==platform || platform=='all')){
                            i+=item.total;
                        }
                        else if(item.t=="U" && (item.p==platform || platform=='all')){
                            u+=item.total;
                        }
                        avgcpi=item.avgcpi;

                        if(u>i){
                            p = 0+"%";
                        }else{
                            p = parseFloat(u/i*100).toFixed(2)+"%"
                        }
                    });

                    if(i>0 || u>0){
                        csvData+="\r\n"+avgcpi+","+i+","+ source +","+u+","+p;
                    }

                });
            }
            common.returnCSV(params,csvData);
        }
    }

    metricesApi.getChatBotSession = function(params){
        let sessionData={
            current : [],
            previous : [],
            currentTotal:0
        };

        let argProps = {
            'startDate_C':{'required':true,'type':'String'},
            'endDate_C':{'required':true,'type':'String'},
            'startDate_P':{'required':true,'type':'String'},
            'endDate_P':{'required':true,'type':'String'},

        },dateRange={};

        if (!(dateRange = common.validateArgs(params.qstring.args, argProps))) {
            common.returnMessage(params, 400, 'Not enough args');
            return false;
        }

        let query = {}
        let currentSearchFilter = [];
        //params.qstring.app_id = "57ef55cf266d9e8c1af2f408";
        common.fillTimeObjectQuery(query, currentSearchFilter, dateRange.startDate_C, dateRange.endDate_C, 'facebook');
        let previousSearchFilter = [];
        common.fillTimeObjectQuery(query, previousSearchFilter, dateRange.startDate_P, dateRange.endDate_P, 'facebook');
        // get total session duration
        query['facebook.tsd'] = 1;

        common.db.collection('timely_chatbot_sessions').find({_id:common.db.ObjectID(params.qstring.app_id)},query).toArray(function(err, result){
            if(!err){
                if(result.length > 0){
                    let data = metricesApi.timelySessionWithTime(result, currentSearchFilter, false);
                    sessionData.current         = data.currentSession;
                    sessionData.currentTotal    = data.currentTotal;
                    sessionData.periodDuration  = data.periodDuration;
                    sessionData.totalDuration   = data.totalDuration;
                    sessionData.previous        = metricesApi.timelySessionWithTime(result, previousSearchFilter, true);
                    // get current month dau and mau
                    metricesApi.getChatBotActiveUserDauAndMau(params,function(err, monthData){
                        if(err){
                            logger.error(`error => ${err}`);
                        }
                        else{
                            sessionData.dau  = monthData.dau;
                            sessionData.mau  = monthData.mau;
                            sessionData.activeUsers  = monthData.activeUsers;
                        }
                        common.returnOutput(params,sessionData);
                    });
                }
                else{
                     common.returnOutput(params,sessionData);
                }
            }
            else{
                logger.error(`error => ${err}`);
                common.returnOutput(params,sessionData);
            }
        });

    }

    metricesApi.timelySessionWithTime = function(data, filterArray, isPrevious){
        let currentObject   = {}
        let currentSession  = [];
        let tempPlatform    = '';
        let previousObject  = {}
        data                = data[0];
        let timesList       = [];
        let counter         = -1;
        let currentTotal    = 0;
        let previousTotal   = 0;
        let totalDuration   = 0;
        let periodDuration  = 0;

        filterArray.forEach(function(value){
            if(value.p){
                if(data.hasOwnProperty(value.p)){
                    let platform = value.p;
                    if( tempPlatform != platform ){
                        timesList       = [];
                        tempPlatform = platform;
                        counter++;
                        let tmp = {};
                        tmp[platform] = [];
                        currentSession.push(tmp);
                    }
                    if(data[platform].hasOwnProperty(value.y)){
                        if(data[platform][value.y].hasOwnProperty(value.m)){
                            if(data[platform][value.y][value.m].hasOwnProperty(value.d)){
                                let dataObj = data[platform][value.y][value.m][value.d];
                                if(dataObj){
                                    let timeList = Object.keys(dataObj); // take out times from object keys
                                    timeList.forEach(function(timeName){ // times loop

                                        if( timeName != 'total' && timeName !='dau' && timeName != 'tsd'){ // time not be equal total

                                            if(isPrevious){
                                                if(previousObject[platform] == undefined){
                                                    previousObject[platform] = dataObj[timeName]['total'];
                                                }
                                                else{
                                                    previousObject[platform] += dataObj[timeName]['total'];
                                                }
                                            }
                                            else{
                                                if(timesList.indexOf(timeName) === -1){ // check time exists into array or not
                                                    timesList.push(timeName); // push time into array
                                                    let obj = {}; // create new object
                                                    obj[timeName] = 0; // add dynamic time as key in object and init new object on time
                                                    currentSession[counter][platform].push(obj); // push into current session array
                                                }
                                                let index = timesList.indexOf(timeName);  // get current time position in array
                                                currentTotal += dataObj[timeName]['total'];
                                                if( currentSession[counter][platform][index] ){
                                                    if( currentSession[counter][platform][index][timeName] == undefined){
                                                        currentSession[counter][platform][index][timeName] = dataObj[timeName]['total']; // calculate current session total
                                                    }
                                                    else{
                                                        currentSession[counter][platform][index][timeName] += dataObj[timeName]['total']; // calculate current session total
                                                    }
                                                }
                                            }
                                        }
                                        else if(timeName == 'tsd'){
                                            periodDuration += dataObj[timeName];
                                        }
                                    }); // end times loop
                                }
                            }
                        }
                    }
                }
                if(data[value.p] && data[value.p]['tsd']){
                    totalDuration += data[value.p]['tsd'];
                }
            }
        });

        // send previous session information
        if(isPrevious){
            return previousObject;
        }
        else{
            currentObject = {currentSession:currentSession, currentTotal:currentTotal, periodDuration:periodDuration, totalDuration:totalDuration }
            return currentObject;
        }
    }

    // get current month dau, mau and active users count
    metricesApi.getChatBotActiveUserDauAndMau = function(params, callback){
        let query = {}
        let platforms = ['facebook'];
        common.fillDauMauObjectQuery(query, platforms);
        common.db.collection('timely_chatbot_sessions').find({_id:common.db.ObjectID(params.qstring.app_id)},query).toArray(function(err, result){
            if(!err){
                let obj = {dau:0, mau:0, activeUsers:{facebook:0}};
                if(result[0]){
                    let currentEpoch = common.getCurrentEpochTime();
                    if(result[0]['facebook']){
                        if(result[0]['facebook'][moment(currentEpoch*1000).format('YYYY')] &&
                            result[0]['facebook'][moment(currentEpoch*1000).format('YYYY')][moment(currentEpoch*1000).format('M')] &&
                            result[0]['facebook'][moment(currentEpoch*1000).format('YYYY')][moment(currentEpoch*1000).format('M')][moment(currentEpoch*1000).format('D')]){
                            if(result[0]['facebook'][moment(currentEpoch*1000).format('YYYY')][moment(currentEpoch*1000).format('M')][moment(currentEpoch*1000).format('D')]['dau']){
                                obj.dau += result[0]['facebook'][moment(currentEpoch*1000).format('YYYY')][moment(currentEpoch*1000).format('M')][moment(currentEpoch*1000).format('D')]['dau'];
                            }
                        }
                        if(result[0]['facebook'][moment(currentEpoch*1000).format('YYYY')] &&
                            result[0]['facebook'][moment(currentEpoch*1000).format('YYYY')][moment(currentEpoch*1000).format('M')]){
                            if(result[0]['facebook'][moment(currentEpoch*1000).format('YYYY')][moment(currentEpoch*1000).format('M')]['mau']){
                                obj.mau += result[0]['facebook'][moment(currentEpoch*1000).format('YYYY')][moment(currentEpoch*1000).format('M')]['mau'];
                            }
                        }
                        obj.activeUsers.facebook += (result[0]['facebook_active_users'])? result[0]['facebook_active_users'] : 0;
                    }
                }
                callback(null, obj);
            }
            else{
                callback(err, null);
            }
        });
    }

    //Function for find week no date formate (dowOffset): 2019,12,08
    Date.prototype.getWeek = function (dowOffset) {
        dowOffset = typeof(dowOffset) == 'int' ? dowOffset : 0; 
        let newYear = new Date(this.getFullYear(),0,1);
        let day = newYear.getDay() - dowOffset; 
        day = (day >= 0 ? day : day + 7);
        let daynum = Math.floor((this.getTime() - newYear.getTime() - 
        (this.getTimezoneOffset()-newYear.getTimezoneOffset())*60000)/86400000) + 1;
        let weeknum;
        //if the year starts before the middle of a week
        if(day < 4) {
            weeknum = Math.floor((daynum+day-1)/7) + 1;
            if(weeknum > 52) {
                nYear = new Date(this.getFullYear() + 1,0,1);
                nday = nYear.getDay() - dowOffset;
                nday = nday >= 0 ? nday : nday + 7;
                /*if the next year starts before the middle of
                  the week, it is week #1 of that year*/
                weeknum = nday < 4 ? 1 : 53;
            }
        }
        else {
            weeknum = Math.floor((daynum+day-1)/7);
        }
        return weeknum;
    };

    metricesApi.getCombinedLogFile = function (params) {
		let adminAccess = (params.member.global_admin) ? true : params.member.user_role.admin
		if (params.member.global_admin || (adminAccess && adminAccess.includes(params.qstring.args.app_id))) {
			try {
				const pathName = path.resolve(__dirname, "../../../combined.log")
				params.res.download(pathName)
			} catch (err) {
				logger.error(`error occured in downloading combined log file", ${err}`);
				common.returnOutput(params, {})
			}

		} else {
			common.returnMessage(params, 401, validate.getErrorMessage('UnAuthorizedUser'));
		}
	}
    metricesApi.getRawUserData = async function (params) {
		let adminAccess = (params.member.global_admin) ? true : params.member.user_role.admin
        let managerAccess = (params.member.global_admin) ? true : params.member.user_role.manager
		if (params.member.global_admin || (adminAccess && adminAccess.includes(params.qstring.args.app_id)) || (managerAccess && managerAccess.includes(params.qstring.args.app_id))) {
			try {
				const fetchData = require("../data/didDetails").fetchData
				let appid = params.qstring.args.app_id
				let did = params.qstring.args.did
				let data = await fetchData(appid, did)
				common.returnOutput(params, data)
			} catch (err) {
				logger.error(`error occured in getRawUserData", ${err}`);
				common.returnOutput(params, {})
			}

		} else {
			common.returnMessage(params, 401, validate.getErrorMessage('UnAuthorizedUser'));
		}

	}

    //Short URL utm builder start 
    metricesApi.postShortUrl = function (params) {
        let url = params.qstring.args
        const characters = 'abcdefghijklmnopqrstuvwxyz0123456789'
        function makeid(length) {
            let result = ''
            for (var i = 0; i < length; i++) {
                result += characters.charAt(crypto.randomInt(characters.length - 1));
            }
            return result;
        }
        common.db.collection('apps').findOne({ '_id': common.db.ObjectID(params.qstring.app_id) }, function (err, result) {
            if (err) {
                logger.error("err in mongoDB", err)
                common.returnOutput(params, 500, "Error");
            } else {
                let baseUrl = result.appsettingsBaseUrl
                let shortUrl = baseUrl + makeid(7);
                var oneYear = 31536000;//one year in seconds
                cacheApi.setKey(shortUrl, url);
                cacheApi.expire(shortUrl, oneYear);
                common.db.collection('campaigns_' + params.qstring.app_id).findOne({ '_id': common.db.ObjectID(params.qstring.campId) }, function (err, result) {
                    if (!result || err) {
                        logger.error("cannot find campaign in db", err)
                        common.returnOutput(params, 500, "Error");
                    } else {
                        common.db.collection('campaigns_' + params.qstring.app_id).update({ '_id': common.db.ObjectID(params.qstring.campId) }, { $set: { 'url': { 'shortUrl': shortUrl, 'longUrl': url.url } } }, function (err, result) {
                            if (err || result == null) {
                                logger.error("err occured in saving url in mongo", err)
                                common.returnOutput(params, 500, "Error");
                            }else{
                                logger.info("Saved utm urls in the db")
                                // common.returnOutput(params,200,result);
                                common.returnOutput(params, [shortUrl]);
                            }
                        })
                    }
                })
            }
        })
    }
    
}(metricesApi));

module.exports = metricesApi;
