#!/usr/bin/env python
# coding=utf-8
#
# Copyright (C) [YEAR] [YOUR NAME], [YOUR EMAIL]
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
#
"""
Description of this extension
"""

import inkex
import inkex.command
import numpy as np
import sys
import os.path
from matplotlib import image as im 
import matplotlib.pyplot as pl
import matplotlib as mpl
from PIL import Image
import subprocess
from inkex import Group
import re

def tupleListToDict(l):
    return {a:b for a,b in l}


def discrete_laplacian(M):
    L = -4*M
    L += np.roll(M, (0,-1), (0,1))
    L += np.roll(M, (0,+1), (0,1))
    L += np.roll(M, (-1,0), (0,1))
    L += np.roll(M, (+1,0), (0,1))
    
    return L
def gray_scott_update(A, B, DA, DB, f, k, delta_t):
    LA = discrete_laplacian(A)
    LB = discrete_laplacian(B)
    
    diff_A = (DA*LA - A*B**2 + f*(1-A)) * delta_t
    diff_B = (DB*LB + A*B**2 - (k+f)*B) * delta_t
    
    A += diff_A
    B += diff_B
    
    return A, B


delta_t = 1.0

DA = 0.16
DB = 0.08

f = 0.060
k = 0.062



class DiffusionReaction(inkex.EffectExtension):
    def add_arguments(self, pars):
        pars.add_argument("--dpi", type=int, default=24, help="dpi")
        pars.add_argument("--iterations", type=int, default=24, help="iterations")
    
    def rescale(self, bb, svg_obj):
        scaling = tupleListToDict(svg_obj.items())
        transform_matrix = svg_obj.getchildren()[1].get('transform')
        values = list(map(float, re.search(r'\((.*?)\)',transform_matrix).group(1).split()))
        x_scale = values[0]*((bb[1]-bb[0])/float(scaling['width'][0:-2]))
        y_scale = values[3]*((bb[3]-bb[2])/float(scaling['height'][0:-2]))
        x_translate = bb[0]
        y_translate = bb[3]
        x_scale = str(round(x_scale, 3))
        y_scale = str(round(y_scale, 3))
        x_translate = str(round(x_translate, 3))
        y_translate = str(round(y_translate, 3))
        svg_obj.getchildren()[1].set('transform',"translate("+x_translate+","+y_translate+") scale("+x_scale+","+y_scale+")")
        return svg_obj

    def effect(self):
        bbs = []
        svg = self.options.input_file
        png = os.path.splitext(svg)[0] + ".png"
        for node in self.svg.selected.values():
             (x1, x2), (y1, y2) = node.bounding_box()
             bbs.append([x1, x2, y1, y2])
        bbs = np.array(bbs)
        bb = (min(bbs[:,0]), max(bbs[:,1]), min(bbs[:,2]), max(bbs[:,3]))
        inkex.command.inkscape(svg,"--export-filename="+png, "--export-dpi=" +str(self.options.dpi) ,"--export-id="+'/;'.join([node.get_id()  for node in self.svg.selected.values()]))
        image_ = im.imread(png)
        grey = (image_[:,:,0] + image_[:,:,1] + image_[:,:,2]) > 0
        A = image_[:,:,0]
        B = image_[:,:,1]
        for t in range(self.options.iterations):
            A, B = gray_scott_update(A, B, DA, DB, f, k, delta_t)
            B*=grey
        pl.show()
        A = A >0.6
        PIL_image = Image.fromarray(np.uint8(A * 255) , 'L')
        PIL_image.save("/tmp/diffusion.bmp",  format='BMP')
        subprocess.check_output("potrace /tmp/diffusion.bmp -s -o /tmp/diffusion.svg", shell=True)
        layer = self.svg.get_current_layer()
        svg_obj = inkex.elements.load_svg("/tmp/diffusion.svg").getroot()
        svg_obj = self.rescale(bb, svg_obj)
        self.svg.add((svg_obj.getchildren()[1]))
        os.remove("/tmp/diffusion.bmp")
        os.remove("/tmp/diffusion.svg")

        


if __name__ == '__main__':
    DiffusionReaction().run()
