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

"""
Qualifier handler for EMBL feature tables
"""

import os
import re
import json
import logging
from .utilities import *

class Qualifier( object ):

    PREVIOUS_ERRORS = []

    def __init__(self, qualifier, dict_qualifiers, mandatory = False, legal_dbxref=[], value = [], no_wrap= None):
        """
        Initializes a Qualifier, loads json definition and starts
        parsing the input data.
        """
        self.name = qualifier
        self.no_wrap = no_wrap
        self.mandatory = mandatory
        self.legal_dbxref = legal_dbxref
        self._load_definition(dict_qualifiers)
        self.value = []
        if value:
            self.add_value( value )

    def __repr__(self):
        """
        Prints the current Qualifier in EMBL format
        """
        return self.embl_format()

    def _load_definition(self, dict_qualifiers):
        """
        Loads the json definition for a qualifier type and sets its
        own attributes based on the content
        """
        try:
            for key, value in dict_qualifiers.items():
                if key != "legal_dbxref":
                    setattr(self, key, value)

        except IOError as e:
            logging.error(e)

    def _by_value_format(self, value):
        """
        This is the main function of the qualifier class, it attempts to validate qualifier
        format by using the value_format tag of the qualifier definition.
        These definitions are written for humans though, not for scripts...
        TODO: keep implementing these
        """
        logging.debug("_by_value_format %s",value)
        formatted_value = value

        if not hasattr(self, "value_format"):
            return value

        try:
            if self.value_format == "none": # no value taken
                if value:
                    logging.info("Qualifier '%s' has value '%s', but none expected." % (self.name, value))
                return ""
            elif self.value_format.startswith("\"<database:identifier>\""): # Handle dbxref's
                value = value if type(value) == type([]) else [value]

                for val in value:
                    if val.split(':')[0].lower() in self.legal_dbxref:
                        formatted_value = val
                    else:
                        msg = "Unknown db_xref '%s' - skipped." % (val.split(':')[0])
                        if msg not in Qualifier.PREVIOUS_ERRORS:
                            logging.warning(msg)
                            Qualifier.PREVIOUS_ERRORS += [msg]
                        formatted_value=None
            elif self.value_format == "<identifier>":
                pass
            elif self.value_format == "\"text\"":
                formatted_value = value
                if formatted_value[0] == "\"":
                    formatted_value = formatted_value[1:]
                if formatted_value[-1] == "\"":
                    formatted_value = formatted_value[:-1]
            elif self.value_format == "1 or 2 or 3":
                formatted_value = int(value) + 1
                if formatted_value not in [1,2,3]:
                    logging.error("Value format '1 or 2 or 3' has value: %i" % formatted_value)
            else:
                logging.debug("No rule to format '%s'" % self.value_format)

            # TODO: implement validators for all value_format types
        except Exception as e:
            import traceback
            logging.error(e)
            logging.info("---------+----------------------------------------")
            logging.info("QUALIFIER|  Name: %s" % self.name)
            logging.info("---------+ Value: %s" % value)
            logging.info(" Formatted value: %s" % formatted_value)
            logging.info("       Mandatory: %s" % self.mandatory)
            logging.info("    Value format: %s" % self.value_format)
            logging.info("-"*50 + "\n")
            #logging.info("      dir(self): %s" % dir(self))
            traceback.print_exc(limit=5)
            import sys
            sys.exit(1)

        return formatted_value

    def embl_format(self, no_wrap=None):
        """
        Format lines as EMBL format, limiting lines to 80 characters
        """
        output = ""
        value = self.value
        if type(value) != type([]):
            value = [value]
        for val in value:
            string=""
            if val == []:
                continue
            if type(val) == type([]) and len(val):
                val = val[0]
            if not val: # if empty => no value
                string = "/{}".format(self.name)
            elif type(val) in [type(""), type("")]: #if a string => we add quote to the value
                string = "/{}=\"{}\"".format(self.name, val)
            else:# A value but is an integer => we do not add quote
                 string = "/{}={}".format(self.name, val)
            #if getattr(self, "value_type", None) == "none":
            #    string = "/%s" % (self.name)
            #    continue

            output += multiline("FT", string, wrap=59, no_wrap = no_wrap)

        return output

    def add_value(self, value):
        """
        Adds a value to the current set of values for this qualifier.
        Qualifier wihtout value is possible. e.g environmental_sample
        """
        logging.debug("add_value")
        self.value = [self.value] if type(self.value) != type([]) else self.value

        new_value = self._by_value_format(value)
        if new_value or new_value == "":
            if new_value not in self.value:
                logging.debug("%s - Changing value: '%s' to '%s'" % (self.name, value, new_value))
                self.value.append(new_value)
                logging.debug("%s - Current value: '%s'" % (self.name, self.value))
            else:
                logging.debug("%s - Value: '%s' already exists" % (self.name, self.value))

    def set_value(self, value):
        logging.debug("xxx set_value %s", value)
        value = value if type(value) == type([]) else [value]
        self.value = [self._by_value_format(v) for v in value]

if __name__ == '__main__':

    import argparse
    from BCBio import GFF

    parser = argparse.ArgumentParser( description = __doc__ )
    parser.add_argument("test_gff", help="gff file to load a test qualifier from")
    parser.add_argument("-v", "--verbose", action="count", default=2, help="increase verbosity")
    parser.add_argument("-q", "--quiet", action="count", default=0, help="decrease verbosity")

    args = parser.parse_args()

    logging.basicConfig(format='%(asctime)s %(levelname)s: %(message)s',
                        level = (5-args.verbose+args.quiet)*10,
                        datefmt="%H:%M:%S")

    for record in GFF.parse(open(args.test_gff)):
        break

    for feature in record.features:
        for qualifier, value in feature.qualifiers.items():
            print("%s: %s" % (qualifier, value))
            print(Qualifier(qualifier, value, "qualifiers"))
        break
