import argparse
import os.path
from pygcode import *


def append_code_from_file(filename, output_gcode, last_file):
    output_gcode.append(Line("; start of file " + filename))
    with open(filename, 'r') as fh:
        for line_text in fh.readlines():
            line = Line(line_text)
            for code in line.block.gcodes:
                if code == GCodeEndProgram():
                    # Hopefully only M02 can break continuity
                    # also hope that there is only M02 on the last line
                    output_gcode.append(Line("; end of file " + filename))
                    return
            output_gcode.append(line)
    output_gcode.append(Line("; end of file " + filename))


def append_rotation(output_gcode, angle, speed):
    output_gcode.append(Line("; rotate to " + str(angle)))
    output_gcode.append(Line(str(GCodeLinearMove(A=angle)) + " " + str(GCodeFeedRate(speed))))


def append_move_xy(output_gcode, x, y, speed):
    output_gcode.append(Line("; move to x: " + str(x) + " y: " + str(y)))
    output_gcode.append(Line(str(GCodeLinearMove(X=x, Y=y)) + " " + str(GCodeFeedRate(speed))))


def append_move_z(output_gcode, z, speed):
    output_gcode.append(Line("; move to z: " + str(z)))
    output_gcode.append(Line(str(GCodeLinearMove(Z=z)) + " " + str(GCodeFeedRate(speed))))


parser = argparse.ArgumentParser(
    description='Simple G-code converter utility for conversion of two input files into one double-sided')


def files(s):
    try:
        filename, angle = s.split(':')
        angle = int(angle)
        if not os.path.isfile(filename):
            raise ValueError("Path to file is not correct: " + filename)
        return filename, angle
    except:
        raise argparse.ArgumentTypeError("G-code file list must be filename:angle")


def coordinates(s):
    try:
        x, y, z = map(int, s.split(':'))
        return x, y, z
    except:
        raise argparse.ArgumentTypeError("Safe position must be x:y:z")


# hack how not to show required arguments in optional where are all non-positional by default
required_arguments = parser.add_argument_group('required arguments')
required_arguments.add_argument('--files_input', help="G-code files with angles of rotation in deg filename:angle",
                                dest="files_input", type=files, nargs='+', required=True)
required_arguments.add_argument('--file_output', help="Output G-code", dest="file_output", required=True)
required_arguments.add_argument('--safe_position', help="Position (X,Y,Z) where we can safely rotate A axis",
                                dest="safe_position", type=coordinates, required=True)
required_arguments.add_argument('--speed_xy', help="Speed of X and Y axis for movement into safe position",
                                dest="speed_xy", type=int, required=True)
required_arguments.add_argument('--speed_z', help="Speed of Z axis for movement into safe position", dest="speed_z",
                                type=int, required=True)
required_arguments.add_argument('--speed_a', help="Speed of A axis in deg/min", dest="speed_a", type=int, required=True)

argres = parser.parse_args()
safe_x, safe_y, safe_z = argres.safe_position
speed_xy = argres.speed_xy
speed_z = argres.speed_z
speed_a = argres.speed_a

output_gcode = []

output_gcode.append(Line("; this code was generated by A-axis G-code generator available at: https://github.com/joelmatejka/a-axis-g-code-generator"))
output_gcode.append(Line("; arguments passed to the script are following: " + str(argres)))

for (filename, angle) in argres.files_input:
    append_move_z(output_gcode, safe_z, speed_z)
    append_move_xy(output_gcode, safe_x, safe_y, speed_xy)
    append_rotation(output_gcode, angle, speed_a)
    append_code_from_file(filename, output_gcode, False)

# TODO: shall we move at the and to zero A position?
# append_rotation(output_gcode, 0, speed_a)

output_gcode.append(GCodeEndProgram())

# print('\n'.join(str(line) for line in output_gcode))

with open(argres.file_output, 'w') as fh:
    for line in output_gcode:
        fh.write(str(line) + '\n')

import argparse
import os.path
from pygcode import *


def append_code_from_file(filename, output_gcode, last_file):
    output_gcode.append(Line("; start of file " + filename))
    with open(filename, 'r') as fh:
        for line_text in fh.readlines():
            line = Line(line_text)
            for code in line.block.gcodes:
                if code == GCodeEndProgram():
                    # Hopefully only M02 can break continuity
                    # also hope that there is only M02 on the last line
                    output_gcode.append(Line("; end of file " + filename))
                    return
            output_gcode.append(line)
    output_gcode.append(Line("; end of file " + filename))


def append_rotation(output_gcode, angle, speed):
    output_gcode.append(Line("; rotate to " + str(angle)))
    output_gcode.append(Line(str(GCodeLinearMove(A=angle)) + " " + str(GCodeFeedRate(speed))))


def append_move_xy(output_gcode, x, y, speed):
    output_gcode.append(Line("; move to x: " + str(x) + " y: " + str(y)))
    output_gcode.append(Line(str(GCodeLinearMove(X=x, Y=y)) + " " + str(GCodeFeedRate(speed))))


def append_move_z(output_gcode, z, speed):
    output_gcode.append(Line("; move to z: " + str(z)))
    output_gcode.append(Line(str(GCodeLinearMove(Z=z)) + " " + str(GCodeFeedRate(speed))))


parser = argparse.ArgumentParser(
    description='Simple G-code converter utility for conversion of two input files into one double-sided')


def files(s):
    try:
        filename, angle = s.split(':')
        angle = int(angle)
        if not os.path.isfile(filename):
            raise ValueError("Path to file is not correct: " + filename)
        return filename, angle
    except:
        raise argparse.ArgumentTypeError("G-code file list must be filename:angle")


def coordinates(s):
    try:
        x, y, z = map(int, s.split(':'))
        return x, y, z
    except:
        raise argparse.ArgumentTypeError("Safe position must be x:y:z")


# hack how not to show required arguments in optional where are all non-positional by default
required_arguments = parser.add_argument_group('required arguments')
required_arguments.add_argument('--files_input', help="G-code files with angles of rotation in deg filename:angle",
                                dest="files_input", type=files, nargs='+', required=True)
required_arguments.add_argument('--file_output', help="Output G-code", dest="file_output", required=True)
required_arguments.add_argument('--safe_position', help="Position (X,Y,Z) where we can safely rotate A axis",
                                dest="safe_position", type=coordinates, required=True)
required_arguments.add_argument('--speed_xy', help="Speed of X and Y axis for movement into safe position",
                                dest="speed_xy", type=int, required=True)
required_arguments.add_argument('--speed_z', help="Speed of Z axis for movement into safe position", dest="speed_z",
                                type=int, required=True)
required_arguments.add_argument('--speed_a', help="Speed of A axis in deg/min", dest="speed_a", type=int, required=True)

argres = parser.parse_args()
safe_x, safe_y, safe_z = argres.safe_position
speed_xy = argres.speed_xy
speed_z = argres.speed_z
speed_a = argres.speed_a

output_gcode = []

output_gcode.append(Line("; this code was generated by A-axis G-code generator available at: https://github.com/joelmatejka/a-axis-g-code-generator"))
output_gcode.append(Line("; arguments passed to the script are following: " + str(argres)))

for (filename, angle) in argres.files_input:
    append_move_z(output_gcode, safe_z, speed_z)
    append_move_xy(output_gcode, safe_x, safe_y, speed_xy)
    append_rotation(output_gcode, angle, speed_a)
    append_code_from_file(filename, output_gcode, False)

# TODO: shall we move at the and to zero A position?
# append_rotation(output_gcode, 0, speed_a)

output_gcode.append(GCodeEndProgram())

# print('\n'.join(str(line) for line in output_gcode))

with open(argres.file_output, 'w') as fh:
    for line in output_gcode:
        fh.write(str(line) + '\n')

# Hopefully only M02 can break continuity # also hope that there is only M02 on the last line # hack how not to show required arguments in optional where are all non-positional by default # TODO: shall we move at the and to zero A position? # append_rotation(output_gcode, 0, speed_a) # print('\n'.join(str(line) for line in output_gcode))