import os
from datetime import datetime
from past.utils import old_div
import PIL
import reportlab
import reportlab.lib.colors as rlcolors
import reportlab.pdfgen.canvas as rlcanvas
import reportlab.platypus as platypus
from reportlab.lib.units import inch
styles = reportlab.lib.styles.getSampleStyleSheet()
HeaderStyle = styles["Heading1"]
ParaStyle = styles["Normal"]
gray = rlcolors.Color(old_div(136., 256), old_div(136., 256),
                      old_div(136., 256))
colors = [
    "#75D44A", "#BF58CB", "#D44B33", "#88C7D4", "#3B3628", "#CE497C", "#72D49B",
    "#59345F", "#5C7B37", "#707AC9", "#C78A3B", "#C7BD94", "#CE98B5", "#CECF4F",
    "#874236", "#597576"
]
blackColorMap = {
    5: 0xFF000000,
    7: 0xFF000000,
    8: 0xFF000000,
    9: 0xFF000000,
    13: 0xFF000000,
    14: 0xFF000000,
    15: 0xFF000000,
    16: 0xFF000000,
    17: 0xFF000000,
    35: 0xFF000000,
    53: 0xFF000000
}
[docs]def new_page(Elements):
    '''
    insert page break
    '''
    Elements.append(platypus.PageBreak()) 
[docs]def add_vtable(Elements, table, style, width_list):
    '''
    add table, where header is in the first column
    '''
    width = [w * inch for w in width_list]
    Elements.append(platypus.Table(table, width, style=style)) 
[docs]def add_table(Elements, table, style, col_width):
    '''
    horizontal table, where the header is on the first row
    '''
    nfields = len(table[0])
    if isinstance(col_width, int) or isinstance(col_width, float):
        width = nfields * [col_width * inch]
    else:
        width = [w * inch for w in col_width]
    Elements.append(platypus.Table(table, width, style=style)) 
[docs]def add_and_parse_SMILES(smiles_str):
    """ parse SMILES string such that it fits on the page """
    smiles_style = ParaStyle
    smiles_style.fontSize = 10
    l = len(smiles_str)
    new_str = ''
    prev_idx = 0
    max_length = 66
    if l <= max_length:
        return smiles_str
    # output smiles only upto 3 lines; otherwise it gets messy.
    elif l > max_length * 3:
        return smiles_str[:max_length] + '...'
    for i in list(range(0, l, max_length))[1:]:
        new_str += smiles_str[prev_idx:i + 1] + ' '
        prev_idx = i + 1
    if prev_idx < l:
        new_str += smiles_str[prev_idx:l]
    return platypus.Paragraph(new_str, smiles_style) 
[docs]def add_spacer(Elements):
    Elements.append(platypus.Spacer(1, 11)) 
[docs]def get_image(fn, height, width):
    with PIL.Image.open(fn) as img_temp:
        size = img_temp.size
    (sx, sy) = aspectScale(size[0], size[1], height, width)
    img = platypus.Image(fn, sx * inch, sy * inch)
    return img 
[docs]def report_add_ms_logo(Elements):
    logo_path = os.path.join(os.environ.get("MMSHARE_EXEC"), "..", "..",
                             "python", "scripts", "event_analysis_dir",
                             "schrodinger_ms_logo.png")
    logo_img = platypus.Image(logo_path, 1.50 * inch, 0.43 * inch)
    logo_img.hAlign = 'RIGHT'
    Elements.append(logo_img) 
[docs]def report_add_logo(Elements):
    logo_path = os.path.join(os.environ.get("MMSHARE_EXEC"), "..", "..",
                             "python", "scripts", "event_analysis_dir",
                             "schrodinger_logo.png")
    logo_img = platypus.Image(logo_path, 1.605 * inch, 0.225 * inch)
    logo_img.hAlign = 'RIGHT'
    Elements.append(logo_img) 
[docs]def get_pargph(txt, fixed=False, fontsize=11, color='black', hAlign='left'):
    style = ParaStyle
    style.fontName = 'Courier' if fixed else 'Helvetica'
    style.fontSize = fontsize
    style.textColor = color
    style.hAlign = hAlign
    return platypus.Paragraph(txt, style) 
[docs]def pargph(Elements,
           txt,
           fixed=False,
           fontsize=11,
           color='black',
           leading=None):
    """
    Add a paragraph to the report
    :param list Elements: Report elements to add the paragraph to
    :param str txt: The paragraph text
    :param int fontsize: The size of the paragraph font
    :param str color: Font color
    :param leading: Spacing between paragraph lines, the default will be used
        if nothing is passed
    :type leading: int or None
    """
    style = ParaStyle
    style.fontName = 'Courier' if fixed else 'Helvetica'
    style.fontSize = fontsize
    style.textColor = color
    if leading:  # Set leading if a custom one has been provided
        style.leading = leading
    para = platypus.Paragraph(txt, style)
    Elements.append(para) 
[docs]def aspectScale(ix, iy, bx, by):
    '''Scale image to fit into box (bx,by) keeping aspect ratio'''
    if ix > iy:
        # fit to width
        scale_factor = old_div(bx, float(ix))
        sy = scale_factor * iy
        if sy > by:
            scale_factor = old_div(by, float(iy))
            sx = scale_factor * ix
            sy = by
        else:
            sx = bx
    else:
        # fit to height
        scale_factor = old_div(by, float(iy))
        sx = scale_factor * ix
        if sx > bx:
            scale_factor = old_div(bx, float(ix))
            sx = bx
            sy = scale_factor * iy
        else:
            sy = by
    return (sx, sy) 
[docs]class NumberedCanvas(rlcanvas.Canvas):
[docs]    def __init__(self, *args, **kwargs):
        rlcanvas.Canvas.__init__(self, *args, **kwargs)
        self._saved_page_states = [] 
[docs]    def showPage(self):
        self._saved_page_states.append(dict(self.__dict__))
        self._startPage() 
[docs]    def save(self):
        """add page info to each page (page x of y)"""
        num_pages = len(self._saved_page_states)
        for state in self._saved_page_states:
            self.__dict__.update(state)
            self.drawFixedContents(num_pages)
            rlcanvas.Canvas.showPage(self)
        rlcanvas.Canvas.save(self) 
[docs]    def drawFixedContents(self, page_count):
        """
        Draw nonflowables such as footers, headers and fixed graphics
        :param int page_count: Total number of pages
        """
        self.setFont("Helvetica", 8)
        self.drawRightString(8 * inch, 0.3 * inch,
                             "Page %d of %d" % (self._pageNumber, page_count))
        s = "Schrödinger Inc. Report generated " + datetime.now().strftime(
            "%m-%d-%Y %H:%M")
        self.drawString(0.8 * inch, 0.3 * inch, s)