"""
Defines types for describing different kinds of mass spectrometry
data files and their contents, and a database of controlled vocabulary
terms for them.
"""

import os
import re
import hashlib
from typing import List, Union
import warnings

from collections import OrderedDict

try:
    from collections.abc import MutableMapping, Mapping
except ImportError:
    from collections import MutableMapping, Mapping

from six import string_types as basestring

from .cv import Term, TermSet

try:
    FileNotFoundError
except NameError:
    FileNotFoundError = OSError

class IDParserBase(object):
    """A base class for ID parsing and formatting."""

    def parse(self, text):
        """
        Parse a string looking for fields defined by this ID format.

        Parameters
        ----------
        text : str
            The string to parse

        Returns
        -------
        dict:
            The parsed fields of the ID string.
        """
        raise NotImplementedError()

    def format(self, fields):
        """
        Format a set of fields as a nativeID string.

        Parameters
        ----------
        fields : dict
            The fields to populate the nativeID from.

        Returns
        -------
        str
        """
        raise NotImplementedError()

    def __call__(self, text):
        """
        Parse a string looking for fields defined by this ID format.

        Parameters
        ----------
        text : str
            The string to parse

        Returns
        -------
        dict:
            The parsed fields of the ID string.

        See Also
        --------
        :meth:`parse`
        """
        return self.parse(text)

class IDFormat(Term, IDParserBase):
    """
    Describes a named spectrum identifier format, either
    using a controlled-vocabulary term or user-defined name.

    A :class:`IDFormat` is equal to its name and its controlled
    vocabulary identifier.

    An instance may also be used to parse a string in its format
    using its :meth:`parse` method, creating a :class:`dict` of
    its fields.

    Attributes
    ----------
    parser: NativeIDParser
        A parser for the specified nativeID format type.
    """

    def __init__(self, name, id, description, category, specialization):
        super(IDFormat, self).__init__(
            name, id, description, category, specialization)
        self.parser = NativeIDParser.from_term(self)

    def parse(self, text):
        """
        Parse a string looking for fields defined by this term's nativeID
        format

        Parameters
        ----------
        text : str
            The string to parse

        Returns
        -------
        dict:
            The parsed fields of the ID string.
        """
        if self.parser is None:
            raise ValueError(
                "This IDFormat doesn't have a pattern!")
        return self.parser.parse(text)

    def format(self, fields):
        """
        Format a set of fields as a nativeID string.

        Parameters
        ----------
        fields : dict
            The fields to populate the nativeID from.

        Returns
        -------
        str
        """
        return self.parser.format(fields)

    def __call__(self, text):
        return self.parse(text)

class FileFormat(Term):
    """
    Describes a named mass spectrometry data file format, either
    using a controlled-vocabulary term or user-defined name.

    A :class:`FileFormat` is equal to its name and its controlled
    vocabulary identifier.
    """

    pass

class FileContent(Term):
    """
    Describes a named mass spectrometry data file content type,
    either using a controlled-vocabulary term or user-defined name.

    A :class:`FileContent` is equal to its name and its controlled
    vocabulary identifier.
    """

    pass

class DataAcquisitionAspect(Term):
    """
    Describes a named mass spectrometry data acquisition method
    aspect, either using a controlled-vocabulary term or user-defined
    name.

    """

    BASE_TERM = "MS:1003214"

data_acquisition_aspects = []

# [[[cog
# import cog
# from ms_deisotope.data_source.metadata.cv import render_list
# render_list('mass spectrometry acquisition method aspect',
#             "data_acquisition_aspects", term_cls_name="DataAcquisitionAspect", writer=cog.out)
# ]]]
# CV Version: 4.1.114
data_acquisition_aspects = TermSet([
    DataAcquisitionAspect('data-independent acquisition', 'MS:1003215',
                          ('Mass spectrometer data acquisition method wherein mass '
                           'selection for fragmentation is configured according to a '
                           'pre-determined program, rather than based on any detected '
                           'precursor ions.'),
                          'mass spectrometry acquisition method aspect',
                          ['mass spectrometry acquisition method aspect', 'spectrum generation information']),
    DataAcquisitionAspect('dissociation of full mass range', 'MS:1003216',
                          ('Mass spectrometer data acquisition method wherein all '
                           'precursor ions of which the instrument is capable are '
                           'fragmented at once..'),
                          'mass spectrometry acquisition method aspect',
                          ['mass spectrometry acquisition method aspect', 'spectrum generation information']),
    DataAcquisitionAspect('dissociation of scanning quadrupole across a specified mass range', 'MS:1003217',
                          ('Mass spectrometer data acquisition method wherein ????.'),
                          'mass spectrometry acquisition method aspect',
                          ['mass spectrometry acquisition method aspect', 'spectrum generation information']),
    DataAcquisitionAspect('dissociation of sequential mass ranges', 'MS:1003218',
                          ('Mass spectrometer data acquisition method wherein a series '
                           'of limited mass range fragmentation selection windows are '
                           'preconfigured.'),
                          'mass spectrometry acquisition method aspect',
                          ['mass spectrometry acquisition method aspect', 'spectrum generation information']),
    DataAcquisitionAspect('ion mobility separation', 'MS:1003219',
                          ('Mass spectrometer data acquisition method wherein precursor '
                           'ions are separated by their ion mobility properties prior to '
                           'measurement.'),
                          'mass spectrometry acquisition method aspect',
                          ['mass spectrometry acquisition method aspect', 'spectrum generation information']),
    DataAcquisitionAspect('data-dependent acquisition', 'MS:1003221',
                          ('Mass spectrometer data acquisition method wherein MSn '
                           'spectra are triggered based on the m/z of precursor ions '
                           'detected in the same run.'),
                          'mass spectrometry acquisition method aspect',
                          ['mass spectrometry acquisition method aspect', 'spectrum generation information']),
    DataAcquisitionAspect('selected ion monitoring', 'MS:1000205',
                          ('The operation of a mass spectrometer in which the '
                           'intensities of several specific m/z values are recorded '
                           'rather than the entire mass spectrum.'),
                          'mass spectrometry acquisition method aspect',
                          ['data-independent acquisition', 'mass spectrometry acquisition method', 'mass spectrometry acquisition method aspect', 'data file content', 'acquisition parameter', 'spectrum generation information']),
    DataAcquisitionAspect('selected reaction monitoring', 'MS:1000206',
                          ('Data acquired from specific product ions corresponding to '
                           'm/z selected precursor ions recorded via multiple stages of '
                           'mass spectrometry. Selected reaction monitoring can be '
                           'performed in time or in space.'),
                          'mass spectrometry acquisition method aspect',
                          ['data-independent acquisition', 'mass spectrometry acquisition method', 'mass spectrometry acquisition method aspect', 'data file content', 'acquisition parameter', 'spectrum generation information']),
    DataAcquisitionAspect('data independent acquisition from dissociation of sequential mass ranges', 'MS:1003224',
                          ('Data independent mass spectrometer acquisition method '
                           'wherein a preconfigured sequence of mass ranges are '
                           'fragmented. Examples of such an approach include SWATH-MS, '
                           'FT-ARM, HRM, and PAcIFIC.'),
                          'mass spectrometry acquisition method aspect',
                          ['dissociation of sequential mass ranges', 'data-independent acquisition', 'mass spectrometry acquisition method', 'mass spectrometry acquisition method aspect', 'data file content', 'acquisition parameter', 'spectrum generation information']),
    DataAcquisitionAspect('data independent acquisition from dissociation of sequential mass ranges after ion mobility separation', 'MS:1003225',
                          ('Data independent mass spectrometer acquisition method '
                           'wherein a preconfigured sequence of mass ranges are '
                           'fragmented after being separated by ion mobility. An example '
                           'of such an approach is Bruker diaPASEF.'),
                          'mass spectrometry acquisition method aspect',
                          ['dissociation of sequential mass ranges', 'ion mobility separation', 'data-independent acquisition', 'mass spectrometry acquisition method', 'mass spectrometry acquisition method aspect', 'data file content', 'acquisition parameter', 'spectrum generation information']),
    DataAcquisitionAspect('data independent acquisition from dissociation of full mass range after ion mobility separation', 'MS:1003226',
                          ('Data independent mass spectrometer acquisition method '
                           'wherein the full mass range is fragmented after being '
                           'separated by ion mobility. Examples of such an approach '
                           'include HDMS^E and IMS-AIF.'),
                          'mass spectrometry acquisition method aspect',
                          ['dissociation of full mass range', 'ion mobility separation', 'data-independent acquisition', 'mass spectrometry acquisition method', 'mass spectrometry acquisition method aspect', 'data file content', 'acquisition parameter', 'spectrum generation information']),
    DataAcquisitionAspect('data independent acquisition from dissociation of full mass range', 'MS:1003227',
                          ('Data independent mass spectrometer acquisition method '
                           'wherein the full mass range is fragmented. Examples of such '
                           'an approach include MS^E, AIF, and bbCID.'),
                          'mass spectrometry acquisition method aspect',
                          ['dissociation of full mass range', 'ion mobility separation', 'data-independent acquisition', 'mass spectrometry acquisition method', 'mass spectrometry acquisition method aspect', 'data file content', 'acquisition parameter', 'spectrum generation information']),
    DataAcquisitionAspect('data independent acquisition from dissociation of scanning quadrupole across mass range', 'MS:1003228',
                          ('Data independent mass spectrometer acquisition method '
                           'wherein ???. An example of such an approach is Waters SONAR.'),
                          'mass spectrometry acquisition method aspect',
                          ['data-independent acquisition', 'dissociation of scanning quadrupole across a specified mass range', 'mass spectrometry acquisition method', 'mass spectrometry acquisition method aspect', 'data file content', 'acquisition parameter', 'spectrum generation information']),
])
# [[[end]]]

class DataAcquisitionMethod(Term):
    """
    Describes a named mass spectrometry data acquisition method,
    either using a controlled-vocabulary term or user-defined name.
    """

    BASE_TERM = "MS:1003213"

    def is_dda(self) -> bool:
        """Check if this method is data-dependent or not."""
        return self.has_aspect('MS:1003221') or not self.has_aspect('MS:1003215')

    def is_dia(self) -> bool:
        """Check if this method is data-independent or not"""
        return self.has_aspect('MS:1003215')

    def is_ion_mobility(self) -> bool:
        """Check if this method includes ion mobility"""
        return self.has_aspect('MS:1003219')

    def has_aspect(self, aspect: Union[str, DataAcquisitionAspect]) -> bool:
        """
        Check if this method has a particular aspect.

        Parameters
        ----------
        aspect : str or :class:`DataAcquisitionAspect`
            The aspect to check for. Strings will be resolved to their matching aspects.

        Returns
        -------
        bool
        """
        if not isinstance(aspect, DataAcquisitionAspect):
            aspect: DataAcquisitionAspect = data_acquisition_aspects.get(aspect)
        return aspect.name in self.specialization

data_acquisition_methods = []

# [[[cog
# import cog
# from ms_deisotope.data_source.metadata.cv import render_list
# render_list('mass spectrometry acquisition method',
#             "data_acquisition_methods", term_cls_name="DataAcquisitionMethod", writer=cog.out)
# ]]]
# CV Version: 4.1.114
data_acquisition_methods = TermSet([
    DataAcquisitionMethod('selected ion monitoring', 'MS:1000205',
                          ('The operation of a mass spectrometer in which the '
                           'intensities of several specific m/z values are recorded '
                           'rather than the entire mass spectrum.'),
                          'mass spectrometry acquisition method',
                          ['data-independent acquisition', 'mass spectrometry acquisition method', 'mass spectrometry acquisition method aspect', 'data file content', 'acquisition parameter', 'spectrum generation information']),
    DataAcquisitionMethod('selected reaction monitoring', 'MS:1000206',
                          ('Data acquired from specific product ions corresponding to '
                           'm/z selected precursor ions recorded via multiple stages of '
                           'mass spectrometry. Selected reaction monitoring can be '
                           'performed in time or in space.'),
                          'mass spectrometry acquisition method',
                          ['data-independent acquisition', 'mass spectrometry acquisition method', 'mass spectrometry acquisition method aspect', 'data file content', 'acquisition parameter', 'spectrum generation information']),
    DataAcquisitionMethod('data independent acquisition from dissociation of sequential mass ranges', 'MS:1003224',
                          ('Data independent mass spectrometer acquisition method '
                           'wherein a preconfigured sequence of mass ranges are '
                           'fragmented. Examples of such an approach include SWATH-MS, '
                           'FT-ARM, HRM, and PAcIFIC.'),
                          'mass spectrometry acquisition method',
                          ['dissociation of sequential mass ranges', 'data-independent acquisition', 'mass spectrometry acquisition method', 'mass spectrometry acquisition method aspect', 'data file content', 'acquisition parameter', 'spectrum generation information']),
    DataAcquisitionMethod('data independent acquisition from dissociation of sequential mass ranges after ion mobility separation', 'MS:1003225',
                          ('Data independent mass spectrometer acquisition method '
                           'wherein a preconfigured sequence of mass ranges are '
                           'fragmented after being separated by ion mobility. An example '
                           'of such an approach is Bruker diaPASEF.'),
                          'mass spectrometry acquisition method',
                          ['dissociation of sequential mass ranges', 'ion mobility separation', 'data-independent acquisition', 'mass spectrometry acquisition method', 'mass spectrometry acquisition method aspect', 'data file content', 'acquisition parameter', 'spectrum generation information']),
    DataAcquisitionMethod('data independent acquisition from dissociation of full mass range after ion mobility separation', 'MS:1003226',
                          ('Data independent mass spectrometer acquisition method '
                           'wherein the full mass range is fragmented after being '
                           'separated by ion mobility. Examples of such an approach '
                           'include HDMS^E and IMS-AIF.'),
                          'mass spectrometry acquisition method',
                          ['dissociation of full mass range', 'ion mobility separation', 'data-independent acquisition', 'mass spectrometry acquisition method', 'mass spectrometry acquisition method aspect', 'data file content', 'acquisition parameter', 'spectrum generation information']),
    DataAcquisitionMethod('data independent acquisition from dissociation of full mass range', 'MS:1003227',
                          ('Data independent mass spectrometer acquisition method '
                           'wherein the full mass range is fragmented. Examples of such '
                           'an approach include MS^E, AIF, and bbCID.'),
                          'mass spectrometry acquisition method',
                          ['dissociation of full mass range', 'ion mobility separation', 'data-independent acquisition', 'mass spectrometry acquisition method', 'mass spectrometry acquisition method aspect', 'data file content', 'acquisition parameter', 'spectrum generation information']),
    DataAcquisitionMethod('data independent acquisition from dissociation of scanning quadrupole across mass range', 'MS:1003228',
                          ('Data independent mass spectrometer acquisition method '
                           'wherein ???. An example of such an approach is Waters SONAR.'),
                          'mass spectrometry acquisition method',
                          ['data-independent acquisition', 'dissociation of scanning quadrupole across a specified mass range', 'mass spectrometry acquisition method', 'mass spectrometry acquisition method aspect', 'data file content', 'acquisition parameter', 'spectrum generation information']),
])
# [[[end]]]

type_pat = re.compile("([A-Za-z]+)=xsd:(%s+)" % '|'.join(
    {'IDREF', "long", 'nonNegativeInteger', 'positiveInteger', 'string'}))

xsd_to_regex = {
    "IDREF": r"(\S+)",
    "long": r"(-?\d+)",
    "nonNegativeInteger": r"(\d+)",
    "positiveInteger": r"(\d+)",
    "string": r"(\S+)",
}

xsd_to_type = {
    "IDREF": str,
    "long": int,
    "nonNegativeInteger": int,
    "positiveInteger": int,
    "string": str,
}

class NativeIDParser(IDParserBase):
    """
    A parser for a single nativeID format.

    These may be automatically derived from the CV-param defining them by parsing the
    XSD string included, but no guarantee is available.
    """

    def __init__(self, parser, tokens, name):
        self.parser = parser
        self.tokens = OrderedDict(tokens)
        self.name = name

    @classmethod
    def from_term(cls, term):
        """
        Construct a :class:`NativeIDParser` from :class:`IDFormat` term.

        Parameters
        ----------
        term : IDFormat
            The nativeID format specification to build a parser for

        Returns
        -------
        :class:`NativeIDParser`:
            The constructed parser, or :const:`None` if no regular expression could be
            constructed.
        """
        if "Native format defined by" in term.description:
            tokens = []
            desc = term.description.split(
                "Native format defined by", 1)[1].rstrip()
            for mat in type_pat.finditer(desc):
                tokens.append(mat.groups())
            parser = re.compile(
                ''.join([r"(%s)=%s\s?" % (k, xsd_to_regex[v]) for k, v in tokens]))
            return cls(parser, tokens, term.name)
        return None

    def parse(self, string):
        """
        Parse a string according to this parser's pattern,
        returning the type-cast fields as a :class:`dict`.

        Parameters
        ----------
        string : str
            The string to parse

        Returns
        -------
        dict
            The fields of the scan ID

        Raises
        ------
        ValueError:
            If the string does not conform to the expected pattern
        """
        match = self.parser.match(string)
        if match is None:
            return OrderedDict()
        groups = match.groups()
        n = len(groups)
        i = 0
        fields = OrderedDict()
        while i < n:
            k = groups[i]
            v = groups[i + 1]
            i += 2
            try:
                v = int(v)
            except ValueError:
                pass
            fields[k] = v
        return fields

    def format(self, fields):
        """
        Format a set of fields as a nativeID string.

        Parameters
        ----------
        fields : dict
            The fields to populate the nativeID from.

        Returns
        -------
        str
        """
        parts = []
        for key in self.tokens:
            parts.append("%s=%s" % (key, fields[key]))
        return ' '.join(parts)

class MultipleIDFormats(Mapping, IDParserBase):
    """
    Represent an ambiguous group of multiple nativeID formats.

    Implements the :class:`~collections.abc.Mapping` interface.

    Attributes
    ----------
    id_formats : OrderedDict
        A mapping of format name to :class:`IDFormat` instances
    """

    def __init__(self, id_formats):
        self.id_formats = id_formats

    def parse(self, text):
        fields = OrderedDict()
        for name, parser in self.id_formats.items():
            fields = parser.parse(text)
            if not fields:
                continue
            else:
                fields['id_format'] = name
                break
        return fields

    def format(self, fields):
        format_name = fields.get('id_format')
        id_format = self.id_formats[format_name]
        return id_format.format(fields)

    def __iter__(self):
        return iter(self.id_formats)

    def __getitem__(self, key):
        return self.id_formats[key]

    def __len__(self):
        return len(self.id_formats)

    def __repr__(self):
        template = "{self.__class__.__name__}({self.id_formats})"
        return template.format(self=self)

id_formats = []

# [[[cog
# import cog
# from ms_deisotope.data_source.metadata.cv import render_list
# render_list('native spectrum identifier format',
#             "id_formats", term_cls_name="IDFormat", writer=cog.out)
# ]]]
# CV Version: 4.1.114
id_formats = TermSet([
    IDFormat('Thermo nativeID format', 'MS:1000768',
             ('Native format defined by '
              'controllerType=xsd:nonNegativeInteger '
              'controllerNumber=xsd:positiveInteger '
              'scan=xsd:positiveInteger.'),
             'native spectrum identifier format',
             ['native spectrum identifier format']),
    IDFormat('Waters nativeID format', 'MS:1000769',
             ('Native format defined by function=xsd:positiveInteger '
              'process=xsd:nonNegativeInteger scan=xsd:nonNegativeInteger.'),
             'native spectrum identifier format',
             ['native spectrum identifier format']),
    IDFormat('WIFF nativeID format', 'MS:1000770',
             ('Native format defined by sample=xsd:nonNegativeInteger '
              'period=xsd:nonNegativeInteger cycle=xsd:nonNegativeInteger '
              'experiment=xsd:nonNegativeInteger.'),
             'native spectrum identifier format',
             ['native spectrum identifier format']),
    IDFormat('Bruker/Agilent YEP nativeID format', 'MS:1000771',
             ('Native format defined by scan=xsd:nonNegativeInteger.'),
             'native spectrum identifier format',
             ['native spectrum identifier format']),
    IDFormat('Bruker BAF nativeID format', 'MS:1000772',
             ('Native format defined by scan=xsd:nonNegativeInteger.'),
             'native spectrum identifier format',
             ['native spectrum identifier format']),
    IDFormat('Bruker FID nativeID format', 'MS:1000773',
             ('Native format defined by file=xsd:IDREF.'),
             'native spectrum identifier format',
             ['native spectrum identifier format']),
    IDFormat('multiple peak list nativeID format', 'MS:1000774',
             ('Native format defined by index=xsd:nonNegativeInteger.'),
             'native spectrum identifier format',
             ['native spectrum identifier format']),
    IDFormat('single peak list nativeID format', 'MS:1000775',
             ('Native format defined by file=xsd:IDREF.'),
             'native spectrum identifier format',
             ['native spectrum identifier format']),
    IDFormat('scan number only nativeID format', 'MS:1000776',
             ('Native format defined by scan=xsd:nonNegativeInteger.'),
             'native spectrum identifier format',
             ['native spectrum identifier format']),
    IDFormat('spectrum identifier nativeID format', 'MS:1000777',
             ('Native format defined by spectrum=xsd:nonNegativeInteger.'),
             'native spectrum identifier format',
             ['native spectrum identifier format']),
    IDFormat('Bruker U2 nativeID format', 'MS:1000823',
             ('Native format defined by declaration=xsd:nonNegativeInteger '
              'collection=xsd:nonNegativeInteger '
              'scan=xsd:nonNegativeInteger.'),
             'native spectrum identifier format',
             ['native spectrum identifier format']),
    IDFormat('no nativeID format', 'MS:1000824',
             ('No nativeID format indicates that the file tagged with this '
              'term does not contain spectra that can have a nativeID '
              'format.'),
             'native spectrum identifier format',
             ['native spectrum identifier format']),
    IDFormat('Shimadzu Biotech nativeID format', 'MS:1000929',
             ('Native format defined by source=xsd:string '
              'start=xsd:nonNegativeInteger end=xsd:nonNegativeInteger.'),
             'native spectrum identifier format',
             ['native spectrum identifier format']),
    IDFormat('SCIEX TOF/TOF nativeID format', 'MS:1001480',
             ('Native format defined by jobRun=xsd:nonNegativeInteger '
              'spotLabel=xsd:string spectrum=xsd:nonNegativeInteger.'),
             'native spectrum identifier format',
             ['native spectrum identifier format']),
    IDFormat('Agilent MassHunter nativeID format', 'MS:1001508',
             ('Native format defined by scanId=xsd:nonNegativeInteger.'),
             'native spectrum identifier format',
             ['native spectrum identifier format']),
    IDFormat('spectrum from database integer nativeID format', 'MS:1001526',
             ('Native format defined by databasekey=xsd:long.'),
             'native spectrum identifier format',
             ['native spectrum identifier format']),
    IDFormat('Mascot query number', 'MS:1001528',
             ('Native format defined by query=xsd:nonNegativeInteger.'),
             'native spectrum identifier format',
             ['native spectrum identifier format', 'spectrum identification result details']),
    IDFormat('spectrum from ProteinScape database nativeID format', 'MS:1001531',
             ('Native format defined by databasekey=xsd:long.'),
             'native spectrum identifier format',
             ['native spectrum identifier format', 'spectra data details', 'search input details']),
    IDFormat('spectrum from database string nativeID format', 'MS:1001532',
             ('Native format defined by databasekey=xsd:string.'),
             'native spectrum identifier format',
             ['native spectrum identifier format', 'spectra data details', 'search input details']),
    IDFormat('SCIEX TOF/TOF T2D nativeID format', 'MS:1001559',
             ('Native format defined by file=xsd:IDREF.'),
             'native spectrum identifier format',
             ['native spectrum identifier format']),
    IDFormat('Scaffold nativeID format', 'MS:1001562',
             ('Scaffold native ID format.'),
             'native spectrum identifier format',
             ['native spectrum identifier format']),
    IDFormat('Bruker Container nativeID format', 'MS:1002303',
             ('Native identifier (UUID).'),
             'native spectrum identifier format',
             ['native spectrum identifier format']),
    IDFormat('UIMF nativeID format', 'MS:1002532',
             ('Native format defined by frame=xsd:nonNegativeInteger '
              'scan=xsd:nonNegativeInteger '
              'frameType=xsd:nonNegativeInteger.'),
             'native spectrum identifier format',
             ['native spectrum identifier format']),
    IDFormat('Bruker TDF nativeID format', 'MS:1002818',
             ('Native format defined by frame=xsd:nonNegativeInteger '
              'scan=xsd:nonNegativeInteger.'),
             'native spectrum identifier format',
             ['native spectrum identifier format']),
    IDFormat('Shimadzu Biotech QTOF nativeID format', 'MS:1002898',
             ('Native format defined by scan=xsd:nonNegativeInteger.'),
             'native spectrum identifier format',
             ['native spectrum identifier format']),
    IDFormat('Bruker TSF nativeID format', 'MS:1003283',
             ('Native format defined by frame=xsd:nonNegativeInteger.'),
             'native spectrum identifier format',
             ['native spectrum identifier format']),
])
# [[[end]]]

file_formats = []

# [[[cog
# import cog
# from ms_deisotope.data_source.metadata.cv import render_list
# render_list('mass spectrometer file format',
#             "file_formats", term_cls_name="FileFormat", writer=cog.out)
# ]]]
# CV Version: 4.1.114
file_formats = TermSet([
    FileFormat('Waters raw format', 'MS:1000526',
               ('Waters data file format found in a Waters RAW directory, '
                'generated from an MS acquisition.'),
               'mass spectrometer file format',
               ['mass spectrometer file format', 'file format']),
    FileFormat('ABI WIFF format', 'MS:1000562',
               ('Applied Biosystems WIFF file format.'),
               'mass spectrometer file format',
               ['mass spectrometer file format', 'file format']),
    FileFormat('Thermo RAW format', 'MS:1000563',
               ('Thermo Scientific RAW file format.'),
               'mass spectrometer file format',
               ['mass spectrometer file format', 'file format']),
    FileFormat('PSI mzData format', 'MS:1000564',
               ('Proteomics Standards Inititative mzData file format.'),
               'mass spectrometer file format',
               ['mass spectrometer file format', 'file format']),
    FileFormat('Micromass PKL format', 'MS:1000565',
               ('Micromass PKL file format.'),
               'mass spectrometer file format',
               ['mass spectrometer file format', 'file format']),
    FileFormat('ISB mzXML format', 'MS:1000566',
               ('Institute of Systems Biology mzXML file format.'),
               'mass spectrometer file format',
               ['mass spectrometer file format', 'file format']),
    FileFormat('Bruker/Agilent YEP format', 'MS:1000567',
               ('Bruker/Agilent YEP file format.'),
               'mass spectrometer file format',
               ['mass spectrometer file format', 'file format']),
    FileFormat('mzML format', 'MS:1000584',
               ('Proteomics Standards Inititative mzML file format.'),
               'mass spectrometer file format',
               ['mass spectrometer file format', 'file format']),
    FileFormat('DTA format', 'MS:1000613',
               ('SEQUEST DTA file format.'),
               'mass spectrometer file format',
               ['mass spectrometer file format', 'file format']),
    FileFormat('ProteinLynx Global Server mass spectrum XML format', 'MS:1000614',
               ('Peak list file format used by ProteinLynx Global Server.'),
               'mass spectrometer file format',
               ['mass spectrometer file format', 'file format']),
    FileFormat('parameter file', 'MS:1000740',
               ('Parameter file used to configure the acquisition of raw data '
                'on the instrument.'),
               'mass spectrometer file format',
               ['mass spectrometer file format', 'file format']),
    FileFormat('Bioworks SRF format', 'MS:1000742',
               ('Thermo Finnigan SRF file format.'),
               'mass spectrometer file format',
               ['mass spectrometer file format', 'intermediate analysis format', 'file format']),
    FileFormat('Bruker BAF format', 'MS:1000815',
               ('Bruker BAF raw file format.'),
               'mass spectrometer file format',
               ['mass spectrometer file format', 'file format']),
    FileFormat('Bruker U2 format', 'MS:1000816',
               ('Bruker HyStar U2 file format.'),
               'mass spectrometer file format',
               ['mass spectrometer file format', 'file format']),
    FileFormat('Bruker FID format', 'MS:1000825',
               ('Bruker FID file format.'),
               'mass spectrometer file format',
               ['mass spectrometer file format', 'file format']),
    FileFormat('Shimadzu Biotech database entity', 'MS:1000930',
               ('Shimadzu Biotech format.'),
               'mass spectrometer file format',
               ['mass spectrometer file format', 'file format']),
    FileFormat('Mascot MGF format', 'MS:1001062',
               ('Mascot MGF file format.'),
               'mass spectrometer file format',
               ['mass spectrometer file format', 'file format']),
    FileFormat('PerSeptive PKS format', 'MS:1001245',
               ('PerSeptive peak list file format.'),
               'mass spectrometer file format',
               ['mass spectrometer file format', 'file format']),
    FileFormat('SCIEX API III format', 'MS:1001246',
               ('PE SCIEX peak list file format.'),
               'mass spectrometer file format',
               ['mass spectrometer file format', 'file format']),
    FileFormat('Bruker XML format', 'MS:1001247',
               ('Bruker data exchange XML format.'),
               'mass spectrometer file format',
               ['mass spectrometer file format', 'file format']),
    FileFormat('text format', 'MS:1001369',
               ('Simple text file format of \\"m/z [intensity]\\" values for a '
                'PMF (or single MS2) search.'),
               'mass spectrometer file format',
               ['mass spectrometer file format', 'file format']),
    FileFormat('Phenyx XML format', 'MS:1001463',
               ('Phenyx open XML file format.'),
               'mass spectrometer file format',
               ['mass spectrometer file format', 'intermediate analysis format', 'file format']),
    FileFormat('MS2 format', 'MS:1001466',
               ('MS2 file format for MS2 spectral data." [PMID:15317041, '
                'DOI:10.1002/rcm.1603'),
               'mass spectrometer file format',
               ['mass spectrometer file format', 'file format']),
    FileFormat('SCIEX TOF/TOF database', 'MS:1001481',
               ('Applied Biosystems/MDS Analytical Technologies TOF/TOF '
                'instrument database.'),
               'mass spectrometer file format',
               ['mass spectrometer file format', 'file format']),
    FileFormat('Agilent MassHunter format', 'MS:1001509',
               ('A data file format found in an Agilent MassHunter directory '
                'which contains raw data acquired by an Agilent mass '
                'spectrometer.'),
               'mass spectrometer file format',
               ['mass spectrometer file format', 'file format']),
    FileFormat('Proteinscape spectra', 'MS:1001527',
               ('Spectra from Bruker/Protagen Proteinscape database.'),
               'mass spectrometer file format',
               ['mass spectrometer file format', 'file format']),
    FileFormat('SCIEX TOF/TOF T2D format', 'MS:1001560',
               ('Applied Biosystems/MDS Analytical Technologies TOF/TOF '
                'instrument export format.'),
               'mass spectrometer file format',
               ['mass spectrometer file format', 'file format']),
    FileFormat('mz5 format', 'MS:1001881',
               ('mz5 file format, modelled after mzML.'),
               'mass spectrometer file format',
               ['mass spectrometer file format', 'file format']),
    FileFormat('Bruker Container format', 'MS:1002302',
               ('Bruker Container raw file format.'),
               'mass spectrometer file format',
               ['mass spectrometer file format', 'file format']),
    FileFormat('SCiLS Lab format', 'MS:1002385',
               ('SCiLS Lab file format.'),
               'mass spectrometer file format',
               ['mass spectrometer file format', 'file format']),
    FileFormat('Andi-MS format', 'MS:1002441',
               ('AIA Analytical Data Interchange file format for mass '
                'spectrometry data.'),
               'mass spectrometer file format',
               ['mass spectrometer file format', 'file format']),
    FileFormat('UIMF format', 'MS:1002531',
               ('SQLite-based file format created at Pacific Northwest '
                'National Lab. It stores an intermediate analysis of ion- '
                'mobility mass spectrometry data.'),
               'mass spectrometer file format',
               ['mass spectrometer file format', 'file format']),
    FileFormat('MS1 format', 'MS:1002597',
               ('MS1 file format for MS1 spectral data." [PMID:15317041'),
               'mass spectrometer file format',
               ['mass spectrometer file format', 'file format']),
    FileFormat('Bruker TDF format', 'MS:1002817',
               ('Bruker TDF raw file format.'),
               'mass spectrometer file format',
               ['mass spectrometer file format', 'file format']),
    FileFormat('mzMLb format', 'MS:1002838',
               ('mzMLb file format, mzML encapsulated within HDF5." [PSI:PI'),
               'mass spectrometer file format',
               ['mass spectrometer file format', 'file format']),
    FileFormat('msalign format', 'MS:1002899',
               ('msalign file format.'),
               'mass spectrometer file format',
               ['mass spectrometer file format', 'file format']),
    FileFormat('feature format', 'MS:1002900',
               ('TopFD feature file format.'),
               'mass spectrometer file format',
               ['mass spectrometer file format', 'file format']),
    FileFormat('chrom format', 'MS:1002966',
               ('The Lipid Data Analyzer native chrom format.'),
               'mass spectrometer file format',
               ['mass spectrometer file format', 'file format']),
    FileFormat('Andromeda:apl file format', 'MS:1002996',
               ('Peak list file format of the Andromeda search engine.'),
               'mass spectrometer file format',
               ['mass spectrometer file format', 'file format']),
    FileFormat('Shimadzu Biotech LCD format', 'MS:1003009',
               ('Shimadzu Biotech LCD file format.'),
               'mass spectrometer file format',
               ['mass spectrometer file format', 'file format']),
    FileFormat('Bruker TSF format', 'MS:1003282',
               ('Bruker TSF raw file format.'),
               'mass spectrometer file format',
               ['mass spectrometer file format', 'file format']),
])
# [[[end]]]

content_keys = []

# [[[cog
# import cog
# from ms_deisotope.data_source.metadata.cv import render_list
# render_list('data file content',
#             "content_keys", term_cls_name="FileContent", writer=cog.out)
# ]]]
# CV Version: 4.1.114
content_keys = TermSet([
    FileContent('mass spectrum', 'MS:1000294',
                ('A plot of the relative abundance of a beam or other '
                 'collection of ions as a function of the mass-to-charge ratio '
                 '(m/z).'),
                'data file content',
                ['data file content', 'spectrum type']),
    FileContent('PDA spectrum', 'MS:1000620',
                ('OBSOLETE Spectrum generated from a photodiode array detector '
                 '(ultraviolet/visible spectrum).'),
                'data file content',
                ['data file content', 'spectrum type']),
    FileContent('electromagnetic radiation spectrum', 'MS:1000804',
                ('A plot of the relative intensity of electromagnetic '
                 'radiation as a function of the wavelength.'),
                'data file content',
                ['data file content', 'spectrum type']),
    FileContent('emission spectrum', 'MS:1000805',
                ('A plot of the relative intensity of electromagnetic '
                 'radiation emitted by atoms or molecules when excited.'),
                'data file content',
                ['data file content', 'spectrum type']),
    FileContent('absorption spectrum', 'MS:1000806',
                ('A plot of the relative intensity of electromagnetic '
                 'radiation absorbed by atoms or molecules when excited.'),
                'data file content',
                ['data file content', 'spectrum type']),
    FileContent('ion current chromatogram', 'MS:1000810',
                ('Representation of the current of ions versus time.'),
                'data file content',
                ['data file content', 'chromatogram type']),
    FileContent('electromagnetic radiation chromatogram', 'MS:1000811',
                ('Representation of electromagnetic properties versus time.'),
                'data file content',
                ['data file content', 'chromatogram type']),
    FileContent('mass spectrometry acquisition method', 'MS:1003213',
                ('Specific aspect of a mass spectrometer method by which mass '
                 'ranges are selected and possibly dissociated.'),
                'data file content',
                ['data file content', 'acquisition parameter']),
    FileContent('charge inversion mass spectrum', 'MS:1000322',
                ('The measurement of the relative abundance of ions that '
                 'result from a charge inversion reaction as a function of '
                 'm/z.'),
                'data file content',
                ['mass spectrum', 'data file content', 'spectrum type']),
    FileContent('constant neutral gain spectrum', 'MS:1000325',
                ('A spectrum formed of all product ions that have been '
                 'produced by gain of a pre-selected neutral mass following '
                 'the reaction with and addition of the gas in a collision '
                 'cell.'),
                'data file content',
                ['mass spectrum', 'data file content', 'spectrum type']),
    FileContent('constant neutral loss spectrum', 'MS:1000326',
                ('A spectrum formed of all product ions that have been '
                 'produced with a selected m/z decrement from any precursor '
                 'ions. The spectrum shown correlates to the precursor ion '
                 'spectrum. See also neutral loss spectrum.'),
                'data file content',
                ['mass spectrum', 'data file content', 'spectrum type']),
    FileContent('e/2 mass spectrum', 'MS:1000328',
                ('A mass spectrum obtained using a sector mass spectrometer in '
                 'which the electric sector field E is set to half the value '
                 'required to transmit the main ion-beam. This spectrum '
                 'records the signal from doubly charged product ions of '
                 'charge-stripping reactions.'),
                'data file content',
                ['mass spectrum', 'data file content', 'spectrum type']),
    FileContent('precursor ion spectrum', 'MS:1000341',
                ('Spectrum generated by scanning precursor m/z while '
                 'monitoring a fixed product m/z.'),
                'data file content',
                ['mass spectrum', 'data file content', 'spectrum type']),
    FileContent('product ion spectrum', 'MS:1000343',
                ('OBSOLETE A mass spectrum recorded from any spectrometer in '
                 'which the appropriate m/z separation scan function is set to '
                 'record the product ion or ions of selected precursor ions.'),
                'data file content',
                ['mass spectrum', 'data file content', 'spectrum type']),
    FileContent('MS1 spectrum', 'MS:1000579',
                ('Mass spectrum created by a single-stage MS experiment or the '
                 'first stage of a multi-stage experiment.'),
                'data file content',
                ['mass spectrum', 'data file content', 'spectrum type']),
    FileContent('MSn spectrum', 'MS:1000580',
                ('MSn refers to multi-stage MS2 experiments designed to record '
                 'product ion spectra where n is the number of product ion '
                 'stages (progeny ions). For ion traps, sequential MS/MS '
                 'experiments can be undertaken where n > 2 whereas for a '
                 'simple triple quadrupole system n=2. Use the term ms level '
                 '(MS:1000511) for specifying n.'),
                'data file content',
                ['mass spectrum', 'data file content', 'spectrum type']),
    FileContent('CRM spectrum', 'MS:1000581',
                ('Spectrum generated from MSn experiment with three or more '
                 'stages of m/z separation and in which a particular multi- '
                 'step reaction path is monitored.'),
                'data file content',
                ['mass spectrum', 'data file content', 'spectrum type']),
    FileContent('SIM spectrum', 'MS:1000582',
                ('Spectrum obtained with the operation of a mass spectrometer '
                 'in which the abundances of one ion or several ions of '
                 'specific m/z values are recorded rather than the entire mass '
                 'spectrum (Selected Ion Monitoring).'),
                'data file content',
                ['mass spectrum', 'data file content', 'spectrum type']),
    FileContent('SRM spectrum', 'MS:1000583',
                ('Spectrum obtained when data are acquired from specific '
                 'product ions corresponding to m/z values of selected '
                 'precursor ions a recorded via two or more stages of mass '
                 'spectrometry. The precursor/product ion pair is called a '
                 'transition pair. Data can be obtained for a single '
                 'transition pair or multiple transition pairs. Multiple time '
                 'segments of different transition pairs can exist in a single '
                 'file. Single precursor ions can have multiple product ions '
                 'consitituting multiple transition pairs. Selected reaction '
                 'monitoring can be performed as tandem mass spectrometry in '
                 'time or tandem mass spectrometry in space.'),
                'data file content',
                ['mass spectrum', 'data file content', 'spectrum type']),
    FileContent('total ion current chromatogram', 'MS:1000235',
                ('Representation of the total ion current detected in each of '
                 'a series of mass spectra versus time.'),
                'data file content',
                ['ion current chromatogram', 'data file content', 'chromatogram type']),
    FileContent('selected ion current chromatogram', 'MS:1000627',
                ('Representation of an array of the measurements of a specific '
                 'single ion current versus time.'),
                'data file content',
                ['ion current chromatogram', 'data file content', 'chromatogram type']),
    FileContent('basepeak chromatogram', 'MS:1000628',
                ('Representation of an array of the most intense peaks versus '
                 'time.'),
                'data file content',
                ['ion current chromatogram', 'data file content', 'chromatogram type']),
    FileContent('selected ion monitoring chromatogram', 'MS:1001472',
                ('Representation of an array of the measurements of a '
                 'selectively monitored ion versus time.'),
                'data file content',
                ['ion current chromatogram', 'data file content', 'chromatogram type']),
    FileContent('selected reaction monitoring chromatogram', 'MS:1001473',
                ('Representation of an array of the measurements of a '
                 'selectively monitored reaction versus time.'),
                'data file content',
                ['ion current chromatogram', 'data file content', 'chromatogram type']),
    FileContent('consecutive reaction monitoring chromatogram', 'MS:1001474',
                ('OBSOLETE Representation of an array of the measurements of a '
                 'series of monitored reactions versus time.'),
                'data file content',
                ['ion current chromatogram', 'data file content', 'chromatogram type']),
    FileContent('absorption chromatogram', 'MS:1000812',
                ('Representation of light absorbed by the sample versus time.'),
                'data file content',
                ['electromagnetic radiation chromatogram', 'data file content', 'chromatogram type']),
    FileContent('emission chromatogram', 'MS:1000813',
                ('Representation of light emitted by the sample versus time.'),
                'data file content',
                ['electromagnetic radiation chromatogram', 'data file content', 'chromatogram type']),
    FileContent('selected ion monitoring', 'MS:1000205',
                ('The operation of a mass spectrometer in which the '
                 'intensities of several specific m/z values are recorded '
                 'rather than the entire mass spectrum.'),
                'data file content',
                ['data-independent acquisition', 'mass spectrometry acquisition method', 'mass spectrometry acquisition method aspect', 'data file content', 'acquisition parameter', 'spectrum generation information']),
    FileContent('selected reaction monitoring', 'MS:1000206',
                ('Data acquired from specific product ions corresponding to '
                 'm/z selected precursor ions recorded via multiple stages of '
                 'mass spectrometry. Selected reaction monitoring can be '
                 'performed in time or in space.'),
                'data file content',
                ['data-independent acquisition', 'mass spectrometry acquisition method', 'mass spectrometry acquisition method aspect', 'data file content', 'acquisition parameter', 'spectrum generation information']),
    FileContent('data independent acquisition from dissociation of sequential mass ranges', 'MS:1003224',
                ('Data independent mass spectrometer acquisition method '
                 'wherein a preconfigured sequence of mass ranges are '
                 'fragmented. Examples of such an approach include SWATH-MS, '
                 'FT-ARM, HRM, and PAcIFIC.'),
                'data file content',
                ['dissociation of sequential mass ranges', 'data-independent acquisition', 'mass spectrometry acquisition method', 'mass spectrometry acquisition method aspect', 'data file content', 'acquisition parameter', 'spectrum generation information']),
    FileContent('data independent acquisition from dissociation of sequential mass ranges after ion mobility separation', 'MS:1003225',
                ('Data independent mass spectrometer acquisition method '
                 'wherein a preconfigured sequence of mass ranges are '
                 'fragmented after being separated by ion mobility. An example '
                 'of such an approach is Bruker diaPASEF.'),
                'data file content',
                ['dissociation of sequential mass ranges', 'ion mobility separation', 'data-independent acquisition', 'mass spectrometry acquisition method', 'mass spectrometry acquisition method aspect', 'data file content', 'acquisition parameter', 'spectrum generation information']),
    FileContent('data independent acquisition from dissociation of full mass range after ion mobility separation', 'MS:1003226',
                ('Data independent mass spectrometer acquisition method '
                 'wherein the full mass range is fragmented after being '
                 'separated by ion mobility. Examples of such an approach '
                 'include HDMS^E and IMS-AIF.'),
                'data file content',
                ['dissociation of full mass range', 'ion mobility separation', 'data-independent acquisition', 'mass spectrometry acquisition method', 'mass spectrometry acquisition method aspect', 'data file content', 'acquisition parameter', 'spectrum generation information']),
    FileContent('data independent acquisition from dissociation of full mass range', 'MS:1003227',
                ('Data independent mass spectrometer acquisition method '
                 'wherein the full mass range is fragmented. Examples of such '
                 'an approach include MS^E, AIF, and bbCID.'),
                'data file content',
                ['dissociation of full mass range', 'ion mobility separation', 'data-independent acquisition', 'mass spectrometry acquisition method', 'mass spectrometry acquisition method aspect', 'data file content', 'acquisition parameter', 'spectrum generation information']),
    FileContent('data independent acquisition from dissociation of scanning quadrupole across mass range', 'MS:1003228',
                ('Data independent mass spectrometer acquisition method '
                 'wherein ???. An example of such an approach is Waters SONAR.'),
                'data file content',
                ['data-independent acquisition', 'dissociation of scanning quadrupole across a specified mass range', 'mass spectrometry acquisition method', 'mass spectrometry acquisition method aspect', 'data file content', 'acquisition parameter', 'spectrum generation information']),
    FileContent('enhanced multiply charged spectrum', 'MS:1000789',
                ('MS1 spectrum that is enriched in multiply-charged ions '
                 'compared to singly-charged ions.'),
                'data file content',
                ['MS1 spectrum', 'mass spectrum', 'data file content', 'spectrum type']),
    FileContent('time-delayed fragmentation spectrum', 'MS:1000790',
                ('MSn spectrum in which the product ions are collected after a '
                 'time delay, which allows the observation of lower energy '
                 'fragmentation processes after precursor ion activation.'),
                'data file content',
                ['MSn spectrum', 'mass spectrum', 'data file content', 'spectrum type']),
    FileContent('total ion currents', 'MS:4000104',
                ('Tabular representation of the total ion current detected in '
                 'each of a series of mass spectra.'),
                'data file content',
                ['table', 'total ion current chromatogram', 'QC metric value type', 'ion current chromatogram', 'data file content', 'chromatogram type']),
])
# [[[end]]]

spectrum_representation = []
# [[[cog
# import cog
# from ms_deisotope.data_source.metadata.cv import render_list
# render_list('spectrum representation',
#             "spectrum_representation", term_cls_name="FileContent", writer=cog.out)
# ]]]
# CV Version: 4.1.114
spectrum_representation = TermSet([
    FileContent('centroid spectrum', 'MS:1000127',
                ('Processing of profile data to produce spectra that contains '
                 'discrete peaks of zero width. Often used to reduce the size '
                 'of dataset.'),
                'spectrum representation',
                ['spectrum representation']),
    FileContent('profile spectrum', 'MS:1000128',
                ('A profile mass spectrum is created when data is recorded '
                 'with ion current (counts per second) on one axis and '
                 'mass/charge ratio on another axis.'),
                'spectrum representation',
                ['spectrum representation']),
])
# [[[end]]]

content_keys = content_keys + spectrum_representation

id_formats_by_name = {k.name: k for k in id_formats}
file_formats_by_name = {k.name: k for k in file_formats}
content_keys_by_name = {k.name: k for k in content_keys}

MS_MS1_Spectrum = content_keys.get('MS1 spectrum')
MS_MSn_Spectrum = content_keys.get('MSn spectrum')

def id_format(name):
    """
    Translate a given name or identifier into a :class:`IDFormat`
    instance.

    If no match is found in the database of known :class:`IDFormat`
    types, a new dummy :class:`IDFormat` is returned with all fields
    set to the value of ``name``

    Returns
    -------
    IDFormat
    """
    try:
        return id_formats[name]
    except KeyError:
        if name is None:
            return None
        return IDFormat(name, name, name, name, [name])

def file_format(name):
    """
    Translate a given name or identifier into a :class:`FileFormat`
    instance.

    If no match is found in the database of known :class:`FileFormat`
    types, a new dummy :class:`FileFormat` is returned with all fields
    set to the value of ``name``

    Returns
    -------
    FileFormat
    """
    try:
        return file_formats[name]
    except KeyError:
        if name is None:
            return None
        return FileFormat(name, name, name, name, [name])

def content_key(name):
    """
    Translate a given name or identifier into a :class:`FileContent`
    instance.

    If no match is found in the database of known :class:`FileContent`
    types, a new dummy :class:`FileContent` is returned with all fields
    set to the value of ``name``

    Returns
    -------
    FileContent
    """
    try:
        return content_keys[name]
    except KeyError:
        if name is None:
            return None
        return FileContent(name, name, name, name, [name])

class FileInformation(MutableMapping):
    """
    Describes the type of data found in this file and the
    source files that contributed to it.

    Implements the :class:`MutableMapping` Interface

    Attributes
    ----------
    contents : dict
        A mapping between controlled vocabullary names or user-defined
        names and an optional value. For standard controlled names see
        :data:`content_keys`
    source_files : list of :class:`.SourceFile` objects
        The set of files which either define the current file, or were used
        to create the current file if recorded.
    """

    def __init__(self, contents=None, source_files=None):
        if contents is None:
            contents = {}
        if source_files is None:
            source_files = []
        self.contents = dict(contents)
        self.source_files = list(source_files)
        self._id_format = None

    def add_file(self, source, check=True):
        """
        Add a new file to :attr:`source_files`

        If ``source`` is a string, it will be interpreted as a path
        and an instance of :class:`SourceFile` will be created using
        :meth:`SourceFile.from_path`. Otherwise, it is assumed to be
        an instance of :class:`SourceFile`.

        Parameters
        ----------
        source : str or :class:`SourceFile`
            Either the path to a file to be added to the source file
            collection, or an instance of :class:`SourceFile`
        check : bool, optional
            Whether or not to check and validate that a path points to
            a real file

        Raises
        ------
        ValueError
            If a path fails to validate as real
        """
        if isinstance(source, basestring):
            source = os.path.realpath(source)
            if check:
                if not os.path.exists(source):
                    raise ValueError(
                        "Source File %r does not exist" % (source,))
            source = SourceFile.from_path(source)
        elif not isinstance(source, SourceFile):
            raise TypeError("Must pass an object of type %r, could not coerce %r" % (
                SourceFile, type(source)))
        self.source_files.append(source)

    def add_content(self, key, value=None):
        """
        Adds a new key-value pair to :attr:`contents` with
        an optional value

        Parameters
        ----------
        key : str or :attr:`content`
            The content name, either a CV-term or a user-defined name
        value : object, optional
            The optional value, which should be any type of object whose
            meaning makes sense given the definition of ``key``
        """
        self.contents[key] = value

    def remove_content(self, key):
        """
        Remove a key from :attr:`content`

        Parameters
        ----------
        key : str or :class:`FileContent`
            The content key to remove
        """
        self.contents.pop(key, None)

    def get_content(self, key):
        """
        Retrieve the value of ``key`` from :attr:`contents`.

        This method is aliased to :meth:`__getitem__`

        Parameters
        ----------
        key : str or :class:`FileContent`
            The content key to retrieve

        Returns
        -------
        object
        """
        return self.contents[key]

    def has_content(self, key):
        """
        Check if ``key`` is found in :attr:`content`

        Parameters
        ----------
        key : str or :class:`FileContent`
            The content key to check

        Returns
        -------
        bool
        """
        return key in self.contents

    def acquisition_methods(self) -> List[DataAcquisitionMethod]:
        """
        Retrieve acquisition methods recorded for this data file.

        Returns
        -------
        List[:class:`DataAcquisitionMethod`]
        """
        methods: List[DataAcquisitionMethod] = []
        combos: List[DataAcquisitionMethod] = []
        for (key, _v) in self.contents.items():
            if key in data_acquisition_methods:
                method = data_acquisition_methods.get(key)
                if key in data_acquisition_aspects:
                    combos.append(method)
                else:
                    methods.append(method)
        if not methods:
            return combos
        else:
            for combo in combos:
                for method in methods:
                    if combo.name in method.specialization:
                        break
                else:
                    methods.append(combo)
        return methods

    def __getitem__(self, key):
        return self.get_content(key)

    def __contains__(self, key):
        return self.has_content(key)

    def __setitem__(self, key, value):
        self.add_content(key, value)

    def __delitem__(self, key):
        self.remove_content(key)

    def __repr__(self):
        template = "FileInformation(%s, %s)"
        return template % (self.contents, self.source_files)

    def __len__(self):
        return len(self.contents)

    def __iter__(self):
        return iter(self.contents)

    def copy(self):
        """
        Create a deep copy of this object

        Returns
        -------
        FileInformation
        """
        return self.__class__(
            self.contents.copy(), [f.copy() for f in self.source_files])

    def _find_native_id_format(self):
        options = list()
        unique = set()
        sf = None  # type: SourceFile
        for sf in self.source_files:
            i = sf.id_format
            if i is None:
                continue
            elif i not in unique:
                unique.add(i)
                options.append(i)
        n = len(options)
        if n == 0:
            return id_format("MS:1000824")
        elif n == 1:
            return options[0]
        else:
            no_format = id_format("MS:1000824")
            if no_format in options:
                options.remove(no_format)
                n = len(options)
            if n == 1:
                return options[0]
            else:
                return MultipleIDFormats(OrderedDict([(fmt.name, fmt) for fmt in options]))

    @property
    def id_format(self):
        if self._id_format is None:
            self._id_format = self._find_native_id_format()
        return self._id_format

format_parameter_map = {
    "thermo raw": (id_formats_by_name.get("Thermo nativeID format"),
                   file_formats_by_name.get("Thermo RAW format")),
    "agilent d": (id_formats_by_name.get("Agilent MassHunter nativeID format"),
                  file_formats_by_name.get("Agilent MassHunter format")),
    'mgf': (id_formats_by_name.get("no nativeID format"),
            file_formats_by_name.get('Mascot MGF format')),
    'waters': (id_formats_by_name.get('Waters nativeID format'),
               file_formats_by_name.get("Waters raw format")),
}

class SourceFile(object):
    """
    Represents a single raw data file which either defines or contributed data to another
    data file, the "reference file"

    Attributes
    ----------
    file_format : :class:`~.FileFormat`
        The name of a data file format. See :data:`file_formats`
    id : str
        The unique identifier for this file, among files which contributed to
        the reference file
    id_format : :class:`~.IDFormat`
        The name of a formal identifier schema. See :data:`~.id_formats`
    location : str
        The directory path to this file on the machine it was last read on to contribute to
        or define the reference file
    name : str
        The base name of this file
    parameters : dict
        A set of key-value pairs associated with this file, either encoding extra metadata
        annotations, or precomputed hash checksums
    """

    _checksum_translation_map = {
        'sha1': 'sha1',
        'SHA-1': 'sha1',
        'md5': 'md5',
        'MD5': 'md5'
    }

    @classmethod
    def _resolve_checksum_hash_type(cls, hash_type):
        try:
            return cls._checksum_translation_map[hash_type]
        except KeyError:
            try:
                return cls._checksum_translation_map[hash_type.lower().replace("-", '')]
            except KeyError:
                raise KeyError(hash_type)

    @classmethod
    def from_path(cls, path):
        """
        Construct a new :class:`SourceFile` from a path to a real file on the local
        file system.

        Parameters
        ----------
        path: str
            The path to the file to describe

        Returns
        -------
        SourceFile
        """
        path = os.path.realpath(path)
        name = os.path.basename(path)
        location = os.path.dirname(path)
        idfmt, file_fmt = cls.guess_format(path)
        source = cls(name, location, name, idfmt, file_fmt)
        return source

    def __init__(self, name, location, id=None, id_format=None, file_format=None, parameters=None):
        if id is None:
            id = name
        if parameters is None:
            parameters = {}
        self.name = name
        self.location = location.replace("file:///", '')
        self.id = id
        self.parameters = dict(parameters)
        self._clean_parameters()
        self.id_format = id_format or self.infer_id_format_from_paramters()
        self.file_format = file_format or self.infer_file_format_from_parameters()

    @property
    def id_format(self):
        return self._id_format

    @id_format.setter
    def id_format(self, value):
        if value is None:
            self._id_format = None
        else:
            self._id_format = id_format(str(value))

    @property
    def file_format(self):
        return self._file_format

    @file_format.setter
    def file_format(self, value):
        if value is None:
            self._file_format = None
        else:
            self._file_format = file_format(str(value))

    def _clean_parameters(self):
        self.parameters.pop("location", None)
        self.parameters.pop("id", None)
        self.parameters.pop("name", None)

    def infer_id_format_from_paramters(self):
        try:
            fmt = list(set(self.parameters) & set(id_formats))[0]
            self.parameters.pop(fmt)
            return fmt
        except IndexError:
            return None

    def infer_file_format_from_parameters(self):
        try:
            fmt = list(set(self.parameters) & set(file_formats))[0]
            self.parameters.pop(fmt)
            return fmt
        except IndexError:
            return None

    @property
    def path(self):
        return os.path.join(self.location, self.name)

    def is_resolvable(self):
        return os.path.exists(self.path)

    @staticmethod
    def guess_format(path):
        if not os.path.exists(path):
            return None, None

        id_fmt = "no nativeID format"
        if os.path.isdir(path):
            if os.path.exists(os.path.join(path, 'AcqData')):
                return format_parameter_map['agilent d']
            elif os.path.basename(path).replace(os.sep, '').endswith("raw"):
                return format_parameter_map['waters']
            else:
                warnings.warn(
                    "Could not determine source file type from directory path %r" % (path, ))
                return id_fmt, None

        parts = os.path.splitext(path)
        if len(parts) > 1:
            is_compressed = False
            ext = parts[1]
            if ext.lower() == '.gz':
                is_compressed = True
                parts = os.path.splitext(parts[0])
                ext = parts[1]
            if ext.lower() == '.mzml':
                fmt = file_formats['MS:1000584']
                id_fmt = "no nativeID format"
                hit = False
                if is_compressed:
                    from .._compression import get_opener
                    fh = get_opener(path)
                else:
                    fh = open(path, 'rb')
                with fh:
                    from ..xml_reader import iterparse_until
                    for sf_tag in iterparse_until(fh, 'sourceFile', 'run'):
                        for param in sf_tag.getchildren():
                            if "nativeID" in param.attrib['name']:
                                id_fmt = param.attrib['name']
                                hit = True
                                break
                        if hit:
                            break
                return id_fmt, fmt
            elif ext.lower() == '.mzxml':
                fmt = "ISB mzXML format"
                id_fmt = "scan number only nativeID format"
                return id_fmt, fmt
            elif ext.lower() == '.mgf':
                fmt = file_formats['MS:1001062']
                id_fmt = "no nativeID format"
                return id_fmt, fmt
            elif ext.lower() == '.mzmlb':
                fmt = file_formats['MS:1002838']
                id_fmt = "no nativeID format"
                from ms_deisotope.data_source.mzmlb import determine_if_available, MzMLbLoader
                # TODO: Try to open the file and get the nativeID format information from
                # the XML buffer, either just opening the file fully or by openinhg it at
                # the HDF5 level and grab the first 4k characters from the XML buffer and
                #  doing the same as the mzML case.
                if determine_if_available():
                    handle = MzMLbLoader(path, use_index=False)
                    fid = handle.file_description()
                    id_fmt = fid.id_format
                return id_fmt, fmt
        with open(path, 'rb') as fh:
            lead_bytes = fh.read(30)
            # looking for pattern matching b'\x01\xa1F\x00i\x00n\x00n\x00i\x00g\x00a\x00n\x00'
            decoded = lead_bytes.decode("utf-16")[1:9]
            if decoded == "Finnigan":
                return format_parameter_map['thermo raw']
        return id_format, None

    def __repr__(self):
        template = "SourceFile(%r, %r, %r, %s, %s%s)"
        if self.parameters:
            tail = ", %r" % self.parameters
        else:
            tail = ''
        return template % (
            self.name, self.location,
            self.id, self.id_format, self.file_format,
            tail
        )

    def _compute_checksum(self, hash_type='sha1', buffer_size=2**16):
        from .._compression import get_opener
        hasher = hashlib.new(hash_type)
        buffer_size = int(buffer_size)
        with get_opener(self.path) as fh:
            content_buffer = fh.read(buffer_size)
            while content_buffer:
                hasher.update(content_buffer)
                content_buffer = fh.read(buffer_size)
        return hasher.hexdigest()

    def checksum(self, hash_type='sha1'):
        hash_type = self._resolve_checksum_hash_type(hash_type)
        return self._compute_checksum(hash_type)

    def add_checksum(self, hash_type='sha1'):
        hash_type = self._resolve_checksum_hash_type(hash_type)
        checksum = self.checksum(hash_type)
        if hash_type == 'sha1':
            self.parameters['SHA-1'] = checksum
        elif hash_type == "md5":
            self.parameters['MD5'] = checksum

    def validate_checksum(self):
        if not os.path.exists(self.path):
            FileNotFoundError("%s not found" % (self.path,))
        if 'SHA-1' in self.parameters:
            checksum = self.checksum('sha1')
            return self.parameters['SHA-1'] == checksum
        elif 'MD5' in self.parameters:
            checksum = self.checksum("md5")
            return self.parameters['MD5'] == checksum
        else:
            warnings.warn(
                "%r did not have a reference checksum. Could not validate" % (self,))
            return True

    def has_checksum(self, hash_type=None):
        if hash_type is None:
            return ("SHA-1" in self.parameters) or ("MD5" in self.parameters)
        elif self._resolve_checksum_hash_type(hash_type) == 'sha1':
            return ("SHA-1" in self.parameters)
        elif self._resolve_checksum_hash_type(hash_type) == 'md5':
            return "MD5" in self.parameters

    def __eq__(self, other):
        if other is None:
            return False
        if self.path == other.path:
            if self.is_resolvable() and other.is_resolvable():
                return self.checksum() == other.checksum()
            else:
                if self.is_resolvable():
                    for hash_type in ['SHA-1', 'MD5']:
                        if other.has_checksum(hash_type):
                            return self.checksum(hash_type) == other.parameters[hash_type]
                elif other.is_resolvable():
                    for hash_type in ['SHA-1', 'MD5']:
                        if self.has_checksum(hash_type):
                            return other.checksum(hash_type) == self.parameters[hash_type]
                else:
                    for hash_type in ['SHA-1', 'MD5']:
                        if self.has_checksum(hash_type) and other.has_checksum(hash_type):
                            return other.parameters[hash_type] == self.parameters[hash_type]
        return False

    def __ne__(self, other):
        return not self == other

    def copy(self):
        return self.__class__(self.name, self.location, self.id,
                              self.id_format, self.file_format,
                              parameters=self.parameters.copy())

__all__ = [
    "IDFormat", "FileFormat", "FileContent",
    "id_formats", "file_formats", "content_keys",
    "id_format", "file_format", "content_key",
    "FileInformation", "SourceFile"
]


#! /usr/bin/env python3
# -*- coding: utf-8 -*-

"""Collect annotated utterances to create the emotion corpus"""
import numpy
import os
import random
import re

RE_OTHER = re.compile(r'[^GLNORSUWZ]')

def letter_to_vector(letter):
    return {
        'G': (0, 0, 1, 0),  # gniew - anger
        'L': (0, 0, -1, 0), # lęk - fear
        'N': (0, 0, 0, 0),  # neutralność - neutral
        'O': (0, 1, 0, 0),  # oczekiwanie - anticipation
        'R': (1, 0, 0, 0),  # radość - joy
        'S': (-1, 0, 0, 0), # smutek - sadness
        'U': (0, 0, 0, 1),  # ufność - trust
        'W': (0, 0, 0, -1), # wstręt - disgust
        'Z': (0, -1, 0, 0), # zaskoczenie - surprise
    }[letter]

def letters_to_vector(letters):
    vectors_list = [letter_to_vector(letter) for letter in letters]
    return tuple([numpy.mean(coords) for coords in zip(*vectors_list)])

def main(input_dir, output_dir):
    data = {}
    for filename in os.listdir(input_dir):
        with open(os.path.join(input_dir, filename), 'r', encoding='utf-8') as file:
            for line in file:
                line = line.strip()
                if not line:
                    continue
                # print(line)
                # print(line.split('\t'))
                try:
                    annotation, utterance = line.split('\t', maxsplit=2)
                except ValueError:
                    continue
                data.setdefault(utterance, []).append(annotation)
    with open(os.path.join(output_dir, 'train/train.tsv'), 'w') as trainset, \
            open(os.path.join(output_dir, 'dev-0/in.tsv'), 'w') as devset_in, \
            open(os.path.join(output_dir, 'dev-0/out.tsv'), 'w') as devset_out, \
            open(os.path.join(output_dir, 'test-A/in.tsv'), 'w') as testset_in, \
            open(os.path.join(output_dir, 'test-A/out.tsv'), 'w') as testset_out:
        for utterance, annotations in data.items():
            if len(annotations) > 3:
                r = random.random()
                if r < 0.2:
                    print('{}\t{}'.format(annotations, utterance),
                          file=trainset)
                else:
                    sentic_vectors = [letters_to_vector(annotation) for annotation in annotations]
                    sentic_vector = tuple([numpy.mean(coords) for coords in zip(*sentic_vectors)])
                    sentic_vector_str = '\t'.join(str(coord) for coord in sentic_vector)
                    if r < 0.4:
                        print(utterance,
                              file=devset_in)
                        print(sentic_vector_str,
                              file=devset_out)
                    else:
                        print(utterance,
                              file=testset_in)
                        print(sentic_vector_str,
                              file=testset_out)

if __name__ == '__main__':
    main('corpora/crowd', 'challenge')


num1 = int(input('Escreva um número: '))
num2 = int(input('Escreva outro número: '))
n = 0

print("""----------MENU----------
   [1] Somar
   [2] Multiplicar
   [3] Maior
   [4] Novos números
   [5] Sair do programa
----------MENU----------""")

while n != 5:
    n = int(input('Insira a sua opção: '))
    if n == 1:
        print(f'A soma entre os dois dá {num1 + num2}!')
        print('-----------------------')
    elif n == 2:
        print(f'A multiplicação entre os dois dá {num1 * num2}')
        print('-----------------------')
    elif n == 3:
        if num1 > num2:
            print(f'O maior entre os dois é o {num1}')
            print('-----------------------')
        else:
            print(f'O maior entre os dois é o {num2}')
            print('-----------------------')
    elif n == 4:
        num1 = int(input('Escreva um número: '))
        num2 = int(input('Escreva outro número: '))
    elif n == 5:
        print('----------FIM----------')
    else:
        print('Opção inválida! Tente novamente!')
        print('-----------------------')


class Pet:
    def __init__(self, name, type, tricks, noise):
        self.name = name
        self.type = type
        self.tricks = tricks
        self.health = 200
        self.energy = 100
        self.noise = noise
    def sleep(self):
        self.energy += 25
        return self
    def eat(self):
        self.energy += 5
        self.health += 10
        return self
    def play(self):
        self.health += 5
        return self
    def noise(self):
        print(self.noise)

class Ninja:
    def __init__(self, f_name, l_name, pet, treats, pet_food):
        self.f_name = f_name
        self.l_name = l_name
        self.pet = pet
        self.treats = treats
        self.pet_food = pet_food
    def walk(self):
        self.pet.play()
        return self
    def give_treat(self):
        if len(self.treats) >0:
            treat = self.treats.pop()
            print(f"Giving {self.pet.name} a {treat}!")
            self.pet.eat()
        else:
            print("Oh shoot! You're out of treats!")
        return self
    def feed(self):
        if len(self.pet_food) >0:
            food = self.pet_food.pop()
            print(f"Feeding {self.pet.name} {food}!")
            self.pet.eat()
        else:
            print("Oh no!! You need more pet food!")
        return self
    def bathe(self):
        self.pet.noise()

treats = ['Ferret Chew Stick', 'Marshall Peanut Butter Bandits', 'Freeze-Dried Raw Chicken Heart']
pet_food = ['Epigen 90', 'Marshall Premium Ferret Food']

tanjiro = Pet("Tanjiro", "Ferret", ['slides through tubes', 'plays with toys', 'naps on shoulder'], "Squeek!")
naomi = Ninja("Naomi", "Glen", tanjiro, treats, pet_food)

naomi.walk();
naomi.feed();
naomi.walk();
naomi.walk();
naomi.give_treat();
naomi.give_treat();
naomi.give_treat();
naomi.give_treat();
naomi.walk();
naomi.feed();
naomi.feed();
naomi.bathe();


import os
os.environ.setdefault('DJANGO_SETTINGS_MODULE','blogproject1.settings')
import django
django.setup()

from testapp.models import *
from faker import Faker
from random import *
fake=Faker()
def phonenumbergen():
    d1=randint(7,9)
    num=''+str(d1)
    for i in range(9):
        num=num+str(randint(0,9))
    return int(num)
def populate(n):
    for i in range(n):
        fdate=fake.random_element(elements=('2021-11-02','2021-10-08','2021-11-12','2021-09-21','2021-12-02','2021-09-28','2021-09-25','2022-01-21','2022-01-19','2021-02-20'))
        fcompany=fake.random_element(elements=('TCS','CTS','INFOSYS','Accenture','Wipro','Capegemini','Hcl','Legato','Tech Mahendra','Bosch','IBM','Global Edge'))
        ftitle=fake.random_element(elements=('project manager','TeamLead','SoftwareEngineer'))
        feligibility=fake.random_element(elements=('B.Tech','M.Tech','MCA','phd'))
        faddress=fake.address()
        femail=fake.email()
        fphonenumber=phonenumbergen()
        hydjobs_record=hydjobs.objects.get_or_create(date=fdate,company=fcompany,title=ftitle,eligibility=feligibility,address=faddress,email=femail,phonenumber=fphonenumber)
        hydjobs_record=punejobs.objects.get_or_create(date=fdate,company=fcompany,title=ftitle,eligibility=feligibility,address=faddress,email=femail,phonenumber=fphonenumber)
        hydjobs_record=blorejobs.objects.get_or_create(date=fdate,company=fcompany,title=ftitle,eligibility=feligibility,address=faddress,email=femail,phonenumber=fphonenumber)
        hydjobs_record=chennaijobs.objects.get_or_create(date=fdate,company=fcompany,title=ftitle,eligibility=feligibility,address=faddress,email=femail,phonenumber=fphonenumber)
populate(15)


from __future__ import annotations

from abc import abstractmethod, ABCMeta
from numbers import Integral
from typing import Iterable

import numpy as np
from sklearn.base import BaseEstimator, clone
from sklearn.metrics import get_scorer
from sklearn.model_selection import cross_validate, KFold

def check_scoring(scoring):
    """Always use R^2 and MSE for evaluation."""

    if scoring is None:
        scoring = set()
    elif isinstance(scoring, Iterable):
        scoring = set(scoring)
    else:
        scoring = {scoring}
    scoring.update({'r2', 'neg_mean_squared_error'})

    return list(scoring)

def check_cv(cv, random_state=None):
    """Enable shuffle by default."""
    if isinstance(cv, Integral):
        cv = KFold(n_splits=cv, shuffle=True, random_state=random_state)
    return cv

class Evaluation(metaclass=ABCMeta):

    def __init__(self, estimator: BaseEstimator, random_state: int, verbose: int):
        self.estimator = estimator
        self.random_state = random_state
        self.verbose = verbose

    @abstractmethod
    def __call__(self, params: dict, **kwargs) -> tuple[list[BaseEstimator], dict]:
        pass

class BaseCrossValidate(Evaluation, metaclass=ABCMeta):
    estimators_: list[BaseEstimator]
    results_: dict

    def cross_validate(self, X: np.ndarray, y: np.ndarray, params: dict, **kwargs):
        scoring = check_scoring(kwargs.pop('scoring', None))
        cv = check_cv(kwargs.pop('cv', None), random_state=self.random_state)

        estimator = clone(self.estimator)
        estimator.set_params(**params)

        # Do cross-validation
        scores = cross_validate(
            estimator=estimator,
            X=X,
            y=y,
            scoring=scoring,
            cv=cv,
            return_estimator=True,
            verbose=self.verbose,
            **kwargs
        )

        return scores

class CrossValidateTest(BaseCrossValidate):
    """Evaluate the estimator using cross validation and an extra test set."""

    def __init__(
            self,
            estimator: BaseEstimator,
            X_train: np.ndarray,
            y_train: np.ndarray,
            X_test: np.ndarray,
            y_test: np.ndarray,
            random_state: int = None,
            verbose: int = 0,
    ):
        super().__init__(estimator=estimator, random_state=random_state, verbose=verbose)
        self.X_train = X_train
        self.y_train = y_train
        self.X_test = X_test
        self.y_test = y_test

    def __call__(self, **kwargs) -> tuple[list[BaseEstimator], dict]:

        scores = self.cross_validate(self.X_train, self.y_train, **kwargs)

        # Save estimators externally
        estimators = scores.pop('estimator')

        # Rename test_scores to val_scores, because we have an additional test set
        new_scores = {}
        for key, value in scores.items():
            if key.startswith('test_'):
                scoring = key.removeprefix('test_')
                new_scores['val_' + scoring] = scores[key]
                scorer = get_scorer(scoring)
                new_scores['test_' + scoring] = np.array(
                    [scorer(estimator, self.X_test, self.y_test) for estimator in estimators])
            else:
                new_scores[key] = value

        self.estimators_, self.results_ = estimators, new_scores
        return estimators, new_scores

class CrossValidate(BaseCrossValidate):
    """Evaluate the estimator using cross validation."""

    def __init__(
            self,
            estimator: BaseEstimator,
            X: np.ndarray,
            y: np.ndarray,
            random_state: int = None,
            verbose: int = 0,
    ):
        super().__init__(estimator=estimator, random_state=random_state, verbose=verbose)
        self.X = X
        self.y = y

    def __call__(self, **kwargs) -> tuple[list[BaseEstimator], dict]:
        scores = self.cross_validate(self.X, self.y, **kwargs)

        # Save estimators externally
        estimators = scores.pop('estimator')

        self.estimators_, self.results_ = estimators, scores
        return estimators, scores


import matplotlib.pyplot as plt
import numpy as np

# Given constants
m = 10
v0 = 100
h0 = 30
k1 = 0.05
k2 = 0.01
g = 9.8

def h(t):
    global h_last, t_last

    h_current = h_last + v(t) * (t - t_last)
    h_last = h_current
    t_last = t

    return h_current

def v(t):
    global v_last

    v_current = v_last + a() * (t - t_last)
    v_last = v_current
    return v_current

def a():

    k = -k1 if v_last >= 0 else k2

    return ((v_last ** 2) * k - m * g) / m

steps = [1, 0.5, 0.1, 0.01, 0.001]
for step in steps:
    # Used for calculations
    v_last = v0
    a_last = 0
    h_last = h0
    t_last = 0

    x_range = np.arange(0, 40, step)
    y_range = [h(_x) for _x in x_range]

    y = [_y for _y in y_range if _y >= 0]
    x = x_range[:len(y)]

    print("[STEP=%.3f] Max height reached: %.2fm at %.2fs | Ground reached at %.2fs" % (step, max(y), x[y.index(max(y))], x[-1]))

    plt.plot(x, y, label=f'h(t) step = {step}')

plt.title("Projektinis aukštis laiko momentu")
plt.xlabel("t (s)")
plt.ylabel("h (m)")

plt.legend()
plt.show()


from django.urls import path
from .views import CloseInvoiceView, InvoiceFromView, InvoiceListView, SimpleTemplateView, InvoiceUpdateView, AddPositionsFormView, CloseInvoiceView, InvoicePositionDeleteView, invoice_pdf_view

app_name = 'invoices'

urlpatterns = [
    path('', InvoiceListView.as_view(),name = 'main'),
    path('new/', InvoiceFromView.as_view(), name='create'),
    # path('<pk>/', SimpleTemplateView.as_view(),name='simple-template'),
    path('<pk>/', AddPositionsFormView.as_view(),name='detail'),
    path('<pk>/update', CloseInvoiceView.as_view(),name='close'),
    path('<pk>/update', InvoiceUpdateView.as_view(),name='update'),
    path('<pk>/pdf/', invoice_pdf_view, name="pdf"),
    path('<pk>/delete/<int:position_pk>/', InvoicePositionDeleteView.as_view(),name='position-delete'),

]