# Stores data about the sequence

# NEEDS TO BE SYNCH WITH THE REST OF BIOPYTHON AND BIOPERL

import sys
if getattr(sys, "version_info", (1, 5))[:2] >= (2,1):
  from Bio import FormatIO
  # Should this be in the module namespace or the record namespace?
  io = FormatIO.FormatIO("SeqRecord",
                         default_input_format = "sequence",
                         default_output_format = "fasta")

class SeqRecord:
    """The SeqRecord object is designed to hold a sequence and information about it.

    Main properties:
    id          - Identifier such as a locus tag (string)
    seq         - The sequence itself (Seq object)

    Additional properties:
    name        - Sequence name, e.g. gene name (string)
    description - Additional text (string)
    dbxrefs     - List of database cross references (list of strings)
    features    - Any (sub)features defined (list of SeqFeature objects)
    annotations - Further information (dictionary)
    """

    def __init__(self, seq, id = None, name = None,
                 description = None, dbxrefs = None,
                 features = None):
        """Create a SeqRecord

        Arguments:
        seq         - Sequence, required (Seq object)
        id          - Sequence identifier, recommended (string)
                      Defaults to "<unknown id>" if not supplied
        name        - Seqeuence name, optional (string)
                      Defaults to "<unknown name>" if not supplied
        description - Seqeuence description, optional (string)
                      Defaults to "<unknown description>" if not supplied
        dbxrefs     - Database cross references, optional (list of strings)
                      Defaults to and empty list if not supplied
        features    - Annotation on parts of the sequence, optional
                      (list of SeqFeatures).
                      Defaults to and empty list if not supplied

        Note that while an id is optional, we recommend you supply a
        unique id string for each record.  This is especially important
        if you wish to write your sequences to a file.

        You can create a 'blank' SeqRecord object can then populated the
        attributes later.  Note that currently the annotations dictionary
        cannot be specified when creating the SeqRecord."""

        # All the optional arguments default to None.  This avoids creating
        # string/list/dict objects which may never be used.  They are created
        # only when required by the property get functions.
        #
        # Note that the effective property defaults are defined in their
        # property get methods below.
        self._seq = seq
        self._id = id
        self._name = name
        self._description = description
        self._dbxrefs = dbxrefs
        self._features = features
        self._annotations = None # cannot be supplied at __init__ (yet?)
        
    def __get_seq(self) :
        return self._seq
    def __set_seq(self, value) :
        self._id = value
    seq = property(__get_seq, __set_seq, doc="Sequence (Seq object)")

    def __get_id(self) :
        if self._id is None : self._id = "<unknown id>"
        return self._id
    def __set_id(self, value) :
        self._id = value
    id = property(__get_id, __set_id, doc="Sequence identifier (string)")

    def __get_name(self) :
        if self._name is None : self.name = "<unknown name>"
        return self._name
    def __set_name(self, value) :
        self._name = value
    name = property(__get_name, __set_name, doc="Sequence name (string)")

    def __get_description(self) :
        if self._description is None : self._description = "<unknown description>"
        return self._description
    def __set_description(self, value) :
        self._description = value
    description = property(__get_description, __set_description, doc="Sequence description (string)")

    def __get_dbxrefs(self) :
        if self._dbxrefs is None : self._dbxrefs = []
        return self._dbxrefs
    def __set_dbxrefs(self, value) :
        self._dbxrefs = value
    dbxrefs = property(__get_dbxrefs, __set_dbxrefs, doc="Database cross references (list of strings)")

    def __get_features(self) :
        if self._features is None : self._features = []
        return self._features
    def __set_features(self, value) :
        self._features = value
    features = property(__get_features, __set_features, doc="Annotations about parts of the sequence (list of SeqFeatures)")

    def __get_annotations(self) :
        if self._annotations is None : self._annotations = {}
        return self._annotations
    def __set_annotations(self, value) :
        self._annotations = value
    annotations = property(__get_annotations, __set_annotations, doc="Annotations about the whole sequence (dictionary)")

    def __str__(self) :
        """Returns a human readable string representation of the object"""
        lines = []
        if self.id : lines.append("ID: %s" % self.id)
        if self.name : lines.append("Name: %s" % self.name)
        if self.description : lines.append("Description: %s" % self.description)
        if self.dbxrefs : lines.append("Database cross-references: " + ", ".join(self.dbxrefs))
        for a in self.annotations:
            #This style mimics GenBank/EMBL features
            lines.append("/%s=%s" % (a, str(self.annotations[a])))
        lines.append(str(self.seq))
        return "\n".join(lines)

    def __repr__(self) :
        """Returns a 'python format' string representation of the object"""
        return "SeqRecord(seq=%s, id=%s, name=%s, description=%s, dbxrefs=%s)" \
        % tuple(map(repr, (self.seq, self.id, self.name, self.description, self.dbxrefs)))
        #Note - We cannot include the annotations in this because (at the moment)
        #they cannot be supplied as an argument to __init__
 
if __name__ == "__main__" :
    #The following is a very quick example of how to create a SeqRecord object,
    #and what str(record) and repr(record) look like.
    from Bio.Seq import Seq
    from Bio.Alphabet.IUPAC import IUPACProtein
    from Bio.Alphabet import generic_protein
    record = SeqRecord(Seq("MASRGVNKVILVGNLGQDPEVRYMPNGGAVANITLATSESWRDKAT" \
                          +"GEMKEQTEWHRVVLFGKLAEVASEYLRKGSQVYIEGQLRTRKWTDQ" \
                          +"SGQDRYTTEVVVNVGGTMQMLGGRQGGGAPAGGNIGGGQPQGGWGQ" \
                          +"PQQPQGGNQFSGGAQSRPQQSAPAAPSNEPPMDFDDDIPF",
                           generic_protein),
                       id="NP_418483.1", name="b4059",
                       description="ssDNA-binding protein",
                       dbxrefs=["ASAP:13298", "GI:16131885", "GeneID:948570"])

    #Note that annotations must be added AFTER creating the record
    record.annotations["note"] = "This annotation was added later"

    print "str(record):\n\n%s\n\n" % str(record)
    print "repr(record):\n\n%s\n\n" % repr(record)

    #One way to create a minimal record.
    record2 = SeqRecord(Seq(""))

