#!/usr/local/bin/python
# -*- coding: utf-8 -*-
"""
Created on Sep 17, 2020

@author: Carima
"""
from serial_rw import serial_rw
import logging
from showslice import showslice
from configparser import ConfigParser
import os
from time import sleep
import cv2


class printThread_info(object):
    """
    classdocs
    """
    # deprecate
    Motor_STOP, Motor_UP, Motor_DOWN, Motor_Home = range(0, 4)
    Z_STOP, Z_UP, Z_DOWN, Z_HOME = range(0, 4)

    def readConfig(self, configPath='system.cfg'):
        # print configPath
        config = ConfigParser()
        config.read(configPath)
        self.ZeroPoint = float(config.get('SETUP', 'ZeroPoint'))
        try:
            self.blade_type = int(config.get('SETUP', 'Blade_type'))
            print("read Blade_type:", self.blade_type)
        except:
            print("fail Blade_type")
            self.blade_type = 1
        # try:
        #     self.ZMotorSpeed = float(config.get('MOTOR_SETUP', 'MotorSpeed'))
        #     self.LowSpeedAmount = float(config.get('MOTOR_SETUP', 'MotorAmount'))
        # except :
        #     return 1
        try:
            self.tiltSpeed_1 = float(config.get('MOTOR_SETUP', 'tiltSpeed_1'))
            self.tiltSpeed_2 = float(config.get('MOTOR_SETUP', 'tiltSpeed_2'))
            self.tiltDistance_1 = float(config.get('MOTOR_SETUP', 'tiltDistance_1'))
            self.tiltDistance_2 = float(config.get('MOTOR_SETUP', 'tiltDistance_2'))
            self.before_Tilt = int(config.get('MOTOR_SETUP', 'before_Tilt'))
        except :
            return 1

    def resinConfig(self, configPath, model):
        # print configPath
        resinconfig = ConfigParser()
        resinconfig.read(configPath)
        models = str(model).split()
        n = len(models)
        if n >= 1:
            model = self.fixModelname(n, models)

        print(model)
            # model = models[0] + '%20' + models[1]
        self.LightStep_Beginning = int(resinconfig.get(model, 'Initial_Exposure_Layers'))
        self.LightTime_Basic = float(resinconfig.get(model, 'Basic_Exposure_Time'))
        self.LightTime_Beginning = float(resinconfig.get(model, 'Initial_Exposure_Time'))
        self.basicWaitTime = float(resinconfig.get(model, 'Basic_Layer_Waiting_Time'))
        self.beginWaitTime = float(resinconfig.get(model, 'Initial_Layer_Waiting_Time'))
        try:
            self.ZMotorSpeed = float(resinconfig.get(model, 'Movement_Speed'))
            self.LowSpeedAmount = float(resinconfig.get(model, 'Movement_Distance'))
            self.InitialMotorDistance = float(resinconfig.get(model, 'Initial_Movement_Distance'))
            self.InitialMotorSpeed = float(resinconfig.get(model, 'Initial_Movement_Speed'))
        except:
            return 1
        try:
            self.tiltSpeed_1 = float(resinconfig.get('MOTOR_SETUP', 'tiltSpeed_1'))
            self.tiltSpeed_2 = float(resinconfig.get('MOTOR_SETUP', 'tiltSpeed_2'))
            self.tiltDistance_1 = float(resinconfig.get('MOTOR_SETUP', 'tiltDistance_1'))
            self.tiltDistance_2 = float(resinconfig.get('MOTOR_SETUP', 'tiltDistance_2'))
            self.before_Tilt = int(resinconfig.get('MOTOR_SETUP', 'before_Tilt'))
        except :
            return 1
        # self.ZMotorAmount = 3
        # self.ZMotorEndUpDistance = int(resinconfig.get(model, 'ZMotorEndUpDistance'))

    def fixModelname(self, n, models):
        m = 1
        model = models[0]
        while m < n:
            model1 = '%20' + models[m - n]
            model = model + model1
            m += 1
        model = model.replace("*", "%2A")
        return model

    def __init__(self, ImageRoot='./images', FileType='png'):
        """
        Constructor
        """
        self.configPath = os.environ.get('HOME', '/home/dp110') + '/carima/system.cfg'
        self.resinconfigPath = os.environ.get('HOME', '/home/dp110') + '/carima/resin.cfg'
        # self.configPath = os.environ.get('HOME','/home/dp110')+'/carima/build-3DPrinter-Desktop-Release/system.cfg'
        # self.resinconfigPath = os.environ.get('HOME','/home/dp110')+'/carima/build-3DPrinter-Desktop-Release/resin.cfg'
        # self.writeConfig(self.configPath)
        self.readConfig(self.configPath)
        # model = 'Model'
        # self.resinConfig(self.resinconfigPath, 'Model')
        # sleep(5)
        self.display = showslice(ImageRoot, 'png')
        self.logger = logging.getLogger('dp110server')
        self.overTry = 0
        self.motorPostion = 0
        self.zeromotorPostion = 0

    def printConnect(self):
        """
        serial = USBSerial(portEngine)
        serial.timeout = 0.1
        serial.writeTimeout = 0.1
        serial.write('\r')
        r = serial.read(1)
        if r=='' or not r in 'PF':
            eport = portPcb
            bport = portEngine
            self.logger.error('port number changed!')
        else:
            eport = portEngine
            bport = portPcb
        """

        if self.Aboard.openSerialPort() == -1:
            self.logger.debug('PCB, Engine connect failed')
            return False

        #         self.board.ser.timeout = 0.2
        #         self.board.ser.writeTimeout = 0.2
        self.Aboard.ser.timeout = None
        self.Aboard.ser.writeTimeout = None
        """
        self.engine.ser.write('\r')
        ret=self.engine.ser.readline()
        if ret=='' or ret[0] not in 'PFI':
            self.logger.debug('engine check failed')
            return False
        """

        """
        v_board = self.board.read_version(200)
        if len(v_board) <> 3:
            self.logger.debug('PCB read_version failed')
            return False
        if v_board[0] < '\x21' and v_board[1] < '\x15':
            self.logger.debug('PCB version mismatch: %X.%X' % (v_board[0], v_board[1]))
            return False
         """

        # e = self.board.z_ledOn_fanOn(200)
        # self.board.UpTray(20, 3000)
        # self.logger.debug('PCB_PAN ON: %s' % e)
        return True

    def testPorts(self):
        self.Aboard = serial_rw(1)
        return 1

    def openPorts(self, port):
        self.motorPostion = 0
        self.zeromotorPostion = 0
        self.Aboard = serial_rw(port)  # 0 to 1 for blade
        return 1

    def SerialTest(self):
        return self.Aboard.SerialTest(1000)

    def printConnect1(self):
        # self.board.ser.timeout = 400
        # self.board.ser.writeTimeout = 400
        self.Aboard.ser.timeout = None
        self.Aboard.ser.writeTimeout = None
        return True

    def printConnect2(self):
        # self.board.ser.timeout = 0.3
        # self.board.ser.writeTimeout = 0.3
        self.Aboard.ser.timeout = 0.5
        self.Aboard.ser.writeTimeout = 0.5
        return True

    def rePrintConnet(self, port):
        self.motorPostion = 0
        self.zeromotorPostion = 0
        try:
            self.Aboard = serial_rw(port)  # ori 0 to 1, blade is 1
            print("reConnect 0")
            return True
        except:
            # self.Aboard = serial_rw(port + 1)  # ori 1, blade is 2
            self.Aboard = serial_rw(1)  # ori 1, blade is 2
            print("reConnect 1")
            return True

    def removeImageFile(self):
        os.system("sudo rm -r /home/pi/carima/buffer/image")
        return True

    def boardGo(self, value, check):
        # print("boardGo: ", value)
        return self.Aboard.z_AbsoluteMove(value, 30000, check)

    def boardGo_DM250K(self, value, check):
        return self.Aboard.z_AbsoluteMove_DM250K(value, 30000, check)

    # add for dm250k tilt
    def boardup_Tilt(self, value, check):
        return self.Aboard.z_AbsoluteMove_up_tilt(value, 30000, check)

    def boarddown_Tilt(self, value, check):
        return self.Aboard.z_AbsoluteMove_down_tilt(value, 30000, check)

    # def boardGo2(self, value, check):
    #     return self.Aboard.z_AbsoluteMove_DP2(value, 30000, check)

    def checkTmpSensor(self):
        # sleep(2)
        try:
            self.Aboard.checkTmpSensor(3000)
            temp1 = float(self.Aboard.checkTmpSensor(3000))
        except:
            return -100
        return temp1

    def ShutdownBuzzer(self):
        return self.Aboard.ShutdownBuzzer(1000)

    def EndPrintBuzzer(self):
        return self.Aboard.EndPrintBuzzer(1000)

    def readRFIDvalue(self):
        SerialNumber = self.Aboard.readRFIDvalue(3000)
        return SerialNumber

    def boardHome(self):
        return self.Aboard.z_home(5000)

    def boardHome_DM250K(self):
        return self.Aboard.z_home_DM250K(5000)

    # add for dm250k tilt
    def tiltHome_DM250K(self):
        return self.Aboard.tilt_home_DM250K(5000)

    def changeSpeed_Tilt(self, lightTime):
        speed_data = int((250000 / (lightTime / 0.0005625)))
        return self.Aboard.changeSpeedValue_tilt(speed_data, 1000)

    def MaxSpeed_Tilt(self):
        speed_data = int((6400 / 0.125) * 2.5)
        return self.Aboard.changeSpeedValue(speed_data, 1000)

    def New_changeTimer(self, motor_speed):
        # ch_motor_time = motor_speed / 0.00015625
        # ch_motor_time = (motor_speed / 0.00015625) - (60*((2-motor_speed)*10))
        motor_time = 1 / motor_speed
        ch_motor_time = int((6400 / motor_time) * 2.5)
        return self.Aboard.changeSpeedValue(ch_motor_time, 1000)

    def MaxSpeed(self):
        speed_data = int((6400 / 0.125) * 2.5)
        return self.Aboard.changeSpeedValue(speed_data, 1000)

    def New_changeTimer_DM250K(self, motor_speed):
        # motor_time = 1 / motor_speed
        # ch_motor_time = int((6400 / motor_time) * 2)
        # return self.Aboard.changeSpeedValue_DM250K(ch_motor_time, 1000)

        # ((모터속도/3600)/0.000078125)-(((모터속도*7)/120)-1)
        speed_data = (motor_speed / 0.000078125) - (((motor_speed * 7) / 120) - 1)
        return self.Aboard.changeSpeedValue_DM250K(speed_data, 1000)

    def MaxSpeed_DM250K(self):
        speed_data = int((6400 / 0.125) * 2)
        return self.Aboard.changeSpeedValue_DM250K(speed_data, 1000)

    def changeTimer(self, light_time):
        one_motor_step = int(round((light_time / 0.00015625), 4))
        two_motor_step = int(one_motor_step + 2740)
        return self.Aboard.changeSpeedValue(two_motor_step, 1000)

    def set_first_motor_speed(self):     # orginalTimer(self)
        self.logger.debug('set_first_motor_speed 51200')
        self.Aboard.changeSpeedValue(int(51200), 1000)
        return 1

    def upboardStop(self):
        if self.motorPosition != 0:
            self.Aboard.upBoardStop(3000)
            return 1
        else:
            return 1

    def downboardStop(self):
        motor_position_stop = self.Aboard.motorPositions(1000)
        # if self.motorPosition < self.ZeroPoint:
        if motor_position_stop < self.ZeroPoint:
            self.Aboard.downBoardStop(3000)
            self.overTry = 0
            return 1
        else:
            return 1

    def motorUpDir(self):
        self.Aboard.motorUpDir(3000)
        return 1

    def motorPositions(self):
        return self.Aboard.motorPositions(3000)

    def motorPositions_DM250K(self):
        return self.Aboard.motorPositions_DM250K(3000)

    def zeroboardUp_DM250K(self, value, check):  # 모터 하향이동
        zero_value = self.zeromotorPostion + value
        self.zeromotorPostion = zero_value
        s = self.Aboard.z_AbsoluteMove_DM250K(zero_value, 30000, check)
        return s

    def zeroboardDown_DM250K(self, value, lthick, check):  # 모터 상향이동
        zero_value = self.zeromotorPostion - value
        if zero_value < 0:
            zero_value = 0
        self.zeromotorPostion = zero_value
        s = self.Aboard.z_AbsoluteMove_DM250K(zero_value, 30000, check)
        return s

    def zeroboardUp(self, value, check):
        s = self.Aboard.z_AbsoluteMove(value, 30000, check)
        return s

    def zeroboardDown(self, value, lthick, check):
        s = self.Aboard.z_AbsoluteMove(value, 30000, check)
        return s

    def boardUp(self, value, check):
        # print("boardUp: ", value)
        zero_value = self.zeromotorPostion - value
        if zero_value < 0:
            zero_value = 0
        self.zeromotorPostion = zero_value
        s = self.Aboard.z_AbsoluteMove(zero_value, 30000, check)
        return s

    def boardDown(self, value, check):
        # print("boardDown: ", value)
        zero_value = self.zeromotorPostion + value
        self.zeromotorPostion = zero_value
        if self.zeromotorPostion > self.ZeroPoint:
            s = self.Aboard.z_AbsoluteMove(self.ZeroPoint, 30000, check)
            self.zeromotorPostion = self.ZeroPoint
        else:
            s = self.Aboard.z_AbsoluteMove(zero_value, 30000, check)
        return s

    def boardUp_DM250K(self, value, check):
        run_value = self.motorPostion - value
        if run_value < 0:
            run_value = 0
        self.motorPostion = run_value
        self.overTry = 0
        s = self.Aboard.z_AbsoluteMove_DM250K(run_value, 30000, check)
        return s

    def boardDown_DM250K(self, value, lthick, check):
        sleep(0.1)
        run_value = self.motorPostion + value
        if run_value >= self.ZeroPoint and self.overTry == 0:
            s = self.Aboard.z_AbsoluteMove(self.ZeroPoint, 30000, check)
            self.motorPosition = self.ZeroPoint
            self.overTry = 1
            return s
        elif run_value > self.ZeroPoint and self.overTry == 1:
            self.motorPosition = self.ZeroPoint
            return True
        elif run_value < self.ZeroPoint and self.overTry == 0:
            self.motorPostion = run_value
            s = self.Aboard.z_AbsoluteMove_DM250K(run_value, 30000, check)
            return s

    def engineOn(self, is_on):
        return 1

    def image_display(self, now_layer):
        try:
            imagefile = os.environ.get('HOME', '/home/pi') + '/carima/buffer/image/SEC_0001.png'
            if os.path.isfile(imagefile):
                img_path = os.environ.get('HOME', '/home/pi') + '/carima/buffer/image/SEC_%04d.png' % now_layer
            else:
                img_path = os.environ.get('HOME', '/home/pi') + '/carima/buffer/image/SEC_%06d.png' % now_layer
            print(img_path)
            return self.display.showSliceImage(img_path, -1)
        except (IOError, ValueError) as e:
            # self.logger.debug('Image Load failed : %s (%s)' % (imgPath, e))
            print("image_display fail")
            return False

    def lightOn1(self, nowLayer, basicTime, beginningTime):
        try:
            imagefile = os.environ.get('HOME', '/home/pi') + '/carima/buffer/image/SEC_0001.png'
            if os.path.isfile(imagefile):
                imgPath = os.environ.get('HOME', '/home/pi') + '/carima/buffer/image/SEC_%04d.png' % nowLayer
            else:
                imgPath = os.environ.get('HOME', '/home/pi') + '/carima/buffer/image/SEC_%06d.png' % nowLayer
            # imgPath = os.environ.get('HOME','/home/pi') + '/carima/build-3DPrinter-Desktop-Release/buffer/image/SEC_%04d.png' % nowLayer
            # imgPath = os.environ.get('HOME','/home/pi') + '/carima/build-3DPrinter-Desktop_Qt_5_15_0_GCC_64bit-Debug/buffer/image/SEC_%04d.png' % nowLayer
            # self.logger.debug('Light Ready : %s' % imgPath)
            if nowLayer > self.LightStep_Beginning:
                # image_on_time = basicTime
                image_on_time = float(basicTime + 0.2)
            else:
                # image_on_time = beginningTime
                image_on_time = float(beginningTime + 0.2)
            # return self.display.FlipshowSliceImage(imgPath, image_on_time)
            return self.display.showSliceImage(imgPath, image_on_time)
        except (IOError, ValueError) as e:
            # self.logger.debug('Image Load failed : %s (%s)' % (imgPath, e))
            return False

    def lightOn4K(self, nowLayer, basicTime, beginningTime, slicer, totalLayer):
        """
        try:
            img_path = os.environ.get('HOME', '/home/pi') + '/carima/buffer/image/SEC_%04d.png' % nowLayer
            # self.logger.debug('Light Ready : %s' % imgPath)
            if nowLayer > self.LightStep_Beginning:
                # image_on_time = basicTime + 840
                image_on_time = basicTime
            else:
                # image_on_time = beginningTime + 840
                image_on_time = beginningTime
            return self.display.showSlice4KImage(img_path, image_on_time)
        except (IOError, ValueError) as e:
            # self.logger.debug('Image Load failed : %s (%s)' % (imgPath, e))
            return False
        """
        if slicer == 'MAGICS':
            try:
                imagefile = os.environ.get('HOME', '/home/pi') + '/carima/buffer/image/SEC_0001.png'
                if os.path.isfile(imagefile):
                    imgPath = os.environ.get('HOME', '/home/pi') + '/carima/buffer/image/SEC_%04d.png' % nowLayer
                else:
                    imgPath = os.environ.get('HOME', '/home/pi') + '/carima/buffer/image/SEC_%06d.png' % nowLayer
                # self.logger.debug('Light Ready : %s' % imgPath)
                # if nowLayer > self.LightStep_Beginning:
                #     lightOnTime = basicTime + 0.84
                # else:
                #     lightOnTime = beginningTime + 0.84
                # return self.display.showSlice4KImage(imgPath, lightOnTime)
            except (IOError, ValueError) as e:
                # self.logger.debug('Image Load failed : %s (%s)' % (imgPath, e))
                return False
        elif slicer == 'CARIMA':
            try:
                if totalLayer < 10000:
                    imgPath = os.environ.get('HOME', '/home/pi') + '/carima/buffer/image/SEC_%04d.png' % nowLayer
                elif totalLayer >= 10000:
                    imgPath = os.environ.get('HOME', '/home/pi') + '/carima/buffer/image/SEC_%05d.png' % nowLayer
                elif totalLayer >= 100000:
                    imgPath = os.environ.get('HOME', '/home/pi') + '/carima/buffer/image/SEC_%06d.png' % nowLayer
                # self.logger.debug('Light Ready : %s' % imgPath)
                # if nowLayer > self.LightStep_Beginning:
                #     lightOnTime = basicTime + 0.84
                # else:
                #     lightOnTime = beginningTime + 0.84
                # return self.display.showSlice4KImage(imgPath, lightOnTime)
            except (IOError, ValueError) as e:
                # self.logger.debug('Image Load failed : %s (%s)' % (imgPath, e))
                return False
            return self.display.showSlice4KImage(imgPath, -1)   # -1 : sleep will do at printThread_4k.py

    def lightOn4K_divide(self, nowLayer, basicTime, beginningTime):
        try:
            imagefile = os.environ.get('HOME', '/home/pi') + '/carima/buffer/image/SEC_0001.png'
            if os.path.isfile(imagefile):
                imgPath = os.environ.get('HOME', '/home/pi') + '/carima/buffer/image/SEC_%04d.png' % nowLayer
            else:
                imgPath = os.environ.get('HOME', '/home/pi') + '/carima/buffer/image/SEC_%06d.png' % nowLayer
            # self.logger.debug('Light Ready : %s' % imgPath)
            if nowLayer > self.LightStep_Beginning:
                image_on_time = basicTime
                divide_display = 3000
            else:
                image_on_time = beginningTime
                divide_display = 6000
            # ImgData = Image().open(imgPath)
            # self.logger.debug('Image Load succeed : %s' % imgPath)
            while image_on_time > divide_display:
                show_divide_display = divide_display + 0.84
                self.display.showSliceImage(imgPath, show_divide_display)
                image_on_time -= divide_display
                self.display.showSliceOffImage()
                cv2.waitKey(1000)
                if image_on_time <= divide_display:
                    self.display.showSliceImage(imgPath, image_on_time)
                    self.display.showSliceOffImage()
                    image_on_time = -0.84
                    return True
            self.display.showSliceImage(imgPath, image_on_time + 0.84)
            # self.engine.engine_LightOn()
            self.logger.debug('--Light On--')
            return True
        except (IOError, ValueError) as e:
            self.logger.debug('Image Load failed : %s (%s)' % (imgPath, e))
            return False

    def BasicImageOn(self):
        imgPath = os.environ.get('HOME', '/home/dp110') + '/carima/dp110server/images/BasicImg.png'
        try:
            return self.display.showSliceImage(imgPath, -1)
        except (IOError, ValueError) as e:
            self.logger.debug('Image Load failed : %s (%s)' % (imgPath, e))
            return False

    def BasicEditImageOn(self):
        imgPath = os.environ.get('HOME', '/home/dp110') + '/carima/basic/BasicImg_edit.png'
        try:
            return self.display.showSliceImage(imgPath, -1)
        except (IOError, ValueError) as e:
            self.logger.debug('Image Load failed : %s (%s)' % (imgPath, e))
            return False

    def BasicImageOn4K(self):
        imgPath = os.environ.get('HOME', '/home/dp110') + '/carima/dp110server/images/BasicImg3840.png'
        try:
            return self.display.showSliceImage(imgPath, -1)
        except (IOError, ValueError) as e:
            self.logger.debug('Image Load failed : %s (%s)' % (imgPath, e))
            return False

    def BasicImageOn1280(self):
        imgPath = os.environ.get('HOME', '/home/pi') + '/carima/dp110server/images/BasicImg1280.png'
        try:
            return self.display.showSliceImage(imgPath, -1)
        except (IOError, ValueError) as e:
            self.logger.debug('Image Load failed : %s (%s)' % (imgPath, e))
            return False

    def BasicImageOff(self):
        self.display.clear()
        return 1

    def printingEndsqeunce(self, nowLayer, basicTime, beginningTime):  # 프린팅 완료 후 종료 시퀀스
        self.lightOn1(nowLayer, basicTime, beginningTime)
        self.display.clear()
        self.removeImageFile()
        self.printConnect2()
        return 1

    def printingsqeunce(self, nowLayer, basicTime, beginningTime):  # 일반편광 프린팅 완료 후 종료 시퀀스
        self.lightOn1(nowLayer, basicTime, beginningTime)
        return 1

    def timeprintingEndsqeunce(self):  # 시간편광 프린팅 완료 후 종료 시퀀스
        self.display.clear()
        self.removeImageFile()
        self.printConnect2()
        return 1

    def ActiveRFID(self):
        returnValue = self.board.ActiveRFID(1000)
        return returnValue

    def enterPasswd(self):
        return self.board.enterPasswd()

    def readDatablock1(self):
        return self.board.readDatablock1()

    def readDatablock2(self):
        RFIDdata1 = str(self.board.readDatablock4())
        RFIDdata2 = str(self.board.readDatablock5())
        RFIDdata3 = str(self.board.readDatablock6())
        if RFIDdata1 == '-1' or RFIDdata2 == '-1' or RFIDdata3 == '-1':
            return -1
        RFIDdata = RFIDdata1 + RFIDdata2 + RFIDdata3

        Endnumber = 0
        for hex2 in RFIDdata:
            Endnumber = Endnumber + 1
            if hex2 == '!':
                return RFIDdata[0:Endnumber - 1]

    def readRFIDSection(self):
        return self.board.readDataSection()

    def InsideLED_fanON(self):
        return self.Aboard.InsideLED_fanON(1000)

    def InsideLED_fanOFF(self):
        return self.Aboard.InsideLED_fanOFF(1000)

    def Shutdown_allLED_fan(self):
        return self.Aboard.Shutdown_allLED_fan(1000)

    def initMotorpostion(self):
        return self.Aboard.initMotorpostion(1000)
