Source: plugins/outbound/fcm/base.js

const EventEmitter = require('events');

const moment = require('moment');
const FCM = require('fcm-node');
const FCMToken = require('../../../models/fctmtokens');

/**
 * 
 * @class Sending new alarms to mobile apps via Firebase Cloud Messaging
 * ALARMiator Zusatzalarmierung
 * 
 * @version: 1.0.1
 * @author:  Stefan Bauer 2020
 */

class fcm extends EventEmitter {
    /**
     *
     * @constructor
     */
    constructor() {
        super();
        global.plgManager.logger.info('-------- PLUGIN FIREBASE CLOUD MESSAGING -----------');
        //this.plgManager = global.plgManager;
        this.registerForEvents();
        this.serviceProcId = null;
        this.loadConfig((success) => {
            
        });
        this.fAlarm = null;
        this.alarmiator = null;
        this.alarmInfo = null;
        this.calculatedTimeStamp = null;
        this.messageBody = null;
        this.messageTitle = null;
        this.fcmtokens = new FCMToken(global.plgManager.logger);
    }

    /**
     * Registration of Events at the plugin manager (hook in to events provided by the plugin manager)
     */
    registerForEvents() {
        global.plgManager.logger.info('PLUGIN | FCM | Registering events')

        global.plgManager.on('event_pluginConfig_refreshed', (namespace) => {
            if (namespace === 'fcm') {
                // plugins config has changed --> refresh
                this.loadConfig((success) => {
                    if (success) {
                        global.plgManager.logger.info('PLUGIN | FCM | successfully reloaded plugin configuration');
                    } else {
                        global.plgManager.logger.error('PLUGIN | FCM | could not reload plugin config!');
                    }
                });
            }
        })

        global.plgManager.on('event_new_alarm', (alarmInfo) => {
            console.log(alarmInfo);
            this.alarmInfo = alarmInfo;
            this.setupFCMInstances();
            this.calculateTimeStamp(this.alarmInfo.alarmdate.value + " " + this.alarmInfo.alarmtime.value);
            this.setMessageBody();
            this.setMessageTitle();
            this.sendMessage();
        })

        global.plgManager.on('event_new_test_alarm', (baseDataId, pluginNamespace, alarmInfo) => {
            if (pluginNamespace === "fcm"){
                global.plgManager.logger.info('PLUGIN | FCM | EVENT event_new_test_alarm recieved -> processing now');
                console.log(alarmInfo);
                this.alarmInfo = alarmInfo;
                this.setupFCMInstances();
                this.calculateTimeStamp(this.alarmInfo.alarmdate.value + " " + this.alarmInfo.alarmtime.value);
                this.setMessageBody();
                this.setMessageTitle();
                this.sendTestAlarm(baseDataId, alarmInfo);
            }
        })
    }


    /**
     * Plugin-specific Getters and Setters
     *
    */
    set fAlarmActive(fAlarmActive) {
        this._fAlarmActive = fAlarmActive;
    }
    get fAlarmActive() {
        return this._fAlarmActive;
    }

    set alarmiatorActive(alarmiatorActive) {
        this._alarmiatorActive = alarmiatorActive;
    }
    get alarmiatorActive() {
        return this._alarmiatorActive;
    }

    /**
     * Plugin-specific implementation
     */

    /**
     * Creates Firebase Cloud Messaging Instances for fAlarm and ALARMiator
     * 
     */
    setupFCMInstances() {
        global.plgManager.logger.debug('PLUGIN | FCM | Setup FCM Instances');

        this.fAlarm = new FCM("AIzaSyB4CKxUDeYC7lU-p0pLsJSJ1kcVRv6AHWk");
        this.alarmiator = new FCM("AIzaSyD3AhR0yQSSGWou8SlKryaFm3pZikeo6r4");
    }

    /**
     * Check plugin config, whether sending alarms to fAlarm and ALARMiator is active 
     * 
     */
    sendMessage() {
        global.plgManager.logger.debug('PLUGIN | FCM | Send Messages');

        if (this.getConfigValue('fAlarmActive') == "true"){
            global.plgManager.logger.debug('PLUGIN | FCM | Sending fAlarm messages');
            this.sendFAlarmMessages();
        }
        if (this.getConfigValue('alarmiatorActive') == "true"){
            global.plgManager.logger.debug('PLUGIN | FCM | Sending Alarmiator messages');
            this.sendAlarmiatorMessages();
        }
    }


    /**
     * Building alarm payload
     * @param {number} baseDataId 
     * @param {operation} alarmInfo 
     */
    sendTestAlarm(baseDataId, alarmInfo){
        
        var fcmKeys = [];

        /* Get FCM token for User from tokenstore*/
        this.fcmtokens.getAllFCMTokensForBasedataAndNamespace("fcm", baseDataId, (fcmrows) => {
             if (fcmrows != null){
                fcmrows.forEach((entry)=> {
                    fcmKeys.push(entry.fcmToken);
                })
            }

            if (this.getConfigValue('fAlarmActive') == "true"){
                global.plgManager.logger.debug('PLUGIN | FCM | Sending fAlarm messages');
                this.sendFAlarmMessagesToFirebase(fcmKeys);
            }

            if (this.getConfigValue('alarmiatorActive') == "true"){
                global.plgManager.logger.debug('PLUGIN | FCM | Sending Alarmiator messages');
                this.sendAlarmiatorMessagesToFirebase(fcmKeys);
            }
        }); 

    }
    /**
     * Format timestamp to app specific format
     * 
     */
    calculateTimeStamp(operationTimeStamp){
        this.calculatedTimeStamp = moment(operationTimeStamp,"DD-MM-YYYY HH:mm").format('YYYY-MM-DDTHH:mm:ss');
    }

    /**
     * Create messagebody for alarm
     * 
     */
    setMessageBody(){
        var message= "";
        message+="## EINSATZGRUND ##";
        message += "\n" + this.alarmInfo.subject.value + " - " + this.alarmInfo.keywordCategory.value + " - " + this.alarmInfo.keywordName.value;
        message+="\n\n## BEMERKUNG ##";
        message += "\n" + this.alarmInfo.message.value;
        message += "\n\nALARMZEIT: " + this.alarmInfo.alarmdate.value + " " + this.alarmInfo.alarmtime.value;
        message+="\n\n"
        message+="## EINSATZSTELLE ##";
        message += "\nORT: " + this.alarmInfo.location.value;
        message += "\nSTRASSE: " + this.alarmInfo.street.value;
        message += "\nOBJEKT: " + this.alarmInfo.object.value;
        message += "\nABSCHNITT: " + this.alarmInfo.section.value;
        message+="\n\n"
        message += "## EINSATZMITTEL ##\n" + this.alarmInfo.gear.value;
        this.messageBody=message;
    }

    /**
     * Creates title for alarm
     * 
     */
    setMessageTitle(){
        this.messageTitle = this.alarmInfo.subject.value + " - " + this.alarmInfo.keywordCategory.value + " - " + this.alarmInfo.keywordName.value;
    }

    /**
     * Sending fAlarm messages to all users in fAlarmReceivers
     * 
     */
    sendFAlarmMessages(){
        var fcmKeysAndroidString = this.getConfigValue('fAlarmReceivers');
        var fcmKeysAndroid = [];

        // check if string is empty
        if (fcmKeysAndroidString){
            fcmKeysAndroid = fcmKeysAndroidString.split(",").map(x => x.trim()).filter(x => x); // filter removes empty results
        }

        /* Get FCM token from tokenstore*/
        this.fcmtokens.getAllFCMTokensForNamespace("fcm", (fcmrows) => {
            if (fcmrows != null){
                fcmrows.forEach((entry)=> {
                    fcmKeysAndroid.push(entry.fcmToken);
                })
            }
            this.sendFAlarmMessagesToFirebase(fcmKeysAndroid);
        }); 
    }

    /**
     * Sending fAlarm messages to firebase
     * @param {array} tokens 
     */
    sendFAlarmMessagesToFirebase(tokens){
        tokens.forEach(currentKey => {
            var fAlarmMessage = { 
                to: currentKey,
                priority: 'high',
            
                data: {
                    awf_key: this.alarmInfo.operationnumber.value,
                    awf_title : this.messageTitle,
                    awf_message : this.messageBody,
                    awf_location: this.alarmInfo.location.value,
                    awf_latlng: this.alarmInfo.lat.value + ";" + this.alarmInfo.lon.value,
                    awf_timestamp : this.calculatedTimeStamp
                }
            };

            this.fAlarm.send(fAlarmMessage, function(err, response){
                if (err) {
                    global.plgManager.logger.error('PLUGIN | FCM | Error sending fAlarm message: ' + err);
                    return console.log(err);
                } else {
                    global.plgManager.logger.info('PLUGIN | FCM | Message sent successfully');
                    console.log('PLUGIN | FCM | Message sent successfully');
                }
            });
        })
    }

    /**
     * Sending ALARMiator messages to all users in ALARMiatorReceivers
     * 
     */
    sendAlarmiatorMessages(){
        var fcmKeysIOSString = this.getConfigValue('ALARMiatorReceivers');
        var fcmKeysIOS = [];

        // check if string is empty
        if (fcmKeysIOSString){
            fcmKeysIOS = fcmKeysIOSString.split(",").map(x => x.trim()).filter(x => x); // filter removes empty results
        }

        /* Get FCM token from tokenstore*/
        this.fcmtokens.getAllFCMTokensForNamespace("fcm", (fcmrows) => {
            if (fcmrows != null){
                fcmrows.forEach((entry)=> {
                    fcmKeysIOS.push(entry.fcmToken);
                })
            }
            this.sendAlarmiatorMessagesToFirebase(fcmKeysIOS);
        });          
    }

    /**
     * Sending Alarmiator messages to firebase
     * @param {array} tokens 
     */
    sendAlarmiatorMessagesToFirebase(tokens){
        var organization="Hartmannshof"
        tokens.forEach(currentKey => {
            var alarmiatorIOSMessage = {
                to: currentKey,
                collapse_key: 'ALARMiator',
                priority: 'high',
                alert: "Einsatz für Feuerwehr "+organization,
                body: this.alarmInfolocation,
                contentAvailable: true,
                notification: {
                  alert: "EINSATZ " + organization,
                  title: "EINSATZ " + organization,
                    body: this.messageTitle + "\nEinsatzort: " + this.alarmInfo.location.value,
                  sound : "Alarm.mp3"
               },
          
                data: {  //you can send only notification or only data(or include both)
                    opid: this.alarmInfo.operationnumber.value,
                    opkeyword: this.alarmInfo.subject.value,
                  opdesc: this.messageBody,
                    oplat: this.alarmInfo.lat.value,
                    oplon: this.alarmInfo.lon.value,
                  optimestamp: this.calculatedTimeStamp,
                  optimestampIncoming: this.calculatedTimeStamp,
                  content_available: "1"
                }
            };
            this.alarmiator.send(alarmiatorIOSMessage, function(err, response){
                if (err) {
                    global.plgManager.logger.error('PLUGIN | FCM | Error sending ALARMiator message: ' + err);
                    return console.log(err);
                } else {
                    // global.plgManager.logger.info('PLUGIN | FCM | Message sent successfully');
                    // console.log('PLUGIN | FCM | Message sent successfully');
                }
            });
        })
    }

    /**
     * Loads configuration for KatSys Service
     * TBD: Needs to be pulled from plugin config store
     */
    loadConfig(callback) {
        global.plgManager.loadConfigFromStore('fcm', (configRows) => {
            if (configRows !== null) {
                this.config = configRows[0];
                this.config = JSON.parse(this.config.configstore);
                callback(true);
            }
            global.plgManager.logger.info('PLUGIN | FCM | Configuration reloaded from core database');
        })
    }

    /**
     * returns config parameter for given fieldname
     * @param {string} fieldname 
     */
    getConfigValue(fieldname) {
        var retVal = null;
        this.config.fields.forEach((field) => {
            if (field.fieldname === fieldname) {
                retVal = field.value;
            } 
        });
        return retVal;
    }

}

module.exports = fcm;