var CVSS_UNDEFINED = "Undefined";

function round_to_1_decimal(val) {
	return Math.round(val * 10)/10;
}

function createVector() {
	var args = new Array(arguments.length);
	for (var i = 0; i < arguments.length; i++) {
		args[i] = arguments[i];
	}
	return args.join("/");
}

function createVector1() {
	var finalVector="";
	var args = new Array(arguments.length);
	for (var i = 0; i < arguments.length; i++) {
		args[i] = arguments[i];
		if(args[i] != null && args[i] != ''  && args[i] != 'Undefind'){
		 finalVector += args[i]+"/";

		}
	}
	return finalVector.substring(0,(finalVector.length -1));
}

function Cvss() {
	var vector;
	this.baseScore = Cvss_baseScore;
	this.impactSubscore = Cvss_impactSubscore;
	this.exploitSubscore = Cvss_exploitSubscore;
	this.temporalScore = Cvss_temporalScore;
	this.envScore = Cvss_envScore;
	this.adjustedBaseScore = Cvss_adjustedBaseScore;
	this.adjustedTemporalScore = Cvss_adjustedTemporalScore;
	this.adjustedImpact = Cvss_adjustedImpact;
	this.fImpact = Cvss_fImpact;
	this.parseC = Cvss_parseC;
	this.parseI = Cvss_parseI;
	this.parseA = Cvss_parseA;
	this.parseB = Cvss_parseB;
	this.parseAV = Cvss_parseAV;
	this.parseAC = Cvss_parseAC;
	this.parseAU = Cvss_parseAU;
	this.parseE = Cvss_parseE;
	this.parseRL = Cvss_parseRL;
	this.parseRC = Cvss_parseRC;
	this.parseCDP = Cvss_parseCDP;
	this.parseTD = Cvss_parseTD;
	this.parseCR = Cvss_parseCR;
	this.parseIR = Cvss_parseIR;
	this.parseAR = Cvss_parseAR;
}

function hasNaN() {
	var args = new Array(arguments.length);
	foundNaN = false;
	for (var i = 0; i < arguments.length; i++) {
		if (isNaN(arguments[i])) {
			foundNaN = true;
		}
	}
	return foundNaN;
}

function Cvss_baseScore(vector) {
	var _exploitability = this.exploitSubscore(vector);
	var _impact = this.impactSubscore(vector);
    var _f = this.fImpact(_impact);

    if (hasNaN(_impact, _exploitability, _f)) {
		return CVSS_UNDEFINED;
    }
	
	return Cvss_baseScoreCalculation(_impact, _exploitability, _f);
}				

function Cvss_baseScoreCalculation(__impact, __exploitability, __f) {
	return round_to_1_decimal( ((0.6 * __impact) + (0.4 * __exploitability) - 1.5) * __f );
}

function Cvss_impactSubscore(vector) {
 	var _confImpact = impactValue(this.parseC(vector));
	var _integImpact = impactValue(this.parseI(vector));
	var _availImpact = impactValue(this.parseA(vector));

    if (hasNaN(_confImpact, _integImpact, _availImpact)) {
		return CVSS_UNDEFINED;
    }

	return 10.41 * (1- (1 - _confImpact) * (1 - _integImpact) *(1 - _availImpact) );
}

function Cvss_exploitSubscore(vector) {
	var _accessVector = accessVectorValue(this.parseAV(vector));
	var _accessComplexity = accessComplexityValue(this.parseAC(vector));
	var _authentication = authValue(this.parseAU(vector));
  
    if (hasNaN(_accessVector, _accessComplexity, _authentication)) {
		return CVSS_UNDEFINED;
    }

	return (20 * _accessVector * _accessComplexity * _authentication );
}

function Cvss_fImpact(impact){
	if (impact == 0) {
	    return 0.0;
	} 
	return 1.176;
}

function Cvss_temporalScore(vector) {
	var _exploitability = exploitValue(this.parseE(vector));
	var _remediationLevel = remedLevelValue(this.parseRL(vector));
	var _reportConfidence = rptConfValue(this.parseRC(vector));
	var _baseScore = this.baseScore(vector);
	
	if (hasNaN(_baseScore)) {
		return CVSS_UNDEFINED;
	}

	return Cvss_temporalScoreCalculation(_baseScore, _exploitability, _remediationLevel, _reportConfidence);
}

function Cvss_temporalScoreCalculation(__baseScore, __exploitability, __remediationLevel, __reportConfidence) {
	return round_to_1_decimal(__baseScore * __exploitability * __remediationLevel * __reportConfidence );
}

function Cvss_envScore(vector) {
 
	var _adjustedTemporal= this.adjustedTemporalScore(vector);
	var _collateralDamagePotential = collateralDamageValue(this.parseCDP(vector));
	var _targetDistribution = targetDistValue(this.parseTD(vector));
	if (hasNaN(_adjustedTemporal, _collateralDamagePotential, _targetDistribution)) {
		return CVSS_UNDEFINED;
	}

	return round_to_1_decimal((_adjustedTemporal  + ((10 - _adjustedTemporal) * _collateralDamagePotential)) * _targetDistribution);
}

function Cvss_adjustedTemporalScore(vector) {
	var _exploitability = exploitValue(this.parseE(vector));
	var _remediationLevel = remedLevelValue(this.parseRL(vector));
	var _reportConfidence = rptConfValue(this.parseRC(vector));
	var _baseScore = this.adjustedBaseScore(vector);

	if (hasNaN(_baseScore)) {
		return CVSS_UNDEFINED;
	}

	return Cvss_temporalScoreCalculation(_baseScore, _exploitability, _remediationLevel, _reportConfidence);
}

function Cvss_adjustedBaseScore(vector) {

	var _exploitability = this.exploitSubscore(vector);
	var _impact = this.adjustedImpact(vector);
    var _f = this.fImpact(_impact);
   
    if (hasNaN(_impact, _exploitability, _f)) {
		return CVSS_UNDEFINED;
    }
	
	return Cvss_baseScoreCalculation(_impact, _exploitability, _f);
}

function Cvss_adjustedImpact(v) {
	var _confImpact = impactValue(this.parseC(v));
	var _integImpact = impactValue(this.parseI(v));
	var _availImpact = impactValue(this.parseA(v));
    var _confReq = envRequirementValue(this.parseCR(v));
	var _integReq = envRequirementValue(this.parseIR(v));
    var _availReq = envRequirementValue(this.parseAR(v));

    return Math.min(10, 10.41 *(1-(1 - _confImpact * _confReq ) * (1 - _integImpact * _integReq ) * (1 - _availImpact * _availReq )));
}

function Cvss_parseC(v) {
	var re = /((^|^.+\/)\s*C\:)(N|P|C|ND)(?:\s*)(?:\/.*$|$)/i;
	return vectValue(re.exec(v));
}

function Cvss_parseI(v) {
	var re = /((^|^.+\/)\s*I\:)(N|P|C|ND)(?:\s*)(?:\/.*$|$)/i;
	return vectValue(re.exec(v));
}

function Cvss_parseA(v) {
	var re = /((^|^.+\/)\s*A\:)(N|P|C|ND)(?:\s*)(?:\/.*$|$)/i;
	return vectValue(re.exec(v));
}

function Cvss_parseB(v) {
	var re = /((^|^.+\/)\s*B\:)(N|C|I|A)(?:\s*)(?:\/.*$|$)/i;
	return vectValue(re.exec(v));
}

function Cvss_parseAV(v) {
	var re = /((^|^.+\/)\s*AV\:)(L|A|N|ND)(?:\s*)(?:\/.*$|$)/i;
	return vectValue(re.exec(v));
}

function Cvss_parseAC(v) {
	var re = /((^|^.+\/)\s*AC\:)(H|M|L|ND)(?:\s*)(?:\/.*$|$)/i;
	return vectValue(re.exec(v));
}

function Cvss_parseAU(v) {
	var re = /((^|^.+\/)\s*AU\:)(N|S|M|ND)(?:\s*)(?:\/.*$|$)/i;
	return vectValue(re.exec(v));
}

function Cvss_parseE(v) {
	var re = /((^|^.+\/)\s*E\:)(U|POC|F|H|ND)(?:\s*)(?:\/.*$|$)/i;
	return vectValue(re.exec(v));
}

function Cvss_parseRL(v) {
	var re = /((^|^.+\/)\s*RL\:)(OF|TF|W|U|ND)(?:\s*)(?:\/.*$|$)/i;
	return vectValue(re.exec(v));
}

function Cvss_parseRC(v) {
	var re = /((^|^.+\/)\s*RC\:)(UC|UR|C|ND)(?:\s*)(?:\/.*$|$)/i;
	return vectValue(re.exec(v));
}

function Cvss_parseCDP(v) {
	var re = /((^|^.+\/)\s*CDP\:)(N|L|LM|MH|H|ND)(?:\s*)(?:\/.*$|$)/i;
	return vectValue(re.exec(v));
}

function Cvss_parseTD(v) {
	var re = /((^|^.+\/)\s*TD\:)(N|L|M|H|ND)(?:\s*)(?:\/.*$|$)/i;
	return vectValue(re.exec(v));
}

function Cvss_parseCR(v) {
 var re = /((^|^.+\/)\s*CR\:)(L|M|H|ND)(?:\s*)(?:\/.*$|$)/i;
 return vectValue(re.exec(v));
}

function Cvss_parseIR(v) {
 var re = /((^|^.+\/)\s*IR\:)(L|M|H|ND)(?:\s*)(?:\/.*$|$)/i;
 return vectValue(re.exec(v));
}

function Cvss_parseAR(v) {
 var re = /((^|^.+\/)\s*AR\:)(L|M|H|ND)(?:\s*)(?:\/.*$|$)/i;
 return vectValue(re.exec(v));
}

function vectValue(grps) {
	if (grps) {
		return grps[grps.length-1];
	} else {
		return CVSS_UNDEFINED;
	}
}

function impactValue(k) {return {'N':0.0, 'P':0.275, 'C':0.660}[k.toUpperCase()]}

function accessVectorValue(k) {return {'L':0.395, 'A':0.646, 'N':1.0}[k.toUpperCase()]}

function accessComplexityValue(k) {return {'H':0.35, 'M':0.61, 'L':0.71}[k.toUpperCase()]}

function authValue(k) {return {'M':0.45, 'S':0.56, 'N':0.704}[k.toUpperCase()]}

function exploitValue(k) {return {'U':0.85, 'POC':0.9, 'F':0.95, 'H':1.0, 'ND':1.00}[k.toUpperCase()]}

function remedLevelValue(k) {return {'OF':0.87, 'TF':0.90, 'W':0.95, 'U':1.00, 'ND':1.00 }[k.toUpperCase()]}

function rptConfValue(k) {return {'UC':0.90, 'UR':0.95, 'C':1.00, 'ND':1.00}[k.toUpperCase()]}

function collateralDamageValue(k) {return {'N':0.0, 'L':0.1, 'LM':0.3, 'MH':0.4, 'H':0.5 ,'ND':0.0 }[k.toUpperCase()]}

function targetDistValue(k) {return {'N':0.0, 'L':0.25, 'M':0.75, 'H':1.0,'ND':1.0}[k.toUpperCase()]}

function envRequirementValue(k) {return {'L':0.5, 'M':1.0, 'H':1.51, 'ND':1.0}[k.toUpperCase()]}