#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Fri Oct 11 08:36:47 2019

@author: suwako
"""
#from functools import lru_cache
import gc
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
import numpy as np
from PIL import Image
from tqdm import tqdm
from threading import Thread
from multiprocessing import Pool, Process
"""n=20
liste = [[[1,1,255] for j in range(n)] for i in range(n)]
fig = np.array(liste)
plt.imshow(fig)
plt.show()"""
#@lru_cache(maxsize=512)
def xn(n, c):
    if n==0:
        return 0
    else:
        return xn(n-1, c)**2 + c

def feigenbaum(n=1000):
    l=[]
    for c in tqdm(np.linspace(-2, 0, num=n), ncols=100):
        for k in range(200, 301):
            l.append([c, xn(k, c)])
    ordo = [p[1] for p in l]
    absci = [p[0] for p in l]
    plt.plot(absci, ordo, 'ro', ms=100/n)
    plt.show()
def zn(n, c):
    if n==0:
        return 0
    else:
        return zn(n-1, c)**2 + c

def mandelbrot(n=512, lim=100, color=(1,5,2)):
    mat=[]
    
    for y in tqdm(np.linspace(-2, 2, num=n), ncols=100):
        l=[]
        for x in np.linspace(-2,2, num=n):
            """for k in range(lim):
                a=zn(k, complex(x,y))
                if abs(a) > 2:
                    break"""
            k = zn2(complex(x,y), lim)
#            l.append([((k*color[0])%255),(k*color[1]*5)%255,(k*color[2]*2)%255])
            l.append([x,y])
        mat.append(l)
    fig = np.array(mat)
    img = Image.fromarray(fig.astype(np.uint8), 'RGB')
    img.save('test.png')
    img.show()

def mandeld(n=512, lim=100, color=(1,5,2), threads=5, window=[(-2,2),(-2,2)], filename="test.png"):
    args=(n, lim, color)
    tasks=np.array_split(np.linspace(*window[0], num=n), threads)
    results=[[] for i in range(threads)]
    """    threads=[mandelThread(tasks[i], args, i) for i in range(threads)]
    for thread in threads:
        thread.start()
    for thread in threads:
        thread.join()"""
    p = Pool(threads)
    results=p.map(mandelWorker, [(tasks[i], args, i, window) for i in range(threads)])
    
    mat = [j for i in results for j in i]
#    mat = results[0]
    fig = np.array(mat)
    img = Image.fromarray(fig.astype(np.uint8), 'RGB')
    img.save(filename)
    del tasks
    del results
    del mat
    del p
    del fig
    del img
import time
def Time(func, *args, **kwargs):
    start_time = time.clock()
    res = func(*args, **kwargs)
    print(time.clock() - start_time, "secondes")
    return res
def mandelWorker(data):
    taches, args, thread, window = data
    #print("Thread", thread, "running.")
    def zn2(c, lim):
        z=0
        k=0
        while k<lim and abs(z) <= 2:
            z = z**2 + c
            k+=1
        return k
    n, lim, color = args
    res=[]
    for y in taches:
        l=[]
        for x in np.linspace(*window[1], num=n):
            k = zn2(complex(x,y), lim)
            l.append([((k*color[0])%255),(k*color[1]*5)%255,(k*color[2]*2)%255])
    #                l.append([x,y])
        res.append(l)
    #print("Thread", thread, "finished.")
    return res
#(-2,2),(-2,2)
def tile(coords, n):
    squares=[coords]
    for i in range(n):
        new_squares=[]
        for sq in squares:
            new_squares.extend(square(sq))
        squares=new_squares
    return squares
def square(coords):
    offset=[-coords[0][0],-coords[1][0]]
    y1,y2,x1,x2 = [cd + offset[j] for j in (0,1) for cd in coords[j]]
    squares=[]
    for y in range(2):
        (y*y2/2,(y+1)*y2/2)
        for x in range(2):
            squares.append(((y*y2/2 - offset[0],(y+1)*y2/2 - offset[0]) ,(x*x2/2 - offset[1],(x+1)*x2/2 - offset[1])))
    return squares
def mandeldd(*args, **kwargs):
    m=Process(target=mandeld, args=args, kwargs=kwargs)
    m.start()
    m.join()

    

def bigpicture(n=2, size=128):
    for i, window in tqdm(enumerate(tile(((-2,2),(-2,2)), n)), ncols=100):
        mandeldd(n=size, lim=255, color=(1,1,1), threads=10, window=window, filename="part_%s.png"%i)
    
    #Merging
    print("Now merging.")
    images = list(map(Image.open, ['part_%s.png'%i for i in range(len(tile(((-2,2),(-2,2)), n)))]))
    width, height = size*(2**n), size*(2**n)
    new_im = Image.new('RGB', (width, height), (255,255,255))
    for i, window in tqdm(enumerate(tile(((0,height),(0,height)), n)), ncols=100):
        new_im.paste(images.pop(0), (int(window[1][0]), int(window[0][0])))
    new_im.save('Bigpicture.png')
    
bigpicture(n=3, size=1024)
#mandeld(n=512, lim=255, color=(1,1,1), threads=10, window=[(-2,2),(-2,2)])
#[((-2.0, 0.0), (-2.0, 0.0)), ((-2.0, 0.0), (0.0, 2.0)), ((0.0, 2.0), (-2.0, 0.0)), ((0.0, 2.0), (0.0, 2.0))]
