const os = require("os");

const fs = require('fs');

require('../config/config');

require('../models/subscribers');

const CryptoJS = require('crypto-js');

const Url = require('url-parse');

const { ObjectID } = require('mongodb');

const shared_consts = require('./shared_nodejs');

const mongoose = require('mongoose');
const Subscription = mongoose.model('subscribers');

const server_constants = require('./server_constants');

// SETTINGS WebPush Configuration
const webpush = require('web-push');

const FILELOG = 'filelog.txt';
const FILEEVENTS = 'logevents.txt';
const FILEMANAGERS = 'logmanagers.txt';
const FILENAVE = 'logNave.txt';
const subject = process.env.URLBASE_APP1;
const publicVapidKey = process.env.PUBLIC_VAPI_KEY;
const privateVapidKey = process.env.PRIVATE_VAPI_KEY;

const FIELDS_REGEX = ['username', 'name', 'surname'];

// Code goes here
const keySize = 256;
const ivSize = 128;
const iterations = 100;

if (process.env.GCM_API_KEY !== "")
  webpush.setGCMAPIKey(process.env.GCM_API_KEY);

webpush.setVapidDetails(subject, publicVapidKey, privateVapidKey);
// console.log('setVapidDetails... config...');


// To Translate!
textlang = {
  it: {
    "L'Email è già stata Verificata": "L'Email è già stata Verificata",
    "Nuova Registrazione": "Nuova Registrazione",
    "Effettuata una Nuova Registrazione": "Effettuata una Nuova Registrazione",
    "partecipanti": "partecipanti",
    'TESTO_ASSISTENZA': "<strong><a href=\"%s\">👉 Per entrare nel Sito AYNI</a></strong>\n\n" +
    "👉 <strong><a href=\"https://ayni.gifteconomy.app/requestresetpwd\">Hai dimenticato la password?</a></strong>\n\n" +
    "👉 <strong>Chat AYNI - EMPOWER</strong>: Entra ⛩ nella nostra Community chat\n%s\n\n" +
    "👉 Canale News e Informazioni <strong><a href=\"%s\">AYNI-BIBLIO</a></strong>\n\n" +
    "👉 <strong>PER AIUTO</strong>: Leggi le Domande più Frequenti:\n%s\n\n" +
    "Chat di Supporto <strong>'AYNI - HELP'</strong>\n<strong>Da Lunedì al Sabato (8:00 - 20:00)</strong>\n%s\n" +
    "1 - Fai la tua <strong>domanda</strong> e chiedi assistenza.\n2 - Dopo aver ricevuto aiuto <strong>Esci dalla chat</strong>.\nPotrai rientrare ogni qualvolta ne avrai la necessità.",
    'BENVENUTO': "Benvenuto",
    'TUE_NAVI': "Ecco le tue Navi programmate",
    'HAI_I_7_REQUISITI': 'PRIMI PASSI OK!\nHai i Primi 7 Requisiti per Entrare nella Lista d\'Imbarco!',
    'NON_HAI_I_7_REQUISITI': 'Attenzione!\nAncora non hai i 7 Requisiti per Entrare nella Lista d\'Imbarco!',
    'HAI_I_9_REQUISITI': 'COMPLIMENTI!\nHai Completato TUTTI i 9 Passi della Guida! Grazie per Aiutare AYNI ad Espandersi!',
    'NON_HAI_I_9_REQUISITI': 'Ricqorda che puoi Aiutare a far Crescere ed Espandere il Movimento, Condividendo con chiunque questo nostro viaggio!',
    'INFO_LA_MIA_LAVAGNA': '✨ Lista dei Passi: ✨ \n',
    'INFO_LAVAGNA_SITO_COMPLETARE': 'Per completare tutti i requisiti vai sul sito:\n%s\nPer vedere lo stato della tua Nave e dei tuoi invitati, clicca sulle 3 linee in alto a sinistra ed accedi alla voce "Lavagna".\n',
    'INFO_LAVAGNA_SITO': 'Per vedere in dettaglio lo stato della tua Nave, sul sito AYNI, clicca sulle 3 linee in alto a sinistra ed accedi alla voce "Lavagna".\n',
    'INFO_LINK_DA_CONDIVIDERE': 'Link da condividere ai tuoi invitati per farli registrare al sito di Ayni:\n\n%s',
    'INFO_LINK_ZOOM': 'Link da condividere per partecipare allo Zoom (Conferenza OnLine):\n%s',
    'ZOOM_CONFERENCE': 'Ecco il programma delle Conferenze (Zoom) aperti a TUTTI:',
    "NON_VERIF": "Non Verificata",
    "VERIF": "Verificata",
    'EMAIL': "Email",
    'BOT': "AYNI BOT",
    'EMAIL_NON_VERIF': "Email Non Verificata\nleggi la tua casella email e trova **\"Confermare la Registrazione a Ayni\"**\ne clicca sul bottone **\"Verifica Registrazione\"**",
    'TELEGRAM_NOT_CONNECTED': "Telegram non associato al tuo account!",
    'NESSUN_INVITATO': 'Non hai invitato nessuno',
    'ZOOM_PARTECIPATO': 'Partecipazione ad almeno 1 Conferenza (Zoom)',
    'LINEE_GUIDA': 'Accettato le Linee Guida',
    'VIDEO_INTRO': 'Visto il Video di AYNI',
    'SCRITTO_SOGNO': 'Hai scritto il tuo Sogno',
    'PAYMENTS': 'Modalità di Pagamento (Obbligatorio Paypal)',
    'INVITATI': 'persone registrate che hai invitato',
    'INVITATI_ATTIVI': 'Invitati con i 7 Requisiti',
    'NONREG': 'Invitati non Registrati',
    'CLICCA_PER_ZOOM': 'AL GIORNO E ORA INDICATA, PER ENTRARE NELLA VIDEO-CONFERENZA, CLICCA QUI',
    'CLICCA_ENTRA': 'CLICCA QUI PER ENTRARE !',
    'ZOOM_INIZIATO': 'QUESTA CONFERENZA E\' INIZIATA!',
    'SCEGLI_VOCE': 'scegli una voce:',
    'INVITATI_LISTA': 'I Tuoi Invitati (in verde con almeno i primi 7 Requisiti)',
    'CIAO': 'Ciao',
    'ADDED_TOLISTAINGRESSO': '<strong>Complimenti ! Hai completato i 7 Passi!🎊</strong>\nSei stato aggiunto alla Lista delle persone che entreranno nella Lista D\'Imbarco !\nNei prossimi giorni riceverai un messaggio quando la tua Nave partirà.',
    'NO_PROG': 'Attualmente non sei ancora dentro alla Lista d\'Imbarco!',
    'SEND_LINK_CHAT_DONATORI': 'Ciao %s!\nLa tua NAVE sta finalmente Salpando!\nEntra nella Gift Chat della nave {%s} cliccando qui: %s',
    'SEND_LINK_CHAT_SOGNATORE': 'Ciao %s!\nOggi Diventi Sognatore !!! 🎊🎊🎊 Entra nella Gift Chat della nave {%s} cliccando qui: %s',
    'ENTRA_GIFT_CHAT': 'Entra nella Gift Chat',
    'DATA_PART_NAVE': 'data di Partenza della Nave:',
    'SOGNATORE': 'SOGNATORE',
    'MEDIATORE': 'MEDIATORE',
    'DONATORI': 'DONATORI',
    'RITESSITURA': 'RITESSITURA',
    'NAVE COMPLETATA': 'NAVE COMPLETATA',
    'Doni Effettuati': 'Doni Effettuati',
    'Tutor che affianchèra il Mediatore': 'Tutor che affianchèra il Mediatore',
    'Giorno di Apertura GIFT CHAT': 'Giorno di Apertura GIFT CHAT',
    'Giorno in cui Inviare il DONO': 'Hai 4 giorni di tempo per inviare il tuo dono. Giorno di Chiusura:',
    'SPOSTATO': 'Sei stato Spostato in una Nuova Nave !',
    'Note': 'Note',
    'TEMPORANEA': 'TEMPORANEA',
    'NAVE': 'NAVE',
    'MSG_SEND_FROM': 'Msg Inviato da',
  },
  si: {
    "Email je že bila preverjena": "Email je že bila preverjenaL'Email è già stata Verificata",
    "Nuova Registrazione": "Nova Registracija",
    "Effettuata una Nuova Registrazione": "Izpelji novo Registracijo",
    "partecipanti": "Udeleženci",
    'TESTO_ASSISTENZA': "Za vstop na spletno stran:\n%s\n\n" +
    "Si pozabil geslo za vstop na stran?\nhttps://ayni.gifteconomy.app/requestresetpwd\n\n" +
    "Klepet AYNI BOT (questa):\nhttps://t.me/notevoleaynibot\n\n" +
    "Klepet AYNI - EMPOWER: Vstopi ⛩ v našo Skupnost klepet:\n%s\n\n" +
    "Canal News AYNI-BIBLIO:\n%s\n\n" +
    "Klepet za Pomoč in Suport: 'AYNI - HELP'\n%s\n" +
    "1 - Postavi svoje vprašanje in prosi za asistenco.\n2 - KO si sprejel pomoč, izstopi iz klepeta.\n " +
    "Vstopil boš lahko vedno, ko boš potreboval pomoč.",
    'BENVENUTO': "Dobrodošel",
    'TUE_NAVI': "Tvoje programirane Ladje",
    'HAI_I_7_REQUISITI': 'PRVI KORAKI OK!\nIzpolnjuješ Prvih 7 Zahtev za vstop na Listo d\'Vkrcanje!',
    'NON_HAI_I_7_REQUISITI': 'Pozor!\nŠe vedno nimaš izpolnjenih 7 Zahtev za vstop na listo\'Vkrcanje!',
    'HAI_I_9_REQUISITI': 'ČESTITAMO!\nIzpolnil si VSEH 9 korakov v navodilih! Hvala ker pomagaš k širitvi AYNI !',
    'NON_HAI_I_9_REQUISITI': 'Zapomni si, če želiš Pomagati Rasti in Širit Gibanje, lahko to storiš z delitvijo med ljudmi!',
    'INFO_LA_MIA_LAVAGNA': '✨ Seznam Krajev: ✨ \n',
    'INFO_LAVAGNA_SITO_COMPLETARE': 'Da izpolneš vse zahteve, pojdi na spletno stran:\n%s\nDa pogledaš status svoje Ladje in status svojih povabljencev, klikni na levi strani zgoraj na tri črte in izberi "Tabla".\n',
    'INFO_LAVAGNA_SITO': 'Da lahko podrobno pogledaš status svoje Ladje,na spletni strani AYNI, klikni, na levi strani zgoraj, na tri črtice in izberi "Tabla".\n',
    'INFO_LINK_DA_CONDIVIDERE': 'Link, ki ga deliš svojim povabljencem, da se lahko registrirajo na spletni strani Ayni:\n\n%s',
    'INFO_LINK_ZOOM': 'Link, ki ga deliš za udeležbo na Zoom (Konferenca OnLine):\n%s',
    'ZOOM_CONFERENCE': 'Tu najdeš datume prihajajočih Zoom-ov:',
    "NON_VERIF": "Ni Preverjena",
    "VERIF": "Preverjena",
    'EMAIL': "Email",
    'BOT': "AYNI BOT",
    'EMAIL_NON_VERIF': "Email ni preverjen\npojdi v svoj poštni nabiralnik in najdi**\"Potrditev Registracije na Ayni\"**<br>e klikni na gumb **\"Potrdi Registracijo\"**",
    'TELEGRAM_NOT_CONNECTED': "Telegram ni povezan s tvojim računom!",
    'NESSUN_INVITATO': 'Nisi povabil nikogar',
    'ZOOM_PARTECIPATO': 'Udeležba na vsaj 1 Konferenci (Zoom-u)',
    'LINEE_GUIDA': 'Sprejemam pogoje poslovanja',
    'VIDEO_INTRO': 'Pogledal sem video AYNI',
    'SCRITTO_SOGNO': 'Sem zapisal Sanje',
    'PAYMENTS': 'Načini Plačila (Obvezen Paypal)',
    'INVITATI': 'registrirane osebe, ki si povabil',
    'INVITATI_ATTIVI': 'Povabljenci s 7 Zahtevami',
    'NONREG': 'Neregistrirani povabljenci',
    'CLICCA_PER_ZOOM': 'NA DOLOČENO URO IN DATUM, ZA VSTOP V VIDEO KONFERENCO,KLIKNI TU',
    'CLICCA_ENTRA': 'KLIKNI TU ZA VSTOP !',
    'ZOOM_INIZIATO': 'TA KONFERENCA JE\' PRIČELA!',
    'SCEGLI_VOCE': 'Izberi eno možnost:',
    'INVITATI_LISTA': 'Tvoji povabljenci (v zelenem, s izpolnjenimi vsaj 7-imi zahtevami)',
    'CIAO': 'Zdravo',
    'ADDED_TOLISTAINGRESSO': 'Si bil dodan na Seznam oseb, ki bodo vstopile v Listo D\'Vkrcanje !',
    'NO_PROG': 'Trenutno še nisi na Listi d\'Vkrcanja!',
    'SEND_LINK_CHAT_DONATORI': 'Zdravo %s!\nTvoja LADJA bo končno Izplula!\nVstopi v Darilni (Gift) klepet s klikom tu: %s',
    'SEND_LINK_CHAT_SOGNATORE': 'Zdravo %s!\nDanes Postajaš Sanjač !!! 🎊🎊🎊 Vstopi v Darilni Klepet  {%s} s klikom tu: %s',
    'ENTRA_GIFT_CHAT': 'Vstopi v Darilni Klepet',
    'DATA_PART_NAVE': 'Datum odhoda ladje:',
    'SOGNATORE': 'Sanjača',
    'MEDIATORE': 'MEDIATOR',
    'DONATORI': 'DONATOR',
    'RITESSITURA': 'Avtomatičen Vpis',
    'NAVE COMPLETATA': 'LADJE DOSTAVLJEN',
    'Doni Effettuati': 'Darila narejena',
    'Tutor che affianchèra il Mediatore': 'Tutor, ki bo podpiral Mediatorja',
    'Giorno di Apertura GIFT CHAT': 'Dan odpiranja GIFT CHAT',
    'Giorno in cui Inviare il DONO': 'Dan za pošiljanje DARILA',
    'SPOSTATO': 'Prestavljen si v Novo Ladjico !',
    'Note': 'Opombe',
    'TEMPORANEA': 'ZAČASNA',
    'NAVE': 'LADJE',
    'MSG_SEND_FROM': 'sporočilo, ki ga je poslal',
  },
  es: {
    "L'Email è già stata Verificata": "El correo electrónico ya ha sido verificado",
    "Nuova Registrazione": "Nuevo Registro",
    "Effettuata una Nuova Registrazione": "Se ha realizado un nuevo registro",
    "partecipanti": "participantes",
    'TESTO_ASSISTENZA': "Para entrar en el sitio de AYNI:\n%s\n\n" +
    "¿Olvidó su contraseña para acceder al sitio?\nhttps://ayni.gifteconomy.app/requestresetpwd\n\n" +
    "Chat AYNI BOT (este):\nhttps://t.me/notevoleaynibot\n\n" +
    "Chat AYNI - EMPOWER: Entra en ⛩ en nuestra comunidad de chat:\n%s\n\n" +
    "Chat de ayuda y soporte: 'AYNI - HELP'\nDe lunes a sábado (8:00 - 21:00)\n%s\n" +
    "1 - Haga su pregunta y pida ayuda.\n2 - Después de que consigas ayuda, sal de la sala de chat.\nPuedes volver cuando necesites ayuda..",
    'BENVENUTO': "Bienvenido",
    'TUE_NAVI': "Aquí están sus naves programadas",
    'HAI_I_7_REQUISITI': '¡LOS PRIMEROS PASOS ESTÁN BIEN!\nTiene los primeros 7 requisitos para entrar en la lista de embarque!',
    'NON_HAI_I_7_REQUISITI': '¡Atención!\nTodavía no tienes los 7 requisitos para entrar en la lista de embarque!',
    'HAI_I_9_REQUISITI': '¡FELICITACIONES!\n¡Has completado los 9 pasos de la Guía! Gracias por ayudar a AYNI a expandirse!',
    'NON_HAI_I_9_REQUISITI': 'Recuerda que puedes ayudar a que el Movimiento crezca y se expanda compartiendo nuestro viaje con todos.!',
    'INFO_LA_MIA_LAVAGNA': '✨ Lista de pasos: ✨ \n',
    'INFO_LAVAGNA_SITO_COMPLETARE': 'Para completar todos los requisitos vaya al sitio:\n%s\nPara ver el estado de su nave y sus invitados, haga clic en las 3 líneas de arriba a la izquierda y vaya a "Pizarra".\n',
    'INFO_LAVAGNA_SITO': 'Para ver en detalle el estado de su nave, en el sitio web de AYNI, haga clic en las 3 líneas de la parte superior izquierda y vaya a "Pizarra"..\n',
    'INFO_LINK_DA_CONDIVIDERE': 'Enlaces para compartir con sus invitados para que se registren en el sitio web de Ayni:\n\n%s',
    'INFO_LINK_ZOOM': 'Enlaces para compartir para participar en el Zoom (Conferencia en línea):\n%s',
    'ZOOM_CONFERENCE': 'Aquí puedes encontrar las fechas de programación en el Zoom:',
    "NON_VERIF": "No verificado",
    "VERIF": "Verificado",
    'EMAIL': "Email",
    'BOT': "AYNI BOT",
    'EMAIL_NON_VERIF': "Correo electrónico no verificado\nlea su buzón y encuentre **\"Confirmar Registro a Ayni \"** <marca>y haga clic en el botón **\"Verificar Registro \"**.",
    'TELEGRAM_NOT_CONNECTED': "Telegram no asociado a su cuenta!",
    'NESSUN_INVITATO': 'No invitaste a nadie',
    'ZOOM_PARTECIPATO': 'Participación en al menos 1 Conferencia (Zoom)',
    'LINEE_GUIDA': 'Directrices aceptadas',
    'VIDEO_INTRO': 'Ver el video de AYNI',
    'SCRITTO_SOGNO': 'Escribiste tu sueño',
    'PAYMENTS': 'Métodos de pago (Paypal obligatorio)',
    'INVITATI': 'las personas registradas que usted invitó',
    'INVITATI_ATTIVI': 'Invitado con los 7 requisitos',
    'NONREG': 'Invitados no registrados',
    'CLICCA_PER_ZOOM': 'AL DÍA Y HORA INDICADOS, PARA ENTRAR EN LA VIDEOCONFERENCIA, PULSE AQUÍ',
    'CLICCA_ENTRA': 'HAGA CLIC AQUÍ PARA ENTRAR !',
    'ZOOM_INIZIATO': 'ESTA CONFERENCIA HA COMENZADO!',
    'SCEGLI_VOCE': 'elegir una voz:',
    'INVITATI_LISTA': 'Sus invitados (en verde con al menos los 7 primeros requisitos)',
    'CIAO': 'Hola',
    'ADDED_TOLISTAINGRESSO': 'Has sido añadido a la lista de personas que entrarán en Lista de embarque!',
    'NO_PROG': 'Actualmente no está en la lista de embarque.!',
    'SEND_LINK_CHAT_DONATORI': 'Hola %s!\n¡Tu barco por fin está navegando!\nEntra en el Gift Chat haciendo clic aquí: %s',
    'SEND_LINK_CHAT_SOGNATORE': '¡Hola!\n¡Hoy te conviertes en un soñador! 🎊🎊🎊 Entre en el Chat de Regalos de la nave {%s} haciendo clic aquí: %s',
    'ENTRA_GIFT_CHAT': 'Entre en el Chat de Regalos',
    'DATA_PART_NAVE': 'fecha de salida de la nave:',
    'SOGNATORE': 'SOÑADOR',
    'MEDIATORE': 'MEDIATOR',
    'DONATORI': 'DONANTES',
    'RITESSITURA': 'RETEJIDO',
    'NAVE COMPLETATA': 'NAVE COMPLETADA',
    'Doni Effettuati': 'Regalos Realizados',
    'Tutor che affianchèra il Mediatore': 'Tutor de apoyo al Donante',
    'Giorno di Apertura GIFT CHAT': 'Día de apertura GIFT CHAT',
    'Giorno in cui Inviare il DONO': 'Día en el que enviar el REGALO',
    'SPOSTATO': 'Has sido trasladado a una nueva nave !',
    'Note': 'Notas',
    'TEMPORANEA': 'TEMPORAL',
    'NAVE': 'NAVE',
    'MSG_SEND_FROM': 'Mensaje enviado por',
  },
  enUs: {
    "partecipanti": "participants",
    'TESTO_ASSISTENZA': "To enter the AYNI Site:\n%s\n\nForgot your password to access the site?\n" +
    "https://ayni.gifteconomy.app/requestresetpwd\nChat AYNI BOT (this one):\nhttps://t.me/notevoleaynibot\n\n" +
    "Chat AYNI - EMPOWER: Enter ⛩ into our chat community:\n%s\n\n" +
    "Canale News AYNI-BIBLIO:\n%s\n\n" +
    "Help and Support Chat: 'AYNI - HELP'.\nMonday to Saturday (8:00 - 20:00)\n%s\n" +
    "1 - Ask your question and ask for assistance.\n2 - After receiving help, exit the chat.\nYou can come back whenever you need help.",
    'BENVENUTO': "Welcome",
    'TUE_NAVI': "Here are your programmed ships",
    'HAI_I_7_REQUISITI': 'FIRST STEPS OK!\nYou have the First 7 Requirements to Enter the Boarding List!',
    'NON_HAI_I_7_REQUISITI': 'Attention!\nYou still do not have the 7 requirements to enter the boarding list!',
    'HAI_I_9_REQUISITI': 'CONGRATULATIONS!\nYou have completed ALL 9 steps of the Guide! Thank you for Helping AYNI Expand!',
    'NON_HAI_I_9_REQUISITI': 'Remember that you can help the Movement grow and expand by sharing our journey with everyone.!',
    'INFO_LA_MIA_LAVAGNA': '✨ Step List: ✨ \n',
    'INFO_LAVAGNA_SITO_COMPLETARE': 'To complete all the requirements go to the site:%s\nTo see the status of your Ship and your guests, click on the 3 lines at the top left and go to "Dashboard"\n',
    'INFO_LAVAGNA_SITO': 'To see in detail the status of your ship, on the AYNI website, click on the 3 lines at the top left and go to "Blackboard".\n',
    'INFO_LINK_DA_CONDIVIDERE': 'Links to share with your guests to have them register on Ayni\'s website:\n\n%s',
    'INFO_LINK_ZOOM': 'Links to share to participate in Zoom (Online Conference):\n%s',
    'ZOOM_CONFERENCE': 'Here you can find the Zoom Conference Planning:',
    "NON_VERIF": "Not Verified",
    "VERIF": "Verified",
    'EMAIL': "Email",
    'BOT': "AYNI BOT",
    'EMAIL_NON_VERIF': "Email Not Verified\nread your mailbox and find **\"Confirm Registration to Ayni \"**<br>and click on the button **\"Verify Registration \"**.",
    'TELEGRAM_NOT_CONNECTED': "Telegram not associated with your account!",
    'NESSUN_INVITATO': 'You didn\'t invite anyone',
    'ZOOM_PARTECIPATO': 'Participation in at least 1 Conference (Zoom)',
    'LINEE_GUIDA': 'Guidelines Accepted',
    'VIDEO_INTRO': 'Seen the AYNI Video',
    'SCRITTO_SOGNO': 'You wrote your Dream',
    'PAYMENTS': 'Methods of Payment (Mandatory Paypal)',
    'INVITATI': 'registered people you invited',
    'INVITATI_ATTIVI': 'Guests with the 7 Requirements',
    'NONREG': 'Non-registered Guests',
    'CLICCA_PER_ZOOM': 'TO THE DAY AND TIME INDICATED, TO ENTER THE VIDEO-CONFERENCE, CLICK HERE',
    'CLICCA_ENTRA': 'CLICK HERE TO ENTER !',
    'ZOOM_INIZIATO': 'THIS CONFERENCE HAS BEGUN!',
    'SCEGLI_VOCE': 'choose a menu item:',
    'INVITATI_LISTA': 'Your Guests (in green with at least the first 7 requirements)',
    'CIAO': 'Hi',
    'ADDED_TOLISTAINGRESSO': 'You have been added to the List of people who will enter the Boarding List!',
    'NO_PROG': 'You are not currently on the boarding list.!',
    'SEND_LINK_CHAT_DONATORI': 'Hi %s!\nYour ship is finally sailing!\nEnter the Gift Chat by clicking here: %s',
    'SEND_LINK_CHAT_SOGNATORE': 'Hello %s!\nToday you become a Dreamer! 🎊🎊🎊 Enter the ship\'s Gift Chat {%s} by clicking here: %s',
    'ENTRA_GIFT_CHAT': 'Enter the ship\'s Gift Chat',
    'DATA_PART_NAVE': 'date of departure of the ship:',
    'SOGNATORE': 'DREAMER',
    'MEDIATORE': 'MEDIATOR',
    'DONATORI': 'DONOR',
    'RITESSITURA': 'RE-ENTER',
    'NAVE COMPLETATA': 'SHIP COMPLETED',
    'Doni Effettuati': 'Gifts Made',
    'Tutor che affianchèra il Mediatore': 'Tutor supporting the Mediator',
    'Giorno di Apertura GIFT CHAT': 'Opening Day GIFT CHAT',
    'Giorno in cui Inviare il DONO': 'Day on which to send the Gift',
    'SPOSTATO': 'You\'ve been moved to a New Ship !',
    'Note': 'Note',
    'TEMPORANEA': 'TEMPORARY',
    'NAVE': 'SHIP',
    'MSG_SEND_FROM': 'Msg sent by',
  },
  fr: {
    "L'Email è già stata Verificata": "Le courrier électronique a déjà été vérifié",
    "Nuova Registrazione": "Nouvelle inscription",
    "Effettuata una Nuova Registrazione": "Un nouvel enregistrement a été effectué",
    "partecipanti": "participants",
    'TESTO_ASSISTENZA': "Pour entrer sur le site AYNI:\n%s\n\n" +
    "Vous avez oublié votre mot de passe pour accéder au site ?\nhttps://ayni.gifteconomy.app/requestresetpwd\n\n" +
    "Chat AYNI BOT (ce):\nhttps://t.me/notevoleaynibot\n\n" +
    "Chat AYNI - EMPOWER : Entrez ⛩ dans notre Community chat:\n%s\n\n" +
    "Canale News AYNI-BIBLIO:\n%s\n\n" +
    "Chat d’Aide et de Support: 'AYNI - HELP'\nDu lundi au samedi (8:00 - 20:00)\n%s\n" +
    "1 - Posez votre question et demandez d’être assisté.\n2 -  Après avoir reçu l’aide, quittez le groupe.\nVous pourrez y entrer chaque fois qu’il vous sera nécessaire.",
    'BENVENUTO': "Bienvenue",
    'TUE_NAVI': "Voici vos navires programmés",
    'HAI_I_7_REQUISITI': 'PREMIÈRES ÉTAPES OK!\nvous avez les 7 premiers Requis pour Entrer dans la liste d\'embarquement!',
    'NON_HAI_I_7_REQUISITI': '\'Attention!\nVous ne remplissez pas encore les 7 conditions pour figurer sur la liste d\'embarquement!',
    'HAI_I_9_REQUISITI': 'FÉLICITATIONS!\n!Vous avez franchi les 9 étapes de la conduite ! Merci d\'avoir aidé AYNI à se développer!',
    'NON_HAI_I_9_REQUISITI': 'N\'oubliez pas que vous pouvez aider le Mouvement à grandir et à se développer en partageant notre voyage avec tout le monde.!',
    'INFO_LA_MIA_LAVAGNA': '✨ Liste des étapes: ✨ \n',
    'INFO_LAVAGNA_SITO_COMPLETARE': 'Pour remplir toutes les conditions, rendez-vous sur le site:\n%s\nPour voir le statut de votre navire et de vos invités, cliquez sur les 3 lignes en haut à gauche et allez sur "Tableau noir".\n',
    'INFO_LAVAGNA_SITO': 'Pour voir en détail le statut de votre navire, sur le site de l\'AYNI, cliquez sur les 3 lignes en haut à gauche et allez sur "Tableau noir".\n',
    'INFO_LINK_DA_CONDIVIDERE': 'Liens à partager avec vos invités pour qu\'ils s\'inscrivent sur le site web d\'Ayni:\n\n%s',
    'INFO_LINK_ZOOM': 'Liens à partager pour participer à Zoom (Conférence en ligne):\n%s',
    'ZOOM_CONFERENCE': 'Vous trouverez ici les dates de programmation sur Zoom:',
    "NON_VERIF": "Non vérifié",
    "VERIF": "Vérifié",
    'EMAIL': "Courriel",
    'BOT': "AYNI BOT",
    'EMAIL_NON_VERIF': "Courriel non vérifié\nlisez votre boîte aux lettres et trouvez **\"Confirmer l'inscription à Ayni \"**<br>et cliquez sur le bouton **\"Vérifier l'inscription \"**.",
    'TELEGRAM_NOT_CONNECTED': "Télégramme non associé à votre compte!",
    'NESSUN_INVITATO': 'Vous n\'avez invité personne',
    'ZOOM_PARTECIPATO': 'Participation à au moins 1 conférence (Zoom)',
    'LINEE_GUIDA': 'Lignes directrices acceptées',
    'VIDEO_INTRO': 'Voir la vidéo AYNI',
    'SCRITTO_SOGNO': 'Vous avez écrit votre rêve',
    'PAYMENTS': 'Modes de paiement (Paypal obligatoire)',
    'INVITATI': 'personnes inscrites que vous avez invitées',
    'INVITATI_ATTIVI': 'Invité avec les 7 exigences',
    'NONREG': 'Invités non enregistrés',
    'CLICCA_PER_ZOOM': 'AU JOUR ET À L\'HEURE INDIQUÉS, POUR ENTRER DANS LA VIDÉOCONFÉRENCE, CLIQUEZ ICI',
    'CLICCA_ENTRA': 'CLIQUEZ ICI POUR ENTRER !',
    'ZOOM_INIZIATO': 'CETTE CONFÉRENCE A COMMENCÉ!',
    'SCEGLI_VOCE': 'choisir une voix:',
    'INVITATI_LISTA': 'Vos invités (en vert avec au moins les 7 premières exigences)',
    'CIAO': 'Salut',
    'ADDED_TOLISTAINGRESSO': 'Vous avez été ajouté à la liste d\'embarquement !',
    'NO_PROG': 'Vous n\'êtes pas encore sur la liste d\'embarquement.!',
    'SEND_LINK_CHAT_DONATORI': 'Salut %s!\nVotre SHIP prend enfin la mer.!\nEntrez dans le Chat Cadeau en cliquant ici: %s',
    'SEND_LINK_CHAT_SOGNATORE': 'Bonjour %s !\nAujourd\'hui, vous devenez un Rêveur ! 🎊🎊🎊 Entrez dans le chat des cadeaux du navire {%s} en cliquant ici : %s',
    'ENTRA_GIFT_CHAT': 'Entrez dans le chat des cadeaux',
    'DATA_PART_NAVE': 'la date de départ du navire:',
    'SOGNATORE': 'Rêveur',
    'MEDIATORE': 'Médiateur',
    'DONATORI': 'DONATEUR',
    'RITESSITURA': 'RETESSITURA',
    'NAVE COMPLETATA': 'NAVIRE COMPLÉTÉ',
    'Doni Effettuati': 'Don effectués',
    'Tutor che affianchèra il Mediatore': 'Le tuteur qui soutient le Mediateur',
    'Giorno di Apertura GIFT CHAT': 'Jour d\'ouverture GIFT CHAT',
    'Giorno in cui Inviare il DONO': 'Envoyer le jour il DONO',
    'SPOSTATO': 'Vous avez été transféré sur un nouveau navire !',
    'Note': 'Notes',
    'TEMPORANEA': 'TEMPORAIRE',
    'NAVE': 'NAVIRE',
    'MSG_SEND_FROM': 'Message envoyé par',
  },
  pt: {
    "L'Email è già stata Verificata": "",
    "Nuova Registrazione": "Novo Registo",
    "Effettuata una Nuova Registrazione": "Foi efectuado um novo registo",
    "partecipanti": "participantes",
    'TESTO_ASSISTENZA': "Para entrar no site do AYNI:\n%s\n\n" +
    "Esqueceu sua senha para acessar o site?\nhttps://ayni.gifteconomy.app/requestresetpwd\n\n" +
    "Chat AYNI BOT (isto):\nhttps://t.me/notevoleaynibot\n\n" +
    "Chat AYNI - EMPOWER: Entrar em ⛩ na nossa comunidade de chat:%s\n\n" +
    "Canale News AYNI-BIBLIO:\n%s\n\n" +
    "Chat de Ajuda e Suporte: 'AYNI - HELP'.\nDe segunda a sábado (8:00 - 20:00 ITALY)\n%s\n" +
    "1 - Faça a sua pergunta e peça ajuda.\n2 - Depois de receber ajuda, saia do chat.\nPode voltar sempre que precisar de o fazer..",
    'BENVENUTO': "Bem-vindo",
    'TUE_NAVI': "Aqui estão os seus navios programados",
    'HAI_I_7_REQUISITI': 'PRIMEIROS PASSOS OK!\nVocê tem os 7 primeiros requisitos para entrar na lista de embarque!',
    'NON_HAI_I_7_REQUISITI': 'Atenção!\nVocê ainda não tem os 7 requisitos para entrar na lista de embarque!',
    'HAI_I_9_REQUISITI': 'FELICITAÇÕES!\nVocê completou TODAS as 9 etapas da condução! Obrigado por ajudar a AYNI a expandir!',
    'NON_HAI_I_9_REQUISITI': 'Lembre-se que pode ajudar o Movimento a crescer e expandir-se, partilhando a nossa jornada com todos!',
    'INFO_LA_MIA_LAVAGNA': '✨ Lista de etapas: ✨ \n',
    'INFO_LAVAGNA_SITO_COMPLETARE': 'Para completar todos os requisitos ir para o sitio:\n%s\nPer vedere lo stato della tua Nave e dei tuoi invitati, clicca sulle 3 linee in alto a sinistra ed accedi alla voce "Lavagna".\n',
    'INFO_LAVAGNA_SITO': 'Para ver em detalhe o estado do seu navio, no site da AYNI, clique nas 3 linhas no canto superior esquerdo e vá para "DashBoard"..\n',
    'INFO_LINK_DA_CONDIVIDERE': 'Links para partilhar com os seus convidados para que se registem no website da Ayni:\n\n%s',
    'INFO_LINK_ZOOM': 'Links para partilhar para participar na Zoom (Conferência Online):\n%s',
    'ZOOM_CONFERENCE': 'Aqui está o programa das Conferências (Zoom) aberto a TODOS:',
    "NON_VERIF": "Não verificado",
    "VERIF": "Verificado",
    'EMAIL': "Email",
    'BOT': "AYNI BOT",
    'EMAIL_NON_VERIF': "Email Não verificado\nleia a sua caixa de correio e encontre **\"Confirmar o registo à Ayni\"**<br>e clique no botão **\"Verificação do registo\"**",
    'TELEGRAM_NOT_CONNECTED': "Telegrama não associado à sua conta!",
    'NESSUN_INVITATO': 'Você não convidou ninguém',
    'ZOOM_PARTECIPATO': 'Participação em pelo menos 1 Conferência (Zoom)',
    'LINEE_GUIDA': 'Directrizes Aceites',
    'VIDEO_INTRO': 'Ver o vídeo do AYNI',
    'SCRITTO_SOGNO': 'Você escreveu o seu sonho',
    'PAYMENTS': 'Formas de pagamento (Obrigatório Paypal)',
    'INVITATI': 'pessoas registadas que convidou',
    'INVITATI_ATTIVI': 'Convidado com os 7 Requisitos',
    'NONREG': 'Convidados não registados',
    'CLICCA_PER_ZOOM': 'PARA O DIA E HORA INDICADOS, PARA ENTRAR NA VÍDEO-CONFERÊNCIA, CLIQUE AQUI',
    'CLICCA_ENTRA': 'CLIQUE AQUI PARA ENTRAR !',
    'ZOOM_INIZIATO': 'ESTA CONFERÊNCIA JÁ COMEÇOU!',
    'SCEGLI_VOCE': 'escolha uma voz:',
    'INVITATI_LISTA': 'Os seus convidados (em verde com, pelo menos, os 7 primeiros requisitos)',
    'CIAO': 'Olá',
    'ADDED_TOLISTAINGRESSO': 'Foi acrescentado à Lista de Embarque !',
    'NO_PROG': 'Actualmente, ainda não consta da lista de embarque.!',
    'SEND_LINK_CHAT_DONATORI': 'Olà %s!\nO seu SHIP está finalmente a zarpar.!\nEntre no Gift Chat, clicando aqui: %s',
    'SEND_LINK_CHAT_SOGNATORE': 'Olá %s!\nHoje você se torna um sonhador! 🎊🎊🎊 Entre no Gift Chat do navio {%s} clicando aqui: %s',
    'ENTRA_GIFT_CHAT': 'Entre no Gift Chat do navio',
    'DATA_PART_NAVE': 'data de partida do navio:',
    'SOGNATORE': 'SONHEIROS',
    'MEDIATORE': 'MEDIATOR',
    'DONATORI': 'DONATORES',
    'RITESSITURA': 'ENTRE EM',
    'NAVE COMPLETATA': 'NAVIO COMPLETADO',
    'Doni Effettuati': 'Regalo Feitos',
    'Tutor che affianchèra il Mediatore': 'Tutor que apoia o Mediator',
    'Giorno di Apertura GIFT CHAT': 'Dia de Abertura GIFT CHAT',
    'Giorno in cui Inviare il DONO': 'Dia em que enviar o REGALO',
    'SPOSTATO': 'Você foi transferido para um novo navio !',
    'Note': 'Notas',
    'TEMPORANEA': 'TEMPORÁRIO',
    'NAVE': 'NAVE',
    'MSG_SEND_FROM': 'Mensagem enviada por',
  },
};


module.exports = {
  INITDB_FIRSTIME: true,
  ACAPO: '\n',

  LANGADMIN: 'it',

  AYNI: '7',
  SIP: '9',

  APORTADOR_NONE: '------',

  TYPE_PROJECT: 1,
  TYPE_TODO: 2,

  TipoMsg: {
    SEND_LINK_CHAT_DONATORI: 1,
    SEND_MSG: 2,
    SEND_MSG_SINGOLO: 3,
    SEND_TO_ALL: 10,
  },

  Placca: {
    DONATORI: 1,
    TUTTI: 2,

    STR_SOGNATORE: 'Sognatore',
    STR_MEDIATORE: 'Mediatore',
    STR_MEDIATORI: 'Mediatori',
    STR_DONATORI: 'Donatori',
    SOGNATORE: 'E1 🌈 ',
    MEDIATORE: 'A1 💦 ',
    SONOFUOCO: 0,
    SONOACQUA: 3,
    SONOTERRA: 2,
    SONOARIA: 1,
  },

  FieldType: {
    boolean: 1,
    date: 2,
    string: 4,
    binary: 8,
    html: 16,
    select: 32,
    number: 64,
    typeinrec: 128,
    multiselect: 256,
    password: 512,
    listimages: 1024,
    exact: 2048,
  },

  MAX_PHASES: 5,
  FIRST_PROJ: '__PROJECTS',
  EXECUTE_CALCPROJ: true,

  gettranslate(text, lang) {
    try {
      return textlang[lang][text]
    } catch (e) {
      return textlang['it'][text]
    }
  },

  getlangbyres(res) {
    // ++Todo: res estrarre la lingua
    let lang = '';
    try {
      lang = res.lang
    } catch (e) {

    }
    if (!lang) {
      lang = 'it';
    }
    return lang
  },

  get__(text, lang) {
    try {
      return textlang[lang][text]
    } catch (e) {
      return textlang['it'][text]
    }
  },

  getres__(text, res) {
    let lang = this.getlangbyres(res);
    try {
      return textlang[lang][text]
    } catch (e) {
      return textlang['it'][text]
    }
  },

  getHostname: function () {
    return os.hostname()
  },
  testing: function () {
    return (process.env.TESTING_ON === '1')
  },

  mylog: function (...args) {
    if (!this.testing())
      console.log(args)
  },

  mylogoff: function (...args) {
    // doing nothing
  },

  mylogshow: function (...args) {
    console.log(args)
  },

  mylogserr: function (...args) {
    console.error(args)
  },

  allfieldSendMsg: function () {
    return ['userId', 'source', 'dest', 'message', 'datemsg', 'read', 'deleted', 'origin', 'idapp', 'status', 'options']
  },

  allfieldTodo: function () {
    return ['userId', 'pos', 'category', 'descr', 'priority', 'statustodo', 'created_at', 'modify_at',
      'completed_at', 'expiring_at', 'enableExpiring', 'id_prev', 'progress', 'modified', 'phase', 'assigned_to_userId', 'hoursplanned', 'hoursworked', 'start_date', 'themecolor', 'themebgcolor']
  },

  allfieldMyEvent: function () {
    return ['userId',]
  },

  allfieldTodoWithId: function () {
    return ['_id', ...this.allfieldTodo()]
  },

  // #TODO Projects++ Add fields ...
  allfieldProject: function () {
    return ['userId', 'pos', 'typeproj', 'id_main_project', 'id_parent', 'descr', 'longdescr', 'hoursplanned', 'hoursleft', 'themecolor', 'themebgcolor', 'hoursworked', 'priority', 'statusproj', 'created_at', 'modify_at',
      'completed_at', 'expiring_at', 'enableExpiring', 'id_prev', 'progressCalc', 'modified', 'live_url', 'test_url', 'begin_development', 'begin_test', 'totalphases', 'actualphase', 'hoursweeky_plannedtowork', 'endwork_estimate'
      , 'privacyread', 'privacywrite']
  },

  allfieldBooking: function () {
    return ['idapp', 'userId', 'id_bookedevent', 'numpeople', 'msgbooking', 'modified', 'infoevent', 'datebooked', 'booked']
  },

  allfieldBookingChange: function () {
    return ['numpeople', 'msgbooking', 'modified', 'infoevent', 'datebooked', 'booked']
  },

  allfieldProjectWithId: function () {
    return ['_id', ...this.allfieldProject()]
  },

  jsonCopy(src) {
    return JSON.parse(JSON.stringify(src))
  },

  CloneRecordToNew(src) {
    const myrec = Object.assign({}, src);
    delete myrec._doc['_id'];
    myrec._id = new ObjectID();

    return myrec._doc
  },

  sendBackNotif: function (subscription, payload) {

    console.log('sendBackNotif:', subscription, payload);
    // Pass object into sendNotification
    return webpush.sendNotification(subscription, JSON.stringify(payload))
      .catch(err => {
        if (err.statusCode === 410) {
          // Gone: is not valid anymore (Expired probably!), so I have to delete from my db
          return Subscription.findOneAndRemove({ _id: subscription._id })
        } else {
          console.log('Subscription is no longer valid: ', err);
        }
      })
      .then(ris => {
        // console.log('ris', ris)
      })
      .catch(err => console.error(err))
  },

  sendNotificationToUser: function (userId, title, content, openUrl, openUrl2, tag, actions) {

    let payload = {
      actions,
      title: title,
      content,
      url: openUrl,
      url2: openUrl2,
      tag,
      // ttl: req.body.ttl,
      // icon: req.body.icon,
      // image: req.body.image,
      // badge: req.body.badge,
      // tag: req.body.tag
    };

    return Subscription.find({ userId }, (err, subscriptions) => {
      if (err) {
        console.error(`Error occurred while getting subscriptions`);
        // res.status(500).json({
        //   error: 'Technical error occurred'
        // });

        //++ Rimuovi questo record !?

        return false;
      } else {
        let conta = 0;
        let parallelSubscriptionCalls = subscriptions.map((subscription) => {
          const trovati = subscriptions.length;
          return new Promise((resolve, reject) => {
            const pushSubscription = {
              endpoint: subscription.endpoint,
              keys: {
                p256dh: subscription.keys.p256dh,
                auth: subscription.keys.auth
              }
            };

            conta++;


            const parse = require('url-parse');
            const parsedUrl = parse(subscription.endpoint);
            const audience = parsedUrl.protocol + '//' + parsedUrl.hostname;

            const vapidHeaders = webpush.getVapidHeaders(
              audience,
              process.env.URLBASE_APP1,
              process.env.PUBLIC_VAPI_KEY,
              process.env.PRIVATE_VAPI_KEY,
              'aes128gcm'
            );

            const pushOptions = {
              vapidDetails: {
                subject: process.env.URLBASE_APP1,
                privateKey: process.env.PRIVATE_VAPI_KEY,
                publicKey: process.env.PUBLIC_VAPI_KEY,
              },
              TTL: payload.ttl,
              headers: vapidHeaders
            };

            console.log('************  INVIO WEBPUSH.SENDNOTIFICATION N° ', conta, '/', trovati, 'A', subscription.browser);
            // console.log('vapidDetails', pushOptions.vapidDetails);

            // payload.title = process.env.URLBASE_APP1 + ' Msg n° ' + conta + '/' + trovati;
            // payload.message += subscription.browser ;

            const pushPayload = JSON.stringify(payload);

            // console.log('A1) SUBS: pushSubscription', pushSubscription);
            // console.log('A2) OPZIONI: pushOptions', pushOptions);
            // console.log('A3) MSG_TO_SEND: pushPayload', pushPayload);

            webpush.sendNotification(
              pushSubscription,
              pushPayload,
              // pushOptions
            ).then((value) => {
              resolve({
                status: true,
                endpoint: subscription.endpoint,
                data: value
              });
            }).catch((err) => {
              reject({
                status: false,
                endpoint: subscription.endpoint,
                data: err
              });
            });
          }).catch(error => {
            console.log('ERROR: sendNotificationToUser', error.data.body)
          });
        });
        // q.allSettled(parallelSubscriptionCalls).then((pushResults) => {
        //   console.info(pushResults);
        // });
        // res.json({
        //   data: 'Push triggered'
        // });
        return true;
      }
    });

  },
  // **********************
  // SORT WITH PREV_ID
  // **********************
  mapSort: function (linkedList) {
    let sortedList = [];
    let remainingList = [];
    var map = new Map();
    var currentId = null;

    // console.log('linkedList', linkedList);

    // index the linked list by previous_item_id
    for (var i = 0; i < linkedList.length; i++) {
      var item = linkedList[i];
      if (item.id_prev === server_constants.LIST_START) {
        // first item
        currentId = String(item._id);
        // console.log('currentId', currentId);
        sortedList.push(item);
      } else {
        map.set(String(item.id_prev), i);
      }
    }

    let conta = 0;
    while (conta < linkedList.length) {
      // get the item with a previous item ID referencing the current item
      var nextItem = linkedList[map.get(currentId)];
      if (nextItem === undefined) {

      } else {
        sortedList.push(nextItem);
        currentId = String(nextItem._id);
      }
      conta++;
    }

    if (linkedList.length > sortedList.length) {
      // If are not in the list, I'll put at the bottom of the list
      // console.log('ATTENZIONE !!! ', sortedList.length, linkedList.length);
      for (const itemlinked of linkedList) {
        const elemtrov = sortedList.find((item) => item._id === itemlinked._id);
        if (elemtrov === undefined) {
          sortedList.push(itemlinked);
        }
      }
    }

    // console.log('DOPO sortedList', sortedList);

    return sortedList;
  },

  checkUserOk(userpassed, userauth, res) {
    this.mylog('checkUserOk', userpassed, userauth);
    if (String(userpassed) !== String(userauth)) {
      // I'm trying to write something not mine!
      this.mylog('userId = ', userpassed, 'req.user._id', userauth);
      return { exit: true, ret: res.status(404).send({ code: server_constants.RIS_CODE_TODO_CREATING_NOTMYUSER }) }
    } else {
      return { exit: false, ret: false }
    }

  },

  convertHTMLtoText(myhtml) {
    let msg = myhtml;
    msg = msg.replace('&quot;', '"');
    msg = msg.replace('&gt;', '>');
    msg = msg.replace('&lt;', '<');
    msg = msg.replace('&amp;', '&');
    msg = msg.replace('<br>', '\n');

    return msg
  },

  convertTexttoHtml(myhtml) {
    // let msg = myhtml;
    // msg = msg.replace('\n', '<br>');

    // return msg

    return myhtml;
  },

  removeSpecialCharForEmail(myhtml) {
    let msg = myhtml;
    msg = msg.replace(/"/g, '\'');

    return msg
  },

  getNomeAppByIdApp: function (idapp) {

    const myapp =
      MYAPPS.find(item => item.idapp === idapp);
    if (myapp)
      return myapp.name;
    else
      return '';
  },

  getHostByIdApp: function (idapp) {

    const myapp =
      MYAPPS.find(item => item.idapp === idapp);
    if (myapp) {
      let siteport = (myapp.portapp !== "0") ? (':' + myapp.portapp) : "";

      return myapp.host + siteport;
    } else
      return '';
  },

  isAbilitaNave: function (idapp) {
    const myapp = MYAPPS.find(item => item.idapp === idapp);
    return myapp.abilitanave;
  },

  getdirByIdApp: function (idapp) {

    const myapp =
      MYAPPS.find(item => item.idapp === idapp);
    if (myapp) {
      return myapp.dir;
    } else
      return '';
  },

  getAdminEmailByIdApp: function (idapp) {
    const myapp = MYAPPS.find((item) => item.idapp === idapp);
    if (myapp)
      return myapp.adminemail;
    else
      return '';
  },

  getreplyToEmailByIdApp: function (idapp) {
    const myapp = MYAPPS.find((item) => item.idapp === idapp);
    if (myapp)
      return myapp.replyTo;
    else
      return '';
  },

  getpathregByIdApp: function (idapp, lang) {
    const myapp = MYAPPS.find((item) => item.idapp === idapp);
    if (myapp)
      return 'registration' + myapp.pathreg_add + '/' + lang;
    else
      return '';
  },

  isManagAndAdminDifferent(idapp) {
    const manag = this.getManagerEmailByIdApp(idapp);
    return (manag !== this.getAdminEmailByIdApp(idapp)) && (manag !== '');
  },

  getManagerEmailByIdApp: function (idapp) {
    const myapp = MYAPPS.find((item) => item.idapp === idapp);
    if (myapp)
      return myapp.manageremail;
    else
      return '';
  },

  getEmailByIdApp: function (idapp) {
    const myapp = MYAPPS.find((item) => item.idapp === idapp);
    return (myapp) ? myapp.email_from : ''
  },

  getPwdByIdApp: function (idapp) {
    const myapp = MYAPPS.find((item) => item.idapp === idapp);
    return (myapp) ? this.decryptdata(myapp.email_pwd) : ''
  },

  getTelegramBotNameByIdApp: function (idapp) {
    const myapp = MYAPPS.find((item) => item.idapp === idapp);
    return (myapp) ? myapp.telegram_bot_name : ''
  },

  getTelegramKeyByIdApp: function (idapp) {
    const myapp = MYAPPS.find((item) => item.idapp === idapp);
    return (myapp) ? myapp.telegram_key : ''
  },

  getQueryTable(idapp, params) {
    // console.log('idapp', idapp);
    // console.table(params);

    if (typeof params.startRow !== 'number') {
      throw new Error('startRow must be number')
    } else if (typeof params.endRow !== 'number') {
      throw new Error('endRow must be number')
    }

    let query = [];
    if (params.filter && params.fieldsearch) {

      let myregexp = {};
      myregexp = new RegExp(params.filter.trim().replace(' ', '|'), "ig");

      const myfilters = [];
      params.fieldsearch.forEach((rec) => {
        const data = {};
        if (rec.type === this.FieldType.exact) {
          data[rec.field] = params.filter.trim();
        } else if (rec.type === this.FieldType.string) {
          data[rec.field] = myregexp;
        } else if (rec.type === this.FieldType.number) {
          data[rec.field] = parseInt(params.filter.trim());
        }
        myfilters.push(data);
      });

      query = [
        { $match: { $or: myfilters } },
      ]
    }

    let filtriadded = [];

    // if (params.table === 'extralist') {
    //   if (params.filterand.includes(shared_consts.FILTER_EXTRALIST_DELETED))
    //     filtriadded.push({ deleted: true });
    //   else
    //     filtriadded.push({ deleted: { $exists: false } });
    // }

    if (params.filterand) {

      if (params.filterand.includes(shared_consts.FILTER_EXTRALIST_NOT_REGISTERED))
        filtriadded.push({ registered: false });

      if (params.filterand.includes(shared_consts.FILTER_EXTRALIST_NOT_CONTACTED)) {
        filtriadded.push({ contacted: { $exists: false } });
      }
      if (params.filterand.includes(shared_consts.FILTER_EXTRALIST_WITH_NOTE))
        filtriadded.push({
          'note': { $exists: true },
          "$expr": { "$gt": [{ "$strLenCP": "$note" }, 1] }
        });
      if (params.filterand.includes(shared_consts.FILTER_USER_NO_ZOOM))
        filtriadded.push({ 'profile.saw_zoom_presentation': false });
      if (params.filterand.includes(shared_consts.FILTER_USER_NO_INVITANTE))
        filtriadded.push({
          aportador_solidario: { $exists: false }
        });
      if (params.filterand.includes(shared_consts.FILTER_USER_NO_TELEGRAM_ID))
        filtriadded.push({ 'profile.teleg_id': { $lt: 1 } });
      if (params.filterand.includes(shared_consts.FILTER_USER_CODICE_AUTH_TELEGRAM))
        filtriadded.push({ 'profile.teleg_checkcode': { $gt: 1 } });
      if (params.filterand.includes(shared_consts.FILTER_USER_NO_EMAIL_VERIFICATA))
        filtriadded.push({ verified_email: false });
      if (params.filterand.includes(shared_consts.FILTER_USER_NO_DREAM))
        filtriadded.push({
          'profile.my_dream': {
            $exists: false
          }
        });
      if (params.filterand.includes(shared_consts.FILTER_USER_TELEGRAM_BLOCKED))
        filtriadded.push({ 'profile.teleg_id_old': { $gt: 1 } });

    }


    if (filtriadded.length > 0)
      query.push({ $match: { $and: filtriadded } });

    if (idapp > 0) {
      query.push({ $match: { idapp } });
    }

    // console.log('QUERYMATCH', query[0].$match.or);
    // console.log('filter', params.filter);

    if (params.sortBy) {
      // maybe we want to sort by blog title or something
      const mysort = { $sort: params.sortBy };
      // console.log('sortBy', params.sortBy);
      // console.table(mysort);
      query.push(mysort)
    }

    let numrowend = params.endRow - params.startRow;
    if (numrowend < 0)
      numrowend = 1;

    query.push(
      {
        $group: {
          _id: null,
          // get a count of every result that matches until now
          count: { $sum: 1 },
          // keep our results for the next operation
          results: { $push: '$$ROOT' }
        }
      },
      // and finally trim the results to within the range given by start/endRow
      {
        $project: {
          count: 1,
          rows: { $slice: ['$results', params.startRow, numrowend] }
        }
      }
    );

    // console.log('query', query);

    return query;

  },

  executeQueryTable(mythistable, idapp, params) {
    let query = this.getQueryTable(idapp, params);

    return mythistable
      .aggregate(query)
      .then(([ris]) => {
        if (ris) {
          // console.table(ris.rows);
          // console.log('ROW ', ris.count);
          return ({ count: ris.count, rows: ris.rows })
        } else {
          return ({ count: 0, rows: [] })
        }
      })
      .catch(err => {
        console.error(err);
        return {
          count: 0, rows: []
        }
      });

  },
  async DuplicateAllRecords(mythistable, idapporig, idappdest) {
    console.log(mythistable.name);

    const numrec = await mythistable.findAllIdApp(idappdest).then((arrrec) => {
      if (arrrec && arrrec.length > 1) {
        return arrrec.length; // Has Already set
      } else {
        return 0;
      }
    });

    // Before check if exist more than 1 record in the destination,
    // if Yes don't copy
    if (numrec <= 0) {
      return await mythistable.findAllIdApp(idapporig).then(async (arrrec) => {
        let num = 0;

        for (let ind = 0; ind < arrrec.length; ind++) {
          let newrec = new mythistable(arrrec[ind]._doc);
          newrec._id = new ObjectID();
          newrec.idapp = idappdest;

          await newrec.save((err, rec) => {
            if (rec) {
              num++;
            }

          });

        }
        return num;
      });
    }
  },


  isBitActive(bit, whattofind) {
    return ((bit & whattofind) === whattofind)
  },

  SetBit(myval, bit) {
    myval = myval & bit;
    return myval
  },

  async snooze(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
  },

  IncDateNow(secs) {
    let mydate = new Date(new Date().getTime() + secs);
    // console.log('mydate', mydate);
    return mydate
  },

  AddDate(mydate, days) {
    let date = new Date(mydate);
    date.setTime(date.getTime() + days * 86400000);
    return date;
  },

  isMonToSat() {
    const dayOfWeek = new Date(new Date()).getDay();
    return dayOfWeek >= 1 && dayOfWeek <= 6
  },

  // var startTime = '15:10:10';
  // var endTime = '22:30:00';
  isBetweenTwoTime(startTime, endTime) {

    currentDate = new Date();

    startDate = new Date(currentDate.getTime());
    startDate.setHours(startTime.split(":")[0]);
    startDate.setMinutes(startTime.split(":")[1]);
    startDate.setSeconds(startTime.split(":")[2]);

    endDate = new Date(currentDate.getTime());
    endDate.setHours(endTime.split(":")[0]);
    endDate.setMinutes(endTime.split(":")[1]);
    endDate.setSeconds(endTime.split(":")[2]);


    valid = startDate < currentDate && endDate > currentDate;

    return valid;
  },

  getlimiti(mypos) {

    if (mypos.col < 0) {
      mypos.col = 0;
    }

    if (mypos.riga < 0) {
      mypos.riga = 0;
      mypos.col = 0;
    }

    return mypos;
  },

  getRigaColByPosUp(mypos) {
    if (mypos.numup > 0) {
      mypos.riga = mypos.riga - mypos.numup;
      mypos.col = Math.ceil(mypos.col / (Math.pow(2, mypos.numup)));
    }
    if (mypos.numup < 0) {
      mypos.riga = mypos.riga - mypos.numup;
      mypos.col = Math.ceil(mypos.col * (Math.pow(2, -mypos.numup)));
    }
    if (mypos.riga < 1) {
      mypos.riga = 1;
    }
    if (mypos.col < 1) {
      mypos.col = 1;
    }
  },

  getRigaColGenerica(idapp, riga, col, numup) {
    mypos = {
      idapp,
      riga,
      col,
      numup
    };

    if (idapp === tools.AYNI) {
      this.getRigaColByPosUp(mypos);
      ris = this.getlimiti(mypos);
    }

    return ris;
  },

  getRigaColSognatoreByDonatore(idapp, riga, col) {
    return this.getRigaColGenerica(idapp, riga, col, 6);
  },

  getRigaColMediatoreByFuoco(idapp, riga, col) {
    return this.getRigaColGenerica(idapp, riga, col, 3);
  },

  getRigaColSognatoreByMediatore(idapp, riga, col) {
    return this.getRigaColGenerica(idapp, riga, col, 3);
  },

  appendLeadingZeroes(n) {
    if (n <= 9) {
      return "0" + n;
    }
    return n
  },

  getWeekDayByLang(date, lang) {
    if (!lang)
      lang = 'it';

    const dayOfWeek = new Date(date).getDay();

    const myday = {
      it: ['Domenica', 'Lunedì', 'Martedì', 'Mercoledì', 'Giovedì', 'Venerdì', 'Sabato'],
      enUs: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
      fr: ['Dimanche', 'Lundi', 'Mardi', 'Mercredi', 'Jeudi', 'Vendredi', 'Samedi'],
      es: ['Domingo', 'Lunes', 'Martes', 'Miércoles', 'Jueves', 'iernes', 'Sábado'],
      pt: ['Domingo', 'Segunda', 'Terça', 'Quarta', 'Quinta', 'Sexta', 'Sábado'],
      de: ['Sonntag', 'Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag'],
      si: ['Nedelja', 'Ponedeljek', 'Torek', 'Sreda', 'četrtek', 'Petek', 'Sobota'],
    }

    return isNaN(dayOfWeek) ? '' : myday[lang][dayOfWeek].substring(0, 3)
  },

  getWeekDay(date) {
    //Create an array containing each day, starting with Sunday.
    const weekdays = [
      "Domenica", "Lunedì", "Martedì", "Mercoledì", "Giovedí", "Venerdì", "Sabato"
    ];
    //Use the getDay() method to get the day.
    const day = date.getDay();
    //Return the element that corresponds to that index.
    return weekdays[day];
  },

  getstrDateTimeShort(mydate, lang) {
    if (mydate) {
      // console.log('getstrDate', mytimestamp)
      return this.getWeekDayByLang(mydate, lang) + ' ' + this.appendLeadingZeroes(mydate.getDate()) + '/' + this.appendLeadingZeroes(mydate.getMonth() + 1) + ' ORE ' + this.appendLeadingZeroes(mydate.getHours()) + ':' + this.appendLeadingZeroes(mydate.getMinutes());
    } else {
      return '';
    }
  },

  getstrDateShort(mydate, lang) {
    if (mydate) {
      // console.log('getstrDate', mytimestamp)
      return this.getWeekDayByLang(mydate, lang).substring(0, 3) + ' ' + this.appendLeadingZeroes(mydate.getDate()) + '/' + this.appendLeadingZeroes(mydate.getMonth() + 1);
    } else {
      return '';
    }
  },

  getstrDateLong(mydate, lang) {
    if (mydate) {
      // console.log('getstrDate', mytimestamp)
      return this.getWeekDayByLang(mydate, lang) + ' ' + this.appendLeadingZeroes(mydate.getDate()) + '/' + this.appendLeadingZeroes(mydate.getMonth() + 1) + '/' + mydate.getFullYear();
    } else {
      return '';
    }
  },

  getlinkzoom(idconf) {
    if (idconf === '')
      idconf = '6668882000';
    return 'https://zoom.us/j/' + idconf
  },

  getmd5(mystr) {
    return CryptoJS.MD5(mystr.toLowerCase()).toString();
  },

  getHash(mystr) {
    return CryptoJS.SHA512(mystr, { outputLength: 256 }).toString();
  },

  encrypt(msg, pass) {
    var salt = CryptoJS.lib.WordArray.random(128 / 8);

    var key = CryptoJS.PBKDF2(pass, salt, {
      keySize: keySize / 32,
      iterations: iterations
    });

    var iv = CryptoJS.lib.WordArray.random(128 / 8);

    var encrypted = CryptoJS.AES.encrypt(msg, key, {
      iv: iv,
      padding: CryptoJS.pad.Pkcs7,
      mode: CryptoJS.mode.CBC

    });

    // salt, iv will be hex 32 in length
    // append them to the ciphertext for use  in decryption
    var transitmessage = salt.toString() + iv.toString() + encrypted.toString();
    return transitmessage;
  },

  decrypt(transitmessage, pass) {
    var salt = CryptoJS.enc.Hex.parse(transitmessage.substr(0, 32));
    var iv = CryptoJS.enc.Hex.parse(transitmessage.substr(32, 32))
    var encrypted = transitmessage.substring(64);

    var key = CryptoJS.PBKDF2(pass, salt, {
      keySize: keySize / 32,
      iterations: iterations
    });

    var decrypted = CryptoJS.AES.decrypt(encrypted, key, {
      iv: iv,
      padding: CryptoJS.pad.Pkcs7,
      mode: CryptoJS.mode.CBC

    });
    return decrypted;
  },

  cryptdata(mydata) {
    // Encrypt
    //return CryptoJS.AES.encrypt(JSON.stringify(mydata), process.env.SECRK);
    return this.encrypt(mydata, process.env.SECRK);
  },


  decryptdata(mydatacrypted) {
    // Decrypt
    // const bytes = CryptoJS.AES.decrypt(mydatacrypted.toString(), process.env.SECRK);
    // return JSON.parse(bytes.toString(CryptoJS.enc.Utf8));
    return this.decrypt(mydatacrypted, process.env.SECRK).toString(CryptoJS.enc.Utf8);
  },

  BoolToInt(mybool) {
    return (mybool) ? -1 : 0
  },

  StrToBool(mystr) {
    return (mystr === '-1') ? true : false
  },

  writelogfile(mystr, filename) {
    //   fs.appendFile(FILELOG, mystr, function (err) {
    //     if (err) throw err;
    //     console.log('Saved!');
    //   });

    // mystr = this.getstrDateTimeShort(Date.now()) + ' ' + mystr;
    const stream = fs.createWriteStream(filename, { flags: 'a' });
    stream.write('\n' + mystr);
    stream.end();
  },

  writelog(mystr) {
    this.writelogfile(mystr, FILELOG);
  },

  writeEventsLog(mystr) {
    this.writelogfile(mystr, FILEEVENTS);
  },

  writeManagersLog(mystr) {
    this.writelogfile(mystr, FILEMANAGERS);
  },

  writeNaveLog(mystr) {
    this.writelogfile(mystr, FILENAVE);
  },

  move(oldPath, newPath, callback) {

    fs.rename(oldPath, newPath, function (err) {
      if (err) {
        if (err.code === 'EXDEV') {
          copy();
        } else {
          callback(err);
        }
        return;
      }
      callback();
    });

    function copy() {
      const readStream = fs.createReadStream(oldPath);
      const writeStream = fs.createWriteStream(newPath);

      readStream.on('error', callback);
      writeStream.on('error', callback);

      readStream.on('close', function () {
        fs.unlink(oldPath, callback);
      });

      readStream.pipe(writeStream);
    }
  },

  delete(path, callback) {

    fs.unlink(path, function (err) {
      if (err) {
        console.error(err);
        callback(err);
        return
      }
      callback();
    });
  },

  mkdirpath(dirPath) {
    // if (!fs.accessSync(dirPath, fs.constants.R_OK | fs.constants.W_OK)) {
    if (!fs.existsSync(dirPath)) {
      try {
        fs.mkdirSync(dirPath, { recursive: true });
      }
      catch (e) {
        mkdirpath(path.dirname(dirPath));
        mkdirpath(dirPath);
      }
    }
  },

  extractNameAndSurnameByComplete(name_complete) {
    const suffissoCognome = ['Del', 'La', 'De', 'Lo'];

    let campi = name_complete.split(" ");
    let namesurname = {
      name: '',
      surname: '',
    };

    if (campi.length === 2) {
      namesurname.name = campi[0];
      namesurname.surname = campi[1];
    } else if (campi.length === 3) {
      if (suffissoCognome.includes(campi[1])) {
        namesurname.name = campi[0];
        namesurname.surname = campi[1] + " " + campi[2];
      } else {
        namesurname.name = campi[0] + " " + campi[1];
        namesurname.surname = campi[2];
      }
    } else if (campi.length === 4) {
      namesurname.name = campi[0] + " " + campi[1];
      namesurname.surname = campi[2] + " " + campi[3];
    } else if (campi.length > 4) {
      namesurname.name = campi[0] + " " + campi[1];
      namesurname.surname = " " + campi[2];
      for (let ind = 3; ind < campi.length; ind++) {
        namesurname.surname += " " + campi[ind];
      }
    }

    return namesurname
  },

  getiPAddressUser(req) {
    try {
      const striniziale = '::ffff:';
      if (req.ip.indexOf(striniziale) >= 0) {
        return req.ip.substring(striniziale.length)
      } else {
        return req.ip;  // Express
      }

    } catch (e) {
      return ''
    }
  },
  removespaces(mystr) {
    return mystr.replace(/\s+/g, '')
  },

  ModificheConsentite(table, fieldsvalue, idrec, user) {
    if (table === 'users') {
      if ('aportador_solidario' in fieldsvalue) {
        return true;
      }
      if ('ALL' in fieldsvalue) {
        //++Todo: Cancellalo solo se sono io il creatore dell'utente ... o se posso!
        return true
      }
    }

    if (table === 'listaingressos') {
      if ('invitante_username' in fieldsvalue) {
        return true;
      }
      if ('username' in fieldsvalue) {
        return true;
      }
    }

    if (table === 'navi') {
      if ('date_made_gift' in fieldsvalue) {
        return true;
      }
      if ('made_gift' in fieldsvalue) {
        return true;
      }
    }
    if (table === 'navepersistente') {
      if ('link_chat' in fieldsvalue) {
        return true;
      }
    }

    return false;
  },

  NotifyIfDelRecord(table) {
    if ((table === 'users') || (table === 'extralist')) {
      return true;
    }

    return false;
  },

  getFirstWord(mystr) {
    const myarr = mystr.split(" ");
    if (myarr.length > 0)
      return myarr[0];
    else
      return mystr
  },

  getFirst2Car(mystr) {
    if (!!mystr)
      return mystr.substring(0, 2) + '.';
    else
      return ''
  },


};
