"""Go image recognition lines-finding module"""

import sys
from math import sin, cos, pi

try:
    import Image, ImageDraw
except ImportError, msg:
    print >> sys.stderr, msg
    sys.exit(1)

import filters
from hough import Hough

def find_lines(image, show_all, do_something, verbose):

    if verbose:
        print >> sys.stderr, "preprocessing"

    if show_all:
        do_something(image, "original image")

    im_l = image.convert('L')
    if show_all:
        do_something(im_l, "ITU-R 601-2 luma transform")

    if verbose:
        print >> sys.stderr, "edge detection"

    im_edges = filters.edge_detection(im_l)
    if show_all:    
        do_something(im_edges, "edge detection")

    im_h = filters.high_pass(im_edges, 100)
    if show_all:
        do_something(im_h, "high pass filters")
    
    if verbose:
        print >> sys.stderr, "hough transform"

    hough1 = Hough(im_h.size)
    im_hough = hough1.transform(im_h)
    if show_all:
        do_something(im_hough, "hough transform")

   # im_hough = filters.peaks(im_hough)
   # if show_all:
   #     do_something(im_hough, "peak extraction")
               
    im_h2 = filters.high_pass(im_hough, 96)
    if show_all:
        do_something(im_h2, "second high pass filters")

    im_h2 = filters.components2(im_h2)
    if show_all:
        do_something(im_h2, "components centers")

    if verbose:
        print >> sys.stderr, "second hough transform"

    hough2 = Hough(im_h2.size) 
    # im_hough might be used instead im_h2, but at the moment it brings a lot of
    # noise to the second transform, which later confuses the center-finding
    # mechanism (which is not very robust yet)
    im_hough2 = hough2.transform(im_h2)
    if show_all:
        do_something(im_hough2, "second hough transform")

    im_h3 = filters.high_pass(im_hough2, 120)
    if show_all:
        do_something(im_h3, "third high pass filter")
     
    im_h3 = filters.components(im_h3)
    if show_all:
        do_something(im_h3, "half centers")

    if verbose:
        print >> sys.stderr, "finding the grid"

    lines_m = hough2.all_lines_h(im_h3)
    lines = []
    im_c = im_h2.convert('RGB').convert('RGB', (1, 0.5, 0.5, 0))
    draw_c = ImageDraw.Draw(im_c)
    bounds = []

    for line_l in lines_m:
        im_line = Image.new('L', im_h2.size)
        draw = ImageDraw.Draw(im_line)
        line_points = set()
        for line in line_l:
            draw.line(line_from_angl_dist(line, im_h2.size), fill=255, width=7)
            draw_c.line(line_from_angl_dist(line, im_c.size), fill=(70, 70, 70), width=7)
            for p in combine(im_h2, im_line):
                line_points.add(p)
        for point in line_points:
            draw_c.point(point, fill=(120, 255, 120))
        lines.append(hough1.lines_from_list(line_points))
        line_points = list(line_points)
        line_points.sort()
        bounds += [line_points[0], line_points[-1]]

    if show_all:
        do_something(im_c, "hough x lines")

    image_g = image.copy()
    draw = ImageDraw.Draw(image_g)
    for line in [l for s in lines for l in s]:
        draw.line(line_from_angl_dist(line, image.size), fill=(120, 255, 120))
    if show_all:
        do_something(image_g, "lines")
   
    return lines, lines_m[0][0], lines_m[1][0], bounds, hough1, im_h

def combine(image1, image2):
    im_l1 = image1.load()
    im_l2 = image2.load()

    on_both = []

    for x in xrange(image1.size[0]):
        for y in xrange(image1.size[1]):
            if im_l1[x, y] and im_l2[x, y]:
                on_both.append((x, y))
    return on_both

def line_from_angl_dist((angle, distance), size):
    if pi / 4 < angle < 3 * pi / 4:
        y1 = - size[1] / 2
        x1 = int(round((y1 * cos(angle) + distance) / sin(angle))) + size[0] / 2
        y2 = size[1] / 2 
        x2 = int(round((y2 * cos(angle) + distance) / sin(angle))) + size[0] / 2
        return [(x1, 0), (x2, size[1])]
    else:
        x1 = - size[0] / 2
        y1 = int(round((x1 * sin(angle) - distance) / cos(angle))) + size[1] / 2
        x2 = size[0] / 2 
        y2 = int(round((x2 * sin(angle) - distance) / cos(angle))) + size[1] / 2
        return [(0, y1), (size[0], y2)]
