# Copyright 3D Control Systems, Inc. All Rights Reserved 2017-2019.
# Built in San Francisco.

# This software is distributed under a commercial license for personal,
# educational, corporate or any other use.
# The software as a whole or any parts of it is prohibited for distribution or
# use without obtaining a license from 3D Control Systems, Inc.

# All software licenses are subject to the 3DPrinterOS terms of use
# (available at https://www.3dprinteros.com/terms-and-conditions/),
# and privacy policy (available at https://www.3dprinteros.com/privacy-policy/)

import logging
import time


MOVEMENT_FEEDRATE = 600
EXTRUDER_FEEDRATE = 60
MAX_ATTEMPTS = 3


unread_responses = ''


COMMANDS = {'enter_joystick': 'G91 M83',
            'exit_joystick': 'G90\nM82',
            'move': 'G1 %s',
            'extrude': 'G1 E%s',
            'enable_fan': 'M106 S255',
            'disable_fan': 'M107',
            'set_extruder_temp': 'M104 S%s T0',
            'set_bed_temp': 'M140 S%s',
            'home_x': 'G28 X',
            'home_y': 'G28 Y',
            'home_z': 'G28 Z',
            'home': 'G28'}


def process_printer_response(response, _=None):
    if response:
        if isinstance(response, bytes):
            response = response.decode('utf-8')
        if not response.endswith('\n'):
            response += '\n'
        global unread_responses
        unread_responses += response # a hacky way to fight a multiline gcodes ok when using joystick
        #TODO separate joystick from console and only add callbacks on console commands


def clear_response():
    global unread_responses
    unread_responses = ''


def init_callback(printer_interface, attempt=0):
    try:
        printer_interface.sender.add_response_callback(process_printer_response)
    except AttributeError:
        time.sleep(1)
        if attempt < MAX_ATTEMPTS:
            attempt += 1
            init_callback(printer_interface, attempt)


def get_printers_info(printer_interface):
    printers_info = {'coordinate': {'x': 0.0, 'y': 0.0, 'z': 0.0},
                     'extruder': {'amount': 1, 'temp': None, 'target_temp': None},
                     'bed': {'temp': None, 'target_temp': None},
                     'log': ''}
    if printer_interface:
        printer_report = printer_interface.status_report()
        temps = printer_report.get('temps')
        target_temps = printer_report.get('target_temps')
        if temps and target_temps:
            printers_info['temps'] = temps
            printers_info['target_temps'] = target_temps
            #TODO this code and the page's js
            printers_info['bed']['temp'] = temps[0]
            printers_info['extruder']['temp'] = temps[1]
            printers_info['bed']['target_temp'] = target_temps[0]
            printers_info['extruder']['target_temp'] = target_temps[1]
    else:
        process_printer_response('Printer not found. Probably it was disconnected.')
    if unread_responses:
        printers_info['log'] = unread_responses
        clear_response()
    return printers_info


def send_gcode(printer_interface, str_gcode):
    if isinstance(str_gcode, (bytes, str)):
        str_gcode = str_gcode.upper()
    try:
        logging.getLogger(__name__).debug('Sending gcodes "' + str_gcode + '" to ' + printer_interface.printer_name + '...')
        printer_interface.sender.unbuffered_gcodes(str_gcode)
    except (AttributeError, TypeError):
        process_printer_response('Unable to send gcode "%s". Please restart joystick from main page.' % str_gcode)
    except Exception as e:
        logging.getLogger(__name__).debug('...failed!\n' + str(e))
        process_printer_response(str(e))
    else:
        logging.getLogger(__name__).debug('...sent')


def execute_command(printer_interface, command, value=None):
    if command in COMMANDS:
        logging.getLogger(__name__).info('Executing command for %s: %s %s' % (getattr(printer_interface, 'printer_name', "Unknown"), command, value))
        command_text = COMMANDS[command]
        if "%" in command_text:
            command_text = command_text % value
            if command == 'move':
                command_text += ' F' + str(MOVEMENT_FEEDRATE)
        return send_gcode(printer_interface, command_text)
