#! /usr/bin/python

'''
plasmac_gcode_arcs.py

Copyright (C) 2019  Phillip A Carter

This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc
51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
'''

import os
import sys
import linuxcnc
import math
 
ini = linuxcnc.ini(os.environ['INI_FILE_NAME'])
infile = sys.argv[1]
materialFile = ini.find('EMC', 'MACHINE').lower() + '_material.cfg'
arcsEnable = int(ini.find('PLASMAC', 'ARCS_ENABLE') or 0)
arcsAll = int(ini.find('PLASMAC', 'ARCS_ALL') or 0)
radius1 = int(ini.find('PLASMAC', 'ARC_RADIUS_1') or 0)
radius2 = int(ini.find('PLASMAC', 'ARC_RADIUS_2') or 0)
radius3 = int(ini.find('PLASMAC', 'ARC_RADIUS_3') or 0)
radius4 = int(ini.find('PLASMAC', 'ARC_RADIUS_4') or 0)
radius5 = int(ini.find('PLASMAC', 'ARC_RADIUS_5') or 0)
reduce1 = int(ini.find('PLASMAC', 'ARC_VELOCITY_1') or 100)
reduce2 = int(ini.find('PLASMAC', 'ARC_VELOCITY_2') or 100)
reduce3 = int(ini.find('PLASMAC', 'ARC_VELOCITY_3') or 100)
reduce4 = int(ini.find('PLASMAC', 'ARC_VELOCITY_4') or 100)
reduce5 = int(ini.find('PLASMAC', 'ARC_VELOCITY_5') or 100)
materialsExist = True
lastLineArc = False
lastX = 0
lastY = 0
reduction = 0
 
# get arc radius and set velocity percentage
def get_arc_radius(lastX, lastY, endX, endY, setI, setJ):
    global reduction
    global lastLineArc
    if 'r' in line:
        radius = float(line.split('r')[1])
    else:
        radius = math.sqrt(((endX - (lastX + setI)) ** 2) + ((endY - (lastY + setJ)) ** 2))
    if radius < radius1:
        if reduction != reduce1:
            arc_setup(reduce1, radius)
    elif radius < radius2:
        if reduction != reduce2:
            arc_setup(reduce2, radius)
    elif radius < radius3:
        if reduction != reduce3:
            arc_setup(reduce3, radius)
    elif radius < radius4:
        if reduction != reduce4:
            arc_setup(reduce4, radius)
    elif radius < radius5:
        if reduction != reduce5:
            arc_setup(reduce5, radius)
    else: # no reduction required
        if lastLineArc:
            print('m67e3q0 (Arc Complete, Velocity 100%)')
        lastLineArc = False
        reduction = 0

# output the velocity percentage
def arc_setup(velocity, radius):
    global lastLineArc
    print('m67e3q{0} (Radius: {1:0.3f}, Velocity: {0}%)'.format(velocity, radius))
    lastLineArc = True
    reduction = velocity

# get a position
def get_position(axis):
    tmp1 = line.split(axis)[1]
    if not tmp1[0].isdigit() and not tmp1[0] == '-':
        tmp1 = tmp1[1:]
    tmp2 = ''
    while tmp1[0].isdigit() or tmp1[0] == '.' or tmp1[0] == '-':
        tmp2 += tmp1[0]
        tmp1 = tmp1[1:]
    return float(tmp2)

# get the last X and Y positions
def get_last_position(Xpos, Ypos):
    if line.startswith('g') or \
       line.startswith('x') or \
       line.startswith('y'):
        if 'x' in line:
            Xpos = get_position('x')
        if 'y' in line:
            Ypos = get_position('y')
    return Xpos, Ypos

# comment out all Z commands
def comment_z_commands():
    global lastLineArc
    newline = ''
    newz = ''
    removing = 0
    comment = 0
    for bit in line:
        if comment:
            if bit == ')':
                comment = 0
            newline += bit
        elif removing:
            if bit in '0123456789.- ':
                newz += bit
            else:
                removing = 0
                if newz:
                    newz = newz.rstrip() + ')'
                newline += bit
        elif bit == '(':
            comment = 1
            newline += bit
        elif bit == 'z':
            removing = 1
            newz += '(' + bit
        else:
            newline += bit
    if arcsEnable and lastLineArc:
        print 'm67e3q0 (Arc Complete, Velocity 100%)'
        lastLineArc = False
        reduction = 0
    print('{} {}'.format(newline.rstrip(), newz))

# get a list of known materials
with open(materialFile, 'r') as f_in:
    materialList = [0]
    for line in f_in:
        if not line.startswith('#'):
            if line.startswith('[MATERIAL_NUMBER_') and line.strip().endswith(']'):
                a,b,c = line.split('_')
                t_number = int(c.replace(']',''))
                materialList.append(t_number)
f = open(infile, 'r')
 
# check for valid material number
for line in f:
    if 'm190' in line.lower():
        first, last = line.lower().strip().split('p',1)
        material = ''
        # get the material number
        for mNumber in last.strip():
            if mNumber in '0123456789':
                material += mNumber
            else:
             break
        # if invalid material number
        if int(material) not in materialList:
            if materialsExist:
                print(';The following materials are missing from:\n;{}'.format(materialFile))
            materialsExist = False
            print(';Material #{}'.format(material))

# process every line
if materialsExist:
    f = open(infile, 'r')
    for line in f:
        # convert to lower case and remove spaces
        line = line.strip(' ').lower().replace(' ','')
        # remove line numbers
        if line.startswith('n'):
            line = line.split('n',1)[-1]
            while line[0].isdigit() or line[0] == '.':
                line = line[1:]
        # remove leading 0's from G & M codes
        if line.startswith('g') or line.startswith('m'):
            while line[1] == '0':
                if line[2].isdigit():
                    line = line[:1] + line[2:]
                else:
                    break
        # test for an arc
        if (line.startswith('g2') or line.startswith('g3')) and line[2].isalpha():
            if arcsEnable:
                endX = lastX
                endY = lastY
                setI = setJ = 0
                if 'x' in line: endX = get_position('x')
                if 'y' in line: endY = get_position('y')
                if 'i' in line: setI = get_position('i')
                if 'j' in line: setJ = get_position('j')
                if arcsAll or (lastX == endX and lastY == endY):
                    get_arc_radius(lastX, lastY, endX, endY, setI, setJ)
                lastX, lastY = get_last_position(lastX, lastY)
            print(line.rstrip())
        # if a commented line then print it
        elif line.startswith(';') or line.startswith('('):
            print line.rstrip()
        # if no Z in line then print it
        elif not 'z' in line:
            if arcsEnable:
                lastX, lastY = get_last_position(lastX, lastY)
                if lastLineArc:
                    print('m67e3q0 (Arc Complete)')
                    lastLineArc = False
                    reduction = 0
                if line.startswith('m2') or line.startswith('m30') or line.startswith('%'):
                    print('m68e3q0')
            lastX, lastY = get_last_position(lastX, lastY)
            print(line.rstrip())
        # if no other axes in line then print it
        elif 1 not in [c in line for c in 'xyabcuvw']:
            print(line.rstrip())
        # mixed axes in line
        else:
            if arcsEnable:
                lastX, lastY = get_last_position(lastX, lastY)
            comment_z_commands()
else:
    if arcsEnable:
        print('m68e3q0\n')
    print('M2')
