from docxtpl import DocxTemplate, InlineImage
from docx.shared import Cm
import warnings

class TPL():
    """ Class to help you fill a word template with fme features.
    Make sure the feature feeding the python caller contains all 
    necessary features.

    You can pass a width along to an image by adding a second 
    variable with the same only starting with breedte_, give the 
    width in centimeters. Example usage:

    foto_plangebied         : location/to/png/file/foto.png
    breedte_foto_plangebied : 20

    Args:
        - path: path the word template.

    Example Usage:
        TPL(path).fill_tplFME(feature).save_tpl(savepath)
    """


    def __init__(self,path:str):
        self.tpl = DocxTemplate(path)
        self.vars = self.tpl.get_undeclared_template_variables()
    

    def get_all_FMEattributes(self,feature) -> dict:
        """Get all the fme attributes and their values in a dict.

        Args:
            - feature: the fme feature
        
        Returns:
            - Dictionary with all the fme features names and values.
        """
        dic = {}
        for attribute_name in feature.getAllAttributeNames():
            dic[attribute_name] = feature.getAttribute(attribute_name)
        return dic


    def fill_tplFME(self,feature, defaultWidthImage: float = 14.0, fillAllVars: bool = True):
        """Fill the word template with all the matching fme 
        features.

        Args:
            - feature: the fme feature
            - defaultWidthImage: the stand width of an image in cm

        Returns:
            - self
        """
        context = {}
        fmevars = self.get_all_FMEattributes(feature)
        keys = list(fmevars.keys())
        rej = []
        for var in self.vars:
            # for tables
            if var[:5] == 'rows_':
                table_name = var[5:]
                list_prefix = '_list_' + table_name
                keysRelated = [k.split(".")[1] for k in keys if k.startswith(list_prefix)]
                uniqueKeysRelated = list(set(keysRelated))

                if len(keysRelated) == 0:
                    raise Exception('The following table is unfilled: '+ str(var)
                                    +', If you want an empty row give an empty row as input.')
                else:
                    n_rows = int(len(keysRelated) / len(uniqueKeysRelated))
                    fill = []
                    for i in range(n_rows): 
                        libfill = {}
                        for kr in uniqueKeysRelated: 
                            libfill[kr] = fmevars[list_prefix + "{%d}." % i + kr]
                        fill.append(libfill)
                    context[var] = fill
            elif var in keys:
                value = str(fmevars[var])
                if value != '':
                    # for images
                    if value[-4:] == '.png' or value[-4:] == '.jpg' or value[-4:] == '.PNG' or value[-4:] == '.JPG':
                        width_attribute = "breedte_" + var
                        if width_attribute in keys:
                            widthImage = float(fmevars[width_attribute])
                        else:
                            widthImage = defaultWidthImage
                        context[var] = InlineImage(self.tpl, value, width = Cm(widthImage))
                    # normal vars
                    else:
                        context[var] = value
                else:
                    context[var] = value
            # unfilled vars
            else:
                context[var] = "{{"+ var + "}}"
                rej.append(var)
        if len(rej) > 0:
            if fillAllVars:
                raise Exception('The following variables are unfilled: ', rej)
            else:
                warnings.warn('The following variables are unfilled: '+ str(rej), UserWarning)
        self.context = context
        return self


    def save_tpl(self,savepath:str) -> None:
        """Renders and saves the word template
        
        Args:
            - savepath: path to where to save the template.
        
        Returns:
            - The filled word template.
        """
        self.tpl.render(self.context)
        self.tpl.save(savepath)