<?php

/**
 * @author Michal Prochazka
 * @author Jakub Mlcak
 */
class VulnerabilityDao
{
    private $db;

    public function __construct(DbManager $dbManager)
    {
        $this->db = $dbManager;
    }

    /**
     * Stores the vulnerability in the DB
     */
    public function create(Vulnerability $vulnerability)
    {
        $this->db->query("insert into Vulnerability set
            operator='" . $vulnerability->getOperator() . "',
            cveDefId=" . $this->db->escape($vulnerability->getCveDefId()) . ",
            osGroupId=" . $this->db->escape($vulnerability->getOsGroupId()) . ",
            name=" . $this->db->escape($vulnerability->getName()) . ",
            version=" . $this->db->escape($vulnerability->getVersion()) . ",
            release=" . $this->db->escape($vulnerability->getRelease()) . ",
            archId=" . $this->db->escape($vulnerability->getArchId()));

        # Set the newly assigned id
        $vulnerability->setId($this->db->getLastInsertedId());
    }

    /**
     * Stores multiple vulnerabilities, using insert ignore to avoid errors during duplicates
     */
    public function createMultiple($vulnerabilities)
    {
        # If vulnerabilities is not an array, then quit
        if (!is_array($vulnerabilities)) {
            return;
        }
        $sql = 'insert ignore into Vulnerability (`name`, version, `release`, `archId`, operator, `cveDefId`, osGroupId) values ';
        $firstEntry = true;
        foreach ($vulnerabilities as $vuln) {
            # Do not add comma before first entry
            if ($firstEntry) {
                $firstEntry = false;
            } else {
                $sql .=',';
            }
            $sql .= "('".$this->db->escape($vuln->getName())."',".
                "'".$this->db->escape($vuln->getVersion())."',".
                "'".$this->db->escape($vuln->getRelease())."',".
                "'".$this->db->escape($vuln->getArchId())."',".
                "'".$vuln->getOperator()."',".
                "'".$this->db->escape($vuln->getCveDefId())."',".
                "'".$this->db->escape($vuln->getOsGroupId())."')";
        }
        $this->db->query($sql);
    }

    /**
     * Get the vulnerability by its ID
     */
    public function getById($id)
    {
        if (!is_numeric($id)) {
            return null;
        }
        return $this->db->queryObject("select Vulnerability.id as _id, Vulnerability.name as _name, Vulnerability.version as _version,
            Vulnerability.`release` as _release, Vulnerability.archId as _archId, Vulnerability.operator as _operator, Vulnerability.cveDefId as _cveDefId,
            Vulnerability.osGroupId as _osGroupId, Arch.name as _archName, OsGroup.name as _osGroupName from Vulnerability
            inner join Arch on Vulnerability.archId = Arch.id
            inner join OsGroup on Vulnerability.osGroupId = OsGroup.id
            where Vulnerability.id = '" . $this->db->escape($id) . "'", "Vulnerability");
    }

    public function getIdsByCveNameAndOsId($cveName, $osId = -1)
    {
        $sql = "select Vulnerability.id from Vulnerability
            inner join CveCveDef on Vulnerability.cveDefId = CveCveDef.cveDefId
            inner join Cve on (CveCveDef.cveId = Cve.id and Cve.name = '" . $this->db->escape($cveName) . "')";
        if ($osId != -1) {
            $sql .= " inner join OsOsGroup on Vulnerability.osGroupId = OsOsGroup.osGroupId and OsOsGroup.osId = '" . $this->db->escape($osId) . "'";
        }
        $sql .= " order by Vulnerability.name";
        return $this->db->queryToSingleValueMultiRow($sql);
    }

    /**
     * Return array of Vulnerabilities for a specific package name and arch ID
     */
    public function getVulnerabilitiesByNameArchId($name, $archId)
    {
        $sql = "select Vulnerability.id as _id, Vulnerability.name as _name, Vulnerability.version as _version,
            Vulnerability.`release` as _release, Vulnerability.archId as _archId, Vulnerability.operator as _operator, Vulnerability.cveDefId as _cveDefId,
            Vulnerability.osGroupId as _osGroupId, Arch.name as _archName, OsGroup.name as _osGroupName from Vulnerability
            inner join Arch on Vulnerability.archId = Arch.id
            inner join OsGroup on Vulnerability.osGroupId = OsGroup.id
            where Vulnerability.name='" . $this->db->escape($name) . "' and (Arch.name='all' or Vulnerability.archId='" . $this->db->escape($archId) . "')";

        # Create objects
        $vulnerabilities = $this->db->queryObjects($sql, "Vulnerability");

        if ($vulnerabilities == null) {
            $vulnerabilities = array();
        }
        return $vulnerabilities;
    }

    public function delete_with_cveDefId($cveDefIds)
    {
        if (!is_array($cveDefIds) || empty($cveDefIds))
            return;

        $ids = array();
        foreach ($cveDefIds as $id)
            array_push($ids, $this->db->escape($id));

        $par = "(" . join(",", $ids) . ")";
        $sql = "delete from Vulnerability where cveDefId in " . $par;
        $this->db->query($sql);
    }
}
