import mecode

class BaseValue:
    def __init__(self, name, typical, min = None, max = None, long_name = None, descr = None):
        self.name = name
        self.typical = typical
        self.min = min
        self.max = max
        self.long_name = long_name
        self.descr = descr
class BaseCmd:
    def __init__(self, name, validator=None, **values):
        self.name = name
        if validator is None:
            validator = lambda g, **kwparams: True
        self.validator = validator
        self.values = values
class PrinterValue(BaseValue):
    def __init__(self, char, name, short, typical, min = None, max = None):
        super().__init__(name = char, typical = typical, min = min, max = max, long_name = short, descr = name)
class PrinterFlag:
    pass
class PrinterCmd(BaseCmd):
    def __init__(self, name, cmd, doc=None, validator=None, **values):
        super().__init__(name, validator=validator, **values)
        self.cmd = cmd
        self.doc = doc
    def __call__(self, g):
        output = self.cmd
        kwparams = {
            char: value.typical if isinstance(value, BaseValue) else True
            for char, value in self.values.items()
        }
        assert(self.validator(g, **kwparams))
        for char, typical in kwparams.items():
            output += ' ' + char
            if typical is not True:
                output += str(typical)
        if self.doc is not None:
            output += ' ; ' + self.doc.replace('\n', '; ')
        g.write(output)
class MecodeValue(BaseValue):
    pass
class MecodeCmd(BaseCmd):
    def __call__(self, g):
        kwparams = {
            name: value.typical
            for name, value in self.values.items()
        }
        assert(self.validator(g, **kwparams))
        return getattr(g, self.name)(**kwparams)

# adds "*_cmds[]" of PrinterCmd to globals based on some copypasted text
import _parser
exec(_parser.immed_cmds_code(), globals(), locals())
exec(_parser.delay_cmds_code(), globals(), locals())
exec(_parser.wait_cmds_code(), globals(), locals())

def sufficient_temperature_for_feed(gcode, min_temp=200):
    temps = gcode._p.current_temperature()
    if temps['T'] < min_temp:
        if temps['T/'] < min_temp:
            return False
        while gcode._p.current_temperature()['T'] < min_temp:
            print('waiting for temperature')
            sleep(0.5)
    return True
    
immed_cmds.extend([
    MecodeCmd('feed',
        rate=MecodeValue(
            'rate', typical=5.0, min=0.0,
            descr='The speed to move the tool head (feed) in mm/s.'
        ),
        validator=lambda gcode, rate: rate == 0 or sufficient_temperature_for_feed(g)
    )
])

with mecode.G(
        direct_write=True,
        direct_write_mode='serial',
        printer_port='/dev/ttyUSB0',
        baudrate=115200,
        two_way_comm=True,
        setup=True,
) as g:
    g.break_and_continue()
    #print(g._p.current_position())
    #print(g._p.current_temperature())
    #print(g.write('M105', resp_needed=True))
    #g.break_and_continue()
    g.auto_home()
    #g.finish_moves()
    for cmd in delay_cmds:
        cmd(g)
    for cmd in immed_cmds:
        cmd(g)
    g.finish_moves()
    #g.move(10, 10)
    #g.finish_moves()
    #g.arc(x=10, y=5, radius=20, direction='CCW')
    #g.finish_moves()
    g.meander(5, 10, spacing=1)
    g.finish_moves()
    #g.abs_move(x=1, y=1)
    #g.finish_moves()
    #g.home()
    #g.finish_moves()
