#! /usr/bin/env python
#
# ==================================================================
#
# LSST / StarDICE
#
# Micro-Controle motors (MM2500)
#
# Authors: Laurent Le Guillou
# Date: 2019-02-18
#
# ==================================================================

import sys
import os, os.path
import time

from . import mm2500

# ============ XY control ==========================================

class XY(object):
    """
    High level class representing the XY motorized support.
    """

    # default_ports = { 'x': "/dev/ttyS16",
    #                   'y': "/dev/ttyS17",
    #                   'z': "/dev/ttyS18" }

    default_ports =    { 'x': "/dev/ttyS0",
                         'y': "/dev/ttyS0"}

    # default_serials =  { 'x':  '9050719',
    #                      'y': '10050833',
    #                      'z':  '9050809',
    #                      'a': '15051379' }

    default_axis_ids = { 'x': 1,
                         'y': 2 }

    # all_axes = ['x', 'y']
    
    # ---------- Constructor ---------------------------------

    def __init__(self,
                 ports = default_ports, 
                 # serials = default_serials,
                 axis_ids = default_axis_ids,
                 debug = True):

        self.ports = ports
        # self.serials = serials
        self.axis_ids = axis_ids

        self.axes = { 'x': None, 
                      'y': None }

        self.all_axes = list(self.axes.keys())
        
        self.homed = False

        self.debug = debug

    # ---------- Open the various devices --------------------

    def open(self, check = False):
        """
        Open all the connected devices.
        """

        # -- Open each axis ----------------------------------

        for ax in self.all_axes:

            if ( not(ax in self.ports) or
                 # not(self.serials.has_key(ax)) or
                 not(ax in self.axis_ids) ): continue

            if self.debug: 
                print(( "Opening '%s' axis on port %s ..." % 
                                      (ax, self.ports[ax]) ), file=sys.stderr)
            # Opening the Axis

            axis = mm2500.MM2500(port = self.ports[ax],
                                 axis_id = self.axis_ids[ax],
                                 debug = self.debug)
            try: 
                axis.open()
            except IOError:
                if self.debug: 
                    print(( "No axis '%s' on port %s." % 
                                          ( ax, self.ports[ax] ) ), file=sys.stderr)
                continue
                    

            if self.debug: 
                print(( "Opening axis '%s' on port %s done." % 
                                      ( ax, self.ports[ax] ) ), file=sys.stderr)

            # motor_serial = axis.get_serial()
            # # print repr(motor_serial)

            # if motor_serial != self.serials[ax]:
            #     raise IOError("Wrong Axis (wrong/unknown serial number)")

            self.axes[ax] = axis

        # -- Manage missing axes depending on the options

        if check:
            if self.axes['x'] == None:
                raise IOError("Missing X Axis")

            if self.axes['y'] == None:
                raise IOError("Missing Y Axis")



    # ---------- Close the one/two devices -------------------

    def close(self):
        """
        Close the three/four devices.
        """ 
        for ax in self.all_axes:
            if (self.axes[ax] != None):
                self.axes[ax].close()

            
    # ---------- Setup the motors ----------------------------

    def setup(self):
        """
        Initialize each connected motor (init strings).
        """

        for ax in self.all_axes:
            if (self.axes[ax] != None):
                self.axes[ax].setup()
            else:
                if self.debug: 
                    print("%s axis disabled." % ax, file=sys.stderr)


    # ---------- Home procedure for the motors ---------------

    def home(self, force = False):
        """
        Find the zero index for all motors.
        """ 

        for ax in self.all_axes:
            if (self.axes[ax] != None):
                self.axes[ax].home()
            else:
                if self.debug: 
                    print("%s axis disabled." % ax, file=sys.stderr)

        self.homed = True


    # ---------- Park position -------------------------------


    def park(self):
        """
        Park the XY out of the light beam.
        """ 

        # For the moment, park position is the home position.

        self.home()


    # ---------- Current motor position ---------------------- 

    def get_position(self):
        """
        Return the current position on the XY motors 
        (as a dictionary).
        It is then possible to do move(**get_position())
        """

        position = {}

        if (self.axes['x'] != None):
            position['x'] = self.axes['x'].get_position()
        else:
            if self.debug: 
                print("X axis disabled.", file=sys.stderr)

        if (self.axes['y'] != None):
            position['y'] = self.axes['y'].get_position()
        else:
            if self.debug: 
                print("Y axis disabled.", file=sys.stderr)

        return dict(position)


    position = property(get_position, doc = "XY current position")

    # # ---------- Compute the target position -----------------

    # def compute_target(self,
    #                    x  = None, y  = None
    #                    dx = None, dy = None):

    #     pos = self.get_position()
    #     xc = pos['x']
    #     yc = pos['y']

    #     xt, yt = xc, yc
        
    #     if x != None:  xt = x
    #     if dx != None: xt += dx
        
    #     if y != None:  yt = y
    #     if dy != None: yt += dy
        
    #     return xt, yt

    # ---------- Move absolute and relative ------------------ 

    def move(self, 
             x  = None, y  = None,
             dx = None, dy = None,
             wait = True, check = True):
        """
        Move the XY to the given position (or offset).
        This function can do relative and absolute movements.
        """

        ## First, check the geometric limits
        #
        # Due to the complicated shape of the permitted volume,
        # the limits *MUST* be checked before and after each 
        # independant movement.
        # Reason: it may happen that the target is allowed, 
        # but the separate movements to go there are not!!!

        # -------- X axis ------------------------------------

        if (self.axes['x'] != None):

            if x != None:
                # if check:
                #     xt, yt, zt = self.compute_target(x=x)
                #     self.check_target(xt, yt, zt)

                self.axes['x'].move_absolute(position = x,  
                                             wait = wait, check = check)

            if dx != None:

                # if check:
                #     xt, yt, zt = self.compute_target(dx=dx)
                #     self.check_target(xt, yt, zt)

                self.axes['x'].move_relative(offset = dx, 
                                             wait = wait, check = check)
        else:
            if self.debug: 
                print("X axis disabled.", file=sys.stderr)

        # -------- Y axis ------------------------------------

        if (self.axes['y'] != None):

            if y != None:

                # if check:
                #     xt, yt, zt = self.compute_target(y=y)
                #     self.check_target(xt, yt, zt)

                self.axes['y'].move_absolute(position = y,  
                                             wait = wait, check = check)

            if dy != None:

                # if check:
                #     xt, yt, zt = self.compute_target(dy=dy)
                #     self.check_target(xt, yt, zt)

                self.axes['y'].move_relative(offset = dy, 
                                             wait = wait, check = check)

        else:
            if self.debug: 
                print("Y axis disabled.", file=sys.stderr)



# ==================================================================
