# Copyright (c) 2017, The MITRE Corporation. All rights reserved.
# See LICENSE.txt for complete terms.

from mixbox import fields

import stix
import stix.utils as utils
import stix.bindings.exploit_target as exploit_target_binding
import stix.bindings.stix_common as stix_common_binding
from stix.common import DateTimeWithPrecision, StructuredTextList
from stix.common.related import GenericRelationshipList, RelatedObservable
from mixbox import entities, fields
from stix.common import References

class Vulnerability(stix.Entity):
    """Implementation of STIX ``Vulnerability``.

    Args:
        title (optional): A string title.
        description (optional): A string description.
        short_description (optional): A string short description.

    """
    _binding = exploit_target_binding
    _binding_class = _binding.VulnerabilityType
    _namespace = "http://stix.mitre.org/ExploitTarget-1"

    is_known = fields.BooleanField("is_known")
    is_publicly_acknowledged = fields.BooleanField("is_publicly_acknowledged")
    title = fields.TypedField("Title")
    descriptions = fields.TypedField("Description", type_="stix.common.StructuredTextList")
    short_descriptions = fields.TypedField("Short_Description", type_="stix.common.StructuredTextList")
    cve_id = fields.TypedField("CVE_ID")
    osvdb_id = fields.TypedField("OSVDB_ID")
    source = fields.TypedField("Source")
    cvss_score = fields.TypedField("CVSS_Score", "stix.exploit_target.vulnerability.CVSSVector")
    discovered_datetime = fields.TypedField("Discovered_DateTime", DateTimeWithPrecision)
    published_datetime = fields.TypedField("Published_DateTime", DateTimeWithPrecision)
    affected_software = fields.TypedField("Affected_Software", "stix.exploit_target.vulnerability.AffectedSoftware")
    references = fields.TypedField("References", References)

    def __init__(self, title=None, description=None, short_description=None):
        super(Vulnerability, self).__init__()
        self.title = title
        self.descriptions = StructuredTextList(description)
        self.short_descriptions = StructuredTextList(short_description)
        self.references = []

    @property
    def description(self):
        """A single description about the contents or purpose of this object.

        Default Value: ``None``

        Note:
            If this object has more than one description set, this will return
            the description with the lowest ordinality value.

        Returns:
            An instance of :class:`.StructuredText`
        """
        return next(iter(self.descriptions or []), None)

    @description.setter
    def description(self, value):
        self.descriptions = value

    def add_description(self, description):
        """Adds a description to the ``descriptions`` collection.

        This is the same as calling "foo.descriptions.add(bar)".
        """
        self.descriptions.add(description)

    @property
    def short_description(self):
        """A single short description about the contents or purpose of this
        object.

        Default Value: ``None``

        Note:
            If this object has more than one short description set, this will
            return the description with the lowest ordinality value.

        Returns:
            An instance of :class:`.StructuredText`
        """
        return next(iter(self.short_descriptions or []), None)

    @short_description.setter
    def short_description(self, value):
        self.short_descriptions = value

    def add_short_description(self, description):
        """Adds a description to the ``short_descriptions`` collection.

        This is the same as calling "foo.short_descriptions.add(bar)".
        """
        self.short_descriptions.add(description)

    def add_reference(self, reference):
        if not reference:
            return

        self.references.append(reference)

class CVSSVector(stix.Entity):
    """
    Common Vulnerabilit Scoring System object, representing its component measures
    
    """
    _binding = exploit_target_binding
    _binding_class = exploit_target_binding.CVSSVectorType
    _namespace = "http://stix.mitre.org/ExploitTarget-1"

    overall_score = fields.TypedField("Overall_Score")
    base_score = fields.TypedField("Base_Score")
    base_vector = fields.TypedField("Base_Vector")
    temporal_score = fields.TypedField("Temporal_Score")
    temporal_vector = fields.TypedField("Temporal_Vector")
    environmental_score = fields.TypedField("Environmental_Score")
    environmental_vector = fields.TypedField("Environmental_Vector")

    def __init__(self):
        super(CVSSVector, self).__init__()


class AffectedSoftware(GenericRelationshipList):
    _binding = exploit_target_binding
    _binding_class = exploit_target_binding.AffectedSoftwareType
    _namespace = "http://stix.mitre.org/ExploitTarget-1"

    affected_software = fields.TypedField("Affected_Software", RelatedObservable, multiple=True, key_name="affected_software")


# NOT AN ACTUAL STIX TYPE!
class _Vulnerabilities(stix.TypedList):
    _contained_type = Vulnerability
