"""
Helper to generate XLSX Spreadsheets in an uniform way.
"""
from datetime import date

import openpyxl
from openpyxl.styles import NamedStyle, Font, Border, Side

DEFAULT_FONT = Font(name='Philosopher', size=10, bold=False, color='000000')
THIN_BORDER = Border(
    bottom=Side(style='thin', color="d3d7cf"),
    top=Side(style='thin', color="d3d7cf"))
XLSX_STYLES = dict()

XLSX_STYLES['Content'] = NamedStyle(
    name='Content',
    font=DEFAULT_FONT,
    border=THIN_BORDER
)

XLSX_STYLES['Headline'] = NamedStyle(
    name="Headline",
    font=openpyxl.styles.Font(name='Philosopher', size=11,
                              bold=True, color='ffffff'),
    fill=openpyxl.styles.PatternFill(fill_type='solid',
                                     start_color='a40000',
                                     end_color='a40000')
)

XLSX_STYLES['Date'] = NamedStyle(
    name='Date',
    font=DEFAULT_FONT,
    border=THIN_BORDER,
    number_format='dd.mm.yyyy'
)

XLSX_STYLES['Date Time'] = NamedStyle(
    name='Date Time',
    font=DEFAULT_FONT,
    border=THIN_BORDER,
    number_format='dd.mm.yyyy hh:MM'
)

XLSX_STYLES['Float'] = NamedStyle(
    name='Float',
    font=DEFAULT_FONT,
    border=THIN_BORDER,
    number_format='#,##0.00'
)

XLSX_STYLES['Integer'] = NamedStyle(
    name='Integer',
    font=DEFAULT_FONT,
    border=THIN_BORDER,
    number_format='#,##0'
)


def getattr_recursive(obj, attr_string):
    """A recusive version of gettattr. the attr_string is splitted on the ".".

    :param obj: a python object.
    :param attr_string: the desired attribute of the object.
    :return: a getattr_recursice(obj, 'attr1.attr2') will return the value of attr2 of attr1 from obj
    """
    attr_list = attr_string.split('.')
    return_value = None
    for attr in attr_list:
        return_value = getattr(obj, attr)
        obj = return_value
    return return_value


class Workbook(object):
    workbook = None

    def __init__(self):
        """Generate an XLSX Workbook in memory

        :rtype: object
        """
        self.workbook = openpyxl.Workbook()
        [self.workbook.add_named_style(style) for style in XLSX_STYLES.values()]
        [self.workbook.remove(sheet) for sheet in self.workbook.worksheets]

    def generate_sheet(self, title, columns_settings, object_list,
                       orientation='landscape'):
        """

        :param title: Title of the Sheet
        :param columns_settings: a list of dicts for the settings of each column
        :param object_list: List of objects that should be added to the sheet
        :param orientation: Paper Orientation 'landscape' or 'portrait'
        """
        row = 1
        ws = self.workbook.create_sheet()
        ws.title = title
        ws.syncHorizontal = True
        ws.filterMode = True

        # setup print orientation
        ws.page_setup.fitToHeight = 0
        ws.page_setup.fitToWidth = 1
        if orientation == 'landscape':
            ws.page_setup.orientation = ws.ORIENTATION_LANDSCAPE
        else:
            ws.page_setup.orientation = ws.ORIENTATION_PORTRAIT
        ws.page_setup.paperSize = ws.PAPERSIZE_A4
        ws.print_options.horizontalCentered = True

        # setup page header
        ws.oddHeader.left.text = title
        ws.oddHeader.left.size = 14
        ws.oddHeader.left.font = "Amerika Sans"
        ws.oddHeader.left.color = "000000"

        ws.oddHeader.right.text = str(date.today())
        ws.oddHeader.right.size = 14
        ws.oddHeader.right.font = "Amerika Sans"
        ws.oddHeader.right.color = "000000"

        # write table header
        for column, data in enumerate(columns_settings, 1):
            cell = ws.cell(column=column, row=row, value=data['title'])
            cell.style = 'Headline'
        row += 1

        # write the table content
        for line in object_list:
            for column, settings in enumerate(columns_settings, 1):
                cell = ws.cell(column=column, row=row,
                               value=getattr_recursive(line, settings['attr']))
                cell.style = settings['style']
            row += 1

        # write table footer
        for column, settings in enumerate(columns_settings, 1):
            cell = ws.cell(column=column, row=row, value=settings.get('footer'))
            cell.style = settings['style']
        row += 1

        # set column widths
        for settings in columns_settings:
            ws.column_dimensions[settings['col']].width = settings['width']

    def save(self, *args, **kwargs):
        return self.workbook.save(*args, **kwargs)
