/*
 * This file is part of dependency-check-core.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * Copyright (c) 2012 Jeremy Long. All Rights Reserved.
 */
package org.owasp.dependencycheck.dependency;

import java.io.Serializable;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;

/**
 * Contains the information about a vulnerability.
 *
 * @author Jeremy Long
 */
public class Vulnerability implements Serializable, Comparable<Vulnerability> {

    /**
     * The serial version uid.
     */
    private static final long serialVersionUID = 307319490326651052L;
    /**
     * The name of the vulnerability.
     */
    private String name;

    /**
     * Get the value of name.
     *
     * @return the value of name
     */
    public String getName() {
        return name;
    }

    /**
     * Set the value of name.
     *
     * @param name new value of name
     */
    public void setName(String name) {
        this.name = name;
    }
    /**
     * the description of the vulnerability.
     */
    private String description;

    /**
     * Get the value of description.
     *
     * @return the value of description
     */
    public String getDescription() {
        return description;
    }

    /**
     * Set the value of description.
     *
     * @param description new value of description
     */
    public void setDescription(String description) {
        this.description = description;
    }
    /**
     * References for this vulnerability.
     */
    private SortedSet<Reference> references = new TreeSet<Reference>();

    /**
     * Get the value of references.
     *
     * @return the value of references
     */
    public Set<Reference> getReferences() {
        return references;
    }

    /**
     * Set the value of references.
     *
     * @param references new value of references
     */
    public void setReferences(SortedSet<Reference> references) {
        this.references = references;
    }

    /**
     * Adds a reference to the references collection.
     *
     * @param ref a reference for the vulnerability
     */
    public void addReference(Reference ref) {
        this.references.add(ref);
    }

    /**
     * Adds a reference.
     *
     * @param referenceSource the source of the reference
     * @param referenceName the referenceName of the reference
     * @param referenceUrl the url of the reference
     */
    public void addReference(String referenceSource, String referenceName, String referenceUrl) {
        final Reference ref = new Reference();
        ref.setSource(referenceSource);
        ref.setName(referenceName);
        ref.setUrl(referenceUrl);
        this.references.add(ref);
    }
    /**
     * A set of vulnerable software.
     */
    private SortedSet<VulnerableSoftware> vulnerableSoftware = new TreeSet<VulnerableSoftware>();

    /**
     * Get the value of vulnerableSoftware.
     *
     * @return the value of vulnerableSoftware
     */
    public Set<VulnerableSoftware> getVulnerableSoftware() {
        return vulnerableSoftware;
    }

    /**
     * Set the value of vulnerableSoftware.
     *
     * @param vulnerableSoftware new value of vulnerableSoftware
     */
    public void setVulnerableSoftware(SortedSet<VulnerableSoftware> vulnerableSoftware) {
        this.vulnerableSoftware = vulnerableSoftware;
    }

    /**
     * Adds an entry for vulnerable software.
     *
     * @param cpe string representation of a CPE entry
     * @return if the add succeeded
     */
    public boolean addVulnerableSoftware(String cpe) {
        return addVulnerableSoftware(cpe, null);
    }

    /**
     * Adds an entry for vulnerable software.
     *
     * @param cpe string representation of a cpe
     * @param previousVersion the previous version (previousVersion - cpe would be considered vulnerable)
     * @return if the add succeeded
     */
    public boolean addVulnerableSoftware(String cpe, String previousVersion) {
        final VulnerableSoftware vs = new VulnerableSoftware();
        vs.setCpe(cpe);
        if (previousVersion != null) {
            vs.setPreviousVersion(previousVersion);
        }
        return updateVulnerableSoftware(vs);
    }

    /**
     * Adds or updates a vulnerable software entry.
     *
     * @param vulnSoftware the vulnerable software
     * @return if the update succeeded
     */
    public boolean updateVulnerableSoftware(VulnerableSoftware vulnSoftware) {
        if (vulnerableSoftware.contains(vulnSoftware)) {
            vulnerableSoftware.remove(vulnSoftware);
        }
        return vulnerableSoftware.add(vulnSoftware);
    }
    /**
     * The CWE for the vulnerability.
     */
    private String cwe;

    /**
     * Get the value of cwe.
     *
     * @return the value of cwe
     */
    public String getCwe() {
        return cwe;
    }

    /**
     * Set the value of cwe.
     *
     * @param cwe new value of cwe
     */
    public void setCwe(String cwe) {
        this.cwe = cwe;
    }
    /**
     * CVSS Score.
     */
    private float cvssScore;

    /**
     * Get the value of cvssScore.
     *
     * @return the value of cvssScore
     */
    public float getCvssScore() {
        return cvssScore;
    }

    /**
     * Set the value of cvssScore.
     *
     * @param cvssScore new value of cvssScore
     */
    public void setCvssScore(float cvssScore) {
        this.cvssScore = cvssScore;
    }
    /**
     * CVSS Access Vector.
     */
    private String cvssAccessVector;

    /**
     * Get the value of cvssAccessVector.
     *
     * @return the value of cvssAccessVector
     */
    public String getCvssAccessVector() {
        return cvssAccessVector;
    }

    /**
     * Set the value of cvssAccessVector.
     *
     * @param cvssAccessVector new value of cvssAccessVector
     */
    public void setCvssAccessVector(String cvssAccessVector) {
        this.cvssAccessVector = cvssAccessVector;
    }
    /**
     * CVSS Access Complexity.
     */
    private String cvssAccessComplexity;

    /**
     * Get the value of cvssAccessComplexity.
     *
     * @return the value of cvssAccessComplexity
     */
    public String getCvssAccessComplexity() {
        return cvssAccessComplexity;
    }

    /**
     * Set the value of cvssAccessComplexity.
     *
     * @param cvssAccessComplexity new value of cvssAccessComplexity
     */
    public void setCvssAccessComplexity(String cvssAccessComplexity) {
        this.cvssAccessComplexity = cvssAccessComplexity;
    }
    /**
     * CVSS Authentication.
     */
    private String cvssAuthentication;

    /**
     * Get the value of cvssAuthentication.
     *
     * @return the value of cvssAuthentication
     */
    public String getCvssAuthentication() {
        return cvssAuthentication;
    }

    /**
     * Set the value of cvssAuthentication.
     *
     * @param cvssAuthentication new value of cvssAuthentication
     */
    public void setCvssAuthentication(String cvssAuthentication) {
        this.cvssAuthentication = cvssAuthentication;
    }
    /**
     * CVSS Confidentiality Impact.
     */
    private String cvssConfidentialityImpact;

    /**
     * Get the value of cvssConfidentialityImpact.
     *
     * @return the value of cvssConfidentialityImpact
     */
    public String getCvssConfidentialityImpact() {
        return cvssConfidentialityImpact;
    }

    /**
     * Set the value of cvssConfidentialityImpact.
     *
     * @param cvssConfidentialityImpact new value of cvssConfidentialityImpact
     */
    public void setCvssConfidentialityImpact(String cvssConfidentialityImpact) {
        this.cvssConfidentialityImpact = cvssConfidentialityImpact;
    }
    /**
     * CVSS Integrity Impact.
     */
    private String cvssIntegrityImpact;

    /**
     * Get the value of cvssIntegrityImpact.
     *
     * @return the value of cvssIntegrityImpact
     */
    public String getCvssIntegrityImpact() {
        return cvssIntegrityImpact;
    }

    /**
     * Set the value of cvssIntegrityImpact.
     *
     * @param cvssIntegrityImpact new value of cvssIntegrityImpact
     */
    public void setCvssIntegrityImpact(String cvssIntegrityImpact) {
        this.cvssIntegrityImpact = cvssIntegrityImpact;
    }
    /**
     * CVSS Availability Impact.
     */
    private String cvssAvailabilityImpact;

    /**
     * Get the value of cvssAvailabilityImpact.
     *
     * @return the value of cvssAvailabilityImpact
     */
    public String getCvssAvailabilityImpact() {
        return cvssAvailabilityImpact;
    }

    /**
     * Set the value of cvssAvailabilityImpact.
     *
     * @param cvssAvailabilityImpact new value of cvssAvailabilityImpact
     */
    public void setCvssAvailabilityImpact(String cvssAvailabilityImpact) {
        this.cvssAvailabilityImpact = cvssAvailabilityImpact;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final Vulnerability other = (Vulnerability) obj;
        if ((this.name == null) ? (other.name != null) : !this.name.equals(other.name)) {
            return false;
        }
        return true;
    }

    @Override
    public int hashCode() {
        int hash = 5;
        hash = 41 * hash + (this.name != null ? this.name.hashCode() : 0);
        return hash;
    }

    /**
     * Compares two vulnerabilities.
     *
     * @param v a vulnerability to be compared
     * @return a negative integer, zero, or a positive integer as this object is less than, equal to, or greater than
     * the specified vulnerability
     */
    public int compareTo(Vulnerability v) {
        return v.getName().compareTo(this.getName());
    }

    /**
     * The CPE id that caused this vulnerability to be flagged.
     */
    private String matchedCPE;
    /**
     * Whether or not all previous versions were affected.
     */
    private String matchedAllPreviousCPE;

    /**
     * Sets the CPE that caused this vulnerability to be flagged.
     *
     * @param cpeId a CPE identifier
     * @param previous a flag indicating whether or not all previous versions were affected (any non-null value is
     * considered true)
     */
    public void setMatchedCPE(String cpeId, String previous) {
        matchedCPE = cpeId;
        matchedAllPreviousCPE = previous;
    }

    /**
     * Get the value of matchedCPE.
     *
     * @return the value of matchedCPE
     */
    public String getMatchedCPE() {
        return matchedCPE;
    }

    /**
     * Get the value of matchedAllPreviousCPE.
     *
     * @return the value of matchedAllPreviousCPE
     */
    public String getMatchedAllPreviousCPE() {
        return matchedAllPreviousCPE;
    }

    /**
     * Determines whether or not matchedAllPreviousCPE has been set.
     *
     * @return true if matchedAllPreviousCPE is not null; otherwise false
     */
    public boolean hasMatchedAllPreviousCPE() {
        return matchedAllPreviousCPE != null;
    }
}
