let xss = require("xss");
let common = {},
moment = require('moment-timezone'),
logger = require('../../logger'),
crypto = require('crypto'),
mongo = require('mongoskin'),
cryptoApi = require('./semusi.crypto.js'),
awsHelper = require('./../parts/data/aws.data.js'),
semusiConfig = require('../../api/config'),
pg = require('pg'),
fs = require('fs'),
AWS = require('aws-sdk'),
psqlUtils = require('../utils/pgsql.utils.js'),
path = require('path'),
validate = require('../constants/constants.js'),
sequelize = require('sequelize'),
Promise = require('bluebird'),
cacheApi = require('./semusi.cache.js');
(function (common) { 
    common.campaignStatsKyes = ["Campaign_Received", "Campaign_Viewed", "Campaign_Clicked", "Campaign_Deleted"];
    common.campaignStats = {
        received:"Campaign_Received",
        receivedId: 100,
        viewed: "Campaign_Viewed",
        viewedId: 200,
        clicked:"Campaign_Clicked",
        clickedId:300,
        deleted:"Campaign_Deleted",
        deletedId:400
    }
    common.campaignStatsOld = {
        received:"received",
        receivedId: 100,
        viewed: "viewed",
        viewedId: 200,
        clicked:"clicked",
        clickedId:300,
        deleted:"deleted",
        deletedId:400
    }

    common.dbMap = {
        'events': 'e',
        'total': 't',
        'new': 'n',
        'unique': 'u',
        'duration': 'd',
        'durations': 'ds',
        'frequency': 'f',
        'loyalty': 'l',
        'sum': 's',
        'count': 'c'
    };

    common.dbUserMap = {
        'device_id': 'did',
        'first_seen': 'fs',
        'last_seen': 'ls',
        'session_duration': 'sd',
        'total_session_duration': 'tsd',
        'session_count': 'sc',
        'device': 'd',
        'carrier': 'c',
        'gender': 'g',
        'city': 'cty',
        'country_code': 'cc',
        'platform': 'p',
        'platform_version': 'pv',
        'app_version': 'av',
        'app_code':'ac',
        'installer':'ins',
        'last_begin_session_timestamp': 'lbst',
        'last_end_session_timestamp': 'lest',
        'has_ongoing_session': 'hos',
        'alias':'alias',
        'sdk_version':'sdkv',
        'resolution':'res',
        'locale':'l',
        'time_zone':'tz'
    };


    let dbName;
    let dbOptions = { safe:false, maxPoolSize: semusiConfig.mongodb.max_pool_size || 1000 };
            common.db = mongo.db(semusiConfig.mongodb.productionUrl, {native_parser: true, 'auto_reconnect': true, 'poolSize': 500, socketOptions: {
                keepAlive: true,
                connectTimeoutMS: 30000,
                socketTimeoutMS: 30000,
                reconnectTries: Number.MAX_VALUE,
                reconnectInterval: 5000
            }});

        // citus connection
        common.pgCitusDB = new pg.Pool(semusiConfig.postgreSQL.productionCitus);
        common.pgCitusDB.connect()
          .then(client =>{
            logger.info(`Citus connected with PG`);
              common.pgCitusDBClient = client;
          })
          .catch(e =>{
            logger.error(`error: could not connect with PG  => ${e.message}`);
          });


    common.db.ObjectID = mongo.ObjectID;

    common.connectWithProd = function(){
        common.proddb = mongo.db(semusiConfig.mongodb.productionUrl, {native_parser: true, 'auto_reconnect': true, 'poolSize': 100, socketOptions: {
            keepAlive: 50,
            connectTimeoutMS: 1000,
            socketTimeoutMS: 0
        }});
        common.proddb.ObjectID = mongo.ObjectID;
    }

    common.config = semusiConfig;

    //common.time = time;

    common.moment = moment;

    common.crypto = crypto;

    common.getDescendantProp = function (obj, desc) {
        desc = String(desc);

        if (desc.indexOf(".") === -1) {
            return obj[desc];
        }

        let arr = desc.split(".");
        while (arr.length && (obj = obj[arr.shift()]));

        return obj;
    };

    common.isNumber = function (n) {
        return !isNaN(parseFloat(n)) && isFinite(n);
    };

    common.zeroFill = function(number, width) {
        width -= number.toString().length;

        if (width > 0) {
            return new Array(width + (/\./.test(number) ? 2 : 1)).join('0') + number;
        }

        return number + ""; // always return a string
    };

    common.arrayAddUniq = function (arr, item) {
        if (arr.indexOf(item) === -1) {
            arr[arr.length] = item;
        }
    };

    common.shaHash = function (str, addSalt) {
        let salt = (addSalt) ? new Date().getTime() : '';
        return crypto.createHmac(semusiConfig.shaV1Hash, salt + '').update(str + '').digest('hex');
    };

    common.mdALgo = function (str) {
        return crypto.createHash(semusiConfig.mdALgo).update(str + '').digest('hex');
    };

    // Creates a time object in the format object["2012.7.20.property"] = increment.
    common.fillTimeObject = function (params, object, property, increment) {
        increment = (increment) ? increment : 1,
            timeObj = params.time;

        if (!timeObj || !timeObj.yearly || !timeObj.monthly || !timeObj.weekly || !timeObj.daily || !timeObj.hourly) {
            return false;
        }

        object[timeObj.yearly + '.' + property] = increment;
        object[timeObj.monthly + '.' + property] = increment;
        object[timeObj.daily + '.' + property] = increment;

        // If the property parameter contains a dot, hourly data is not saved in
        // order to prevent two level data (such as 2012.7.20.TR.u) to get out of control.
        if (property.indexOf('.') === -1) {
            object[timeObj.hourly + '.' + property] = increment;
        }

        // For properties that hold the unique visitor count we store weekly data as well.
        if (property.substr(-2) == ("." + common.dbMap["unique"]) ||
            property == common.dbMap["unique"] ||
            property.substr(0,2) == (common.dbMap["frequency"] + ".") ||
            property.substr(0,2) == (common.dbMap["loyalty"] + ".") ||
            property.substr(0,3) == (common.dbMap["durations"] + "."))
        {
            object[timeObj.yearly + ".w" + timeObj.weekly + '.' + property] = increment;
        }
    };

            /**
  * Asynchronously retrieves App settings from the database.
  * This function retrieves the Apps doc from db ,based on the passed Appid.
  *
  * @returns {Promise<object>} A Promise that resolves with the Apps object if successful, or rejects with an error if unsuccessful.
  */

   common.retrieveAppSettings =  async function (app_id) {
        return new Promise((resolve, reject) => {
            // Querying the 'apps' collection in the database to find the settings associated with the passed appid.
            common.db.collection('apps').findOne({'_id': common.db.ObjectID(app_id) }, (err, appSettings) => {
                if (err) {
                    reject(err);
                } else {
                    // If no error occurs and the app are found, resolve the Promise with the retrieved apps object
                    // or an empty object if no apps are found.
                    resolve(appSettings || {});
                }
            });
        });
    }
    common.getUserIdObject=function(u) {
        //if _custom is present and _custom has UserId
        if ( u._custom && u._custom.UserId) {
            return common.formatClientId(u._custom);
        } 
        
      //if _custom_UserId or _custom_UserID is present 
        if (u._custom_UserId || u._custom_UserID) {
            const userId = u._custom_UserId || u._custom_UserID;
              let res = common.isJson(userId) ? JSON.parse(userId) : userId 
            return  (Array.isArray(res)) ? res : [res];
        }
    
        // by default set as undefined
        return undefined;
    }
      //Check string is valid JSON before parse  
  common.isJson = function(str) {
    try {
        JSON.parse(str);
    } catch (e) {
          return false;
    }
      return true;
  }
//   commented for now
//    common.populateSurveyObject = function(template, ) {
//     let data={}
//     if (template && template.q) {
//         template.q.forEach(function(item) {
//             let question = {};
//             let options = [];
//             question.id = item.id;
//             question.qt = item.questionText;
//             question.t = item.questionType;
//             question.st = item.sampleText;
//             question.oo = item.otherOption;
//             item.questionOptions.forEach(function(opt) {
//                 let option = {};
//                 option.ot = opt.optionText;
//                 options.push(option);
//             });
//             question.qo = options;
//             data.push(question);
//         });
//     }
//     return data;
// }

    // this function takes input as dd-mm-yyy to epoch
    common.getDateToEpoch = function datesToEpoch(dateString) {
            const dateParts = dateString.split('-');
            const year = parseInt(dateParts[2]);
            const month = parseInt(dateParts[1]) - 1; // Months are 0-based
            const day = parseInt(dateParts[0]);
            const date = new Date(year, month, day);
            return date.getTime() / 1000; // Convert to seconds since epoch
    }
    common.getIp= function(request){
        return resultIp = request.headers['x-forwarded-for'] || request.connection.remoteAddress;
    }
    /**
     * getCookieValue method return the value of a cookie
     * @param {*} headersCookies 
     * @param {*} cookieName 
     * @returns 
     */
        common.getCookieValue = function(headersCookies, cookieName) {
            const cookies = headersCookies.split(';');
            for (let i = 0; i < cookies.length; i++) {
                const cookie = cookies[i].trim();
                if (cookie.startsWith(cookieName + '=')) {
                return cookie.substring(cookieName.length + 1);
                }
            }
            return null; // Cookie not found
        }

  common.populateRatingObject = function(template) {
     let data={}
    data.q = template.question;
    data.ai = template.activeImage;
    data.di = template.disabledImage;
    data.m = template.message;
    data.at = template.title;
    data.sbtnTxt = template.sbBtnText;
    data.sbtnClr = template.sbBtnClr;
    data.starCount = template.starCount;
    data.starRatingText = template.starRatingText;
    data.starClr = template.starColour;
    data.bgClr = template.bgColour;

    return data
}
    /**
     * getAttributeCondition method returns the attrCondition which will be appended in the query
     * @param {*} attributeList 
     * @returns 
     */
    common.getAttributeCondition = function(attributeList){
            let attrCondition = ''
            attributeList.map((data, index) => {
                attrCondition += `name = '${data.name}' AND key= '${data.event}' ${(attributeList.length > 0 && index < attributeList.length - 1) ? 'OR ' : ''}`
            })
            return attrCondition;
    }

    /**
     * getEventCondition method returns eventCondition which will be appended in the query
     * @param {*} eventsList 
     * @returns 
     */
    
    common.getEventCondition = function(eventsList){
            let eventCondition = ''
            eventsList.map((event, index) => {
            eventCondition += `name = '${event}' ${(eventsList.length > 1 && index < eventsList.length - 1) ? ' OR ' :''}`
            })
            return eventCondition;
    }
    // this function returns a masked Email  
    common.getMaskedEmail = function(email){
        email = email.split('');
        let finalArr=[];
        let len = email.indexOf('@');
        email.forEach((item,pos)=>{
        (pos>=1 && pos<=len-2) ? finalArr.push('*') : finalArr.push(email[pos]);
        })
        return finalArr.join('')
    }
    common.getMaskClientId = function(did){
        if(did){
            did = did.toString()
            let str = did.replace(/^.{4}/g, '****');
            let maskDeviceId = str.slice(0, -4) + "****";
		    return maskDeviceId
        }else{
            return ''
       }
	}
    // this function returns webpush template data object for activecmp 
    common.populateWebPushObject = async function(template,app_id,camp_id){
        let data={};
        data.title = template.title;
        data.message = template.message;
        data.tid = undefined;
        data.camp_id = camp_id;
        data.eurl = (template.externalUrl) ? template.externalUrl : undefined;
        data.url = (template.externalUrl) ? template.externalUrl : undefined;
        data.app_id = (app_id) ? app_id : '';
        let blob = semusiConfig.blobContainerCDN;
		if(semusiConfig.uploadAssets[0]=="Azure"){
			blob += app_id 
		}
        if(common.isValidUrl(template.icon)){
            data.icon =  template.icon;
        }else{
            data.icon =  (template.icon == "") ? "" : (template.icon.includes(validate.getCDN("azureCDN"))) ? blob + template.icon.substring(template.icon.lastIndexOf('/')) : blob+template.icon ;
        }
        if(common.isValidUrl(template.extendedImage)){
            data.eni =  template.extendedImage;
        }else{
            // we have to check if template.extendedImage exist or not
            data.eni =  (template.eni == "") ? "" : (template.extendedImage &&  template.extendedImage.includes(validate.getCDN("azureCDN"))) ? blob + template.extendedImage.substring(template.extendedImage.lastIndexOf('/')) : blob+template.extendedImage ;
            // we have to check if template.extendedImage exist or not
            data.eni =  (template.eni == "") ? "" : (template.extendedImage &&  template.extendedImage.includes(validate.getCDN("azureCDN"))) ? blob + template.extendedImage.substring(template.extendedImage.lastIndexOf('/')) : blob+template.extendedImage ;
        }
        data.action = (template.actions) ? template.actions : undefined;
        if (template.cdata) {
            let cdataObj = await common.getCdataObj(template.cdata)
            data.cdata = cdataObj;
        }
        if (template.cdata) {
            let cdataObj = await common.getCdataObj(template.cdata)
            data.cdata = cdataObj;
        }
        return data;
    }
    common.populateWebPopUpObject = function(template,app_id,camp_id){
        let data={};    
        data.hc = template.hc;
        data.dc = template.dc;
        data.br = template.br;
        data.wh = template.wh;
        data.ps = template.ps;
        data.bg = template.bg;
        data.mode = template.mode;
        data.title = template.title;
        data.message = template.message;
        data.tid = undefined;
        data.camp_id = camp_id;
        data.url = (template.url) ? template.url : undefined;
        data.app_id = (app_id) ? app_id : '';
        if(common.isValidUrl(template.icon)){
            data.icon =  template.icon;
        }else{
            data.icon =  (template.icon != "") ? new URL(semusiConfig.blobContainerCDN.slice(0, -1)).origin+template.icon : ""  ;
        }

        return data;
    }
    common.populateInAppObject = async function (template,app_id) {
        //getting the blob
        let blob = semusiConfig.blobContainerCDN
        //incase of azure append appid 
        if(semusiConfig.uploadAssets[0]=="Azure"){
            blob += app_id 
        }
       let data={}
       let azureCdn = "/appice-prod-campaign-images/uploads/campaignFiles/campaignimages";
    data.mode = (template.view_mode) ? template.view_mode :template.mode;
    // Notification image
    if(template.notificationImage){
        if(common.isValidUrl(template.notificationImage)|| template.notificationImage == undefined){
            data.ni =  template.notificationImage;
        }else{
                //for existing templates whose  notificationImage contains half blobContainerCdn
            template.notificationImage = ( template.notificationImage.includes(azureCdn) ) ? template.notificationImage.substring(template.notificationImage.lastIndexOf("/")) : template.notificationImage
            data.ni =  (template.notificationImage != "") ? blob+ template.notificationImage : ""  ;
        }
    }else{
        data.ni = template.ni || ''
    }
    //Icon image
    if(template.iconImage){
        if(common.isValidUrl(template.iconImage)|| template.iconImage == undefined){
            data.ii =  template.iconImage;
        }else{
                //for existing templates whose  notificationImage contains half blobContainerCdn
            template.iconImage = ( template.iconImage.includes(azureCdn) ) ? template.iconImage.substring(template.iconImage.lastIndexOf("/")) : template.iconImage
            data.ii =  (template.iconImage != "") ? blob+ template.iconImage : ""  ;
        }
    }else{
        //pass empty strings if it is not found
        data.ii = template.ii || ''
    }
    data.et = template.notificationType || template.et || '';
    data.aurl = template.actionUrl || template.aurl || '';
    
      if (template.showAction || template.sa) {
        data.sa = template.showAction || template.sa;
          //if show action is true then only add action-title to the payload of ActiveCampaigns 
          if (template.actionTitle != null && template.actionTitle != undefined || template.at != null && template.at != undefined) {
              data.at = template.actionTitle || template.at || '';
          }
    }else{
        data.sa = false
    }    
    data.atc = template.submitBtnTextClr || template.atc || '';
    data.htc = template.headerTextClr || template.htc  ||  '';
    data.dtc = template.descriptionTextClr ||  template.dtc || '';
    data.bgc = template.backgroundColor ||  template.bgc || '';
    // decoding the values  for each key of cdata 
    if(template.cdata){

        let cdataObj = await common.getCdataObj(template.cdata)
        data.cdata = cdataObj
    }
    if(data.mode == 'Header' || data.mode == 'Footer' ){
        //pass empty strings if it is not found
        data.nh = template.notificationHeader || template.nh || '' ;
        data.nd = template.notificationDescription || template.nd || '';
    }
    return data
}
common.populatePushObject = async function(template,appId,api_key) {
    let data = {}

     data.nh = (template.notificationHeader)? template.notificationHeader : template.nh ;
     data.nd = (template.notificationDescription) ? template.notificationDescription:template.nd ;
     let ni = (template.notificationImage) ? template.notificationImage :template.ni ;
     //add image base url using getBaseUrl function 
     if(common.isValidUrl(ni)|| ni == undefined){
        data.ni =  ni ? ni : "";
    }else{
        data.ni =  (ni != "") ? semusiConfig.blobContainerCDN.slice(0, -1)+ ni : ""  ;
    }
    
     data.end = (template.expandedNotificationDescription) ? template.expandedNotificationDescription :template.end ;
     if(data.end == null){
        data.end = "";
    }
    //  let eni = (template.expandedNotificationImage) ? template.expandedNotificationImage : template.eni;
    //       //add image base url using getBaseUrl function 
    //   if(common.isValidUrl(eni) || ni==undefined){
    //     data.eni =  eni ? eni : "";
    // }else{
    //     data.eni = (eni != "") ? semusiConfig.blobContainerCDN.slice(0, -1)+eni : ""  ;
    // }
    // after yono issue code comment top code
    if(common.isValidUrl(template.expandedNotificationImage)){
        data.eni =  template.expandedNotificationImage;
    }else{
        // if it is already a valid url 
        if(common.isValidUrl(template.eni)){
            data.eni = template.eni
        }else{
        data.eni = (template.expandedNotificationImage != "") ? semusiConfig.blobContainerCDN.slice(0, -1)+template.expandedNotificationImage : ""  ;
     }
    }
    data.and = template.and ? template.and : "";
    data.ty = template.ty ? template.ty : "";
    let eurl = (template.externalUrl) ? template.externalUrl : template.eurl;
    data.eurl = eurl ? eurl :"";
    data.et = (template.notificationType) ? template.notificationType : template.et;
     data.actions = template.actions;
     data.sound = template.sound;
     data.vibrate = template.vibrate;
     data.badge = template.badge;
     if (template.cdata) {
        let cdataObj = await common.getCdataObj(template.cdata)
             data.cdata = cdataObj;
     }
     return data;
 }


   common.setActiveGeoFenceData = function(campaigns,templateData){
        let childApproved;
        let childDeleted;
        let sdkDeletedFlag;
        let payload = [];
        let data = {};
        if (campaigns.childIds && campaigns.childIds.length > 0) {
            if (campaigns.childIds.approved == true) {
                childApproved = true;
            } else {
                childApproved = false;
            }
            if (campaigns.childIds.deleted == true) {
                childDeleted = true;
            } else {
                childDeleted = false;
            }
            sdkDeletedFlag = campaigns.d;
        } else {
            sdkDeletedFlag = campaigns.d;
        }
        let obj = {};
        obj._id = campaigns._id;
        obj.tid = campaigns.tid;
        obj.t = campaigns.t;
        obj.sd = campaigns.sd;
        obj.ed = campaigns.ed;
        obj.ud = campaigns.ud;
        obj.d = sdkDeletedFlag;
        obj.delays = campaigns.delays;
        obj.delayi = campaigns.delayi;
        obj.delayu = campaigns.delayu;
        obj.fre = {};
        if (campaigns.c_arr) {
            obj.c_arr = campaigns.c_arr;
        }
        obj.fre.dp = 0;
        if (campaigns.d == false) {
            obj.fre = campaigns.fre;
            obj.fre.dp = 0;
            if (campaigns.daySelector == "ALLWEEK") {
                obj.allweek = true;
                obj.days = [];
            } else {
                obj.allweek = false;
                obj.days = campaigns.days;
            }
            if (campaigns.timeSelector == "ALLDAY") {
                obj.allday = true;
            } else {
                obj.allday = false;
                if (campaigns.time && campaigns.time.length > 0) {
                    obj.time = {
                        start: campaigns.time[0],
                        end: campaigns.time[1]
                    };
                } else {
                    obj.time = {
                        start: 8,
                        end: 20
                    };
                }
        
            }
        }
        data.nh = templateData.template.notificationHeader;
        data.nd = templateData.template.notificationDescription;
        data.ni = templateData.template.notificationImage;
        data.end = templateData.template.expandedNotificationDescription;
        data.eni = templateData.template.expandedNotificationImage;
        data.eurl = templateData.template.externalUrl;
        data.et = templateData.template.notificationType;
        data.actions = templateData.template.actions;
        data.sound = templateData.template.sound;
        data.vibrate = templateData.template.vibrate;
        data.badge = templateData.template.badge;
        if (templateData.template.cdata) {
            data.cdata = templateData.template.cdata;
        }
        obj.data = data;
        logger.info(`Object Data => ${obj}`)
        obj.aud = JSON.parse(campaigns.segmentinfo);
        payload.push(obj);
        return payload;
    }
 


  common.fillCampaignStatsDateWise = function (params) {

        let query = {};
        let dateRange = params.range;
        let platform = params.platform;
        dateRange.sd = moment(dateRange.sd * 1000);
        dateRange.ed = moment(dateRange.ed * 1000);

        while (moment(dateRange.sd).valueOf() <= moment(dateRange.ed).valueOf()) {

            query['android.' + moment(dateRange.sd).format('YYYY_MM_DD')] = 1;
            query['ios.' + moment(dateRange.sd).format('YYYY_MM_DD')] = 1;
            query['web.' + moment(dateRange.sd).format('YYYY_MM_DD')] = 1;

            dateRange.sd = moment(dateRange.sd).add(1, 'days')
        
        }

        return query;
    }

/**
 * Define a function to handle multiple attributes
 * @param {*} events 
 * @returns multiple attributes
*/
common.mulipleAttributes = function(events, step = ''){
    // Initialize an empty query string
    let q = '';
    // Check if there are any attributes in the events object
    if(events.attributes && events.attributes.length > 0){
        // Loop through all attributes in the events object
        for(let i = 0; i < events.attributes.length; i++){
            // Append to the query string based on the attribute's type, name, operator, and values
            q += `${events.attributes[i].attributeName ? ` ${common.checkJsonbInQuery(events.attributes[i].type, step)} '${events.attributes[i].attributeName}'` : ''} ${common.convertToQuery(events.attributes[i].operator, events.attributes[i].value, events.attributes[i].value1)}`;
        }
    }
    // Return the final query string
    return q;
}

//convert to query
common.convertToQuery = function(operator, value, value1, operand, timeunit){
    let query = '';
    if(operand == "pv" || operand == "av"){
      value = String(value);
     }
      if(operator == 'contains'){
           query = "ILIKE "+"'%" +value+ "%'";
      }
      if(operator == 'eq'){ 
         query = "="+"'"+value+ "'";
      }
      if(operator == 'ne' || operator == 'neq'){ 
           query = "!="+"'"+value+ "'";
      }
      if(operator == 'btw' || operator == 'isb'){
        query= "BETWEEN '"+value+"' AND '"+value1+"'";
      }
      if(operator == 'nbtw' || operator == 'isnb'){
        query= "NOT BETWEEN '"+value+"' AND '"+value1+"'";
      }
      if(operator == 'doesnt startsWith') { 
          query = " NOT LIKE "+"'" +value+ "%'"; 
      } 
      if(operator == 'doesnt endsWith'){ 
            query = " NOT LIKE "+"'%" +value+ "'";     
      }
      if(operator == 'startsWith'){
           query = "ILIKE "+"'" +value+ "%'";       
      } 
      if(operator == 'endsWith'){
         query = "ILIKE "+"'%" +value+ "'";
      } 
       if(operator == 'gt'){ 
          query = " >"+"'"+value+ "'"; 
      }
      if(operator == 'gte'){ 
          query = " >="+"'"+value+ "'"; 
      }
      if(operator == 'lt'){
       query = "<"+"'"+value+ "'"; 
      }
      if(operator == 'lte'){
          query = "<="+"'"+value+ "'"; 
         }
      if(operator == 'not_contains'){
          query = "NOT LIKE "+"'%" +value+ "%'"; 
         }
      if(operator == 'nin'){
          let valueData=value.toString();
          let spliceValueData=valueData.split(',');
          let indexData="";
          for(i=0;i<spliceValueData.length;i++){
              indexData +="'"+spliceValueData[i].toString()+"',";
          }
          let notInOperatorData=indexData.replace(/,\s*$/,"");
          query = " Not IN ("+notInOperatorData+")";
      }
      if(operator == 'in'){ 
          let valueData=value.toString();
          let spliceValueData=valueData.split(',');
          let indexData="";
          for(i=0;i<spliceValueData.length;i++){
              indexData +="'"+spliceValueData[i].toString()+"',";
          }
          let InOperatorData=indexData.replace(/,\s*$/,"");
          query = "IN ("+InOperatorData+")";
      }
         if(timeunit == 'days' || timeunit == 'd'){
          let d = new Date();
          d.setDate(d.getDate() - parseInt(value));
          let epochFs = Math.floor(d.getTime()/1000);
          query = ""+(operator == 'gt' ? "<" : (operator == 'gte' ? "<=" : (operator == 'lt' ? ">" : operator == 'lte' ? ">=" : "")))+" '"+epochFs+"'";
      }
      if(timeunit == 'hours' || timeunit == 'h'){
          let d = new Date();
          d.setHours(d.getHours() - parseInt(value));
          let epochFs = Math.floor(d.getTime()/1000);
          query = ""+(operator == 'gt' ? "<" : (operator == 'gte' ? "<=" : (operator == 'lt' ? ">" : operator == 'lte' ? ">=" : "")))+" '"+epochFs+"'";
      }
      if(timeunit == 'minutes' || timeunit == 'm'){
          let d = new Date();
          d.setMinutes(d.getMinutes() - parseInt(value));
          let epochFs = Math.floor(d.getTime()/1000);
          query = ""+(operator == 'gt' ? "<" : (operator == 'gte' ? "<=" : (operator == 'lt' ? ">" : operator == 'lte' ? ">=" : "")))+" '"+epochFs+"'";
       }
       if(timeunit == 'seconds' || timeunit == 's'){
        let d = new Date();
        d.setSeconds(d.getSeconds() - parseInt(value));
        let epochFs = Math.floor(d.getTime()/1000);
        query = ""+(operator == 'gt' ? "<" : (operator == 'gte' ? "<=" : (operator == 'lt' ? ">" : operator == 'lte' ? ">=" : "")))+" '"+epochFs+"'";
     }
  
     return query;
      
  }

  /**
   * checkJsonbInQuery return AND segment with -> or ->>
   * '->' is used to extract a JSON object's field as a JSON object.
   * '->>' is used to extract a JSON object's field as a text (string) value.
   * @param {*} operator 
   * @returns 
   */

  common.checkJsonbInQuery = function(operator, step = '') {
    const baseQuery = operator === 'number' ? 'segment->' : 'segment->>';

    if (step) {
        return `AND ${step}.${baseQuery}`;
    } else {
        return `AND ${baseQuery}`;
    }
  };

  /* 
   * queryConverter function returns eventtime or dt depends upon customUnit parameter
  */
  common.queryConverter = function(CustomUnit, timeStamp, lastTimeStamp) {
    let query= '';
    if((CustomUnit === 'Minutes') || (CustomUnit === 'Hours')){
       return query = "eventtime >= '" + timeStamp + "' AND eventtime <= '" + lastTimeStamp + "'"; 
    }
       return query = "dt >= date '" + timeStamp + "' and dt <= date '" + lastTimeStamp + "'";
}
    //Format Get App User Client Id Response
    common.formatClientId = function(clientid) {
        let ci; 
        if(common.isJson(clientid)) {
           clientid = JSON.parse(clientid);
        }  
        if(Object.keys(clientid).length > 0){
            let key = Object.keys(clientid);
            // get the location of the UserId
            let index = key.indexOf("UserId");

            //index will be -1 if not found in the above array
            if(index != -1 && key[index] == "UserId") {
                let data =  Object.values(clientid);
                if(common.isJson(data[index])) {
                    data = JSON.parse(data[index]);
                }
                if(data.length) {
                        ci = data.map(item => item.replace(/,/g, "\r\n"));
                    } else {
                        ci = undefined;
                    }
                } else {
                    ci = undefined;
                }
            } else {
                ci = undefined;
            }
            
            return ci;									
        }


    // fill event object of pre populate query
    common.fillEventObjectWithEpoch = function(epoch, object, platform, eventKey, increment){
        increment = (increment != undefined)? increment:1;
        let qDate = moment(epoch).format("YYYY_M_D");
        object[platform+"."+qDate+"."+eventKey] = increment;
    }

    common.calculateDataSize = function (data){
        let bytes = 0;
        let keys = Object.keys(data);
        keys.forEach(function(key){
            bytes += key.length * 2;
            bytes += data[key].length * 2;
        });
        return bytes;
    }

    //Create aggregate key for event attributes.
    common.fillEventAttributeObjectWithEpoch = function(epoch, object, platform, valueKey, increment){
        increment = (increment)? increment:1;
        let datekey = moment(epoch).format("YYYY_M_D");
        object[platform+"."+datekey+"."+valueKey] = increment;
    }

    common.fillEventQueryObject = function(object, array, epochStartDate_C, epochEndDate_C, platform, appId){
        let number = 1;
        let startDate_C = epochStartDate_C;
        let endDate_C = moment(epochEndDate_C).add(number,'days').format('YYYY-MM-DD');
        //let $query = {}
        while(moment(startDate_C).valueOf() < moment(endDate_C).valueOf()){

            let year = moment(startDate_C).format('YYYY');
            let month = parseInt(moment(startDate_C).format('M'));
            let day = parseInt(moment(startDate_C).format('D'));
            let qDate = year+"_"+month+"_"+day;
            object[platform+'.'+qDate] = 1;
            if(array.indexOf(common.timelyEventId(appId, startDate_C)) == -1){
                array.push(common.timelyEventId(appId, startDate_C));
            }
            startDate_C = moment(startDate_C).add(number,'days').format('YYYY-MM-DD');
        }

    }


    //Fill event attribute query object.
    common.fillEventAttributeQueryObject = function(object, array, epochStartDate_C, epochEndDate_C, platform, appId,eventname,attributename){
        let number = 1;
        let startDate_C = epochStartDate_C;
        let endDate_C = moment(epochEndDate_C).add(number,'days').format('YYYY-MM-DD');
        //let $query = {}
        while(moment(startDate_C).valueOf() < moment(endDate_C).valueOf()){

            let year = moment(startDate_C).format('YYYY');
            let month = parseInt(moment(startDate_C).format('MM'));
            let day = parseInt(moment(startDate_C).format('D'));
            let qDate = year+"_"+month+"_"+day;
            object[platform+'.'+qDate] = 1;
            //let tmpDate = year+"-"+month+"-"+day;
           let docId = common.crypto.createHash(semusiConfig.shaV2Hash).update(eventname+attributename+moment(startDate_C).format("YYYYM")+"").digest('hex');
            if(array.indexOf(docId) == -1 ) {
                array.push(docId);
            }
            startDate_C = moment(startDate_C).add(number,'days').format('YYYY-MM-DD');
        }
    }

    // fill timely dashboard collection
    common.fillInstallQueryObject = function(object, array, tempArray, epochStartDate_C, epochEndDate_C, platform, appId){
        let number = 1;
        let startDate_C = epochStartDate_C;
        let endDate_C = moment(epochEndDate_C).add(number,'days').format('YYYY-MM-DD');
        //let $query = {}
        while(moment(startDate_C).valueOf() < moment(endDate_C).valueOf()){

            let year = moment(startDate_C).format('YYYY');
            let month = parseInt(moment(startDate_C).format('MM'));
            let day = parseInt(moment(startDate_C).format('D'));
            let qDate = year+"_"+month+"_"+day;
            object[platform+'.'+qDate] = 1;
            //let tmpDate = year+"-"+month+"-"+day;
            if(tempArray.indexOf(qDate) == -1){
                tempArray.push(qDate);
            }
            if(array.indexOf(common.timelyEventId(appId, startDate_C)) == -1){
                array.push(common.timelyEventId(appId, startDate_C));
            }
            startDate_C = moment(startDate_C).add(number,'days').format('YYYY-MM-DD');
        }
         // get total no
        /*object[platform+'.totalIn'] = 1;
        object[platform+'.totalUn'] = 1;*/
    }

    // prepare timely event id
    common.timelyEventId = function(appId, epoch){
        let dateMonth = moment(epoch).format("YYYYM");
        return appId+dateMonth;
    }
    // prepare timely dashboard
    common.fillHistoryObjectWithEpoch = function(epoch, object, platform, type, increment, isDate){
        increment = (increment)? increment:1;
        isDate = (isDate != undefined)? isDate : true;
        let day = moment(epoch).format("D");
        let mon = parseInt(moment(epoch).format("MM"));
        let year = parseInt(moment(epoch).format("YYYY"));
        let date = year+"_"+mon+"_"+day;
        let hours = moment(epoch).format("H");
        if(isDate){
            object[platform+"."+date+"."+hours+"."+type] = increment;
        }
        else{
            object[platform+"."+type] = increment;
        }
    }

    // prepare timely dashboard
    common.fillUpdateMetaDataWithEpoch = function(epoch, object, platform, type, increment, isDate){
        isDate = (isDate != undefined)? isDate : true;
        let day = moment(epoch).format("D");
        let mon = parseInt(moment(epoch).format("MM"));
        let year = parseInt(moment(epoch).format("YYYY"));
        let date = year+"_"+mon+"_"+day;
        let hours = moment(epoch).format("H");
        if(isDate){
            object[platform+"."+date+"."+hours+"."+type] = increment;
        }
        else{
            object[platform+"."+type] = increment;
        }
    }

    // prepare query for get app active users and sessions
    common.fillAppsQueryObject = function(object, appId, appName, array, tempArray, epochStartDate_C, epochEndDate_C, platform){
        let number = 1;

        let startDate_C = epochStartDate_C;
        let endDate_C = moment(epochEndDate_C).add(number,'days').format('YYYY-MM-DD');
        while(moment(startDate_C).valueOf() < moment(endDate_C).valueOf()){
            let qDate = moment(startDate_C).format('YYYY_M_D')
            object[platform+'.'+appName+'.'+qDate] = 1;
            if(tempArray.indexOf(qDate) == -1){
                tempArray.push(qDate);
            }

            let _id = appId+moment(startDate_C).format("YYYYM");
            if(array.indexOf(_id) == -1){
                array.push(_id);
            }
            startDate_C = moment(startDate_C).add(number,'days').format('YYYY-MM-DD');
        }
    }

    common.mergeObject = function(obj, src) {
        for (let key in src) {
            if (src.hasOwnProperty(key)) obj[key] = src[key];
        }
        return obj;
    }

    // get current utc epoph time
    common.getCurrentEpochTime = function(){
        let d = new Date();
        d = moment.utc(d);
        return parseInt(d.valueOf()/1000);
    }

    // get current utc epoph time
    common.getCurrentDayDate = function(){
        let currentEpoch = common.getCurrentEpochTime();
        return moment(currentEpoch*1000).format('DMYYYY');
    }

    // get current utc epoph time
    common.getPreviousDate = function(day){
        let currentEpoch = common.getCurrentEpochTime();
        return moment(currentEpoch*1000).subtract(day,'days').format('DMYYYY');
    }

    // Adjusts the time to current app's configured timezone appTimezone and returns a time object.
    common.initTimeObj = function (appTimezone, reqTimestamp) {
        let currTimestamp,
            currDate,
            currDateWithoutTimestamp = new Date();

        // Check if the timestamp parameter exists in the request and is a 10 digit integer
        if (reqTimestamp && (reqTimestamp + "").length === 10 && common.isNumber(reqTimestamp)) {
            // If the received timestamp is greater than current time use the current time as timestamp
            currTimestamp = (reqTimestamp > common.getCurrentEpochTime()) ? common.getCurrentEpochTime() : parseInt(reqTimestamp, 10);
            currDate = new Date(currTimestamp * 1000);
        } else {
            currTimestamp = common.getCurrentEpochTime(); // UTC
            currDate = new Date();
        }
        // validate apptimezone
        if(appTimezone) {
            currDate.setTimezone(appTimezone);
            currDateWithoutTimestamp.setTimezone(appTimezone);
        }

        let tmpMoment = moment(currDate);

        return {
            now: tmpMoment,
            nowUTC: moment.utc(currDate),
            nowWithoutTimestamp: moment(currDateWithoutTimestamp),
            timestamp: currTimestamp,
            yearly: tmpMoment.format("YYYY"),
            monthly: tmpMoment.format("YYYY.M"),
            daily: tmpMoment.format("YYYY.M.D"),
            hourly: tmpMoment.format("YYYY.M.D.H"),
            weekly: Math.ceil(tmpMoment.format("DDD") / 7)
        };
    };

    common.fillTimeObjectQuery = function(object, array, epochStartDate_C, epochEndDate_C, platform, format, type, number){
        format = (format)? format : 'YYYY.M.D';
        type = (type)? type : 'days';
        number = (number)? number : 1;

        let startDate_C = epochStartDate_C;
        let endDate_C = moment(epochEndDate_C).add(number,'days').format('YYYY-MM-DD');
        //let $query = {}
        while(moment(startDate_C).valueOf() < moment(endDate_C).valueOf()){
            let day = moment(startDate_C).format(format);
            object[platform+'.'+day] = 1;

            array.push({
                y: moment(startDate_C).format('YYYY'),
                m: moment(startDate_C).format('M'),
                d: moment(startDate_C).format('D'),
                p: platform
            });
            startDate_C = moment(startDate_C).add(number,type).format('YYYY-MM-DD');
        }
    }

    // prepare dau, mau and active users query
    common.fillDauMauObjectQuery = function(obj, chatBot, params){
        if(chatBot){
            let currentEpoch = common.getCurrentEpochTime();
            chatBot.forEach(function(p){
                obj[p+'.'+moment(currentEpoch*1000).format('YYYY.M.D')+'.dau'] = 1;
                obj[p+'.'+moment(currentEpoch*1000).format('YYYY.M')+'.mau'] = 1;
                obj[p+'_active_users'] = 1;
            })
        }
        else{
            let currentEpoch = common.getCurrentEpochTime();
            obj['android_active_users'] = 1;
            obj['ios_active_users'] = 1;
            obj['web_active_users'] = 1;

            if (params) {
                // let startDate_C_real = params.qstring.args.startDate_CNew;
                // d = new Date(startDate_C_real);
                // 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 = moment(new Date(startDateObj.setDate(startDateObj.getDate() - startDateObj.getDay()))).format('YYYY-MM-DD');
               
                 //Getting start from, start day of previous month for MAU
                 let startDate = moment(params.qstring.args.startDate_CNew).subtract(30, 'days').valueOf();
                 let startDate_C = common.adjustStartDate(startDate);
              
                 let endDate_C = moment(params.qstring.args.endDate_CNew);
                 endDate_C = common.adjustEndDate(endDate_C);
                 //let $query = {}
                while (moment(startDate_C).valueOf() <= moment(endDate_C).valueOf()) {
                    obj['android.' + moment(startDate_C).format('YYYY.M.D') + '.dau'] = 1;
                    obj['ios.' + moment(startDate_C).format('YYYY.M.D') + '.dau'] = 1;
                    obj['web.' + moment(startDate_C).format('YYYY.M.D') + '.dau'] = 1;
                    obj['android.' + moment(startDate_C).format('YYYY.M.D') + '.wau'] = 1;
                    obj['ios.' + moment(startDate_C).format('YYYY.M.D') + '.wau'] = 1;
                    obj['web.' + moment(startDate_C).format('YYYY.M.D') + '.wau'] = 1;
                    obj['android.' + moment(startDate_C).format('YYYY.M.D') + '.mau'] = 1;
                    obj['ios.' + moment(startDate_C).format('YYYY.M.D') + '.mau'] = 1;
                    obj['web.' + moment(startDate_C).format('YYYY.M.D') + '.mau'] = 1;

                    startDate_C = moment(startDate_C).add(1, 'days').format('YYYY-MM-DD');
                }

                // let edate = common.getCurrentEpochTime();
                // let start = moment(edate * 1000).subtract(30, 'days').valueOf() / 1000;
                // edate = moment(edate * 1000).add(1, 'days').valueOf() / 1000;

                // while (moment(start).valueOf() < moment(edate).valueOf()) {
                //     obj['android.' + moment(start * 1000).format('YYYY.M.D') + '.mau'] = 1;
                //     obj['ios.' + moment(start * 1000).format('YYYY.M.D') + '.mau'] = 1;
                //     obj['web.' + moment(start * 1000).format('YYYY.M.D') + '.mau'] = 1;
                //     start = moment(start * 1000).add(1, 'days').valueOf() / 1000;
                // }
            }
        }
    }


    // prepare dau, mau and active users query
    common.fillDauMauObjectQueryWithPlatforms = function (obj, params) {
        // get start and end date
        // let startDate_C = params.qstring.args.startDate_CNew;

          //Getting start from, start day of previous month for MAU
          let startDate = moment(params.qstring.args.startDate_CNew).subtract(30, 'days').valueOf();
          let startDate_C = common.adjustStartDate(startDate);

          let endDate_C = moment(params.qstring.args.endDate_CNew);
          endDate_C = common.adjustEndDate(endDate_C);

        // calulate start to end date loop for get data for specific dates
        while (moment(startDate_C).valueOf() <= moment(endDate_C).valueOf()) {

            // prepare object for DAU
            obj['android.' + moment(startDate_C).format('YYYY.M.D') + '.dau'] = 1;
            obj['ios.' + moment(startDate_C).format('YYYY.M.D') + '.dau'] = 1;
            obj['web.' + moment(startDate_C).format('YYYY.M.D') + '.dau'] = 1;

            // prepare object for WAU
            obj['android.' + moment(startDate_C).format('YYYY.M.D') + '.wau'] = 1;
            obj['ios.' + moment(startDate_C).format('YYYY.M.D') + '.wau'] = 1;
            obj['web.' + moment(startDate_C).format('YYYY.M.D') + '.wau'] = 1;

            // prepare object for MAU
            obj['android.' + moment(startDate_C).format('YYYY.M.D') + '.mau'] = 1;
            obj['ios.' + moment(startDate_C).format('YYYY.M.D') + '.mau'] = 1;
            obj['web.' + moment(startDate_C).format('YYYY.M.D') + '.mau'] = 1;

            // increase date for next day data
            startDate_C = moment(startDate_C).add(1, 'days').format('YYYY-MM-DD');
        }
    }

    common.adjustStartDate = function(startDate){
        let firstDay = new Date(new Date(startDate).getFullYear(), new Date(startDate).getMonth(), 1).getDate();
        let firstMonth = new Date(new Date(startDate).getFullYear(), new Date(startDate).getMonth(), 1).getMonth();
        let firstYear = new Date(new Date(startDate).getFullYear(), new Date(startDate).getMonth(), 1).getFullYear();
        //getting start date from start of month
        let startDate_C = new Date(`${firstMonth+1}/${firstDay}/${firstYear}`).valueOf();
        return startDate_C;
    }

    common.adjustEndDate = function(endDate){
        let yyyy = new Date(endDate).getFullYear();
        let mm = new Date(endDate).getMonth();
        let dd = new Date(yyyy,mm+1 ,0).getDate();
        let end = new Date(`${mm+1}/${dd}/${yyyy}`).valueOf();
        return end;
    }

    common.dateDifference = function(params){
       return 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;
    }


 //Fill Event Query download csv Object
    common.fillEventDownloadQueryObject = function(object, array, epochStartDate_C, epochEndDate_C, platform, eventArr, selectAll, appId){
        let number = 1;
        let startDate_C = epochStartDate_C;
        let endDate_C = moment(epochEndDate_C).add(number,'days').format('YYYY-MM-DD');

        startDate_C =  startDate_C *1000;
        endDate_C  = moment(epochEndDate_C *1000).valueOf();

            //For selected events 
            while(moment(startDate_C).valueOf() <= moment(endDate_C).valueOf() ){

                //Prepare query for all events passed

                for(let event = 0; event < eventArr.length; event++) {

                    let year = moment(startDate_C).format('YYYY');
                    let month = parseInt(moment(startDate_C).format('M'));
                    let day = parseInt(moment(startDate_C).format('D'));
                    let qDate = year+"_"+month+"_"+day;
                    object[platform+'.'+qDate+'.'+eventArr[event]] = 1;

                     
                    if(array.indexOf(common.timelyEventId(appId, startDate_C)) == -1){
                        array.push(common.timelyEventId(appId, startDate_C));
                    }
                }
                startDate_C = moment(startDate_C).add(number,'days').format('YYYY-MM-DD');
            }

    }


     //Fill event attribute csv download query object.
     common.fillEventAttributeDownloadQueryObject = function(object, array, epochStartDate_C, epochEndDate_C, platform, appId,eventname,attributename){
        let number = 1;
        let startDate_C = epochStartDate_C;
        let endDate_C = moment(epochEndDate_C).add(number,'days').format('YYYY-MM-DD');

        startDate_C =  startDate_C *1000;
        endDate_C  = moment(epochEndDate_C *1000).valueOf();
        while(moment(startDate_C).valueOf() <= moment(endDate_C).valueOf()){
            let year = moment(startDate_C).format('YYYY');
            let month = parseInt(moment(startDate_C).format('MM'));
            let day = parseInt(moment(startDate_C).format('D'));
            let qDate = year+"_"+month+"_"+day;
            object[platform+'.'+qDate] = 1;
            attributename.forEach(function (item) {

                let docId = common.crypto.createHash(semusiConfig.shaV2Hash).update(eventname+item+moment(startDate_C).format("YYYYM")+"").digest('hex');
                if(array.indexOf(docId) == -1 ) {
                    array.push(docId);
                }
            })
            startDate_C = moment(startDate_C).add(number,'days').format('YYYY-MM-DD');
           
        }

        
 }



//this function is to make regex for date ranges
//it takes start date and end date as input
//the regex is paritioned into 5 parts 
//part 2 and part 4 will not exit if year of both dates are same
//order of coding is part1, part5, part3, part2 and part4
common.getRegex = function(startDate, endDate){
    if(new Date(startDate).getDate() >new Date(endDate).getDate()){
    return "Incorrect Date Format";
    }
    let year = new Date(startDate).getFullYear();
    let year2 = new Date(endDate).getFullYear();
    let month1 = new Date(startDate).getMonth()+1;
    let month2 = new Date(endDate).getMonth()+1;
    let day1 = new Date(startDate).getDate();
    let day2 = new Date(endDate).getDate();
    let monthstring1 = month1;
    let monthstring2 = month2;
    let daystring1 = day1;
    let daystring2 = day2;
    //Values less than 10 come in single digit
    //so we add an extra 0 to match required pattern
    if(day1<10){
    daystring1 = '0' + daystring1;
    }
    if(day2<10){
    daystring2 = '0' + daystring2;
    }
    if(month1<10){
    monthstring1 = '0' + monthstring1;
    }
    if(month2<10){
    monthstring2 = '0' + monthstring2;
    }
    let mod1 = year%100
    let mod2 = year2%100
    
    let part1 = '';
    let part2 = '';
    let part3 = '';
    let part4 = '';
    let part5 = '';
    //generic string for days and months of a year
    let generic = '(0[1-9]|1[0-9]|2[0-9]|3[01])((0[1-9]|1[0-2]))'
    //generic string for days of a month
    let generic2 = '(0[1-9]|1[0-9]|2[0-9]|3[01])'
    let final = '';
    
    if(month1==month2&&year==year2){
    //regex for all the days of start month 
    for(let j = day1; j<=day2; j++){
    if(j<10){
    part1 = part1 + '0' + j;
    }
    else{
    part1 = part1 + j;
    }
    if(j!=day2){
    part1 = part1 + '|';
    }
    }
    
    part1 = '(' + part1 + ')'
    part1 = '(D' + part1 + monthstring1 + mod1 + ')';
    return part1;
    }
    
    
    //implementing part 1
    //regex for all the days of start month 
    for(let j = day1; j<=31; j++){
    if(j<10){
    part1 = part1 + '0' + j;
    }
    else{
    part1 = part1 + j;
    }
    if(j!=31){
    part1 = part1 + '|';
    }
    }
    
    part1 = '(' + part1 + ')'
    part1 = '(' + part1 + monthstring1 + mod1 + ')';
  
    
    //implemting part 5
    //all the days of last month
    for(let j = 1; j<=day2; j++){
    if(j<10){
    part5 = part5 + '0' + j;
    }
    else{
    part5 = part5 + j;
    }
    if(j!=day2){
    part5 = part5 + '|';
    }
    }
    
    part5 = '(' + part5 + ')'
    part5 = '(' + part5 + monthstring2 + mod2 + ')';
    /* alert(part5) ;*/
    
    //if both years will be same then part 2 and part 4 will not exist 
    //and part3 will be different
    if(year!=year2){
    //implementing part 3 
    //adding all the years in between start and end year
    for(let k = year + 1; k< year2; k++){
    let temp = k%100;
    part3 = part3 + '(' + generic + temp + ')';
    if(k!=year2-1){
    part3 = part3 + '|';
    }
    }
    /* alert(part3) ;*/
    
    //implementing part 2
    //adding all the months after start month of start year
    for(let l = month1 + 1; l<13; l++){
    if(l<10){
    part2 = part2 + '0' + l;
    }
    else{
    part2 = part2 + l;
    }
    if(l!=12){
    part2 = part2 + '|';
    } 
    }
    
    part2 = '(' + generic2 + '(' + part2 + ')' + mod1 + ')'
    /* alert(part2) ;*/
    
    //implementing part 4
    //adding all the months before end month of end year
    for(let m = 1; m<month2; m++){
    if(m<10){
    part4 = part4 + '0' + m;
    }
    else{
    part4 = part4 + m;
    }
    if(m!=month2-1){
    part4 = part4 + '|';
    } 
    }
    
    part4 = '(' + generic2 + '(' + part4 + ')' + mod2 + ')'
    /* alert(part4) ;*/
    
    //final string including all 5 parts
    final = '(' + part1 + '|' ;
    if(part2!=''){
    final = final + part2 + '|';
    }
    if(part3!=''){
    final = final + part3 + '|';
    }
    if(part4!=''){
    final = final + part4 + '|';
    }
    
    final = final + part5 + ')';
    
    
    /* alert(final) ;*/ 
    
    }
    else{
    //implementing part 3
    //adding all the months of same year
    for(let a = month1 +1 ; a<month2; a++){
    if(a<10){
    part3 = part3 + '0' + a;
    }
    else{
    part3 = part3 + a;
    }
    if(a!=month2-1){
    part3 = part3 + '|';
    } 
    }
    
    part3 = '(' + generic2 + '(' + part3 + ')' + mod1 + ')';
    /* alert(part3) ;*/
    
    
    //final string including all parts
    final = '(' + part1 + '|' ;
    if(part3!='' && month2-month1!=1){
    final = final + part3 + '|';
    }
    final = final + part5+ ')';
    /* alert(final) ;*/
    
    }
    
    final = "(D" + final + ")";
    return final;
    
    }


    //this function is to generate funnel query
    common.getFunnelQuery =  function(startDate,endDate,Events,app_id){

        let query = common.getRegex(startDate, endDate);
      

    if(query!="Incorrect Date Format"){
        for(let i=0; i< Events.length; i++){
            query = query + '.*?B' + Events[i] + 'T';
        }
        let finalQuery = "select count(*) from eventstringaugust_" + app_id + " where eventstring ~ " + "'"+query+"'";
        return finalQuery;
    }
    else {
        return "Invalid Date";
    }

 }

common.generateQuery = function (finalRegex, countOrData, column){
    if(countOrData == false){ //if false we will send data. if true we will send count
        let columnRequired = '';

        for(let i=0; i< column.length; i++){
            columnRequired += column[i].col + " as " + column[i].alias + ","
        }
        columnRequired = columnRequired.slice(0, -1);
        finalRegex = finalRegex.replace("count( did)", columnRequired);
    }
    return finalRegex;
}


    // Creates a time object in the format object["2012.7.20.property"] = increment.
    common.fillTimeObjectWithEpoch = function (paltform, epoch, object, property, increment) {
        increment = (increment) ? increment : 1;

        if (!epoch) {
            return false;
        }

        let timeObj = {};
        timeObj.yearly = moment.unix(epoch).format("YYYY");
        timeObj.monthly = moment.unix(epoch).format("YYYY.M");
        timeObj.daily = moment.unix(epoch).format("YYYY.M.D");

        object[paltform + '.' + timeObj.yearly + '.' + property] = increment;
        object[paltform + '.' + timeObj.monthly + '.' + property] = increment;
        object[paltform + '.' + timeObj.daily + '.' + property] = increment;
    }

    // get dau key for optimise collection
    common.getDauMauKey = function (paltform, epoch, type) {
        if (!epoch) {
            return false;
        }
        let key = {}
        if (type == 'mau') {
            key = { m: paltform + '.' + moment.unix(epoch).format("YYYY.M") + '.' + type, d: paltform + '.' + moment.unix(epoch).format("YYYY.M.D") + '.' + type };
        } else {
            key = paltform + '.' + moment.unix(epoch).format("YYYY.M.D") + '.' + type;
        }

        return key;
    }

    // get day time through epoch
    common.getDayTime = function (epoch) {
        epoch = epoch * 1000;
        let dayTime = '', hours = moment(epoch).format("H");

        if (hours >= 0 && hours < 6) {
            dayTime = 'midnight';
        }
        else if (hours >= 6 && hours < 11) {
            dayTime = 'morning';
        }
        else if (hours >= 11 && hours < 16) {
            dayTime = 'afternoon';
        }
        else if (hours >= 16 && hours < 21) {
            dayTime = 'evening';
        }
        else if (hours >= 21 && hours < 24) {
            dayTime = 'night';
        }

        return dayTime;
    }

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

    common.getDateFromDate = function (date, day) {
        let newDate = parseInt(moment(date, 'DD-MM-YYYY').subtract(day, 'days').valueOf());
        return moment(newDate).format('DD-MM-YYYY');
    }

    common.addTimlyDashboard = function (data, appId) {
        data.pv = (data.pv) ? data.pv : 'NA';
        data.av = (data.av) ? data.av : 'NA';
        data.cc = (data.cc) ? data.cc : 'NA';
        data.cty = (data.cty) ? data.cty : 'NA';

        if (data.pv && data.av && data.history && data.p && data.cc && data.cty) {
            let history = data.history[data.history.length - 1];
            let platform = data.p.toLowerCase();
            let epoch = history.dtEntry * 1000;
            let id = common.timelyEventId(appId, epoch);
            let did = data.did;
            data.pv = data.pv.replace(/\./g, "_");
            data.av = data.av.replace(/\./g, "_");
            history.refname = history.refname.replace(/\./g, "_");
            data.cc = data.cc.replace(/\./g, "_");
            data.cty = data.cty.replace(/\./g, "_");

             
            let dashboardObj = {};

            let cpi = (history.cpi) ? history.cpi : 0;
            if (cpi) {
                common.fillHistoryObjectWithEpoch(epoch, dashboardObj, platform, data.pv + "." + data.av + "." + history.refname + "." + data.cc + "." + data.cty + ".cpi", cpi);
            }

            if (history.isnew == true) { // unique install
                common.fillHistoryObjectWithEpoch(epoch, dashboardObj, platform, data.pv + "." + data.av + "." + history.refname + "." + data.cc + "." + data.cty + ".in");
            } else { // repeat install
                common.fillHistoryObjectWithEpoch(epoch, dashboardObj, platform, data.pv + "." + data.av + "." + history.refname + "." + data.cc + "." + data.cty + ".ri");
            }

            // manage cohort
            dashboardObj[platform + "." + moment(epoch).format("YYYY_M_D") + ".cohort.in"] = 1;

            // fill total installs
            common.fillHistoryObjectWithEpoch(epoch, dashboardObj, platform, "totalIn", 1, false);
            // dump data
            common.db.collection('timely_dashboard').update({ '_id': id }, { '$inc': dashboardObj }, { 'upsert': true }, function (err, response) {
                if (err) {
                    logger.error(`error:  => ${err}`);
                    errorQueue([{ appid: appId, op: 'update', isUpsert: true, data: { '_id': id, '$inc': dashboardObj } }], 'mongo', 'timely_dashboard', 'addTimlyDashboard');
                } else {
                     
                }
            });

        }
        else{
            logger.info(`addTimlyDashboard dashboardObj not valid if condition`);  
        }
    }

    common.substractTimlyDashboard = function (data, appId, callback) {
        if (data.pv && data.av && data.history && data.p && data.cc && data.cty) {
            let history = data.history;
            let platform = data.p.toLowerCase();
            let epoch = history.dtEntry * 1000;
            let id = common.timelyEventId(appId, epoch);
            data.pv = data.pv.replace(/\./g, "_");
            data.av = data.av.replace(/\./g, "_");
            history.refname = history.refname.replace(/\./g, "_");
            data.cc = data.cc.replace(/\./g, "_");
            data.cty = data.cty.replace(/\./g, "_");

             
            let dashboardObj = {};
            let cpi = (history.cpi) ? history.cpi : 0;
            if (cpi) {
                common.fillUpdateMetaDataWithEpoch(epoch, dashboardObj, platform, data.pv + "." + data.av + "." + history.refname + "." + data.cc + "." + data.cty + ".cpi", -1);
            }

            if (history.isnew == true) { // unique install
                common.fillUpdateMetaDataWithEpoch(epoch, dashboardObj, platform, data.pv + "." + data.av + "." + history.refname + "." + data.cc + "." + data.cty + ".in", -1);
            } else { // repeat install
                common.fillUpdateMetaDataWithEpoch(epoch, dashboardObj, platform, data.pv + "." + data.av + "." + history.refname + "." + data.cc + "." + data.cty + ".ri", -1);
            }
            // manage cohort
            dashboardObj[platform + "." + moment(epoch).format("YYYY_M_D") + ".cohort.in"] = -1;

            // update total install
            common.fillUpdateMetaDataWithEpoch(epoch, dashboardObj, platform, "totalIn", -1, false);
            common.db.collection('timely_dashboard').update({ '_id': id }, { '$inc': dashboardObj }, { 'upsert': true }, function (err, response) {
                if (err) {
                    logger.error(`error: => ${err}`);
                    errorQueue([{ appid: appId, op: 'update', isUpsert: true, data: { '_id': id, '$inc': dashboardObj } }], 'mongo', 'timely_dashboard', 'addTimlyDashboard');
                    callback(false);
                } else {
                    callback(true);
                }
            });
        }
        else{
            logger.info(`substractTimlyDashboard dashboardObj not valid if condition`);
            callback(false);
        }
    }

    /**
     * getCampidnAppidwithDates method returns Array of which is used in campaign Query 
     * @param {*} appid , campid, startDate and endDate  
     * @returns the array of Appid+CampId+Date( in the format of YYYYMM ) those months will be in between startDate and endDate
     */
    common.getCampidnAppidwithDates = function (appid, campid, startDateStr, endDateStr) {
          const formattedElements = [];
          const startDate = new Date(startDateStr);
          const endDate = new Date(endDateStr);
          let currentDate = new Date(startDate);

          while (currentDate <= endDate) {
            const year = currentDate.getFullYear();
            const month = (currentDate.getMonth() + 1).toString().padStart(2, '0');
            const formattedDate = `${year}${month}`;

            const element = `${appid}${campid}${formattedDate}`;
            formattedElements.push(element);

            currentDate.setDate(1);
            currentDate.setMonth(currentDate.getMonth() + 1);
          }

          return formattedElements;
      };
    common.manageCampaignAggregate = function (platform, history, appId, diff) {
        // validate campaign into history
        if (history.utm_campaign) {
            // replace dot if exists into campapign string
            history.utm_campaign = history.utm_campaign.replace(/\./g, "-");

            // manage campaign aggregate collection
            let campaignObj = {};

            if (history.type == 'I') {
                // add cpi avg
                if (history.cpi) {
                    common.fillEventObjectWithEpoch(history.dtEntry * 1000, campaignObj, platform, history.utm_campaign + ".cpi", history.cpi);
                }
                if (history.isnew == true) { // unique install
                    common.fillEventObjectWithEpoch(history.dtEntry * 1000, campaignObj, platform, history.utm_campaign + ".in");
                } else { // repeat install
                    common.fillEventObjectWithEpoch(history.dtEntry * 1000, campaignObj, platform, history.utm_campaign + ".ri");
                }
            }
            else if (history.type == 'U') {
                // store uninstall days difference
                common.fillEventObjectWithEpoch(history.dtEntry * 1000, campaignObj, platform, history.utm_campaign + "." + diff);
                if (history.isnew) { // unique uninstall
                    common.fillEventObjectWithEpoch(history.dtEntry * 1000, campaignObj, platform, history.utm_campaign + ".un");
                } else { // repeat uninstall
                    common.fillEventObjectWithEpoch(history.dtEntry * 1000, campaignObj, platform, history.utm_campaign + ".ru");
                }
            }

            // dump campaign installs and uninstalls
            common.db.collection('campaign_aggregate').update({ '_id': common.db.ObjectID(appId) }, { '$inc': campaignObj }, { 'upsert': true }, function (err, response) {
                if (err) {
                    logger.error(`error: => ${err}`);
                    errorQueue([{ appid: appId, op: 'update', isUpsert: true, data: { '_id': common.db.ObjectID(appId), '$inc': campaignObj } }], 'mongo', 'campaign_aggregate', 'manageCampaignAggregate');
                } else {
                    logger.info("data inserted into campaign_aggregate!");
                }
            });
        }
    }
    common.saveJobsData = function(jobs){
        return new Promise((resolve, reject) =>{
            common.db.collection('exportjobs_' + jobs.app_id).insert(jobs, function (err, res) {
                if (err) {
                    logger.error("jobs error", err);
                    reject(err);
                }
                else {
                    logger.info("jobs created", res);
                    resolve(jobs);
                }
            });
        })
    } 
   /**
     * updateJobsData method Updates the status of jobs ,  
     * @param {*} appid , Appid of the user
     * @param {*} status , status which is to be set to that jobid  
     */
    common.updateJobsData = function(job_id,status,app_id){
     return new Promise((resolve, reject) =>{

        common.db.collection('exportjobs_' + app_id).update({"_id": common.db.ObjectID(job_id )}, {$set:{status:status} }, (err, data) =>{
            if (err) {
                logger.error(`Error ${err}while Updating Status of jobs ${job_id}`);
                reject(err);

            }else {
                logger.info(`jobs Updated status set as ${status} for Job_id ${job_id}`);
                resolve(status);
            }
        });
      })
    } 
    common.returnDefaultFeedbackCampaign = function(){
        
        let startDate = common.getCurrentEpochTime()*1000;
        
        let obj = {};
        obj._id = "xxxxx";
        obj.tid = "xxxxx";
        obj.t = "FEEDBACK";
        obj.sd = startDate*1000;
        obj.ed = common.getFutureEpochTime(1);
        obj.st = moment().valueOf()-180000; //This is used on the client side to manage fetching of active campaigns and ignore device time if it is wrong.
        return obj;
    }


    common.prepareGetActiveCampaignData = async function(data,appId,api_key){
        let returnObj = []
 
    if(data==null || data == undefined){
        logger.error("Recieved undefined or null in prepareGetActiveCampaignData ")
    }else{
        // removing the defaultFeedBack Campaign when all campaigns are removed
        if(data.length == 1 && data[0]._id == "xxxxx") return returnObj
            // Use map to execute asynchronous operations in parallel instead of foreach 
            const asyncTasks = data.map(async function (campData) {
            // check for defaultFeeback campaign 
         if(campData._id !== "xxxxx"){
            let obj = {}

            obj._id = campData._id;
            obj.nm  = campData.nm;
            obj.sd= (typeof campData.sd === 'string') ? parseInt(campData.sd) : campData.sd;
            obj.ed = (typeof campData.ed === 'string') ? parseInt(campData.ed) : campData.ed;
            obj.st = campData.st;
            obj.t = campData.t;
            obj.d = campData.d;
            obj.fre = campData.fre;
            obj.timeSelector = campData.timeSelector;
            obj.time = campData.time;
            obj.delays =parseInt(campData.delays);
            obj.delayi = parseInt(campData.delayi);
            obj.delayu = campData.delayu;
                    //data used to come empty because now will wait for the execution
            switch (campData.t) {
                case "PUSH":
                    obj.data = await common.populatePushObject((campData.template) ? campData.template : campData.data, appId, api_key);
                    break;
                case "IN-APP":
                    obj.data = await common.populateInAppObject((campData.template) ? campData.template : campData.data,appId,api_key,appId);
                    break;
                case "WEB_PUSH":
                    obj.data = await common.populateWebPushObject((campData.template) ? campData.template : campData.data, appId, campData._id);
                    break; 
                case "WEB_POPUP":
                    obj.data = await common.populateWebPopUpObject((campData.template)? campData.template : campData.data,appId,campData._id);
                    break;    
                case "RATING":
                    obj.data = await common.populateRatingObject((campData.template)? campData.template : campData.data,appId,api_key);
                    break;
                    // commented for now
                // case "SURVEY":
                //     let q = [];
                //     obj.data = common.populateSurveyObject((campData.template)? campData.template : campData.data,appId,api_key);
                //     populateSurveyObject(tool.template, q);
                //     To Make Data Dynamic(Added from Dashboard)
                //     obj.data.isSurvey = tool.template.isSurvey;
                //     obj.data.bobgclr = tool.template.bobgclr;
                //     obj.data.nt = tool.template.nt;
                //     obj.data.st = tool.template.st;
                //     obj.data.bgclr = tool.template.bgclr;
                //     obj.data.txclr = tool.template.txclr;
                //     obj.data.q = q;
                //     break;
            }
            obj.allweek = campData.allweek || (campData.daySelector === "ALLWEEK");
            obj.allday = campData.allday || (campData.timeSelector == "ALLDAY");
            obj.days = campData.days ? campData.days : [] ;
            let segement = '';
            if(campData.segmentinfo && typeof campData.segmentinfo === 'string' ){
                segement = JSON.parse((campData.segmentinfo)?campData.segmentinfo:campData.aud);
                if (segement.what.length > 0) {
                    segement = common.whatPrepareForInApp(segement);
                }
            }else{
                segement = (campData.segmentinfo)?campData.segmentinfo:campData.aud;
                if (segement.what.length > 0) {
                    segement = common.whatPrepareForInApp(segement);
                }
            }
            if(segement.q){
                delete (segement.q)
            }
            if(typeof segement  === 'object' ){
                obj.aud = segement;                
            }else{
                obj.aud = JSON.parse(segement);
            }
        
            return obj;
                }
                
                // Return null for entries with _id == 'xxxxx'
                return null;

            });
    
            // Wait for all asynchronous tasks to complete
            returnObj = await Promise.all(asyncTasks);
    
            returnObj = returnObj.filter(obj => obj !== null);

            // Inserting defaultfeedback Campaign
            let defaultItem = common.returnDefaultFeedbackCampaign();
            returnObj.push(defaultItem);
      }
        return returnObj
   
    }

    // Manage active Users with gender wise
    common.usersActiveManage = function(appid, platform, gender='unknown', increment=1){
        platform = platform.toLowerCase();
        let obj = {
            [platform +"."+ gender] : increment
        }
        common.db.collection('active_users_aggregates').update({'_id': common.db.ObjectID(appid)}, {$inc : obj}, { 'upsert': true }, function(err, app) {
            if(err){
                logger.error(`error: => ${err}`); 
            }
        });
    }

    // Returns an extended Date object that has setTimezone function
    common.getDate = function (timestamp, timezone) {
        let tmpDate = (timestamp) ? new Date(timestamp * 1000) : new Date();

        if (timezone) {
            tmpDate.setTimezone(timezone);
        }

        return tmpDate;
    };

    common.getDOY = function (timestamp, timezone) {
        let endDate = (timestamp) ? new Date(timestamp * 1000) : new Date();

        if (timezone) {
            endDate.setTimezone(timezone);
        }

        let startDate = (timestamp) ? new Date(timestamp * 1000) : new Date();

        if (timezone) {
            startDate.setTimezone(timezone);
        }

        startDate.setMonth(0);
        startDate.setDate(1);
        startDate.setHours(0);
        startDate.setMinutes(0);
        startDate.setSeconds(0);
        startDate.setMilliseconds(0);

        let diff = endDate - startDate;
        let oneDay = 1000 * 60 * 60 * 24;
        let currDay = Math.ceil(diff / oneDay);

        return currDay;
    };
    
    common.escape = function(args){
        let obj = {}
        if (args.name) obj.name = xss(args.name);   
          
        if(args.journeyName && args.journeyDescription){
            obj.description = xss(args.journeyDescription)
            obj.name = xss(args.journeyName); 
            obj.startEvent = xss(args.startEvent) 
            obj.endEvent = xss(args.endEvent)  
            obj.platform = xss(args.platform)
            obj.period = xss(args.period)
       }    
  
        if(args.template_name) {
            obj.name = xss(args.template_name); 
            obj.template = {}; 
        } 
        
        if(args.smtp_username) {
            obj.smtp_username = xss(args.smtp_username) 
            obj.smtp_password = xss(args.smtp_password)  
            obj.smtp_host = xss(args.smtp_host)
            obj.smtp_port = xss(args.smtp_port) 
            obj.smtp_fromAddress = xss(args.smtp_fromAddress)
            obj.smtp_fromName = xss(args.smtp_fromName)
        }

        if(args.aws_accessKeyId) {
            obj.aws_accessKeyId = xss(args.aws_accessKeyId) 
            obj.aws_secretAccessKey = xss(args.aws_secretAccessKey)  
            obj.aws_region = xss(args.aws_region)
            obj.aws_sourceEmail = xss(args.aws_sourceEmail) 
        }

        if(args.template && args.template.title){
            obj.template = {};
            obj.template.title = xss(args.template.title);
        }
        if(args.template && args.template.headerTextClr){
            obj.template = {};
            obj.template.headerTextClr = xss(args.template.headerTextClr);
            obj.template.descriptionTextClr =  xss(args.template.descriptionTextClr);
            obj.template.submitBtnTextClr = xss(args.template.submitBtnTextClr);
            obj.template.backgroundColor = xss(args.template.backgroundColor);
            obj.template.iconImage =  xss(args.template.iconImage);
            obj.template.actionTitle = xss(args.template.actionTitle);
            obj.template.actionUrl = xss(args.template.actionUrl);
        }
        if(args.template && (args.template.notificationHeader || args.template.externalUrl)){
            obj.template.notificationHeader = xss(args.template.notificationHeader);
            obj.template.notificationDescription = xss(args.template.notificationDescription);
            obj.template.notificationImage = xss(args.template.notificationImage);
            obj.template.externalUrl = xss(args.template.externalUrl);
            obj.template.expandedNotificationDescription = xss(args.template.expandedNotificationDescription);
        }
  
        if(args.template && args.template.message) obj.template.message = xss(args.template.message);
  
        if(args.template && args.template.url) obj.template.url = xss(args.template.url);
  
        if(args.nm) obj.name = xss(args.nm); 
           
        if(args.sd) obj.sd = xss(args.sd);
          
        if(args.ed) obj.ed = xss(args.ed);
  
        if(args.cd) obj.cd = xss(args.cd)
          
        if(args.appinbox_et) obj.appinbox_et = parseInt(xss(args.appinbox_et));
  
        if(args.fre && args.fre.interval){
            obj.fre= {};
            obj.fre.interval = xss(args.fre.interval);
        }
        if(args.stag && args.stag.max_batch){
            obj.stag = {};
            obj.stag.max_batch = xss(args.stag.max_batch); 
        }
        if(args.stag && args.stag.time) obj.stag.time = xss(args.stag.time)
  
        if(args.description) obj.description = xss(args.description)
  
        if(args.urlscheme) obj.urlscheme = xss(args.urlscheme);
  
        if(args.package) obj.package = xss(args.package);

        if(args.iosUrl) obj.iosUrl = xss(args.iosUrl);

        if(args.googleUrl) obj.googleUrl = xss(args.googleUrl);

        if(args.full_name) obj.full_name = xss(args.full_name);

        if(args.phone) obj.phone = xss(args.phone);

        if(args.full_name && args.title){
            obj.title = xss(args.title);
            obj.company =  xss(args.company);
            obj.password = xss(args.password);
        }
        if(args.ios_cert3){
            obj.ios_cert3 = xss(args.ios_cert3);
            obj.ios_keyid = xss(args.ios_keyid);
            obj.ios_teamid = xss(args.ios_teamid);
            obj.ios_bundleid = xss(args.ios_bundleid);
            obj.ios_topic = xss(args.ios_topic)
        }
        if(args.callbackurl) obj.callbackurl = xss(args.callbackurl);

        if(args.httpMethod) obj.httpMethod = xss(args.httpMethod);

        if(args.concurrentLogin){
            obj.concurrentLogin = xss(args.concurrentLogin);
            obj.state = xss(args.state);
            obj.passwordResetMode = xss(args.passwordResetMode);
        }
        
        if(args.smtp_username){
            obj.smtp_username = xss(args.smtp_username);
            obj.smtp_password = xss(args.smtp_password);
            obj.smtp_host = xss(args.smtp_host);
            obj.smtp_port = xss(args.smtp_port);
            obj.smtp_fromAddress = xss(args.smtp_fromAddress)
            obj.smtp_fromName = xss(args.smtp_fromName)
        }
        if(args.username){
            obj.username = xss(args.username);
            obj.password = xss(args.password);
        }
        if(args.ios){
            obj.android = {};
            obj.android[0] = {};
            obj.ios={};
            obj.ios[0]={}
            obj.web={}
            obj.web[0]={}
            obj.android[0].v = xss(args.android[0].v);
            obj.ios[0].v = xss(args.ios[0].v);
            obj.web[0].v = xss(args.web[0].v);
        }
        if(args.channelObj){
            obj.channelObj = {};
            obj.channelObj.account_id = xss(args.channelObj.account_id);
        }
        if(args.fcmKey) obj.fcmKey = xss(args.fcmKey);

        if(args.webPush){
            obj.webPush = {};
            obj.webPush.privateKey = xss(args.webPush.privateKey)
            obj.webPush.publicKey = xss(args.webPush.publicKey)
            obj.webPush.subject = xss(args.webPush.subject)
        }
  
        return obj;
    }

    /*
     argProperties = { argName: { required: true, type: 'String', max-length: 25, min-length: 25, exclude-from-ret-obj: false }};
     */
    common.validateArgs = function (args, argProperties) {
        let escaped = {};   
        escaped = common.escape(args);
        let returnObj = {};

        if (!args) {
            return false;
        }

        for (let arg in argProperties) {
            if (argProperties[arg].required) {
                if (args[arg] === void 0) {
                    return false;
                }
            }

            if (args[arg] !== void 0) {
                if (argProperties[arg].type) {
                    if (argProperties[arg].type === 'Number' || argProperties[arg].type === 'String') {
                        if (toString.call(args[arg]) !== '[object ' + argProperties[arg].type + ']') {
                            return false;
                        }
                    } else if (argProperties[arg].type === 'Boolean') {
                        if (!(args[arg] !== true || args[arg] !== false || toString.call(args[arg]) !== '[object Boolean]')) {
                            return false;
                        }
                    } else if (argProperties[arg].type === 'Array') {
                        if (!Array.isArray(args[arg])) {
                            return false;
                        }
                    }
                    else if (argProperties[arg].type === 'JSON') {

                    } else {
                        return false;
                    }
                } else {
                    if (toString.call(args[arg]) !== '[object String]') {
                        return false;
                    }
                }

                if (argProperties[arg]['max-length']) {
                    if (args[arg].length > argProperties[arg]['max-length']) {
                        return false;
                    }
                }

                if (argProperties[arg]['min-length']) {
                    if (args[arg].length < argProperties[arg]['min-length']) {
                        return false;
                    }
                }
                
                if(argProperties[arg]['regex']){
                    if (!argProperties[arg]['regex'].test(args[arg])) {
                        if(argProperties[arg]['regex_1']){
                            if (!argProperties[arg]['regex_1'].test(args[arg])) {
                                    return false;
                            }
                        }
                      return false;
                    }
                }

                if (!argProperties[arg]['exclude-from-ret-obj']) {
                    returnObj[arg] = args[arg];
                }
            }
        }

        const clonedObj = {
            ...returnObj,
            id: args.id
        }
        if (args.name && args.description) {
            clonedObj.name = escaped.name;
            clonedObj.description = escaped.description
        }
        if (args.journeyName && args.journeyDescription) {
            clonedObj.journeyName = escaped.name;
            clonedObj.journeyDescription = escaped.description;
            clonedObj.startEvent = escaped.startEvent 
            clonedObj.endEvent = escaped.endEvent 
            clonedObj.platform = escaped.platform 
            clonedObj.period = escaped.period
        }

        if(args.template_name) clonedObj.template_name = escaped.name; 

        if(args.smtp_username) {
            clonedObj.smtp_username = escaped.smtp_username
            clonedObj.smtp_password = escaped.smtp_password 
            clonedObj.smtp_host = escaped.smtp_host
            clonedObj.smtp_port = escaped.smtp_port
            clonedObj.smtp_fromAddress = xss(escaped.smtp_fromAddress)
            clonedObj.smtp_fromName = xss(escaped.smtp_fromName)

        }

        if(args.aws_accessKeyId) {
            clonedObj.aws_accessKeyId = escaped.aws_accessKeyId
            clonedObj.aws_secretAccessKey = escaped.aws_secretAccessKey 
            clonedObj.aws_region = escaped.aws_region
            clonedObj.aws_sourceEmail = escaped.aws_sourceEmail
        }
      
        
        if(args.template_name && args.template.title){
            clonedObj.template_name = escaped.name; 
            clonedObj.template.title ?  clonedObj.template.title = escaped.template.title:'';
            clonedObj.template.message ? clonedObj.template.message = escaped.template.message:'';
            clonedObj.template.url ? clonedObj.template.url = escaped.template.url: '';
        }
        if(args.template && args.template.headerTextClr){
            clonedObj.template.headerTextClr = escaped.template.headerTextClr;
            clonedObj.template.descriptionTextClr = escaped.template.descriptionTextClr;
            clonedObj.template.submitBtnTextClr = escaped.template.submitBtnTextClr;
            clonedObj.template.backgroundColor = escaped.template.backgroundColor;
            clonedObj.template.iconImage = escaped.template.iconImage;
            //pass actionTittle in the argument Object if it passed from frontend
            if(escaped.template.actionTitle){
                clonedObj.template.actionTitle = escaped.template.actionTitle
            }
            clonedObj.template.actionUrl = escaped.template.actionUrl;
        }
        if(args.template_name && (args.template.notificationHeader || args.template.externalUrl)){
            clonedObj.template.notificationHeader = escaped.template.notificationHeader;
            clonedObj.template.notificationDescription = escaped.template.notificationDescription;
            clonedObj.template.notificationImage = escaped.template.notificationImage
            clonedObj.template.externalUrl = escaped.template.externalUrl;
            clonedObj.template.expandedNotificationDescription = escaped.template.expandedNotificationDescription;
        }
        if(args.nm){
            clonedObj.nm = escaped.name;
            clonedObj.sd = escaped.sd;
            clonedObj.ed = escaped.ed;
            clonedObj.cd = escaped.cd;
            clonedObj.appinbox_et = escaped.appinbox_et;
            clonedObj.c_period = escaped.c_period;
            clonedObj.fre.interval ?  clonedObj.fre.interval = escaped.fre.interval:'';
            clonedObj.stag.max_batch ? clonedObj.stag.max_batch = escaped.stag.max_batch : ''
            clonedObj.stag.time ? clonedObj.stag.time = escaped.stag.time : '';
        }
        if(args.urlscheme){
            clonedObj.urlscheme = escaped.urlscheme;
            clonedObj.package = escaped.package;
        }
        if(args.name && args.icon){
            clonedObj.name = escaped.name;
            clonedObj.googleUrl = escaped.googleUrl;
            clonedObj.iosUrl = escaped.iosUrl;
        }
        if(args.full_name){
            clonedObj.full_name = escaped.full_name;
            clonedObj.phone = escaped.phone;
            clonedObj.company = escaped.company;
            clonedObj.title = escaped.title;
            clonedObj.password = escaped.password;
        }
        if(args.ios_cert3){
            clonedObj.ios_cert3 = escaped.ios_cert3;
            clonedObj.ios_keyid = escaped.ios_keyid;
            clonedObj.ios_teamid = escaped.ios_teamid;
            clonedObj.ios_bundleid = escaped.ios_bundleid;
            clonedObj.ios_topic = escaped.ios_topic  
        }
        if(args.callbackurl) clonedObj.callbackurl = escaped.callbackurl;

        if(args.httpMethod) clonedObj.httpMethod = escaped.httpMethod;

        if(args.concurrentLogin){
            clonedObj.concurrentLogin = escaped.concurrentLogin;
            clonedObj.state = escaped.state;
            clonedObj.passwordResetMode = escaped.passwordResetMode;
        }

        if(args.smtp_username){
            clonedObj.smtp_username = escaped.smtp_username;
            clonedObj.smtp_password = escaped.smtp_password;
            clonedObj.smtp_host = escaped.smtp_host;
            clonedObj.smtp_port =escaped.smtp_port;
            clonedObj.smtp_fromAddress = xss(escaped.smtp_fromAddress)
            clonedObj.smtp_fromName = xss(escaped.smtp_fromName)

        }
        if(args.username){
            clonedObj.username = escaped.username;
            clonedObj.password = escaped.password;
        }
        if(args.ios){
            clonedObj.android = {};
            clonedObj.android[0] = {};
            clonedObj.ios={};
            clonedObj.ios[0]={}
            clonedObj.web={}
            clonedObj.web[0]={}
            clonedObj.android[0].v = escaped.android[0].v;
            clonedObj.ios[0].v = escaped.ios[0].v;
            clonedObj.web[0].v = escaped.web[0].v;
        }
        if(args.channelObj){
            clonedObj.channelObj.account_id = escaped.channelObj.account_id;
        }
        if(args.fcmKey){
            clonedObj.fcmKey = escaped.fcmKey;
        }
        if(args.webPush){
            clonedObj.webPush = {};
            clonedObj.webPush.privateKey = escaped.webPush.privateKey;
            clonedObj.webPush.publicKey = escaped.webPush.publicKey;
            clonedObj.webPush.subject = escaped.webPush.subject;
        }

        return clonedObj;
    };

    common.toFirstUpper = function (str) {
        if (str) {
            if(str=='ios'){
                return "iOS"
            }else{
            return str.replace(/\w\S*/g, function (txt) { return txt.charAt(0).toUpperCase() + txt.substr(1); });          
         }
        }
        else {
            return str;
        }

    }

    common.returnMessage = function (params, returnCode, message, optionalData) {
        let result = { result: message };
        if (optionalData && optionalData != undefined) {
            result['user_id'] = optionalData
        }

        params.res.writeHead(returnCode, { 'Content-Type': 'application/json; charset=utf-8' });
        if (params.qstring !== undefined && params.qstring.callback) {
            if (params.url.indexOf('V2') > 0) {
                params.res.write(params.qstring.callback + '(' + cryptoApi.encryptV1(params.res, JSON.stringify(result)) + ')');
            }
            else if (params.url.indexOf('V3') > 0) {
                params.res.write(params.qstring.callback + '(' + cryptoApi.encryptV2(params.res, JSON.stringify(result)) + ')');
            }
            else {
                params.res.write(params.qstring.callback + '(' + JSON.stringify(result) + ')');
            }

        } else {
            if (params.url.indexOf('V2') > 0) {
                params.res.write(cryptoApi.encryptV1(params.res, JSON.stringify(result)));
            }
            else if (params.url.indexOf('V3') > 0) {
                params.res.write(cryptoApi.encryptV2(params.res, JSON.stringify(result)));
            }
            else {
                params.res.write(JSON.stringify(result));
            }
        }
        params.res.end();
    };

    common.returnOutput = function (params, output) {
        params.res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8' });
        if (params.qstring !== undefined && params.qstring.callback) {
            if (params.url.indexOf('V2') > 0) {
                params.res.write(params.qstring.callback + '(' + cryptoApi.encryptV1(params.res, JSON.stringify(output)) + ')');
            }
            else if (params.url.indexOf('V3') > 0) {
                params.res.write(params.qstring.callback + '(' + cryptoApi.encryptV2(params.res, JSON.stringify(output)) + ')');
            }
            else {
                params.res.write(params.qstring.callback + '(' + JSON.stringify(output) + ')');
            }
        } else {
            if (params.url.indexOf('V2') > 0) {
                params.res.write(cryptoApi.encryptV1(params.res, JSON.stringify(output)));
            }
            else if (params.url.indexOf('V3') > 0) {
                params.res.write(cryptoApi.encryptV2(params.res, JSON.stringify(output)));
            }
            else {
                if(output != undefined){  
                    params.res.write(JSON.stringify(output));
                }else{
                    params.res.write("Data Not Found"); 
                }

            }
            
        }

        params.res.end();
    };
// This Function accepts the parameter any string and adds double quotes also 
    common.sanitizeString = function (desc) {
        let itemDesc;
        if (desc) {
            itemDesc = '"'+ desc.replace(/"/g, '""')+'"';
            return itemDesc;
        } else {
            itemDesc = '';
            return itemDesc;
        }
    }

   /**
     * getCdataObj method creates cdata for payloads ,  
     * @param {*} cdata , cdata of any template , can be old or new template
     * @return {*} returns the cdata in a existing format  
     */
    common.getCdataObj = function(cdata){
        let cdataObj= {}
        //new approach of cdata
        if(Array.isArray(cdata)){
            cdata.forEach(obj => {
                const keys = Object.keys(obj);
                   // Find the key other than "type"
                  const keyWithoutType = keys.find(key => key !== "type");
                   cdataObj[keyWithoutType] = ( obj.type == "string" ) ? decodeURIComponent(obj[keyWithoutType]) : JSON.parse(decodeURIComponent(obj[keyWithoutType])) 
               });
        }else{
            //support for existing 
            cdataObj = cdata            
            for (let key of Object.keys(cdataObj)) {
                try {
                cdataObj[key]  = decodeURIComponent(cdataObj[key])
            } catch (error) {
                cdataObj[key] = cdataObj[key] // no need of decoding
            }
            }
        }
        return cdataObj
    }

    common.returnCSV = function (params, output) {
        params.res.setHeader('Content-disposition', 'attachment; filename=' + params.qstring.filename);
        params.res.writeHead(200, { 'Content-Type': 'text/csv' });
        params.res.write(output);
        params.res.end();
    };

    common.getMappedColumnName = function (columnName, map) {
        let mappedColumn = "";
        for (let x = 0; x < map.length; x++) {
            if (columnName == map[x][0]) {
                mappedColumn = map[x][1];
                break;
            }
        }
        return mappedColumn;
    };

    common.getMappedColumnIndex = function (mappedColumn, data) {
        let index = -1;
        for (let x = 0; x < data.length; x++) {
            if (mappedColumn == data[x]) {
                index = x;
                break;
            }
        }
        return index;
    };

    // this function gets date + time from Epoch 
    common.getdatetimeFromEpoch = function (epoch) {
        function tConvert (time) {
          // Check correct time format and split into components
          time = time.toString ().match (/^([01]\d|2[0-3])(:)([0-5]\d)(:[0-5]\d)?$/) || [time];
        
          if (time.length > 1) { // If time format correct
            time = time.slice (1);  // Remove full string match value
            time[5] = +time[0] < 12 ? 'AM' : 'PM'; // Set AM/PM
            time[0] = +time[0] % 12 || 12; // Adjust hours
          }
          return time.join (''); // return adjusted time or original string
        }
      
        let months=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec" ]
        let myDate = new Date(epoch);
        let dateStr = (months[myDate.getMonth()]) + " " + myDate.getDate() + ", " + myDate.getFullYear() + " " +  tConvert(String(myDate.getHours()).padStart(2, '0')  + ":" + String(myDate.getMinutes()).padStart(2, '0') + ":" + String(myDate.getSeconds()).padStart(2, '0') )
        
        return dateStr
      }
    common.getEpochTime = function (strDate, dateFormat) {
        if (strDate !== undefined && strDate !== "") {
            let dateTimeParts = strDate.split(dateFormat.dateTimeSeparator);

            let dateParts = dateTimeParts[0].split(dateFormat.dateSeparator);
            let timeParts = dateTimeParts[1].split(dateFormat.timeSeparator);
            let year = dateParts[dateFormat.yearIndex];
            let month = dateParts[dateFormat.monthIndex];
            let day = dateParts[dateFormat.dayIndex];
            let hours = (dateFormat.hourIndex == -1) ? 0 : timeParts[dateFormat.hourIndex];
            let minutes = (dateFormat.minuteIndex == -1) ? 0 : timeParts[dateFormat.minuteIndex];
            let seconds = (dateFormat.secondIndex == -1) ? 0 : parseInt(timeParts[dateFormat.secondIndex]);


            let d = new Date(month + dateFormat.dateSeparator + day + dateFormat.dateSeparator + year + dateFormat.dateTimeSeparator + hours + dateFormat.timeSeparator + minutes + dateFormat.timeSeparator + seconds);
            d = moment.utc(d);
            return d.valueOf() / 1000;
        }
        else {
            return moment.utc(new Date()).valueOf() / 1000;
        }
    };


    common.getCurrentDate = function () {
        let m_names = new Array("January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December");
        let d = new Date();
        let curr_date = d.getDate();
        let curr_month = d.getMonth();
        let curr_year = d.getFullYear();
        return (curr_date + "-" + m_names[curr_month] + "-" + curr_year);
    }

    common.getFutureEpochTime = function (m) {
        let d = new Date();
        d = moment.utc(d).add(m, 'months');
        return d.valueOf();
    }

    common.getEpochToDate = function (epochDate) {
        epochDate = parseInt(epochDate);
        let m = moment(epochDate);
        let s = m.format();
        return s;
    }
    common.getEpochToDateWithTime = function (epochDate, isMilliseconds, format) {
        epochDate = (isMilliseconds) ? epochDate : parseInt(epochDate * 1000);
        let timeFormat = (format) ? format : 'MMM DD, YYYY hh:mm:ss A';
        let time = moment(epochDate).tz('Asia/Kolkata');
        let second = time.format(timeFormat);
        return second;
    }

     common.whoWhatDids = function (criteria,params) {
        sql = '';
        let operator = '';
        //let criteria = criteria;  
        let criteriaLength = criteria.length;
        let flagSql = '';
        logger.info(`criteriaLength::+> ${criteriaLength}`)
        if(criteriaLength == 1 && criteria[0].category =='Custom Segment'){
            sql = "select distinct did from app_users_"+params.qstring.app_id+" where audsegment->>'audid'='"+criteria[0].value+"';"; 
            return sql;
        }else{
            return "event count reach error outer =>";
        }
    }


    common.constructMatchFromSegment = function (who, match1) {
        let name;
        if (who) {
            for (let obj in who) {
                if (who.hasOwnProperty(obj)) {
                    for (let prop in who[obj]) {
                        if (who[obj].hasOwnProperty(prop)) {
                            if (prop == 'g') {
                                name = 'gender';
                            }
                            else if (prop == 'interests') {
                                name = 'Interests';
                            }
                            else {
                                name = prop;
                            }
                            match1.$match[name] = {};
                            for (let innerProp in who[obj][prop]) {
                                if (name == 'gender' && who[obj][prop][innerProp]) {
                                    match1.$match[name]["$" + innerProp] = who[obj][prop][innerProp].toLowerCase();
                                }
                                else if (name == 'Interests') {
                                    match1.$match[name]["$in"] = [who[obj][prop][innerProp]];
                                }
                                else if (name == 'atrisk' && who[obj][prop][innerProp]) {
                                    match1.$match[name]["$" + innerProp] = (who[obj][prop][innerProp].toLowerCase() == 'true') ? true : false;
                                }
                                else if (name.indexOf('_custom_') >= 0 && who[obj][prop][innerProp]) {
                                    match1.$match[name]["$" + innerProp] = who[obj][prop][innerProp].toString();
                                }
                                else {
                                    match1.$match[name]["$" + innerProp] = who[obj][prop][innerProp];
                                }

                            }
                        }
                    }
                }
            }
             
        }
    };

    common.populateTimeUnit = function(operator){
        if(operator == "gt"){
          return '$lt';
        }else if(operator == "lt"){
          return '$gt';
        }else if(operator == "gte"){
          return '$lte';
        }else if(operator == "lte"){
          return '$gte';
        }
      }

    /* main function */
    common.constructMatchFromCriteria = async function (criteria, app_id = '') {
        logger.info(`criteria from common => ${criteria}`);
        let match = {};
        let currDate = common.getCurrentEpochTime();
        //replaced foreach with map and promise 
        await Promise.all(criteria.map(async function (item) {
            logger.info(`item from criteria => ${item}`);
            if(item.category == 'Custom Vars' && item.operand == '_custom_UserId'){
                if (item.operator == 'in') {
                    let val = (typeof item.value == 'object') ? item.value : item.value.split(',');
                    let arrayPush = []
                    val.forEach(function(item) {
                        arrayPush.push(`["${item}"]`)
                    });
                    match = {"_custom.UserId":{$in:arrayPush}};
                }else {
                    if (item.operator == 'eq') {
                        match._custom = {"UserId": `["${item.value}"]`};
                    }
                }
            }else{   // block other cases
                if (criteria.length == 1 && criteria[0].category == 'Custom Segment') {
                    logger.info(`Criteria Match For Custom Segment`)
                    const audidVal = criteria[0].value
                    const attrColumn = await psqlUtils.executeQuery(`SELECT distinct did FROM app_users_${app_id} WHERE audsegment @> '{"audid${audidVal}":"${audidVal}"}';`);
                 
                    //Default empty array
                    let dids = []
    
            
                    attrValue = attrColumn[0];

                    logger.info(`Response from the Query ${JSON.stringify(attrValue)}`)

                    //if there is any value then handle them and remove the empty ones
                    if(attrValue.length > 0){
                        dids = attrValue.map(item => item.did).filter(did => did !== '');
                    }
    
                    match.did = { $in: dids }
                    return match
                } else {
    
                if (item.operand == "p") {
                    match[item.operand] = {};
                }else{
                    match[item.operand] = {};
                }
                //notification permission
                 if (item.operand == "np") {
                    match[item.operand] = {};
                }else{
                    match[item.operand] = {};
                }
                switch (item.timeunit) {
                    case 'minutes':
                        if (item.operand == "ls") {
                            match[item.operand][common.populateTimeUnit(item.operator)] = currDate - (item.value * 60);
                        }
                        else if (item.operand == "fs") {
                            match[item.operand][common.populateTimeUnit(item.operator)] = currDate - (item.value * 60);
                        }
                        break;
                    case 'hours':
                        if (item.operand == "ls") {
                            match[item.operand][common.populateTimeUnit(item.operator)] = currDate - (item.value * 60 * 60);
                        }
                        else if (item.operand == "fs") {
                            match[item.operand][common.populateTimeUnit(item.operator)] = currDate - (item.value * 60 * 60);
                        }
                        break;
                    case 'days':
                        if (item.operand == "ls") {
                            match[item.operand][common.populateTimeUnit(item.operator)] = currDate - (item.value * 60 * 60 * 24);
                        }
                        else if (item.operand == "fs") {
                            match[item.operand][common.populateTimeUnit(item.operator)] = currDate - (item.value * 60 * 60 * 24);
                        }
                        break;
                    default:
                        if (item.operand == "tsd") {
                            //Convert tsd value to seconds as user will provide minutes
                            match[item.operand]['$' + item.operator] = item.value * 60;
                        }
                        else {
                            logger.info(`aud seg 1  => ${item}`);
                            if (item.operand == 'did' && item.operator == 'in') {
                                logger.info(`aud seg 1  => ${item}`);
                                if (item.value && item.value.indexOf(',') >= 0 ) {
                                    item.value = item.value.split(',');
                                    logger.info(`aud seg 2  => ${item.value}`);
                                }
                                else if(typeof item.value === 'string'){
                                    item.value = [item.value];
                                    logger.info(`aud seg 3  => ${item.value}`);
                                }

                                match[item.operand]['$' + item.operator] = item.value;
                            }
                            else if (item.operator == 'in' && item.value.indexOf(',') >= 0 ) {
                                match[item.operand]['$' + item.operator] = item.value.split(',');
                                
                            }else if (item.operator == 'eq') {
                                match[item.operand]['$'+item.operator] = item.value;
                                
                            }else if (item.operand == 'competingapps.apps.id' && item.operator == 'in') {
                                match[item.operand]['$'+item.operator] = item.value;
                            //Check all the Filters for who Condition 
                            }else if ((item.operand == 'ma' && item.operator == 'in') || (item.operand == 'd' && item.operator == 'in') || (item.operand == 'pv' && item.operator == 'in') || (item.operand == 'av' && item.operator == 'in') || (item.operand == 'c' && item.operator == 'in') || (item.operand == 'ctype' && item.operator == 'in') ) {
                                if (item.value > 0 ) {
                                    match[item.operand]['$'+item.operator] = item.value;
                                }else{
                                    logger.info(`item.value 1 ::>> ${typeof item.value}`);
                                    if(typeof item.value == "object"){
                                        match[item.operand]['$'+item.operator] = item.value;
                                    }else{
                                        match[item.operand]['$'+item.operator] = [item.value];
                                    }
                                    
                                }
                            }else if ((item.operand == 'ma' && item.operator == 'nin') || (item.operand == 'd' && item.operator == 'nin') || (item.operand == 'pv' && item.operator == 'nin') || (item.operand == 'av' && item.operator == 'nin') || (item.operand == 'c' && item.operator == 'nin')) {
                                if (item.value > 0 ) {
                                    match[item.operand]['$'+item.operator] = item.value;
                                }else{
                                    match[item.operand]['$'+item.operator] = item.value;
                                }
                            }
                            else{
                                if(item.category == 'Geo' && item.operator == 'in'){
                                    match[item.operand]['$' + item.operator] = Object.values(item.value); 
                                }else{
                                    match[item.operand]['$'+item.operator] = [item.value];
                                }
                            }
                        }
                        break;
                }
            }
         }
    })); 
        logger.info(`returned match from criteria 4:20 ==>> ${match}`);
        return match;
    }

     /**
     * getGlobalSettings method returns doc of global settings
     * @returns the promise either a doc of global setting or an object Object if not found or error 
     */

      common.getGlobalSettings = function() {
        return new Promise((resolve, reject) => {

            common.db.collection('global_settings').find({ 'domain': semusiConfig.serverDomain }).toArray(function (err, data) {
                if ( err || !data) {
                    logger.error("Error in Finding the Global Settings ");
                    reject(err);                    // Reject the promise with error
                } else {
                    const globalSetting =(data[0]) ? data[0] : {};
                    resolve(globalSetting);         // Resolve the promise with data if found otherwise empty object 
                }
            });
            
        });
    }

    /* new code for match criteria from citus */

     common.constructMatchFromCriteria_new = function (criteria) {
        let match = {};
        let currDate = common.getCurrentEpochTime();
        // Run pg query
        let Sequelize = new sequelize('postgres', 'postgres', '',
                       {
                          host: '10.0.2.90',
                          dialect: 'postgres',
                          port: 5432,
                          ssl: false,
                          pool: {
                            max: 5,
                            min: 0,
                            acquire: 30000,
                            idle: 10000
                          },
                      });
       // Run pg query
        let subQuery  = '{ "Completed" : false}' ;
        let sql = "WITH step1 AS ( SELECT DISTINCT s1.did, s1.KEY FROM events_5e1ac4d981af29fa83e04be3 AS s1 WHERE s1.KEY = 'install'), step2 AS ( SELECT DISTINCT s1.did, s1.KEY, s2.KEY FROM events_5e1ac4d981af29fa83e04be3 AS s1 JOIN events_5e1ac4d981af29fa83e04be3 AS s2 ON s1.did = s2.did WHERE s1.KEY = 'install' AND s2.KEY = 'Registration' AND s2.segment @> '" + subQuery + "'AND s2.dt > Now() - interval '10 day' AND s1.eventtime < s2.eventtime) SELECT count(DISTINCT step1.did) FROM step1 LEFT JOIN step2 ON step1.did = step2.did WHERE step2.did IS NULL"; 
        logger.info("Data === start");
        Sequelize.query(sql).then(projects => {
            logger.info("Data ===then"); 
            logger.info(`projects::: ${projects}`)
          return projects;
        })
        logger.info("Data === End");
    }

    common.populateHistoryObject = function(referrer,refObj){
        try{
            let full_ref = decodeURIComponent(referrer);
        }
        catch(e) {
            logger.error(`decodeURIComponent :: ${e.message}`)  
            let full_ref = referrer;
        }
        let refParts = (full_ref!==undefined)?full_ref.split("&") : "";
        let refname="";
        let trackId="";

        if(full_ref!=undefined && full_ref!=="" && full_ref.toLowerCase()!="self"){
            if(refParts.length>0){
                refObj.fr = full_ref;
                refParts.forEach(function(refPart){
                    if(refPart.toLowerCase().indexOf("utm_source")>=0){
                      let ref = refPart.split("=");
                      if(ref.length>1){
                          refname = ref[1];
                          refObj.refname = refname;
                      }
                    }
                    else if(refPart.toLowerCase().indexOf("gclid")>=0){
                        let ref = refPart.split("=");
                        if(ref.length>1){
                            refObj.refname = 'google ad-words';
                        }
                    }
                    else if(refPart.toLowerCase().indexOf("utm_medium")>=0 || refPart.toLowerCase().indexOf("media_source")>=0 ){
                      let ref = refPart.split("=");
                      if(ref.length>1){
                          refObj.utm_medium = ref[1];
                      }
                    }
                    else if(refPart.toLowerCase().indexOf("utm_content")>=0){
                      let ref = refPart.split("=");
                      if(ref.length>1){
                          refObj.utm_content = ref[1];
                      }
                    }
                    else if(refPart.toLowerCase().indexOf("utm_term")>=0){
                      let ref = refPart.split("=");
                      if(ref.length>1){
                          refObj.utm_term = ref[1];
                      }
                    }
                    else if(refPart.toLowerCase().indexOf("trackid")>=0){
                      let ref = refPart.split("=");
                      if(ref.length>1){
                          refObj.trackId = ref[1];
                      }
                    }
                    else if(refPart.toLowerCase().indexOf("clickid")>=0){
                      let ref = refPart.split("=");
                      if(ref.length>1){
                          refObj.clickId = ref[1];
                      }
                    }
                    else if(refPart.toLowerCase().indexOf("advertid")>=0){
                      let ref = refPart.split("=");
                      if(ref.length>1){
                          refObj.advertId = ref[1];
                      }
                    }
                    else if(refPart.toLowerCase().indexOf("cost_currency")>=0){
                      let ref = refPart.split("=");
                      if(ref.length>1){
                          refObj.cost_currency = ref[1];
                      }
                    }
                    else if(refPart.toLowerCase().indexOf("cost_model")>=0){
                      let ref = refPart.split("=");
                      if(ref.length>1){
                          refObj.cost_model = ref[1];
                      }
                    }
                    else if(refPart.toLowerCase().indexOf("cost_value")>=0){
                      let ref = refPart.split("=");
                      if(ref.length>1){
                    	  if(typeof ref[1] == 'String' || typeof ref[1] == 'string'){
                    		  ref[1] = (ref[1].indexOf(".") >= 0 )? parseFloat(ref[1]) : parseInt(ref[1]);
                    	  }
                          refObj.cpi = ref[1];
                      }
                    }
                    else if(refPart.toLowerCase().indexOf("af_status")>=0){
                      let ref = refPart.split("=");
                      if(ref.length>1 && ref[1].toLowerCase()=="organic"){
                          refObj.refname = "self";
                      }
                    }
                    else if(refPart.toLowerCase().indexOf("fb_adset_name")>=0){
                      let ref = refPart.split("=");
                      if(ref.length>1){
                          refObj.adset_name = ref[1];
                      }
                    }
                    else if(refPart.toLowerCase().indexOf("fb_adgroup_name")>=0){
                      let ref = refPart.split("=");
                      if(ref.length>1){
                          refObj.adgroup_name = ref[1];
                      }
                    }
                    else if(refPart.toLowerCase().indexOf("utm_campaign")>=0 || refPart.toLowerCase().indexOf("campaign")>=0){
                      let ref = refPart.split("=");
                      if(ref.length>1){
                          refObj.utm_campaign = ref[1];
                      }
                    }
                });
                if(refObj.refname==null || refObj.refname==""){
                    refObj.refname="self";
                }
            }
        }
        else{
            refObj.refname = full_ref;
        }

        refObj = common.validateRefname(refObj);
    }

    // validate refname for merge common refname
    common.validateRefname = function(refObj){
        if(refObj.refname){
            refObj.refname = refObj.refname.toLowerCase();
            // check refname and update refname if matched
            if(refObj.refname.toLowerCase() == 'google-play'
                || refObj.refname.toLowerCase() == 'google'
                || refObj.refname.toLowerCase() == '(not set)'){

                refObj.fr=(refObj.fr)? refObj.fr:refObj.refname;
                refObj.refname="self";
            }

            if(refObj.refname.toLowerCase() == 'yes bank'
                || refObj.refname.toLowerCase() == 'utm_source'){
                refObj.refname="taskbucks";
            }
        }
        return refObj;
    }

    // define default audience segments
    common.defaultAudienceSegments = function () {
        return ["All Audience", "All IOS Users", "All Android Users", "All Web Users", "All Users with Competing Apps"];
    }

    // check apple certificate exists or not
    common.checkAppleCertificate_old = function (appid, certificate1, certificate2, callback) {
        let paths = path.join(__dirname, "../../frontend/express/public/appcertificates/" + appid) + "/";
        logger.info(`paths ==========>  ${paths}`)
        logger.info(`certificate1 ==========>  ${certificate1}`)
        logger.info(`certificate2 ==========>  ${certificate2}`)
        if (!fs.existsSync(paths + certificate1) || !fs.existsSync(paths + certificate2)) {
            // download APNS certificate
            common.getCertificatesFromS3(appid, certificate1, function (response) {
                if (response) {
                    // download APNS key certificate
                    common.getCertificatesFromS3(appid, certificate2, function (response) {
                        if (response) {
                            callback(true);
                        }
                        else {
                            callback(false);
                        }
                    });
                }
                else {
                    callback(false);
                }
            });
        }
        else {
            callback(true);
        }
    }
    common.checkAppleCertificate = function (appid, certificate3, callback) {
        let paths = path.join(__dirname, "../../frontend/express/public/appcertificates/" + appid) + "/";
        if (!fs.existsSync(paths + certificate3)) {
            common.getCertificatesFromS3(appid, certificate3, function (response) {
                if (response) {
                    // download APNS key certificate
                    if (response) {
                        callback(true);
                    }else {
                        callback(false);
                    }
                }
                else {
                    callback(false);
                }
            });
        }
        else {
            callback(true);
        }
    }


    // get or download certificate from s3 server
    common.getCertificatesFromS3 = function(appid, certificate, callback){
        let paths = path.join(__dirname,"../../frontend/express/public/appcertificates/" + appid);
        let bucketName;
        if(semusiConfig.IsProduction){
            bucketName = semusiConfig.S3_PROD_CERTBUCKET;
        }else{
            bucketName = semusiConfig.S3_STAGING_CERTBUCKET;
        }

        AWS.config.region = semusiConfig.AWS_REGION;
        AWS.config.update({ accessKeyId: semusiConfig.AWSLAMBDA_ACCESS_KEY_ID , secretAccessKey: semusiConfig.AWSLAMBDA_SECRET_KEY});
        let s3 = new AWS.S3();

        let target_path = 'uploads/appcertificates/' + appid + '/' + certificate;
        let params = {Bucket: bucketName, Key: target_path};

        s3.getObject(params, function (error, certificateData) {
            if (error != null) {
                logger.error(`Failed to retrieve an object:....>>> ${error}`);
              callback(false);
            } else {
                // check app directory and create if not exists
                // if (!fs.existsSync(paths)){
                //     fs.mkdirSync(paths, 0777);
                //     //paths = paths+'/dev'; // check dev directory and create if not exists
                //     //fs.mkdirSync(paths, 0777);
                // }
                /*
                else{
                    paths = paths+'/dev';
                    // check dev directory and create if not exists
                    if (!fs.existsSync(paths)){
                        fs.mkdirSync(paths, 0777);
                    }
                }
                */

                fs.writeFile(paths+"/"+certificate, certificateData.Body, function(err, result){
                    if(err){
                        logger.error(`error while write file:....>>> ${err}`);
                        callback(false);
                    }
                    else{
                        callback(true);
                    }
                });
            }
        });
    }

    // manage active user no into optimise collection
    common.manageActiveUser = function(appId, platform, isAdd, did ){
        platform = platform.toLowerCase();
        let key = platform+"_active_users";
        let updateActiveUsers = {};
        updateActiveUsers[key] = (isAdd)? 1:-1;
        common.db.collection('timely_sessions').update({'_id': common.db.ObjectID(appId)}, {'$inc': updateActiveUsers}, {'upsert': true},function(err, response){
            if(err){
                if(did){
                    common.createCallBackLog(appId, {data:did+moment().format("YYYY-M-D H:m:s")}, "active_failed");
                }
                logger.error(`error ==>>> ${err}`); 
            }
            else{
                if(did){
                    common.createCallBackLog(appId, {data:did+moment().format("YYYY-M-D H:m:s")}, "active_success");
                }

                if(!isAdd){
                     
                }
            }
        });
    }

    // validate epoch time
    common.validateEpochTimeWithServerTime = function(epoch){
        /*if(epoch > (common.getCurrentEpochTime()+parseInt(semusiConfig.eventBufferTime))){
            epoch = common.getCurrentEpochTime();
        }*/
        return epoch;
    }

    /**
 * Downloads a file from Minio to a local file path.
 * @param {string} filename - Name of the file to download from Minio.
 * @param {string} localFilePath - Local file path where the file should be saved.
 * @returns {Promise<boolean>} Promise that resolves to true if file is downloaded successfully, false otherwise.
 */ 
    common.downloadFileFromMinio = function (filename, localFilePath) {
        // Instantiate the Minio client with your configuration
        let minioClient = new Minio.Client({
            endPoint: semusiConfig.endPoint,
            useSSL: semusiConfig.useSSL,
            accessKey: semusiConfig.accessKey,
            secretKey: semusiConfig.secretKey
        });
    
        if (semusiConfig.minioPort) {
            minioClient.port = semusiConfig.minioPort;
        }
    
        return new Promise((resolve, reject) => {
            // Download the file from the specified bucket
            minioClient.fGetObject(semusiConfig.minioBuckets.campaignImages, filename, localFilePath, function (err) {
                if (err) {
                    logger.error(`Error downloading file from Minio: ${JSON.stringify(err)}` );
                    resolve(false); // Reject with false if there's an error
                    return;
                }
    
                logger.info(`File ${filename} downloaded successfully to ${localFilePath}`);
                resolve(true); // Resolve with true upon successful download
            });
        });
    }
      
    common.getHbhourEpoch = function(){
        let hourEpoch = moment().subtract('hours',4)
        return hourEpoch/1000;
    }

    common.getActiveUserKey = function(sc){
        if(sc > 10){
            return "10+";
        }
        else if(sc > 8 && sc <= 10){
            return "8-10";
        }
        else if(sc >= 6 && sc <= 8){
            return "6-8";
        }
        else if(sc >= 2 && sc <= 5){
            return "2-5";
        }
        else if(sc == 1){
            return "1";
        }
    }

    common.getAverageSessionUserKey = function(tsd){
        if(tsd/60 > 5){
            return "5+";
        }
        else if(tsd/60 > 3 && tsd/60 <= 5){
            return "3-5";
        }
        else if(tsd/60 >= 1 && tsd/60 <= 3){
            return "1-3";
        }
        else if(tsd/60 >= .5 && tsd/60 <= 1){
            return "0:5-1";
        }
        else{
            return "<30";
        }
    }

    common.manageActiveSessionUser = function(appId, user_id, no, callback){
        let appName = '';
        cacheApi.getKey("app_id"+appId,function(err,res){
            if(!err ){
                try{
                    res = JSON.parse(res)
                    appName = res.name;
                    common.db.collection('app_users'+appId).findOne({'_id':user_id},{'p':1, 'sc':1, 'tz':1, 'ls':1, 'tsd':1, 'ls_st':1}, function(error, result){
                        if(!error){
                            // no > 0 is used for stop decrement that come at uninstall time
                            if(result && no > 0){
                                let obj = {}
                                if(result.sc){
                                    result.p = result.p.toLowerCase();
                                    result.ls = (result.ls_st)? result.ls_st*1000:result.ls*1000;
                                    let sessionUserObj = {};
                                     
                                    common.fillEventObjectWithEpoch(result.ls, sessionUserObj, result.p+"."+appName, "sc."+common.getActiveUserKey(result.sc), no);
                                    if(no > 0){
                                        common.fillEventObjectWithEpoch(result.ls, sessionUserObj, result.p+"."+appName, "totalsc", result.sc);
                                    }
                                    else{
                                        common.fillEventObjectWithEpoch(result.ls, sessionUserObj, result.p+"."+appName, "totalsc", ((-1)*parseInt(result.sc)));
                                    }
                                    obj['scObj'] = sessionUserObj;
                                    obj['scId'] = common.timelyEventId(appId, result.ls);
                                }

                                if(result.tsd){
                                    result.p = result.p.toLowerCase();
                                    let sessionUserObj = {};
                                    result.ls_st = result.ls_st*1000;
                                    common.fillEventObjectWithEpoch(result.ls_st, sessionUserObj, result.p+"."+appName, "asl."+common.getAverageSessionUserKey(result.tsd), no);
                                    if(no > 0){
                                        common.fillEventObjectWithEpoch(result.ls_st, sessionUserObj, result.p+"."+appName, "totalasl",parseInt(result.tsd));
                                    }
                                    else{
                                        common.fillEventObjectWithEpoch(result.ls_st, sessionUserObj, result.p+"."+appName, "totalasl",((-1)*parseInt(result.tsd)));
                                    }
                                    obj['aslObj'] = sessionUserObj;
                                    obj['aslId'] = common.timelyEventId(appId, result.ls_st);
                                }

                                callback(null, obj);

                            }
                            else{
                                callback('record not found of user', null);
                            }
                        }
                        else if(error){
                            callback(error, null);
                        }
                    });
                }
                catch(e){
                    callback('Invalid parameters!', null);
                }

            }
            else{
                callback('Invalid app id!', null);
            }
        });
    }

    /**
     * SC method used with mongo DB
     * @param {*} obj
     * @param {*} callback
     */
    common.checkActiveUserSc = function(obj, count, callback){
        let appId = obj.appid, appName = '', user_id = obj.user_id, timestamp = parseInt(obj.timestamp);
        cacheApi.getKey("app_id"+appId,function(err,res){
            if(!err ){
                try{
                    res = JSON.parse(res)
                    appName = res.name;
                    logger.info(`user_id => ${user_id}`)
                    common.db.collection('app_users'+appId).findOne({'_id':user_id},{'p':1, 'sc':1, 'tz':1, 'ls':1}, function(error, result){
                        if(!error){
                            if(result){
                                if(result.sc){
                                    result.p = result.p.toLowerCase();
                                    result.ls = result.ls*1000;
                                    let sessionUserObj = {};
                                    let sessionUserArr = [];
                                    let epoch = (timestamp)*1000;
                                     
                                     
                                    if(common.getActiveUserKey(result.sc) != common.getActiveUserKey(parseInt(result.sc)+parseInt(count))){
                                        common.fillEventObjectWithEpoch(result.ls, sessionUserObj, result.p+"."+appName, "sc."+common.getActiveUserKey(result.sc), -1);
                                        //common.fillEventObjectWithEpoch(result.ls, sessionUserObj, result.p+"."+appName, "totalsc", ((-1)*parseInt(result.sc)));
                                        sessionUserArr.push({updateSessionUserObj: sessionUserObj, id: common.timelyEventId(appId, result.ls)});
                                        sessionUserObj = {};
                                        common.fillEventObjectWithEpoch(epoch, sessionUserObj, result.p+"."+appName, "sc."+common.getActiveUserKey(parseInt(result.sc)+parseInt(count)));
                                    }
                                    common.fillEventObjectWithEpoch(epoch, sessionUserObj, result.p+"."+appName, "totalsc", count);
                                    sessionUserArr.push({updateSessionUserObj: sessionUserObj, id: common.timelyEventId(appId, epoch)});
                                    // store logs
                                    storeSessionLog('sclogs', {
                                        appid: appId,
                                        userid: user_id,
                                        query: sessionUserArr,
                                        userdata: result
                                    })
                                    .then((res) =>{
                                        logger.info(`storeSessionLog => ${res}`)
                                    })
                                    .catch((error) =>{
                                        logger.error(`storeSessionLog error => ${error}`)
                                    });

                                    callback(null, sessionUserArr);
                                }
                                else{ // if sc is undefined
                                    result.p = result.p.toLowerCase();
                                    let sessionUserArr = [];
                                    sessionUserObj = {};
                                    let epoch = (timestamp)*1000;
                                    common.fillEventObjectWithEpoch(epoch, sessionUserObj, result.p+"."+appName, "sc."+common.getActiveUserKey(parseInt(count)));
                                    common.fillEventObjectWithEpoch(epoch, sessionUserObj, result.p+"."+appName, "totalsc", parseInt(count));
                                    sessionUserArr.push({updateSessionUserObj: sessionUserObj, id: common.timelyEventId(appId, epoch)});
                                    // store logs
                                    storeSessionLog('sclogs', {
                                        appid: appId,
                                        userid: user_id,
                                        query: sessionUserArr,
                                        userdata: result
                                    })
                                    .then((res) =>{
                                        logger.info(`storeSessionLog => ${res}`)
                                    })
                                    .catch((error) =>{
                                        logger.error(`storeSessionLog error => ${error}`)
                                    });

                                    callback(null, sessionUserArr);
                                }
                            }
                            else{
                                callback('record not found of user', null);
                            }
                        }
                        else if(error){
                            callback(error, null);
                        }
                    });
                }
                catch(e){
                    callback('error in try block', null);
                }
            }
            else if(error){
                callback('record not found of user', null);
            }
        })
    }

    /**
     * TSD method used with mongo DB
     * @param {*} obj
     * @param {*} callback
     */
    common.checkActiveUserAsl = function(obj, callback){
        let appId = obj.appid, appName = '', user_id = obj.user_id, duration = obj.duration;
        cacheApi.getKey("app_id"+appId,function(err,res){
            if(!err ){
                try{
                    res = JSON.parse(res)
                    appName = res.name;
                    common.db.collection('app_users'+appId).findOne({'_id':user_id},{'p':1, 'tsd':1, 'tz':1, 'ls_st':1, 'ls':1}, function(error, result){
                        if(!error){
                            if(result){
                                if(duration>10000 || duration<0 ){
                                    duration = 60;
                                }
                                if(result.tsd){
                                    result.p = result.p.toLowerCase();
                                    result.ls_st = (result.ls_st)? result.ls_st:result.ls;
                                    let sessionUserObj = {};
                                    let sessionUserArr = [];
                                    let epoch = (result.ls)*1000;
                                    result.ls_st = parseInt(result.ls_st)*1000;
                                    if(common.getAverageSessionUserKey(result.tsd) != common.getAverageSessionUserKey(parseInt(result.tsd)+parseInt(duration)) ){
                                        common.fillEventObjectWithEpoch(result.ls_st, sessionUserObj, result.p+"."+appName, "asl."+common.getAverageSessionUserKey(result.tsd), -1);
                                        //common.fillEventObjectWithEpoch(result.ls_st, sessionUserObj, result.p+"."+appName, "totalasl",((-1)*parseInt(result.tsd)));
                                        sessionUserArr.push({updateSessionUserObj: sessionUserObj, id: common.timelyEventId(appId, result.ls_st)});
                                        sessionUserObj = {};
                                        common.fillEventObjectWithEpoch(epoch, sessionUserObj, result.p+"."+appName, "asl."+common.getAverageSessionUserKey(parseInt(result.tsd)+parseInt(duration)));
                                    }

                                    //common.fillEventObjectWithEpoch(epoch, sessionUserObj, result.p+"."+appName, "totalasl",parseInt(result.tsd)+parseInt(duration));
                                    common.fillEventObjectWithEpoch(epoch, sessionUserObj, result.p+"."+appName, "totalasl",parseInt(duration));
                                    sessionUserArr.push({updateSessionUserObj: sessionUserObj, id: common.timelyEventId(appId, epoch)});
                                    // store logs
                                    storeSessionLog('asdlogs', {
                                        appid: appId,
                                        userid: user_id,
                                        query: sessionUserArr,
                                        userdata: result
                                    })
                                    .then((res) =>{
                                        logger.info(`storeSessionLog => ${res}`)
                                    })
                                    .catch((error) =>{
                                        logger.error(`storeSessionLog error => ${error}`)
                                    });

                                    callback(null, sessionUserArr);
                                }
                                else{ // if tsd is undefined
                                    result.p = result.p.toLowerCase();
                                    let sessionUserArr = [];
                                    sessionUserObj = {};
                                    let epoch = (result.ls)*1000;
                                    common.fillEventObjectWithEpoch(epoch, sessionUserObj, result.p+"."+appName, "asl."+common.getAverageSessionUserKey(parseInt(duration)));
                                    common.fillEventObjectWithEpoch(epoch, sessionUserObj, result.p+"."+appName, "totalasl",parseInt(duration));
                                    sessionUserArr.push({updateSessionUserObj: sessionUserObj, id: common.timelyEventId(appId, epoch)});

                                    // store logs
                                    storeSessionLog('asdlogs', {
                                        appid: appId,
                                        userid: user_id,
                                        query: sessionUserArr,
                                        userdata: result
                                    })
                                    .then((res) =>{
                                        logger.info(`storeSessionLog => ${res}`)
                                    })
                                    .catch((error) =>{
                                        logger.error(`storeSessionLog error => ${error}`)
                                    });

                                    callback(null, sessionUserArr);
                                }
                            }
                            else{
                                callback('record not found of user', null);
                            }
                        }
                        else if(error){
                            callback(error, null);
                        }
                    });
                }
                catch(e){
                    callback('Invalid parameters!', null);
                }

            }
            else{
                callback('Invalid app id!', null);
            }
        });
    }

    common.prepareSessionData = function (data, type, current, previous){
        let objData;

        if(type){
            objData = { "android":{currentU:0, previousU:0, currentTsd:0, previousTsd:0, currentTotalSc:0, previousTotalSc:0}, "ios":{currentU:0, previousU:0, currentTsd:0, previousTsd:0, currentTotalSc:0, previousTotalSc:0}, "web":{currentU:0, previousU:0, currentTsd:0, previousTsd:0, currentTotalSc:0, previousTotalSc:0} };
        }
        else{
            objData = { "android":{currentTsd:0, previousTsd:0}, "ios":{currentTsd:0, previousTsd:0}, "web":{currentTsd:0, previousTsd:0} };
        }

        let platforms = ['android','ios','web'];
        if(data){
            data.forEach(function(item){
                logger.info(`item data => ${item}`)
                platforms.forEach(function(platform){
                    if(item[platform]){
                        let platformData = item[platform];
                        let apps = Object.keys(platformData);
                        apps.forEach(function(app){
                            if(objData[platform][app] == undefined){
                                objData[platform][app] = common.getSessionStructure(type);
                            }
                            let dates = Object.keys(platformData[app]);
                            dates.forEach(function(date){
                                if(type){
                                    if(platformData[app][date]['sc']){
                                        common.addActiveUserData(platformData, app, date, platform, objData, previous);
                                    }
                                }
                                if(platformData[app][date]['asl']){
                                    common.addAvrageUserData(platformData, app, date, platform, objData, previous);
                                }
                            });
                        });
                    }
                });
            });
        }
        logger.info(`obj data ==> ${objData}`)
        return objData;
    }

    common.getSessionStructure = function(isBoth){
        if(isBoth){
             return {
                "au":{
                    "10+":0,
                    "8-10":0,
                    "6-8":0,
                    "2-5":0,
                    "1":0
                },
                "asl":{
                    "5+":0,
                    "3-5":0,
                    "1-3":0,
                    "0:5-1":0,
                    "<30":0
                }
            }
        }
        else{
            return {
                    "asl":{
                        "5+":0,
                        "3-5":0,
                        "1-3":0,
                        "0:5-1":0,
                        "<30":0
                    }
                }
        }
    }

    common.addAvrageUserData = function(platformData, app, date, platform, objData, previous){
        if(previous.indexOf(date) != -1){
            let previousTsd = 0;
            if(platformData[app][date]['totalasl']){
                previousTsd += platformData[app][date]['totalasl'];
            }
            objData[platform]['previousTsd'] += previousTsd;
        }
        else{
            if(platformData[app][date]['asl']['5+']){
                objData[platform][app]['asl']['5+'] += platformData[app][date]['asl']['5+'];
            }
            if(platformData[app][date]['asl']['3-5']){
                objData[platform][app]['asl']['3-5'] += platformData[app][date]['asl']['3-5'];
            }
            if(platformData[app][date]['asl']['1-3']){
                objData[platform][app]['asl']['1-3'] += platformData[app][date]['asl']['1-3'];
            }
            if(platformData[app][date]['asl']['0:5-1']){
                objData[platform][app]['asl']['0:5-1'] += platformData[app][date]['asl']['0:5-1'];
            }
            if(platformData[app][date]['asl']['<30']){
                objData[platform][app]['asl']['<30'] += platformData[app][date]['asl']['<30'];
            }

            objData[platform]['currentTsd'] += platformData[app][date]['totalasl'];

        }
    }

    common.addActiveUserData = function(platformData, app, date, platform, objData, previous){
        if(previous.indexOf(date) != -1){
            let totalUsers = 0;
            if(platformData[app][date]['sc']['10+']){
                totalUsers += platformData[app][date]['sc']['10+'];
            }
            if(platformData[app][date]['sc']['8-10']){
                totalUsers += platformData[app][date]['sc']['8-10'];
            }
            if(platformData[app][date]['sc']['6-8']){
                totalUsers += platformData[app][date]['sc']['6-8'];
            }
            if(platformData[app][date]['sc']['2-5']){
                totalUsers += platformData[app][date]['sc']['2-5'];
            }
            if(platformData[app][date]['sc']['1']){
                totalUsers += platformData[app][date]['sc']['1'];
            }
            objData[platform]['previousU'] += totalUsers;
            objData[platform]['previousTotalSc'] += platformData[app][date]['totalsc'];
        }
        else{
            if(platformData[app][date]['sc']['10+']){
                objData[platform][app]['au']['10+'] += platformData[app][date]['sc']['10+'];
                objData[platform]['currentU'] += platformData[app][date]['sc']['10+'];
            }
            if(platformData[app][date]['sc']['8-10']){
                objData[platform][app]['au']['8-10'] += platformData[app][date]['sc']['8-10'];
                objData[platform]['currentU'] += platformData[app][date]['sc']['8-10'];
            }
            if(platformData[app][date]['sc']['6-8']){
                objData[platform][app]['au']['6-8'] += platformData[app][date]['sc']['6-8'];
                objData[platform]['currentU'] += platformData[app][date]['sc']['6-8'];
            }
            if(platformData[app][date]['sc']['2-5']){
                objData[platform][app]['au']['2-5'] += platformData[app][date]['sc']['2-5'];
                objData[platform]['currentU'] += platformData[app][date]['sc']['2-5'];
            }
            if(platformData[app][date]['sc']['1']){
                objData[platform][app]['au']['1'] += platformData[app][date]['sc']['1'];
                objData[platform]['currentU'] += platformData[app][date]['sc']['1'];
            }
            objData[platform]['currentTotalSc'] += platformData[app][date]['totalsc'];
        }
    }

    common.fillCompetingAppsQueryObject = function (object, cId, cName, array, epochStartDate_C, epochEndDate_C, platform, appId) {
        let number = 1;
        let startDate_C = epochStartDate_C * 1000;
        let endDate_C = epochEndDate_C * 1000;
        endDate_C = moment(endDate_C).add(number, 'days').format('YYYY-MM-DD');
        //let $query = {}
        while (moment(startDate_C).valueOf() < moment(endDate_C).valueOf()) {
            let year = moment(startDate_C).format('YYYY');
            let month = parseInt(moment(startDate_C).format('MM'));
            let day = parseInt(moment(startDate_C).format('D'));
            let qDate = year + "_" + month + "_" + day;
            object[platform + '.' + cName + '.' + qDate] = 1;
            if (array.indexOf(common.timelyEventId(cId, startDate_C)) == -1) {
                array.push(common.timelyEventId(cId, startDate_C));
            }
            startDate_C = moment(startDate_C).add(number, 'days').format('YYYY-MM-DD');
        }
    }

    // fill json object for new event optimise collection on user basis
    common.fillNewEventObject = function (obj, epoch, event) {
        obj[moment(epoch).format('YYYY') + "." + moment(epoch).format('M') + "." + moment(epoch).format('D') + "." + event] = 1;
        obj[moment(epoch).format('YYYY') + "." + moment(epoch).format('M') + "." + moment(epoch).format('D') + ".total"] = 1;
        obj[moment(epoch).format('YYYY') + "." + moment(epoch).format('M') + "." + event] = 1;
        obj[moment(epoch).format('YYYY') + "." + moment(epoch).format('M') + ".total"] = 1;
        obj[moment(epoch).format('YYYY') + "." + event] = 1;
        obj[moment(epoch).format('YYYY') + ".total"] = 1;
    }

    common.competingAppsActiveUserAsl = function (param, user_id, capp_id, callback) {
         
        let appId = param.qstring.app_id,
            appName = '',
            did = param.qstring.device_id,
            timestamp = parseInt(param.qstring.timestamp),
            duration = parseInt(param.qstring.duration);
        common.db.collection('app_users' + appId).findOne({ '_id': user_id }, {}, function (error, data) {
            if (!error) {
                if (data) {
                    logger.info(`ASL Data:  ==> ${data}`);
                    if (data.competingapps) {
                        let sessionUserObj = {};
                        let sessionUserArr = [];
                        data.competingapps.apps.forEach(function (result, key) {
                            if (result.id == capp_id) {
                                if (result.tsd) {
                                    //if(common.getAverageSessionUserKey(result.tsd) != common.getAverageSessionUserKey(parseInt(result.tsd)+parseInt(duration))){
                                    data.p = data.p.toLowerCase();
                                    let epoch = (timestamp + parseInt(data.tz)) * 1000;
                                    result.ls_st = parseInt(result.ls_st) * 1000;
                                    sessionUserObj = {};
                                    // common.fillEventObjectWithEpoch(result.ls_st, sessionUserObj, data.p + "." + result.name, "asl." + common.getAverageSessionUserKey(result.tsd), -1);
                                    // sessionUserArr.push({ updateSessionUserObj: sessionUserObj, id: common.timelyEventId(result.id, result.ls_st) });
                                    // sessionUserObj = {};
                                    common.fillEventObjectWithEpoch(epoch, sessionUserObj, data.p + "." + result.name, "asl." + common.getAverageSessionUserKey(parseInt(result.tsd) + parseInt(duration)));
                                    sessionUserArr.push({ updateSessionUserObj: sessionUserObj, id: common.timelyEventId(result.id, epoch) });
                                    /*}
                                    else{
                                        callback('average user session length boundary is same '+common.getAverageSessionUserKey(result.tsd), null);
                                    }*/
                                }
                                else { // if sc is undefined
                                    data.p = data.p.toLowerCase();
                                    sessionUserObj = {};
                                    let epoch = (timestamp + parseInt(data.tz)) * 1000;
                                    common.fillEventObjectWithEpoch(epoch, sessionUserObj, data.p + "." + result.name, "asl." + common.getAverageSessionUserKey(parseInt(duration)));
                                    sessionUserArr.push({ updateSessionUserObj: sessionUserObj, id: common.timelyEventId(result.id, epoch) });
                                }
                            }

                        });

                        if (sessionUserArr.length > 0) {
                            callback(null, sessionUserArr);
                        }
                        else {
                            callback('record not found of user', null);
                        }
                    }
                }
            }
            else if (error) {
                callback(error, null);
            }
        })
    }

    common.competingAppsActiveUserSc = function (param, capp_id, user_id, count, timestamp, callback) {
        let appId = param.qstring.app_id, appName = param.qstring.app_name, did = param.qstring.device_id;
        timestamp = parseInt(timestamp);
        common.db.collection('app_users' + appId).findOne({ '_id': user_id }, {}, function (error, data) {
            if (!error) {
                if (data) {
                    if (data.competingapps) {
                        let sessionUserObj = {};
                        let sessionUserArr = [];
                        data.competingapps.apps.forEach(function (result) {
                            if (result.id == capp_id) {
                                if (result.sc) {
                                    //if(common.getActiveUserKey(result.sc) != common.getActiveUserKey(parseInt(result.sc)+parseInt(count))){
                                    data.p = data.p.toLowerCase();
                                    result.ls = result.ls * 1000;
                                    sessionUserObj = {};
                                    //let sessionUserArr = [];
                                    let epoch = (timestamp + parseInt(data.tz)) * 1000;
                                    // common.fillEventObjectWithEpoch(result.ls, sessionUserObj, data.p + "." + result.name, "sc." + common.getActiveUserKey(result.sc), -1);
                                    // sessionUserArr.push({ updateSessionUserObj: sessionUserObj, id: common.timelyEventId(result.id, result.ls) });
                                    // sessionUserObj = {};
                                    common.fillEventObjectWithEpoch(epoch, sessionUserObj, data.p + "." + result.name, "sc." + common.getActiveUserKey(parseInt(result.sc) + parseInt(count)));
                                    sessionUserArr.push({ updateSessionUserObj: sessionUserObj, id: common.timelyEventId(result.id, epoch) });
                                    //callback(null, sessionUserArr);
                                    /*}
                                    else{
                                        callback('active user boundary is same '+common.getActiveUserKey(result.sc), null);
                                    }*/
                                } else { // if sc is undefined
                                    data.p = data.p.toLowerCase();
                                    //let sessionUserArr = [];
                                    sessionUserObj = {};
                                    let epoch = (timestamp + parseInt(data.tz)) * 1000;
                                    common.fillEventObjectWithEpoch(epoch, sessionUserObj, data.p + "." + result.name, "sc." + common.getActiveUserKey(parseInt(count)));
                                    sessionUserArr.push({ updateSessionUserObj: sessionUserObj, id: common.timelyEventId(result.id, epoch) });
                                    //callback(null, sessionUserArr);
                                }
                            }
                        })

                        if (sessionUserArr.length > 0) {
                            callback(null, sessionUserArr);
                        }
                        else {
                            callback('record not found of user', null);
                        }

                    }
                }
                else {
                    callback('record not found of user', null);
                }
            }
            else if (error) {
                callback(error, null);
            }
        })
    }

    common.getWeeksList = function (startDate, endDate) {
        let weeks = [];
        startDate = moment(startDate, 'YYYY-MM-DD').valueOf();
        endDate = moment(endDate, 'YYYY-MM-DD').valueOf();
        let counter = 1;
        while (startDate <= endDate) {
            weeks.push("previous_" + counter + "_week");
            counter++;
            startDate = moment(startDate).add(7, 'days').valueOf();
        }
        return weeks;
    }

    common.fillCampaignEventObj = function (obj, platform, epoch, device, country, city, place, event, increment) {
        let date = moment(epoch * 1000).format('YYYY_MM_DD');
        let hrs = moment(epoch * 1000).format('HH');
        increment = (increment == undefined) ? 1 : increment;
        obj[platform + "." + date + "." + hrs + "." + device + "." + country + "." + city + "." + place + "." + event] = increment;
    }

    // convert json into qstring
    common.jsonToqstring = function (obj) {
        let qstring = '';
        if (obj) {
            let keys = Object.keys(obj);
            keys.forEach(function (key) {
                if (obj[key]) {
                    if (typeof obj[key] == 'object') {
                        qstring += key + '=' + JSON.stringify(obj[key]) + '&';
                    }
                    else {
                        qstring += key + '=' + obj[key] + '&';
                    }
                }
            })
        }
        return qstring;
    }

    // make copy of criteria and prepare filter
    common.prepareFilter = function (array, filters, tmpCriteria) {
        tmpCriteria = (tmpCriteria == undefined) ? [] : tmpCriteria;
        let category = ['Device', 'Geo'];
        array.forEach(function (obj) {
            tmpCriteria.push(obj);
            // if category match then prepare filter for keen
            if (category.indexOf(obj.category) >= 0) {
                let filter = {};
                filter.property_name = obj.operand;
                // check device
                if (obj.category == 'Device') {
                    if (obj.operand != 'did') {
                        filter.property_name = 'context.who.device.' + obj.operand;
                    }
                } // check location
                else if (obj.category == 'Geo') {
                    filter.property_name = 'context.where.geo.' + obj.operand;
                }

                filter.operator = obj.operator;
                if (obj.operator == "in") {
                    obj.value = obj.value.toString();
                    filter.property_value = obj.value.split(",");
                }
                else {
                    filter.property_value = getValueBasedOnType(obj.type, obj.value);
                }
                filters.push(filter);
            }
        });
    }

    function getValueBasedOnType(type, value) {
        if (type == 'number') {
            return parseFloat(value);
        }
        else if (type = 'string' || type == "regex") {
            return value;
        }
        else if (type == 'boolean') {
            return Boolean(value);
        }
    }

    common.validateSpecialChar = function(str, isVal){
        if( str != "" && typeof str == 'string' ){
            if(isVal){
                //return str.replace(/[`~%!@#$%^&*()|+\-=?;'",<>\{\}\[\]\\\/]/gi, '_');
                return str.replace(/[`~%!#$%^*()\;'",<>\{\}\[\]\\\/]/gi, '_');
            }
            else{
                //return str.replace(/[`~%!@#$%^&*() |+\-=?;'",.<>\{\}\[\]\\\/]/gi, '_');
                return str.replace(/[`~%!#$%^*() \;'",.<>\{\}\[\]\\\/]/gi, '_');
            }
        }
        else{
            return str;
        }
    }

    common.strMatchRatio = function(str1, str2){
        let ratio = 0;
        if( (str1 != "" && typeof str1 == 'string') && (str2 != "" && typeof str2 == 'string') ){
            str1 = str1.split(" ");
            str2 = str2.split(" ");
            let length = str2.length;
            for(let i=0; i<length; i++){
                if( str1.indexOf(str2[i]) >= 0 ){
                    ratio++;
                }
            }

            if(ratio > 0){
                ratio = ratio*100/length;
            }
            return ratio;
        }
        else{
            return ratio;
        }
    }

    common.createCallBackLog = function(app_id, data, fname){
        let logDir = semusiConfig.callbackLog;
        let fileName = logDir + "/"+fname+"_"+ app_id + "_" + moment().year()+''+(moment().month()+1)+''+moment().date()+".log";
        if(fname == "active_failed" || fname == "active_success" || fname == "dashboard_failed" || fname == "dashboard_success"){
            fileName = logDir + "/"+fname+"_"+  app_id + "_" + moment().year()+''+(moment().month()+1)+''+moment().date()+''+moment().format('H')+".log";
        }
        let log = fs.createWriteStream(fileName, {'flags': 'a'});
        // use {'flags': 'a'} to append and {'flags': 'w'} to erase and write a new file
        log.end(JSON.stringify(data,null,4)+",");
    }

    let errorQueue = function(eventsData, type, col, method){
        let obj = {
            method  : method,
            col		: col,
            type 	: type,
            events  : eventsData,
            key 	: "errors"
        };
        awsHelper.writeAPIDataToSQS(obj,function(status){
            return status;
        });
    }

    /**
     * Add logs into table
     * @param {*} table Name
     * @param {*} logObj Contains required info
     */
    let storeSessionLog = function(table, logObj){
        return new Promise((resolve, reject) =>{
            if(semusiConfig.citusLogsApps.indexOf(logObj.appid) >= 0){
                let sql = `INSERT INTO ` +table+ `(appid, userid, qu, userdata)
                        values(
                            '` +logObj.appid+ `',
                            '` +logObj.userid+ `',
                            '` +JSON.stringify(logObj.query)+ `',
                            '` +JSON.stringify(logObj.userdata)+ `'
                        )`;

                        common.pgdbClient.query(sql, function(error, res){
                            if(error){
                                 
                                return reject(error);
                            }
                            else {
                                 
                                return resolve(res)
                            }
                        });
            }
        })
    }

    /**
    * Get Active users aggregate number to render UI
    */
    common.getActiveUsersAggregateNumber = function(appid, isTotal, callback){
        common.db.collection('active_users_aggregates').find({_id:common.db.ObjectID(appid)}).toArray(function(err, result){
            if(!err && result){
                let obj = {android:0, ios:0};
                if(isTotal && result && result.length > 0){
                    //get android active users data
                    obj.android = 0;
                    if(result[0]['android'] && result[0]['android']['M']){
                        obj.android = result[0]['android']['M'];
                    }
                    if(result[0]['android'] && result[0]['android']['F']){
                        obj.android += result[0]['android']['F'];
                    }
                    if(result[0]['android'] && result[0]['android']['unknown']){
                        obj.android += result[0]['android']['unknown'];
                    }

                    // get ios active users data
                    obj.ios = 0;
                    if(result[0]['ios'] && result[0]['ios']['M']){
                        obj.ios = result[0]['ios']['M'];
                    }
                    if(result[0]['ios'] && result[0]['ios']['F']){
                        obj.ios += result[0]['ios']['F'];
                    }
                    if(result[0]['ios'] && result[0]['ios']['unknown']){
                        obj.ios += result[0]['ios']['unknown'];
                    }
                    // get web active users data
                    obj.web = 0;
                    if(result[0]['web'] && result[0]['web']['M']){
                        obj.web = result[0]['web']['M'];
                    }
                    if(result[0]['web'] && result[0]['web']['F']){
                        obj.web += result[0]['web']['F'];
                    }
                    if(result[0]['web'] && result[0]['web']['unknown']){
                        obj.web += result[0]['web']['unknown'];
                    }
                    return callback(null, parseInt(obj.android) + parseInt(obj.ios) + parseInt(obj.web),obj);
                }
                else {
                    return callback(null, result);
                }

            }
            else{
                return callback(err, null);
            }
        });
    }

    /**
     * Convert nosql operator to sql operator
     */
    common.prepareSQLFilter = function(criteria){
        let filter = " Where active=true AND ";
        criteria.forEach((condition, index) =>{
            condition.value = (condition.value && condition.value === 'string')? condition.value.trim(): condition.value;
            switch(condition.operator){
                case "eq" :
                    if(condition.operand.indexOf('_custom')>= 0 ){
                        let users = condition.value.split(",").map((user) =>{
                            return '[{"_custom_UserId": '+user+'}]';
                        });
                        filter += " _custom @> ANY (ARRAY ["+users+"]::jsonb[])";
                    }
                    else if(condition.value.indexOf(';')>= 0 ){
                        filter += ""+ condition.operand + " in('" + condition.value.split(";").join("','") + "')";
                    }
                    else {
                        filter += ""+ condition.operand + "='" +condition.value +"'";
                    }
                    break;
                case "neq" :
                    filter += ""+ condition.operand + "='" +condition.value +"'";
                    break;
                case "in" :
                    condition.value = (condition.value.indexOf(",") >= 0)? condition.value.split(",") : condition.value;
                    condition.value = (Array.isArray(condition.value))? condition.value.join("','") : condition.value;
                    filter += ""+ condition.operand + " in('" + condition.value + "')";
                    break;
                case "nin" :
                    condition.value = (condition.value.indexOf(",") >= 0)? condition.value.split(",") : condition.value;
                    condition.value = (Array.isArray(condition.value))? condition.value.join("','") : condition.value;
                    filter += ""+ condition.operand + " nin('" + condition.value + "')";
                    break;
                case "gt" :
                    filter += ""+ condition.operand + '>' + parseInt(condition.value);
                    break;
                case "gte" :
                    filter += ""+ condition.operand + '>=' + parseInt(condition.value);
                    break;
                case "lt" :
                    filter += ""+ condition.operand + '<' + parseInt(condition.value);
                    break;
                case "lte" :
                    filter += ""+ condition.operand + '<=' + parseInt(condition.value);
                    break;
                case "minutes" :
                    filter += ""+ condition.operand + '<' + parseInt(moment().subtract(parseInt(condition.value), "minutes").valueOf()/1000);
                    break;
                case "hours" :
                    filter += ""+ condition.operand + '<' + parseInt(moment().subtract(parseInt(condition.value), "hours").valueOf()/1000);
                    break;
                case "days" :
                    filter += ""+ condition.operand + '<' + parseInt(moment().subtract(parseInt(condition.value), "days").valueOf()/1000);
                    break;
            }

            if(index < criteria.length-1){
                filter += ' AND '
            }
        });

        return filter;
    }

    /**
     * deleting cache campaign and releted data
     */
     common.deleteCampaignCache = function(app_id, cid){
        //delete campaign  cache
        cacheApi.deleteKey('campaigns_'+app_id,function(err,res){
            logger.info(`Redis key cleared. :: campaigns_ =>> ${app_id}`);
        });
        //delete campaign user cache
        cacheApi.deleteKey("campaignuser_"+app_id+""+cid,function(err,res){
            logger.info(`Redis key cleared. :: campaignuser_ =>> ${app_id} :: ${cid}`);
        });
        //delete campaign event cache
        cacheApi.deleteKey("campaignevent_"+app_id+""+cid,function(err,res){
            logger.info(`Redis key cleared. :: campaignevent_ =>> ${app_id} :: ${cid}`);
        });
    
        //delete campaign event cache
        cacheApi.deleteKey("deliver_user_"+app_id+""+cid,function(err,res){
            logger.info(`Redis key cleared. :: campaigevent_ =>> ${app_id} :: ${cid}`);
        });
    }
    // fill timely dashboard collection
    common.fillDeviceQueryObject = function(object, array, tempArray, epochStartDate_C, epochEndDate_C, platform, appId){
        let number = 1;
        let startDate_C = epochStartDate_C;
        let endDate_C = moment(epochEndDate_C).add(number,'days').format('YYYY-MM-DD');
        //let $query = {}
        while(moment(startDate_C).valueOf() < moment(endDate_C).valueOf()){
            let day = parseInt(moment(startDate_C).format('D'));
            let qDate = day;
            object[platform+'.'+qDate] = 1;
            if(tempArray.indexOf(qDate) == -1){
                tempArray.push(qDate);
            }
            if(array.indexOf(common.timelyEventId(appId, startDate_C)) == -1){
                array.push(common.timelyEventId(appId, startDate_C));
            }
            startDate_C = moment(startDate_C).add(number,'days').format('YYYY-MM-DD');
        }
    }
    // TO get image base url from config 
    common.getBaseUrl = function(){
        return semusiConfig.blobContainerCDN;   
    }
    // TO check image base url from url 
    common.isValidUrl = function(string){
        let url;
        try {
          url = new URL(string);
        } catch (_) {
          return false;  
        }
        return url.protocol === "http:" || url.protocol === "https:";   
    }
    // TO prepare what data for in-app
    common.whatPrepareForInApp = function(segement){
        let what = [];
        segement.what.forEach(function(evt) {
            if(evt.attr != undefined){
                what.push({
                            "process": true,
                            "state": false,
                            "operand": evt.operand,
                            "e_operator":  evt.e_operator,
                            "since":evt.since,
                            "category": "Events",
                            "segment": {
                            "check": {
                                [evt.attr]: 
                                {
                                    "op": evt.operator,
                                    "v": evt.value
                                }
                            }
                            }
                            })
            }else{
                what.push({
                    "process": true,
                    "state": false,
                    "operand": evt.operand,
                    "e_operator": evt.e_operator,
                    "category": "Events",
                    "since": evt.since
                })
            }   
        });
        segement.what = what;
    return segement;
    }
    common.validateUploadFile = (str) => {
        if (str.indexOf('.') !== str.lastIndexOf('.')) {
            return false;
        }
        return true;
    }
    
     common.getFileExtension = (file) => {
        let pathParts = file.split(".")
        let fileExtension = pathParts[pathParts.length - 1];
         return fileExtension;
    }

}(common));

module.exports = common;
