from urllib.request import Request, urlopen
from urllib.error import URLError

try:
    # BeautifulSoup is used for parsing the HTML formatted codon usage tables on 'http://www.kazusa.or.jp/codon/'
    from bs4 import BeautifulSoup
except ImportError as e:
    print('ERROR: {}'.format(e.msg))
    exit(1)


class CodonUsageTable():
    """
    Provides a representation of a specific codon usage table
    url             - String; URL from which the usage table can be obtained.
                      Usually http://www.kazusa.or.jp/codon/cgi-bin/showcodon.cgi?species=<id>&aa=<num>&style=N
    use_frequency   - Boolean; Defines whether usage frequencies/1000 are used instead of fractions. Defaults to 'False'
    """

    def __init__(self, url, use_frequency=False):
        self.url = url
        self.usage_table = {}
        self.use_frequency = use_frequency
        self.fetch_codon_usage_table()


    def add_to_table(self, codon, aa, frequency):
        """
        Add codon and usage frequency to table
        codon     - String; e.g. 'ATG'
        aa        - String; Corresponding amino acid (e.g. 'M')
        frequency - Float: Usage fraction or frequency/1000
        """

        if aa in self.usage_table:
        # If the aa is already present in the table, just add the new codon
            self.usage_table[aa][codon] = {'f': frequency}
        else:
            # Else, create a new entry for the aa and add the codon
            self.usage_table[aa] = {}
            self.usage_table[aa][codon] = {'f': frequency}

    def fetch_codon_usage_table(self):
        """
        Fetch the codon table from http://www.kazusa.or.jp/codon
        """

        request = Request(self.url)
        try:
            opener = urlopen(request)
        except URLError as e:
            if hasattr(e, 'reason'):
                print('Failed to reach server: %s' % e.reason)
            if hasattr(e, 'code'):
                print('Server responded with HTTP error code: %s' % e.code)
            exit(1)

        response = opener.read()
        soup = BeautifulSoup(response)

        # Parse the HTML response and look for <pre></pre> section, containing the usage table
        table_string = str(soup.pre)

        table_string = table_string.replace('<pre>\n', '')  # remove <pre></pre> tags
        table_string = table_string.replace('\n</pre>', '') #

        table_lines = table_string.split('\n') # Split in lines
        for line in table_lines: # Iterate over the lines
            lines = line.split(')') # Splitting the lines at ")" will result in substrings representing the
            # a single codon each
            for codon_raw in lines:
                codon_raw = codon_raw.strip() # strip whitespace characters from the substring

                codon = codon_raw[:3].strip().replace('U', 'T') # The first three characters are the codon
                if codon:
                    aa = codon_raw[4:5].strip() # Position 5 is the aa in one letter code
                    fraction = float(codon_raw[6:10].strip()) # position 6 to 10 is the fraction;

                    frequency = float(codon_raw[11:15].strip()) # position 11 to 14 is the usage frequency/1000
                    # convert to float
                    if self.use_frequency:
                        self.add_to_table(codon, aa, frequency)
                    else:
                        self.add_to_table(codon, aa, fraction)
@@ -1712,24 +1712,87 @@
        try:%0A
+            # attempt to recieve the html file from the server%0A
             
@@ -1843,24 +1843,77 @@
 Error as e:%0A
+            # if this fails, print an error and exit%0A
             
@@ -2131,16 +2131,96 @@
 exit(1)%0A
+            # otherwise read the file and hand over to BeautifulSoup for parsing
 %0A       
@@ -2332,16 +2332,18 @@
 ook for 
+a 
 %3Cpre%3E%3C/p
@@ -2353,17 +2353,16 @@
  section
-,
  contain
@@ -2627,24 +2627,46 @@
 lit in lines
+ at the linebreak '%5Cn'
 %0A        for
@@ -2816,19 +2816,17 @@
 senting 
-the
+a
 %0A       

Prepare for tagging release 0.1: Add comments to LibCharm.CodonUsageTable.