import re


def _fasta_dict_from_file(file_object, header_search='specific'):
    """
    Reads a file of FASTA entries and returns a dict for each entry.
    It parsers the headers such that `>gi|12345|ref|NP_XXXXX| Description`
    returns as `{gi: 12345, ref: 'NP_XXXXX', description : 'Description'}`
    The sequence has all whitespace removed.

    :header_search: One of `specific` or `generic`
    if `specific` tries to parse the header
    if `general` just returns each whitespace separated header
    """

    current_id = dict()
    current_seq = ''
    current_header = None
    pat = re.compile('>(\S+)\s*(.*)')
    header_pat = re.compile(r'(\w+)\|(\w+\.?\w*)?')

    def parse_header(header, pairs=True):
        keys = header_pat.findall(header)
        header_data = dict()
        for key in keys:
            header_data[key[0]] = key[1]
            # gi -> ProteinGI #, ref -> NP_XXXX
        return header_data

    for line in file_object:
        line = line.rstrip()
        m = pat.search(line)
        if m:
            ## new residue line matched, purge the existing one, if not the first
            if current_id:
                ## remove all whitespace and save
                current_seq = ''.join(current_seq.split())
                current_id['sequence'] = current_seq
                yield current_id
                # current_id.clear()  # this is actually bad for list comprehensions
                                      # as it returns empty dictionaries

            current_seq = ''
            header = m.group(1)
            if header_search == 'specific':
                current_id = parse_header(header)
            elif header_search == 'generic':
                current_id = dict(header = header)
            current_id['description'] = m.group(2)

        else:
            ## python 2.6+ makes string concatenation amortized O(n)
            ##  http://stackoverflow.com/a/4435752/1368079
            current_seq += str(line)

    ## don't forget the last one
    current_seq = ''.join(current_seq.split())
    current_id['sequence'] = current_seq
    yield current_id