# Stolen from tgcaptcha/plugins
# http://code.google.com/p/tgcaptcha/source/browse/trunk/tgcaptcha/plugins/image/vanasco_dowty/captcha.py

import random
from PIL import Image, ImageDraw, ImageFont, ImageFilter
import cStringIO as StringIO
import math
from pyramid.view import view_config
from .words import TabMots
from pyramid.response import Response

class Captcha_Img(object):
    def __init__( self, width, height):
        self.width = width
        self.height = height
        self._layers = [
            _PyCaptcha_SineWarp(amplitudeRange = (4, 8) , periodRange=(0.65,0.73) ),
        ]
        
    def getImg(self):
        """Get a PIL image representing this CAPTCHA test, creating it if necessary"""
        if not self._image:
            self._image = self.render()
        return self._image

    def render(self):
        """Render this CAPTCHA, returning a PIL image"""
        size = (self.width,self.height)
        #img = Image.new("RGB", size )
        img = self._image
        for layer in self._layers:
            img = layer.render( img ) or img
        self._image = img
        return self._image

class _PyCaptcha_WarpBase(object):
    """Abstract base class for image warping. Subclasses define a
       function that maps points in the output image to points in the input image.
       This warping engine runs a grid of points through this transform and uses
       PIL's mesh transform to warp the image.
       """
    filtering = Image.BILINEAR
    resolution = 40

    def get_transform(self, image):
        """Return a transformation function, subclasses should override this"""
        return lambda x, y: (x, y)

    def render(self, image):
        r = self.resolution
        xPoints = image.size[0] / r + 2
        yPoints = image.size[1] / r + 2
        f = self.get_transform(image)

        # Create a list of arrays with transformed points
        xRows = []
        yRows = []
        for j in xrange(yPoints):
            xRow = []
            yRow = []
            for i in xrange(xPoints):
                x, y = f(i*r, j*r)

                # Clamp the edges so we don't get black undefined areas
                x = max(0, min(image.size[0]-1, x))
                y = max(0, min(image.size[1]-1, y))

                xRow.append(x)
                yRow.append(y)
            xRows.append(xRow)
            yRows.append(yRow)

        # Create the mesh list, with a transformation for
        # each square between points on the grid
        mesh = []
        for j in xrange(yPoints-1):
            for i in xrange(xPoints-1):
                mesh.append((
                    # Destination rectangle
                    (i*r, j*r,
                     (i+1)*r, (j+1)*r),
                    # Source quadrilateral
                    (xRows[j  ][i  ], yRows[j  ][i  ],
                     xRows[j+1][i  ], yRows[j+1][i  ],
                     xRows[j+1][i+1], yRows[j+1][i+1],
                     xRows[j  ][i+1], yRows[j  ][i+1]),
                    ))

        return image.transform(image.size, Image.MESH, mesh, self.filtering)

class _PyCaptcha_SineWarp(_PyCaptcha_WarpBase):
    """Warp the image using a random composition of sine waves"""

    def __init__(self,
                 amplitudeRange = (1,1),#(2, 6),
                 periodRange    = (1,1)#(0.65, 0.73),
                 ):
        self.amplitude = random.uniform(*amplitudeRange)
        self.period = random.uniform(*periodRange)
        self.offset = (random.uniform(0, math.pi * 2 / self.period),
                       random.uniform(0, math.pi * 2 / self.period))
                       
    def get_transform(self, image):
        return (lambda x, y,
                a = self.amplitude,
                p = self.period,
                o = self.offset:
                (math.sin( (y+o[0])*p )*a + x,
                 math.sin( (x+o[1])*p )*a + y))

@view_config(route_name='captcha')
def DoCaptcha(request):
    ImgSize = (230,100)
    WorkImg = Image.new( 'RGBA', ImgSize, (255, 255, 255, 0) )
    Xmax, Ymax = WorkImg.size
    # Write something on it
    draw = ImageDraw.Draw(WorkImg)

    # use a truetype font
    #font = ImageFont.truetype("/var/lib/defoma/gs.d/dirs/fonts/LiberationMono-Regular.ttf", 40)
    # use it
    font = ImageFont.truetype("jm2l/static/fonts/LiberationMono-Regular.ttf",40)
    # Re-position
    # Choose a word for captcha
    text = random.choice(TabMots)
    Xt, Yt = font.getsize(text)
    OrX, OrY = (ImgSize[0]-Xt)/2, (ImgSize[1]-Yt)/2
    draw.text((OrX, OrY), text, font=font, fill="#000000")
    # Apply a Blur
    # WorkImg=WorkImg.filter(ImageFilter.BLUR)
    # Apply a DETAIL
    WorkImg=WorkImg.filter(ImageFilter.DETAIL)
    # randomize parameters for perspective
    ax, ay = (random.uniform(0.9,1.2) , random.uniform(0.9,1.2)) 
    tx, ty = (random.uniform(0,0.0003),random.uniform(0,0.0003))
    bx, by = (random.uniform(0.5,0.8),random.uniform(0,0.2))
    # Apply perspective to Captcha
    WorkImg= WorkImg.transform(ImgSize, Image.PERSPECTIVE, (ax, bx, -25, by, ay, -10, tx, ty))
    # Apply SinWarp to Captcha
    tr = Captcha_Img(Xmax, Ymax)
    tr._image = WorkImg
    WorkImg = tr.render()
    # Apply a Smooth on it
    WorkImg=WorkImg.filter(random.choice([ImageFilter.SMOOTH, ImageFilter.SMOOTH_MORE]))
    # Save Result
    request.session['Captcha'] = text
    #session.save()
    ImgHandle = StringIO.StringIO()
    WorkImg.save(ImgHandle,'png')
    ImgHandle.seek(0)
    return Response(app_iter=ImgHandle, content_type = 'image/png')
