# -*- coding: utf-8 -*-
from itertools import izip_longest
from os.path import dirname, exists, join

from exceller import ExcelDocument
from pptx.chart.data import ChartData
from pptx.enum.chart import XL_CHART_TYPE
from pptx.enum.shapes import MSO_SHAPE, MSO_SHAPE_TYPE
from pptx.enum.text import PP_ALIGN
from pptx.util import Cm, Pt
from presentation import COLORS
from proceed_config import get_slide_config


def add_slide(ppt, slide_config):
    layout = get_layout_by_name(ppt, slide_config['layout'])
    slide = ppt.slides.add_slide(layout)

    slide = fill_text_holders(slide, slide_config.get('text_holders', {}))
    if slide_config.get('note'):
        slide.notes_slide.notes_text_frame.text = slide_config['note']

    if slide_config.get('images'):
        for img_name, coords in slide_config['images'].iteritems():
            img_path = join(dirname(__file__), 'images', img_name)
            left, top, height = Cm(float(coords['left'])), Cm(float(coords['top'])), Cm(float(coords['height']))
            slide.shapes.add_picture(img_path, left, top, height=height)

    return slide


def add_content_slides(ppt, slide_config, contents):
    s_cnt = 0
    for slice_ in izip_longest(fillvalue=None, *[iter(contents)] * 12):
        s_cnt += 1
        slide = add_slide(ppt, slide_config)

        for i, subtitle in enumerate(slice_, 1):
            num_holder, text_holdes = [
                get_placeholder_by_name(slide, 'text_num_{}'.format(i)),
                get_placeholder_by_name(slide, 'text_{}'.format(i))
            ]
            if subtitle:
                num_holder.text_frame.text = u'%02d' % (i + (s_cnt - 1) * 12)
                text_holdes.text_frame.text = subtitle

        drop_empty_placeholders(slide)

    return ppt


def insert_charts(report, slide, slide_config):

    charts_config = slide_config['charts']
    if not isinstance(charts_config['chart_name'], list):
        chart_names = [charts_config['chart_name'], ]
    else:
        chart_names = charts_config['chart_name']

    if not isinstance(charts_config['sheet_name'], list):
        sheet_names = [charts_config['sheet_name'], ]
    else:
        sheet_names = charts_config['sheet_name']

    if len(sheet_names) > len(chart_names):
        chart_names = chart_names * len(charts_config['sheet_name'])
    elif len(sheet_names) < len(chart_names):
        sheet_names = sheet_names * len(charts_config['chart_name'])

    for p_num, (chart_name, sheet_name) in enumerate(zip(chart_names, sheet_names), 1):
        chart_content = report[sheet_name].charts[chart_name].dump()
        placeholder = get_placeholder_by_name(slide, 'chart_{}'.format(p_num))
        placeholder.insert_chart(XL_CHART_TYPE.COLUMN_CLUSTERED, ChartData(), chart_content)

    return slide


def draw_legend(slide, legend, lang):
    s_names = legend.get('texts')
    if not s_names:
        s_names = legend['texts_{}'.format(lang)]

    if legend.get('top'):
        top = Cm(float(legend['top']))
    else:
        top = Cm(7.03)
    width = height = Cm(0.56)
    for left, s_name, color_key in zip(legend['lefts'], s_names, legend['colors']):
        left = Cm(float(left))

        rect_shp = slide.shapes.add_shape(MSO_SHAPE.RECTANGLE, left, top, width, height)
        fill = rect_shp.fill
        fill.solid()
        fill.fore_color.rgb = COLORS[color_key]
        rect_shp.line.fill.background()

        text_shp = slide.shapes.add_textbox(left + Cm(1), top - Cm(0.3), Cm(0.35 * len(s_name) + 0.3), Cm(1))

        text_frame = text_shp.text_frame
        text_frame.margin_top = Cm(0)
        text_frame.margin_bottom = Cm(0)
        text_frame.margin_left = Cm(0)
        text_frame.margin_right = Cm(0)

        paragraph = text_shp.text_frame.paragraphs[0]
        paragraph.text = s_name
        paragraph.font.size = Pt(24)

    return slide


def fill_text_holders(slide, text_holders):
    for ph_name, content in text_holders.iteritems():
        if type(content) == list:
            try:
                for p_num, text in enumerate(content, 1):
                    text_holder = get_placeholder_by_name(slide, '{}_{}'.format(ph_name, p_num))
                    text_holder.text_frame.text = text.strip()
            except:
                write_bullet_list(slide, ph_name, content)

        else:
            text_holder = get_placeholder_by_name(slide, ph_name)
            text_holder.text_frame.text = content.strip()

    return slide


def write_bullet_list(slide, ph_name, texts):
    text_holder = get_placeholder_by_name(slide, ph_name)
    tf = text_holder.text_frame

    for i, text in enumerate(texts):
        p = tf.paragraphs[0] if i == 0 else tf.add_paragraph()
        p.text = text
        p.alignment = PP_ALIGN.LEFT
        p.level = 2
    return slide


def drop_empty_placeholders(slide):
    for shape in slide.shapes:
        if shape.shape_type is not MSO_SHAPE_TYPE.AUTO_SHAPE and shape.shape_type is not MSO_SHAPE_TYPE.PICTURE:
            if shape.has_text_frame:
                if not shape.text_frame.text:
                    shape.element.getparent().remove(shape.element)

            elif not shape.has_chart and not shape.has_table:
                shape.element.getparent().remove(shape.element)

    return slide


def get_layout_by_name(ppt, lo_name):
    for layout in ppt.slide_layouts:
        if unicode(layout.name) == lo_name:
            return layout

    return None


def get_placeholder_by_name(slide, ph_name):
    for placeholder in slide.placeholders:
        if (hasattr(placeholder, '_layout_placeholder') and placeholder._layout_placeholder.name == ph_name) \
                or (placeholder.name == ph_name):
            return placeholder

    return None


def add_general_slides(ppt, yml_templates, **keys_to_format):
    for slide_template in yml_templates:
        slide_type = slide_template.keys().pop()
        slide_template = slide_template[slide_type]

        slide_config = get_slide_config(slide_template, keys_to_format)
        if slide_type == 'method':
            for key in ['text_holders', 'images']:
                try:
                    for k, v in keys_to_format['method'][key].iteritems():
                        slide_config[key][k] = v
                except KeyError:
                    pass

            add_slide(ppt, slide_config)

        elif slide_type == 'contents':
            fill_contents_slide(ppt, slide_config, keys_to_format['categories'], keys_to_format.get('category_cell'))

        else:
            add_slide(ppt, slide_config)

    return ppt


def fill_contents_slide(ppt, conf, categories, category_cell=None):
    cats = []
    for cat_path in categories:
        if exists(cat_path):
            report = ExcelDocument(cat_path)
            if category_cell is None:
                cats.append(report['Info']['B25'].text)
            else:
                cats.append(report['Info'][category_cell].text)
        else:
            cats.append(cat_path)

    add_content_slides(ppt, conf, cats)

    return ppt
