# 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

LOGGER = logging.getLogger(__name__)
MOVEMENT_FEEDRATE = 2000
EXTRUDER_FEEDRATE = 60
RESPONSE_MAX_LENGTH = 20000
RESPONSE = ''


def process_printer_response(response):
    if response:
        response += '\n'
    global RESPONSE
    RESPONSE += response
    if len(RESPONSE) > RESPONSE_MAX_LENGTH:
        RESPONSE = RESPONSE[len(response):]

def clear_response():
    global RESPONSE
    RESPONSE = ''

def init_callback(printer_interface):
    with printer_interface.printer.recv_callback_lock:
        printer_interface.printer.recv_callback = process_printer_response

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.state_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 refactor me and 4ucking 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 RESPONSE:
        printers_info['log'] = RESPONSE
        clear_response()
    return printers_info

def get_commands(printer_interface):
    try:
        sender = printer_interface.printer_profile['sender']
    except AttributeError as e:
        LOGGER.error('Unable to operate printer %s: %s' % (printer_interface.printer_name, str(e)))
    else:
        if sender == 'makerbot_sender':
            return {'move': 'G92 X0 Y0 Z0\nG1 %s',
                    'extrude': 'G92 A0\nG1 A%s',
                    'enable_fan': 'M106 S255',
                    'disable_fan': 'M107',
                    'set_extruder_temp': 'M104 S%s T0',
                    'set_bed_temp': 'M109 S%s T0',
                    'home_x': 'G162 X',
                    'home_y': 'G162 Y',
                    'home_z': 'G161 Z',
                    'home': 'G162 X Y F2000\nG161 Z F900'}
        else:
            return {'move': 'G91\nG0 %s',
                    'extrude': 'M83\nG91\nT0\nG1 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 send_gcode(printer_interface, str_gcode):
    LOGGER.debug('Sending gcodes "' + str_gcode + '" to ' + printer_interface.printer_name + '...')
    try:
        printer_interface.printer.unbuffered_gcodes(str_gcode)
    except AttributeError:
        process_printer_response('Unable to send gcode "%s". Please restart joystick from main page.' % str_gcode)
    except Exception as e:
        LOGGER.debug('...failed!\n' + str(e))
        process_printer_response(str(e))
    else:
        LOGGER.debug('...sent')

def execute_command(printer_interface, command, value=None):
    LOGGER.info('Executing command for %s: %s %s' % (printer_interface.printer_name, command, value))
    commands = get_commands(printer_interface)
    if command in list(commands.keys()):
        if value or value == 0:
            if command == 'move':
                value += ' F' + str(MOVEMENT_FEEDRATE)
            return send_gcode(printer_interface, get_commands(printer_interface)[command] % (value))
        else:
            return send_gcode(printer_interface, get_commands(printer_interface)[command])