from builtins import object
import os
import json

from vulndb.constants.wasc import WASC_ID_TO_URL
from vulndb.constants.cwe import CWE_URL_FMT
from vulndb.constants.owasp import (OWASP_TOP10_2010_URL_FMT,
                                    OWASP_TOP10_2013_URL_FMT)


class DBVuln(object):
    """
    Wrapper around a vulnerability as defined in vulndb JSON files.

    :see: https://github.com/vulndb/data/issues/5
    :see: https://github.com/vulndb/data
    """
    DB_PATH = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'db')
    DB_VERSION_FILE = 'db-version.txt'
    DEFAULT_LANG = 'en'

    def __init__(self, _id=None, title=None, description=None, severity=None,
                 wasc=None, tags=None, cwe=None, owasp_top_10=None,
                 fix_guidance=None, fix_effort=None, references=None,
                 db_file=None):
        """
        Creates a new DBVuln, setting the internal attributes to the provided
        kwargs.
        """
        self.id = _id
        self.title = title
        self.description = description
        self.severity = severity
        self.wasc = wasc
        self.tags = tags
        self.cwe = cwe
        self.owasp_top_10 = owasp_top_10
        self.fix_guidance = fix_guidance
        self.fix_effort = fix_effort
        self.references = references
        self.db_file = db_file

    @staticmethod
    def get_json_path(language=DEFAULT_LANG):
        """
        :param language: The user's language (en, es, etc.)
        :return: The path where the json files are located
        """
        return os.path.join(DBVuln.DB_PATH, language)

    @staticmethod
    def get_description_path(language=DEFAULT_LANG):
        """
        :param language: The user's language (en, es, etc.)
        :return: The path where the description markdown files are located
        """
        return os.path.join(DBVuln.DB_PATH, language, 'description')

    @staticmethod
    def get_fix_path(language=DEFAULT_LANG):
        """
        :param language: The user's language (en, es, etc.)
        :return: The path where the fix markdown files are located
        """
        return os.path.join(DBVuln.DB_PATH, language, 'fix')

    @staticmethod
    def get_all_languages():
        return os.listdir(DBVuln.DB_PATH)

    @staticmethod
    def get_db_version():
        db_version = os.path.join(os.path.dirname(os.path.realpath(__file__)),
                                  DBVuln.DB_VERSION_FILE)
        return open(db_version).read().strip()

    @classmethod
    def from_file(cls, db_file, language=DEFAULT_LANG):
        """
        This is an alternative "constructor" for the DBVuln class which loads
        the data from a file.

        :param db_file: Contents of a json file from the DB
        :param language: The user's language (en, es, etc.)
        """
        data = DBVuln.load_from_json(db_file, language=language)
        return cls(**data)

    @classmethod
    def from_id(cls, _id, language=DEFAULT_LANG):
        """
        This is an alternative "constructor" for the DBVuln class which searches
        the db directory to find the right file for the provided _id
        """
        db_file = DBVuln.get_file_for_id(_id, language=language)
        data = DBVuln.load_from_json(db_file, language=language)
        return cls(**data)

    def get_owasp_top_10_references(self):
        for owasp_version in self.owasp_top_10:
            for risk_id in self.owasp_top_10[owasp_version]:
                ref = self.get_owasp_top_10_url(owasp_version, risk_id)
                if ref is not None:
                    yield owasp_version, risk_id, ref

    @staticmethod
    def get_file_for_id(_id, language=DEFAULT_LANG):
        """
        Given _id, search the DB for the file which contains the data

        :param _id: The id to search (int)
        :param language: The user's language (en, es, etc.)
        :return: The filename
        """
        file_start = '%s-' % _id

        json_path = DBVuln.get_json_path(language=language)

        for _file in os.listdir(json_path):