# ---------------------------------------------------------------------------- #
## \file mail.py
## \author Sebastien Beaugrand
## \sa http://beaugrand.chez.com/
## \copyright CeCILL 2.1 Free Software license
## \note Python Imap Gtk Mail
# ---------------------------------------------------------------------------- #
import email
import quopri
import traceback
from imap import *


# ---------------------------------------------------------------------------- #
## \fn decode
# ---------------------------------------------------------------------------- #
def decode(h):
    line = ''
    try:
        for s in email.header.decode_header(h):
            if s[1]:
                line += s[0].decode(s[1]) + ' '
            elif isinstance(s[0], str):
                line += s[0] + ' '
            else:
                line += s[0].decode() + ' '
        return line.replace('  ', ' ')
    except Exception as e:
        return ''.join(traceback.format_exception_only(None, e))


# ---------------------------------------------------------------------------- #
## \class Mail
# ---------------------------------------------------------------------------- #
class Mail:
    def __init__(self, imap, num, mlog):
        self.imap = imap
        self.mlog = mlog
        self.num = num
        self.body = b''
        self.offset = -1
        self.messageId = None
        self.eof = False
        self.fetch_header()
        self.err = None

    def fetch_header(self):
        try:
            tmp, data = self.imap.fetch(
                self.num,
                '(BODY[HEADER.FIELDS (DATE FROM SUBJECT MESSAGE-ID)])')
        except Exception as e:
            perror(e, 'fetch header')
            self.imap.start()
            tmp, data = self.imap.fetch(
                self.num, '(BODY[HEADER.FIELDS (FROM SUBJECT MESSAGE-ID)])')
        try:
            for d in data:
                if isinstance(d, tuple):
                    msg = email.message_from_string(d[1].decode())
                    self.headerDate = decode(msg['Date'])
                    self.headerFrom = decode(msg['From'])
                    self.headerSubject = decode(msg['Subject'])
                    self.messageId = decode(msg['Message-ID']).strip()
                    break
        except Exception as e:
            perror(e, 'message_from_string')
            perror(data, 'data')

    def fetch_part_number(self):
        tmp, data = self.imap.fetch(self.num, '(BODYSTRUCTURE)')
        self.structure = str(data[0]).split(')(')
        for n in range(len(self.structure)):
            if self.structure[n].find('"TEXT" "PLAIN"') >= 0:
                self.part = n + 1
                return self.part
        return 0

    def fetch_part(self):
        if self.offset < 0:
            self.offset = 0
            self.charset = self.structure[self.part - 1].split(
                'CHARSET" "')[1].split('"')[0]
        try:
            tmp, data = self.imap.fetch(
                self.num, 'BODY[{}]<{}.{}>'.format(self.part, self.offset,
                                                   256))
        except Exception as e:
            perror(e, 'fetch part')
            imap.start()
            tmp, data = self.imap.fetch(
                self.num, 'BODY[{}]<{}.{}>'.format(self.part, self.offset,
                                                   256))
        self.offset += 256
        if isinstance(data[0][1], int):
            self.eof = True
        else:
            self.body += data[0][1]
        if not self.body:
            perror('empty plain text')
            return ''
        try:
            array = quopri.decodestring(self.body)
        except Exception as e:
            perror(e, 'decodestring')
            array = self.body
        try:
            if array[-1] > 128:
                text = array[:-1].decode(self.charset, errors='replace')
            else:
                text = array.decode(self.charset, errors='replace')
        except Exception as e:
            perror(''.join(traceback.format_exception(None, e,
                                                      e.__traceback__)))
            self.err = ''.join(traceback.format_exception_only(None, e))
            text = str(array)
        if self.eof:
            return text + '\n'
        else:
            return text + '...\n'

    def fetch_preview(self):
        tmp, data = self.imap.fetch(self.num, '(PREVIEW)')
        self.eof = True
        try:
            return data[0][1].decode()
        except Exception as e:
            perror(e, 'preview')
            return data[0].decode()