#!/usr/bin/python
#GPLv2

import png
import os
import sys
import json

def pr(*l):
  print(" ".join(map(str, l)))

with file('settings.json') as fin:
  settings = json.load(fin)
  dpm = float(settings['inputDPI'])/25.4
  spotsize = float(settings['spotSize'])
  machinedpm = float(settings['machineDPI'])/25.4
  basic_speed = float(settings['basicSpeed'])
  oversampling = float(settings['oversampling'])
  focus_speed = float(settings['focusSpeed'])
  travel_speed = float(settings['travelSpeed'])
  focusedZ = float(settings['focusedZ'])
  travelZ = float(settings['travelZ'])
  endZ = float(settings['endZ'])
  passes = int(settings['passes'])


def get_pixel(i, x, y, meta):
  x *= meta['planes']
  w = meta['size'][0]
  l = i[y]
  #print>>sys.stderr, '\n',x
  return l[x]

def get_rect(img, x, y, size, meta):
  r = []
  for i in xrange(x-size, x+size):
    for j in xrange(y-size, y+size):
      r.append(get_pixel(img, x, y, meta))
  return r

def get_rect_avg(img, x, y, size, meta):
  s = 0.0
  count = 0
  #print>>sys.stderr, x,y
  for i in xrange(x-size, x+size):
    for j in xrange(y-size, y+size):
      s += get_pixel(img, x, y, meta)
      count += 1
  return s / count

def get_average(pixels):
  return float(sum(pixels))/len(pixels)


import random
def choose_neighbor(img, x, y, meta, visited, spotsize):
  ns = []
  for _x in range(x-1, x+2):
    for _y in range(y-1, y+2):
      if get_rect_avg(img, _x, _y, spotsize) < 250 and visited[y][x]:
        ns.append((_x,_y))
  return ns[random.randrange(0, len(ns))]

def main():
  # header
  pr('G90') # absolute pos
  pr('G21') # units in mm
  pr('G28') # go home
  pr('G01 Z{} F9000'.format(travelZ)) # go to standby position

  w, h, img, meta = png.Reader(filename=sys.argv[1]).asDirect()
  img = list(img)
  wdpm, hdpm = w/dpm, h/dpm
  linescount = hdpm / spotsize
  rowscount = wdpm / spotsize
  spot_in_img = spotsize * dpm

  global travelZ, focusedZ

  visited = [[False]*int(rowscount)]*int(linescount)

  if passes > 1:
    travelZ += 0.05
    focusedZ += 0.05
  for pass_id in xrange(passes):

    pen_is_up = True
    alt = False
    _cnt = 0
    _speed = basic_speed  # 170 is basic speed, 3 is oversampling
    #l_x, l_y = (0,0)
    for lnum in xrange(int(linescount)):
      rows = xrange(int(rowscount))
      rows = reversed(rows) if alt else rows
      alt = not alt
      _cnt += 1
      if _cnt > 10:
        print>>sys.stderr, 'PASS:', 1+pass_id, '/', passes, "{:.2f}%".format(100*lnum/float(linescount)), '   \r',
        _cnt = 0
      for rnum in rows:
         if visited[lnum][rnum]:
           continue
         visited[lnum][rnum] = True
         while True:
           avg = get_rect_avg(img, int(spot_in_img*rnum+spot_in_img),
                              int(spot_in_img*lnum+spot_in_img),
                              int(spot_in_img), meta)
           _x, _y = lnum*spot_in_img/dpm, rnum*spot_in_img/dpm
           if avg < 150:
             if pen_is_up:
               pr('G01 X{} Y{} Z{} F{}'.format(_x, _y, travelZ, travel_speed))
               pen_is_up = False
               if focus_speed > 0:
                 pr('G01 X{} Y{} Z{} F{}'.format(_x, _y, focusedZ, focus_speed))
               pr('G05 L1')
             
             pr('G01 X{} Y{} Z{} F{}'.format(_x, _y, focusedZ, _speed))
             print>>sys.stderr, rnum, lnum
             rnum, lnum = choose_neighbor(img, int(spot_in_img*rnum+spot_in_img),
                              int(spot_in_img*lnum+spot_in_img),
                              meta, visited, spot_in_img)
             print>>sys.stderr, rnum, lnum
               #l_x, l_y = (_x, _y)
           else:
             if not pen_is_up:
               pr('G01 X{} Y{} Z{} F{}'.format(_x, _y, focusedZ, _speed))
               if focus_speed > 0:
                 pr('G01 X{} Y{} Z{} F{}'.format(_x, _y, travelZ, focus_speed))
               pr('G05 L0')
               pen_is_up = True
             break

    travelZ -= 0.05
    focusedZ -= 0.05
  # footer
  pr('G01 Z{} F9000'.format(endZ))

if __name__ == "__main__":
  main()
