text: var mongoose = require('mongoose');
  var Schema = mongoose.Schema;
  
  var customField = {
      _id:            false,
      customField:  {type: Schema.Types.ObjectId, ref: 'CustomField'},
      text:           String
  }
  
  var VulnerabilityDetails = {
      _id:            false,
      locale:         String,
      // language:       String,
      title:          {type: String, unique: true, sparse: true},
      vulnType:       String,
      description:    String,
      observation:    String,
      remediation:    String,
      customFields:   [customField]
  }
  
  var VulnerabilitySchema = new Schema({
      cvssv3:                 String,
      cvssScore:              String,
      cvssSeverity:           String,
      priority:               {type: Number, enum: [1,2,3,4]},
      remediationComplexity:  {type: Number, enum: [1,2,3]},
      references:             [String],
      details:                [VulnerabilityDetails],
      status:                 {type: Number, enum: [0,1,2], default: 1}, // 0: validated, 1: created, 2: updated,
      category:               String
  
  
  }, {timestamps: true});
  
  /*
  *** Statics ***
  */
  
  // Get all vulnerabilities
  VulnerabilitySchema.statics.getAll = () => {
      return new Promise((resolve, reject) => {
          var query = Vulnerability.find();
          query.exec()
          .then((rows) => {
              resolve(rows);
          })
          .catch((err) => {
              reject(err);
          })
      });
  }
  
  // Get all vulnerabilities for download
  VulnerabilitySchema.statics.export = () => {
      return new Promise((resolve, reject) => {
          var query = Vulnerability.find();
          query.select('details cvssv3 cvssScore cvssSeverity priority remediationComplexity references category -_id')
          query.exec()
          .then((rows) => {
              resolve(rows);
          })
          .catch((err) => {
              reject(err);
          })
      });
  }
  
  // Create vulnerability
  VulnerabilitySchema.statics.create = (vulnerabilities) => {
      return new Promise((resolve, reject) => {
          Vulnerability.insertMany(vulnerabilities, {ordered: false})
          .then((rows) => {
              resolve({created: rows.length, duplicates: 0});
          })
          .catch((err) => {
              if (err.code === 11000) {
                  if (err.result.nInserted === 0)
                      reject({fn: 'BadParameters', message: 'Vulnerability title already exists'});
                  else
                      resolve({created: err.result.nInserted, duplicates: err.writeErrors.length});
              }
              else
                  reject(err);
          })
      })
  }
  
  // Update vulnerability
  VulnerabilitySchema.statics.update = (vulnerabilityId, vulnerability) => {
      return new Promise((resolve, reject) => {
          var VulnerabilityUpdate = mongoose.model("VulnerabilityUpdate");
          var query = Vulnerability.findByIdAndUpdate(vulnerabilityId, vulnerability);
          query.exec()
          .then((row) => {
              if (!row)
                  reject({fn: 'NotFound', message: 'Vulnerability not found'});
              else {
                  var query = VulnerabilityUpdate.deleteMany({vulnerability: vulnerabilityId});
                  return query.exec();
              }
          })
          .then((row) => {
              resolve('Vulnerability updated successfully');    
          })
          .catch((err) => {
              if (err.code === 11000)
                  reject({fn: 'BadParameters', message: 'Vulnerability title already exists'});
              else
                  reject(err);
          })
      });
  }
  
  // Delete all vulnerabilities
  VulnerabilitySchema.statics.deleteAll = () => {
      return new Promise((resolve, reject) => {
          var query = Vulnerability.deleteMany();
          query.exec()
          .then(() => {
              resolve('All vulnerabilities deleted successfully');
          })
          .catch((err) => {
              reject(err);
          })
      });
  }
  
  // Delete vulnerability
  VulnerabilitySchema.statics.delete = (vulnerabilityId) => {
      return new Promise((resolve, reject) => {
          var query = Vulnerability.findByIdAndDelete(vulnerabilityId);
          query.exec()
          .then((rows) => {
              if (rows)
                  resolve(rows);
              else
                  reject({fn: 'NotFound', message: 'Vulnerability not found'});
          })
          .catch((err) => {
              reject(err);
          })
      });
  }
  
  // Get vulnerabilities by language
  VulnerabilitySchema.statics.getAllByLanguage = (locale) => {
      return new Promise((resolve, reject) => {
          var query = Vulnerability.find({'details.locale': locale})
          query.select('details cvssv3 cvssScore cvssSeverity priority remediationComplexity references category')
          query.exec()
          .then((rows) => {
              if (rows) {
                  var result = [];
                  rows.forEach(row => {
                      row.details.forEach(detail => {
                          if (detail.locale === locale && detail.title){
                              var temp = {};
                              temp.cvssv3 = row.cvssv3;
                              temp.cvssScore = row.cvssScore;
                              temp.cvssSeverity = row.cvssSeverity;
                              temp.priority = row.priority;
                              temp.remediationComplexity = row.remediationComplexity;
                              temp.references = row.references;
                              temp.category = row.category;
                              temp.detail= detail;
                              temp._id = row._id;
                              result.push(temp);
                          }
                      })
                  })
                  resolve(result);
              }
              else
                  reject({fn: 'NotFound', message: 'Locale with existing title not found'});
          })
          .catch((err) => {
              reject(err);
          })
      });
  }
  
  VulnerabilitySchema.statics.Merge = (vulnIdPrime, vulnIdMerge, locale) => {
      return new Promise((resolve, reject) => {
          var mergeDetail = null;
          var mergeVuln = null;
          var primeVuln = null;
          var query = Vulnerability.findById(vulnIdMerge);
          query.exec()
          .then((row) => {
              if (!row)
                  reject({fn: 'NotFound', message: 'Vulnerability not found'});
              else {
                  mergeVuln = row;
                  mergeDetail = row.details.find(d => d.locale === locale);
                  var query = Vulnerability.findById(vulnIdPrime);
                  return query.exec();
              }
          })
          .then((row) => {
              if (!row)
                  reject({fn: 'NotFound', message: 'Vulnerability not found'});
              else {
                  if (row.details.findIndex(d => (d.locale === locale && d.title)) !== -1)
                      reject({fn: 'BadParameters', message: 'Language already exists in this vulnerability'});
                  else {
                      primeVuln = row;
                      var removeIndex = mergeVuln.details.map(d => d.title).indexOf(mergeDetail.title);
                      mergeVuln.details.splice(removeIndex, 1)
                      if (mergeVuln.details.length === 0)
                          return Vulnerability.findByIdAndRemove(mergeVuln._id);
                      else
                          return mergeVuln.save();
                  }
              }
          })
          .then(() => {
              var detail = {};
              detail.locale = mergeDetail.locale;
              detail.title = mergeDetail.title;
              if (mergeDetail.vulnType) detail.vulnType = mergeDetail.vulnType;
              if (mergeDetail.description) detail.description = mergeDetail.description;
              if (mergeDetail.observation) detail.observation = mergeDetail.observation;
              if (mergeDetail.remediation) detail.remediation = mergeDetail.remediation;
              if (mergeDetail.customFields) detail.customFields = mergeDetail.customFields
              primeVuln.details.push(detail);
              return primeVuln.save();
          })
          .then(() => {
              resolve('Vulnerability merge successfull');
          })
          .catch((err) => {
              reject(err);
          })
      });
  }
  
  /*
  *** Methods ***
  */
  
  var Vulnerability = mongoose.model('Vulnerability', VulnerabilitySchema);
  module.exports = Vulnerability;