"""Utilities for label generation.
   stolen from: https://github.com/Edinburgh-Genome-Foundry/blabel
"""
import base64
from io import BytesIO
import datetime
import textwrap
from math import floor

import PIL.Image
import barcode as python_barcode
from PIL import Image, ImageDraw, ImageFont
import labelprinter


def now(fmt="%Y-%m-%d %H:%M"):
    """Display the current time.
    Default format is "year-month-day hour:minute" but another format can be
    provided (see ``datetime`` docs for date formatting).
    """
    now = datetime.datetime.now()
    if fmt is not None:
        now = now.strftime(fmt)
    return now


def pil_to_html_imgdata(img, fmt='PNG'):
    """Convert a PIL image into HTML-displayable data.

    The result is a string ``data:image/FMT;base64,xxxxxxxxx`` which you
    can provide as a "src" parameter to a ``<img/>`` tag.
    Examples:
    ---------
    >>> data = pil_to_html_imgdata(my_pil_img)
    >>> html_data = '<img src="%s"/>' % data
    """
    buffered = BytesIO()
    img.save(buffered, format=fmt)
    img_str = base64.b64encode(buffered.getvalue())
    prefix = 'data:image/%s;charset=utf-8;base64,' % fmt.lower()
    return prefix + img_str.decode()


def wrap(text, col_width):
    """Breaks the text into lines with at maximum 'col_width' characters."""
    return "\n".join(textwrap.wrap(text, col_width))


def container_label(data, barcode_class='code128', fmt='png', logo_file='./static/images/djlogo256.png',
                    owner_name='Dirk Jahnke', description='', description_line2='', **options):
    """Return a barcode's image data.
    Powered by the Python library ``python-barcode``. See this library's
    documentation for more details.
    Parameters
    ----------
    data
      Data to be encoded in the datamatrix.
    barcode_class
      Class/standard to use to encode the data. Different standards have
      different constraints.
    fmt
        The format to be used when rendering the resulting image
        png -> png image
        svg -> embeddable code for html img tag
    logo_file
        File path to logo file to be included
    owner_name
        Name of owner printed underneath the logo
    description
        Text to be printed on bottom of the label
    writer_options
      Various options for the writer to tune the appearance of the barcode
      (see python-barcode documentation).
    Returns
    -------
    image_base64_data
      A string ``data:image/png;base64,xxxxxxxxx`` which you can provide as a
      "src" parameter to a ``<img/>`` tag.
    Examples:
    ---------
    >>> data = barcode('EGF12134', barcode_class='code128')
    >>> html_data = '<img src="%s"/>' % data
    Examples of writer options:
    >>> { 'background': 'white',
    >>>   'font_size': 10,
    >>>   'foreground': 'black',
    >>>   'module_height': 15.0,
    >>>   'module_width': 0.2,
    >>>   'quiet_zone': 6.5,
    >>>   'text': '',
    >>>   'text_distance': 5.0,
    >>>   'write_text': True
    >>> }
    """

    with Image.open(logo_file) as logo_img:
        font_size = 22
        font_size_small = 16
        owner_name_font_size = 26
        logo_img = logo_img.resize((128, 128))
        logo_img = logo_img.convert('L')
        threshold = 20
        logo_img = logo_img.point(lambda p: 255 if p < threshold else 0)
        logo_img = logo_img.convert('1')
        constructor = python_barcode.get_barcode_class(barcode_class)
        data = str(data).zfill(constructor.digits)
        writer = {
            'svg': python_barcode.writer.ImageWriter,
            'png': python_barcode.writer.ImageWriter,
            'image': python_barcode.writer.ImageWriter
        }[fmt]
        barcode_img = constructor(data, writer=writer())
        img = barcode_img.render(writer_options=options['writer_options'])
        barcode_xsize, barcode_ysize = img.size
        logo_xsize, logo_ysize = logo_img.size
        label_xsize = 696
        label_ysize = barcode_ysize + font_size if description_line2 == '' else barcode_ysize + 2 * font_size
        result_img = Image.new('1', (label_xsize, label_ysize), 1)
        result_img.paste(logo_img, (owner_name_font_size + 10, floor(barcode_ysize / 2) - 20 - floor(logo_ysize / 2)))
        start_x_for_barcode = logo_xsize + 10
        max_x_for_barcode = 696 - start_x_for_barcode
        result_img.paste(img, (start_x_for_barcode + floor((max_x_for_barcode - barcode_xsize) / 2), 5))
        fnt = ImageFont.truetype("./static/fonts/DejaVuSerif.ttf", font_size)

        owner_name_fnt = ImageFont.truetype("./static/fonts/DejaVuSerif.ttf", owner_name_font_size)
        owner_text_img = Image.new('1', (floor(owner_name_fnt.getlength(owner_name)+1), owner_name_font_size+5), 1)
        d = ImageDraw.Draw(owner_text_img)
        d.text((0,0), owner_name, font=owner_name_fnt)
        owner_text_img = owner_text_img.transpose(PIL.Image.ROTATE_90)
        result_img.paste(owner_text_img, (0, 10))

        d = ImageDraw.Draw(result_img)
        #d.text((20, logo_ysize), owner_name, font=fnt)
        if fnt.getlength(description) > 660:
            fnt_small = ImageFont.truetype("./static/fonts/DejaVuSerif.ttf", font_size_small)
            d.text((0, barcode_ysize), description, font=fnt_small)
            if description_line2 != '':
                d.text((0, barcode_ysize + font_size), description_line2, font=fnt_small)
        else:
            #d.text((30 + floor((660 - fnt.getlength(description)) / 2), barcode_ysize), description, font=fnt)
            d.text((0, barcode_ysize), description, font=fnt)
            if description_line2 != '':
                d.text((0, barcode_ysize + font_size), description_line2, font=fnt)

        if fmt == 'image':
            return result_img
        elif fmt == 'png':
            return pil_to_html_imgdata(result_img, fmt='PNG')
        else:
            prefix = "data:image/svg+xml;charset=utf-8;base64,"
            return prefix + base64.b64encode(result_img).decode()

