#!/usr/bin/python

import os, sys, time, glob
from subprocess import *
from itertools import *
from PIL import Image
from raster_utils import *
from raster_gui import *
import linuxcnc

P, Q = map(float, sys.argv[1:])

try:
    INI_FILE_NAME = os.environ['INI_FILE_NAME']
except KeyError:
    INI_FILE_NAME = '2x_laser.ini'

try:
    ini = linuxcnc.ini(INI_FILE_NAME)
except linuxcnc.error:
    fatal('Expected LinuxCNC configuration in %s' % INI_FILE_NAME)

linuxcnc.nmlfile = ini.find('EMC', 'NML_FILE')
if linuxcnc.nmlfile is None:
    fatal('Expected [EMC]NML_FILE in INI')

axis = ini.find('RASTER', 'AXIS')
if axis is None:
    axis = 0

stat = linuxcnc.stat()

# Get the G92 and G5x work offsets so we can translate
stat.poll()
origin = stat.g5x_offset[axis] + stat.g92_offset[axis]

if stat.current_line < 0:
    fatal('cannot execute M144 from MDI')

IMAGE_PATH = ini.find('RASTER', 'IMAGE_PATH')
if IMAGE_PATH is None:
    IMAGE_PATH = os.environ['HOME']
IMAGE_PATH = IMAGE_PATH.split(os.path.pathsep)
image_name = None
for dir in IMAGE_PATH:
    images = glob.glob(os.path.join(dir, '*-%u.*' % int(P)))
    if images:
        image_name = images[0]
if image_name is None:
    image_name = image_not_found(int(P))
print 'image = %s' % image_name

if os.fork():
    # parent must wait until child is ready, then exit
    #...
    time.sleep(1)
    sys.exit(0)

os.setsid()

streamer = Popen(['halstreamer'], stdin=PIPE)
stream = streamer.stdin

image = Image.open(image_name)

# wait for M145 to send us the image info
X, Y = recv_params()
W, ROWS = recv_params()
XSCANGAP, YSCANGAP = recv_params()

# program units are 1:inch, 2:mm, while linear_units are 0:inch, 1:mm
if stat.program_units == 1 and stat.linear_units == 1:
    scale = 25.4
elif stat.program_units == 2 and stat.linear_units == 0:
    scale = 1/25.4
else:
    scale = 1
X *= scale
Y *= scale
W *= scale
#H *= scale
XSCANGAP *= scale
YSCANGAP *= scale

x_mmpd = XSCANGAP
y_mmpd = YSCANGAP
origin += X

pix_w = int(W / x_mmpd)
pix_h = int(ROWS + 0.5)
W = pix_w * x_mmpd

reverse_fudge = 0.0

print 'rescaling to %u,%u' % (pix_w, pix_h)
#XXX
image = image.resize((pix_w, pix_h), Image.BICUBIC).convert('1')
#image = image.resize((pix_w, pix_h), Image.NEAREST).convert('1')
print "image resized"
image.save('actual.png')
# XXX possibly rotate based on axis
print "image saved"

release_lock()

pix = list(image.getdata())

for y in xrange(0,pix_h):
    forward = (y & 1) == 0

    # laser is off until cued for this line:
    if forward:
        stream.write('0 1 %0.3f\n' % (origin))
    else:
        stream.write('0 0 %0.3f\n' % (origin + W + x_mmpd))

    row = pix[y * pix_w:(y + 1) * pix_w]
    groups = map(lambda (v,run): (v, len(list(run))), groupby(row))
    if forward:
        x = 0
    else:
        groups.reverse()
        x = pix_w
    for v, run in groups:
        if (v <= 127):
            # off until we hit start / on until end
            if forward:
                stream.write('0 0 %0.3f\n' % (origin + x * x_mmpd))
                stream.write('1 0 %0.3f\n' % (origin + (x + run) * x_mmpd))
            else:
                stream.write('0 1 %0.3f\n' % (origin + x * x_mmpd + reverse_fudge))
                stream.write('1 1 %0.3f\n' % (origin + (x - run) * x_mmpd + reverse_fudge))
        if forward:
            x += run
        else:
            x -= run

# finally: laser is off once clearing raster area
if forward:
    stream.write('0 0 %0.3f\n' % (origin + W + x_mmpd))
else:
    stream.write('0 1 %0.3f\n' % (origin))

stream.close()
streamer.wait()

print 'DONE!'
