/*! @file
 *  @brief This file keeps the MoCon device. It supports N motors.
 *
 * @author Frank Kittmann
 * @version 09.06.23
 * @date 2009.06.23
 */

#pragma once

/* $Header: https://svn.mpia.de/gulli/TwiceAsNice/branch/unstable/TwiceAsNice/basda-mocca/src/device/mpia/mocon/NDevice.h 16130 2019-11-26 14:31:10Z mathar $
*/


#include <core/Protocol.h>
#include <mocon/Card.h>
#include <mocon/Module.h>
#include <mocon/CommandIDs.h>
#include <Basda/Mocca/NDevice.h>
#include <Nice/Property/BitSet.h>
#include <Nice/Map/NPoint.h>
#include <Nice/Chat/Line.h>

namespace Basda
{
    /**
     * @brief This is the MoCon device, which support to control N motors.
     *
     * This class auto-generates a motor controller device interface for the MPIA
     * in-house motor controller based on the user defined configuration file.
     * The constructor goes through the property tree and connects to each
     * defined module.
     *
     * The name of a motor can be individually defined in the configuration file.
     * The motor configuration will be stored in the property tree under the
     * motor name. Thereby the motors in the property tree are sorted in
     * alphabetical order. The same order is valid for the values in the vectors
     * of the method parameter. For example the first absolute position in the
     * vector of the method moveAbs belong to the motor A, the second value
     * belong to the motor B, and so on.
     *
     * The motor itself can be connected to any motor controller. That makes the
     * command interface independent from the hardware configuration.
     *
     * The electronic design of the motor controller distinguish between a motor
     * controller card, that provides general commands (like network settings or
     * commands to control multiple motors) and a motor controller module, that
     * provides motor specific commands (like move commands). This class combine
     * the motor controller module and the motor controller card to one device.
     * It can control complex commands, which need a setup procedure first before
     * it can be executed and it can handle event or error messages. It is the
     * basement for all other application that have to operate with the motor
     * controller.
     *
     * @author Frank Kittmann
     * @version 09.06.23
     * @date 2009.06.23
     *
     */
    class MoConNDevice : public Basda::MoccaNDevice
    {
        public:
            /**
             * @brief Constructor
             *
             * The constructor gets the root node of the device as parameter like
             * SVC.DEV.THE_DEVICE and creates a user defined motor controller
             * device. Thereby a motor object is generated for each founded module
             * in the property tree. The generated motor object reserves the motor
             * to avoid a multible access from other clients. The corresponding
             * card object will also be generated and stored in a list.
             *
             * @param _config the root node of the device which contain all modules
             *
             * @see Basda::MoConCard
             * @see Basda::MoConModule
             */
            MoConNDevice(const Nice::JointPtr &_config);

            /**
             * @brief Destructor
             *
             * removes all created bridges
             */
            ~MoConNDevice();

            /**
             * @brief This method creates an ID based on the connection address,
             *        card number and module number separated by a colon to
             *        identify the module/card object in a map.
             *
             * @param _address  the connection string
             * @param _cardNo   the card number
             * @param _moduleNo the module number
             */
            std::string createConnectionID(const std::string &_address,
                                           const unsigned int _cardNo,
                                           const unsigned int _moduleNo);

            /**
             * @brief This method might be called when the service goes in the
             *        INIT state. It connects to all motor controller.
             *
             * Right now it initialize the motor, download the configuration file
             * and get the all amplifier information.
             *
             * @todo implementation of the INIT service states
             */
            virtual void open();

            /**
             * @brief This method might be called when the service goes in the OFFLINE state.
             *
             * The connection to the modules will be closed.
             *
             * @todo implementation of the OFFLINE state
             */
            virtual void close();

            /**
             * @brief This method might be called when the service will be reseted.
             *
             * The connection to the modules will be closed and opened again.
             *
             * @param _asynch the call back object
             *
             * @todo implementation to reset the service
             */
            virtual void reset(Basda::DeviceAsync & = Basda::Device::s_async);

            /**
             * @brief This method returns the version string of the device.
             *
             * @todo implementation of the version string
             */
            virtual void version();

            /**
             * @brief This method initialize the device and set the state to INIT.
             *
             * @param _asynch the call back object
             *
             * @todo implementation of the INIT state
             */
            virtual void init(DeviceAsync & = Basda::Device::s_async);

            /**
             * @brief This method deinitialize the device and set the state to OFFLINE.
             *
             * @param _asynch the call back object
             *
             * @todo implementation of the OFFLINE state
             */
            virtual void deinit(DeviceAsync & = Basda::Device::s_async);

            /**
             * @brief activate something
             *
             * @param _asynch the call back object
             *
             * @todo implementation of the service activation
             */
            virtual void activate(DeviceAsync & = Basda::Device::s_async);

            /**
             * @brief deactivate something
             *
             * @param _asynch the call back object
             *
             * @todo implementation of the service deactivation
             */
            virtual void deactivate(DeviceAsync & = Basda::Device::s_async);

            /**
             * @brief This method send the command string to the electronic.
             *
             * This method is set to public due to requests from Lorenzo Busoni.
             * BUT THE USER OF THIS METHOD TAKE OVER THE RESPONSIBILITY OF THE
             * CORRECT ERROR HANDLING.
             * THE DRIVER DOES NOT HAVE THE CONTROL OVER THAT DEVICE ANY MORE.
             *
             * @param _commandID  the command ID
             * @param _selectID   the sub command ID
             * @param _cardNo     the ID of the MPIA electronic card
             * @param _moduleNo   the ID of the device module
             * @param _parameter  the parameter as string
             * @param _numberOfLines the number of lines that might be read
             *
             * Hi Martin,
             *
             * that's exactly what I was thinking:
             * The use case is (real example from our experience):
             * we discover at the telescope that we need to continuously monitor a
             * given property (PropA) of the MoCon (obviously because of a
             * malfunctioning in the hardware!). Without this monitor, we will be
             * stuck. You can add the required functionality in the Mocca adding the
             * function getPropA: this requires 4 hours and the day is lost. The day
             * after you are stuck because you discover that you miss PropB, and the
             * day is lost again.
             * As an alternative, one can add the 2 lines below in the code (with a
             * comment: "1 10 0 = getPropA") and this requires 5 minutes. The day
             * after one can add  a similar line with 1 11 0. When you're back in
             * Europe you implement getPropA and getPropB in Mocca and you cleanup
             * the code removing the receiveResponseForComment
             *
             * Generally speaking I think it is a safe idea to have a generic
             * interface to access _EVERY_ possible functionality of a device,
             * because soon or later you'll need it. In the case of the Mocon it is
             * quite easy, a good compromise between living dangerously and wasting
             * too much time in the effort of a complete implementation of all the
             * MoCon commands.
             *
             * Lorenzo Busoni
             */
            virtual void chat(std::string _cardNo,
                              std::string _commandID,
                              std::string _moduleNo,
                              std::string _selectID,
                              std::string _parameter,
                              std::string _numberOfLines,
                              Basda::DeviceAsync & = Basda::Device::s_async);

            /**
             * @brief This method was requested by Lorenzo Busoni (lbusoni@arcetri.astro.it 02.03.2012)
             *
             * It supports a direct communication with the MoCon.
             * BUT THE USER OF THIS METHOD TAKES OVER THE RESPONSIBILITY OF THE
             * CORRECT ERROR HANDLING.
             * THE DRIVER DOES NOT HAVE THE CONTROL OVER THAT DEVICE ANY MORE.
             *
             * @param _ret the allocated memory for the command response
             *
             * @see chat
             */
            virtual std::string dontParse(Basda::DeviceAsync & =
                    Basda::Device::s_async);

            /**
             * @brief This method was requested by Lorenzo Busoni (lbusoni@arcetri.astro.it 02.03.2012)
             *
             * It supports a direct communication with the MoCon without to parse the response.
             * BUT THE USER OF THIS METHOD TAKES OVER THE RESPONSIBILITY OF THE
             * CORRECT ERROR HANDLING.
             * THE DRIVER DOES NOT HAVE THE CONTROL OVER THAT DEVICE ANY MORE.
             *
             * @param _commandID   the command ID which is defined in the CommandIDs.h
             * @param _cardNo      the card number
             * @param _moduleNo    the module number
             * @param _ret         the allocated space for the returned data
             * @param _numberOfLines  This parameter limitates how many data
             *                        should be read from the Ethernet buffer.
             *                        All data are read if the value is -1.
             *
             * @return the return parameter is stored in _ret parameter.
             *
             * @see chat
             */
            virtual std::string receiveDataRaw(std::string _cardNo,
                                               std::string _commandID,
                                               std::string _moduleNo,
                                               std::string _numberOfLines,
                                               Basda::DeviceAsync & =
                                                       Basda::Device::s_async);

            /**
             * @brief All motors of the device are looking for the reference
             *        positions and reset the step counter to zero.
             *
             * @param _asynch the call back object
             */
            virtual void moveToHome(Basda::DeviceAsync &_aync =
                    Basda::Device::s_async)
            {
                moveToHomeStart(_aync);
                moveToHomeWait(_aync);
            }

            virtual void moveToHomeStart(Basda::DeviceAsync & =
                    Basda::Device::s_async);
            virtual void moveToHomeWait(Basda::DeviceAsync & =
                    Basda::Device::s_async);

            /**
             * @brief A single motor of the device is looking for the reference
             *        positions and resets the step counter to zero.
             *
             * @param _asynch the call back object
             */
            virtual void moveToHomeSingle(int _motor, Basda::DeviceAsync &_async =
                    Basda::Device::s_async)
            {
                moveToHomeSingleStart(_motor, _async);
                moveToHomeSingleWait(_async);
            }
            virtual void moveToHomeSingleStart(int _motor, Basda::DeviceAsync & =
                    Basda::Device::s_async);
            virtual void moveToHomeSingleWait(Basda::DeviceAsync & =
                    Basda::Device::s_async);

            /**
             * @brief All motors of the device move to the positive software
             *        limit switch.
             *
             * @param _asynch the call back object
             */
            virtual void moveToPositiveLimit(Basda::DeviceAsync &_async =
                    Basda::Device::s_async)
            {
                moveToPositiveLimitStart(_async);
                moveToPositiveLimitWait(_async);
            }
            virtual void moveToPositiveLimitStart(Basda::DeviceAsync &_async =
                    Basda::Device::s_async);
            virtual void moveToPositiveLimitWait(Basda::DeviceAsync &_async =
                    Basda::Device::s_async);

            /**
             * @brief All motors of the device move to the negative software
             *        limit switch.
             *
             * @param _asynch the call back object
             */
            virtual void moveToNegativeLimit(Basda::DeviceAsync &_async =
                    Basda::Device::s_async)
            {
                moveToNegativeLimitStart(_async);
                moveToNegativeLimitWait(_async);
            }
            virtual void moveToNegativeLimitStart(Basda::DeviceAsync &_async =
                    Basda::Device::s_async);
            virtual void moveToNegativeLimitWait(Basda::DeviceAsync &_async =
                    Basda::Device::s_async);

            /**
             * @brief move all motors to the positive limit switches
             *        (_limits[i]>0) or negative (_limits[i]<0) limit switches.
             *
             * @param _limit a vector that contains to which limit the motors
             *               have to move
             *               (_limits[i]= 1 - to positive software limit)
             *               (_limits[i]=-1 - to negative software limit)
             *               (_limits[i]= 2 - to positive hardware limit) - needed to initialize the SE
             *               (_limits[i]=-2 - to negative hardware limit) - needed to initialize the SE
             *               whereas the order of the points is corresponding
             *               to the order of the motor names in the property tree
             *               (alphabetical).
             * @param _asynch the call back object
             */
            virtual void moveToLimit(const Nice::NPoint &_limit,
                                     Basda::DeviceAsync &_async =
                                             Basda::Device::s_async)
            {
                moveToLimitStart(_limit, _async);
                moveToLimitWait(_async);
            }
            virtual void moveToLimitStart(const Nice::NPoint &_limit,
                    Basda::DeviceAsync & =
                            Basda::Device::s_async);
            virtual void moveToLimitWait(Basda::DeviceAsync & =
                            Basda::Device::s_async);

            /**
             * @brief move all motors out of the limit switches.
             *
             * Due to a bug in the MoCon chipset it is required to move all
             * motors out of the limit before move to home.
             * The MoCon will crash otherwise!
             *
             * No asynchronous command is available because the moveToHome method
             * needs this synchronous method to be sure that all motors are out
             * of the limit after that call.
             *
             * @param _motor  the motor ID. The order of motors is the same as
             *                in the property tree (alphabetical).
             *                If the motor ID is -1, all motors will move out of
             *                the limit
             * @param _asynch the call back object
             */
            virtual void moveOutOfLimit(int _motor, Basda::DeviceAsync &_async);

            /**
             * @brief The motors that are stored in the vector, move to the
             *        absolute position.
             *
             * @param _positions are the target positions of type Nice::NPoint
             *                   whereas the order of the points is corresponding
             *                   to the order of the motor names in the property tree
             *                   (alphabetical).
             * @param _asynch the call back object
             */
            virtual void moveAbsolute(const Nice::NPoint &_positions,
                                      Basda::DeviceAsync &_async =
                                              Basda::Device::s_async)
            {
                moveAbsoluteStart(_positions, _async);
                moveAbsoluteWait(_async);
            }
            virtual void moveAbsoluteStart(const Nice::NPoint &_positions,
                                      Basda::DeviceAsync & =
                                              Basda::Device::s_async);
            virtual void moveAbsoluteWait(Basda::DeviceAsync & =
                                              Basda::Device::s_async);

            /**
             * @brief The motors that are stored in the vector move to the
             *        relative position.
             *
             * @param _positions are the target positions of type Nice::NPoint
             *                   whereas the order of the points is corresponding
             *                   to the order of the motor names in the property tree
             *                   (alphabetical).
             * @param _asynch the call back object
             */
            virtual void moveRelative(const Nice::NPoint &_positions,
                                      Basda::DeviceAsync &_async =
                                              Basda::Device::s_async)
            {
                moveRelativeStart(_positions, _async);
                moveRelativeWait(_async);
            }
            virtual void moveRelativeStart(const Nice::NPoint &_positions,
                                      Basda::DeviceAsync & =
                                              Basda::Device::s_async);
            virtual void moveRelativeWait(Basda::DeviceAsync & =
                                              Basda::Device::s_async);

            /**
             * @brief This method set the motors, which will be moved or stopped
             *        synchronously.
             *
             * With the command parameter the motors connected to the same
             * MoCon card as the first motor of this device, will be programmed to
             * execute the movement synchronously. (Motors of the same device
             * can be connected to different MoCon cards, but this command considers
             * only the motors which belongs to the same card of the first motor of
             * that device.)
             *
             * All move, stop and abort command can be used to manipulate the motor
             * movement. The command execution of these command will be done with
             * startMoveSync()
             *
             * @param _motors This is a 8 bit number where every bit belongs to
             *                a motor (bit 0 = motor 1, ... bit 7 = motor 8)
             *                false = motor is not assigned
             *                true  = motor is assigned
             *
             * @see startMoveSync
             */
            virtual void prepareMoveSync(Nice::BitSet _motors);

            /**
             * @brief Start the movement of the motors that are programmed with
             *        prepareMoveSync() and the move, stop and abort commands before.
             *
             * @see prepareMoveSync
             */
            virtual void startMoveSync();

            /**
             * @brief This method setup the acceleration  anv velocity for a
             *        direct point to point move.
             *
             * @param _acceleration
             * @param _velocity
             * @param _deceleration
             */
            void prepareDirectMove(const Nice::NPoint &_acceleration,
                                   const Nice::NPoint &_velocity,
                                   const Nice::NPoint &_deceleration);

            /**
             * @brief This method stops the motor with a deceleration.
             */
            virtual void stop();

            /**
             * @brief Abort the moving of the motor immediately without deceleration.
             *
             * @note Abrupt stop of a quickly running motor can leads to losing steps.
             *       The motor could be damaged too.
             */
            virtual void abort();

            /**
             * @brief This method is deprecated and will be exchanged with
             *        getDeviceencoderPosition()
             * @deprecated
             */
            virtual Nice::NPoint getPosition();

            /**
             * @brief Returns the current positions of all motors.
             *
             * The current position of all motors will be stored in the property
             *
             * - VAR.POSITION.DEVICE_ENCODER
             */
            virtual Nice::NPoint getDeviceEncoderPosition();

            /**
             * @brief Change the absolute position of all motors.
             *
             * The motor will not move, but the MoCon position and incremental
             * psoition will be set to the given position value.
             * The new position value can only be inside the travel range.
             *
             * @param _position a vector with the new MoCon and incremental
             *                  encoder position of all motors
             */
            virtual void setPosition(const Nice::NPoint &_position);

            /**
             * @brief Returns the current positions of all motors.
             *
             * The current position of all motors will be stored in the property
             *
             * - VAR.POSITION.ABSOLUTE_ENCODER
             */
            virtual Nice::NPoint getAbsoluteEncoderPosition();

            /**
             * @brief Returns the current positions of all motors.
             *
             * The current position of all motors will be stored in the property
             *
             * - VAR.POSITION.INCREMENTAL_ENCODER
             */
            virtual Nice::NPoint getIncrementalEncoderPosition();

            /**
             * @brief Returns the current velocity of all motors.
             *
             * The current velocity of all motors will be stored in the property
             *
             * - VAR.VELOCITY
             */
            virtual Nice::NPoint getVelocity();

            /**
             * @brief This method returns the basic settings of all MoCon module.
             *
             * @return A sequence of the basic settings with the following parameter
             *         order: profile, revolution, velocity straight, velocity start,
             *                acceleration, deceleration, jerk
             */
            virtual Nice::SeqSeqDouble getBasicSettings();

            /**
             * @brief Set the velocity configuration parameter of all motors.
             *
             * @param _velocity a vector with the velocity of all motors
             */
            virtual void setVelocitySetting(const Nice::NPoint &_velocity);

            /**
             * @brief Set the acceleration configuration parameter of all motors.
             *
             * @param _acceleration a vector with the acceleration of all motors
             */
            virtual void setAccelerationSetting(const Nice::NPoint &_acceleration);

            /**
             * @brief Set the deceleration configuration parameter of all motors.
             *
             * @param _deceleration a vector with the deceleration of all motors
             */
            virtual void setDecelerationSetting(const Nice::NPoint &_deceleration);

            /**
             * @brief Set the jerk configuration parameter of all motors.
             *
             * @param _jerk a vector with the jerk of all motors
             */
            virtual void setJerkSetting(const Nice::NPoint &_jerk);

            /**
             * @brief Checks if one of the motors is in motion.
             *
             * The method collects the motion flag of every motor and stores it
             * in the property
             *
             * - VAR.MOVING
             *
             * @param _motion returns which motor is in motion
             * @return true if at least one motor is in motion
             */
            virtual bool isMoving(Nice::BitSet &_motion);

            /**
             * @brief Checks if one of the motors is in limit.
             *
             * This method collects the limit flags of all motors and stores it
             * in the property:
             *
             * - VAR.LIMIT
             *
             * @param _limit - return a vector with all motor limit switch flags
             *                 (0 - not in limit; +/-1 in software limit;
             *                 +/-2 in hardware limit)
             *
             * @return is true when the device is in the limit, false otherwise
             */
            virtual bool isAtLimit(Nice::NPoint &_limit);

            /**
             * @brief This method indicate whether the motor is at the home position.
             *
             * @param _atHome each flag in that Bitset indicate whether the motor
             *                is at home (true - motor is at home;). The order of
             *                the bits is corresponding to the order of the motor
             *                names in the property tree (alphabetical).
             */
            virtual bool isAtHome(Nice::BitSet &_atHome);

            /**
            * @brief This method setup and starts the external profile for a XY
            *        device.
            *
            * @param _date the external profile start date
            * @param _positionSequence the point sequence in units of steps
            * @param _frequency samples per second
            *    This is typically 100 in the LN derotator configurations.
            * @param _maxSamplesPerSegment the maximal number for samples in a segment
            *    This is typically 100 in the LN derotator configurations.
            * @param _faultTolerance the maximal deviation
            * @param _async
            */
            virtual void startExternalProfile(const Nice::Date &_date,
                                              const Nice::NPoint &_positionSequence,
                                              unsigned int _frequency,
                                              unsigned int _maxSamplesPerSegment,
                                              unsigned int _faultTolerance,
                                              Basda::DeviceAsync &_async =
                                                      Basda::Device::s_async);

            virtual void shinsStartExternalProfile(const Nice::Date &_date,
                                                   const Nice::NPoint &_positionSequence,
                                                   unsigned int _frequency,
                                                   unsigned int _maxSamplesPerSegment,
                                                   unsigned int _faultTolerance,
                                                   Basda::DeviceAsync &_async = Basda::Device::s_async);

            virtual int shinsGetStartingRamp(const Nice::NPoint & _positionSequence, double time_interval_microseconds);
            virtual int sharkDerotatorBacklashProcedure(int procedure);

            /**
             * @brief This method wait until the next trigger has tobe raised.
             *
             * @param _date the absolute time for the next trigger
             */
            void waitForNextTrigger(Nice::Date _date,
                                    Basda::DeviceAsync &_async =
                                            Basda::Device::s_async);
            void shinsWaitForNextTrigger(Nice::Date _date, Basda::DeviceAsync &_async = Basda::Device::s_async);

            /**
             * @brief This method fit, validates and buffers the external profile.
             *
             * @param _date the start date of the external profile
             * @param _positionSequence the position sequence in steps
             */
            virtual void changeExternalProfile(const Nice::Date &_date,
                                               const Nice::NPoint &_positionSequence);

            /**
             * @brief This method prepares a direct point to point movement of
             *        a xy device.
             *
             * The movement starts using the startExternalProfile method without
             * parameter.
             */
            virtual void prepareExternalProfile(const Nice::SeqSeqInt &_segmentsX,
                                            const Nice::SeqSeqInt &_segmentsY,
                                            Basda::DeviceAsync &_async =
                                                    Basda::Device::s_async);

            /**
             * @brief This method starts a trajectory now.
             */
            virtual void startExternalProfile(Basda::DeviceAsync &_async =
                                                    Basda::Device::s_async);
            virtual void shinsStartExternalProfile(Basda::DeviceAsync &_async = Basda::Device::s_async);

            /**
             * @brief This method sets TCP connection timeout.
             *
             * For each motor, the TCP
             * connection timeout will be stored.
             *
             * @param _tcpConnectionTimeout a vector with the TCP connection timeout
             */
            virtual void setLinkTimeout(Nice::Time _tcpConnectionTimeout);

            /**
             * @brief This method returns TCP connection timeout.
             *
             * For each motor, that name is stored in the vector, the TCP
             * connection timeout will be stored.
             *
             * @return the TCP connection timeout
             */
            virtual Nice::SeqTime getLinkTimeout();

            /**
             * @brief This method synchronize the MoCon time with the PC time.
             *
             * For each motor, that name is stored in the vector, the current MoCon
             * cycles and the PC time will be stored.
             *
             * @see getCurrentTime()
             * @see Basda::MoConModule::synchronizeTime()
             */
            virtual Nice::NPoint getReferenceTime();

            /**
             * @brief This method returns the current MoCon time.
             *
             * For each motor, that name is stored in the vector, the current
             * MoCon cycles and the PC time will be stored.
             *
             * @see getReferenceTime()
             * @see Basda::MoConModule::getCurrentTime()
             */
            virtual Nice::NPoint getCurrentTime();

            /**
             * @brief Returns the status of the position switch.
             *
             * @return a sequence of BitSets.
             */
            virtual Nice::SeqBitSet getPositionSwitchStatus();

            /**
             * @brief Returns if the device is reachable.
             *
             * @return the status of the device.
             */
            virtual bool isReachable();

            /**
             * @brief This method downloads all configuration parameter of the
             *        MoCon.
             */
            void dumpStatusInformation(Basda::DeviceAsync & =
                                               Basda::Device::s_async,
                                       bool _compareParameter = false);

            /**
             * @brief This method indicates all motor whether they have a collision or not.
             *
             * @param _collisions a sequence of points where
             *                    x is the indicator for a collision on the negative side and
             *                    y is the indicator for a collision on the positive side
             */
            void setCollision(Nice::SeqPoint _collisions);

//            void checkMotionError();

            // to avoid compiler warnings :)
            virtual Nice::JointPtrVector description() {return Nice::JointPtrVector();};

            /**
             * @brief This method allows to use a different kind of Chat class.
             *
             * This method is necessary to test the device with a MoCon simulator.
             */
            void setChatType(std::map<std::string, Nice::ChatLinePtr> _chat);

            virtual Nice::Completion getProgress();

        private:
            void createInstances();

            /**
             * @brief This method add the following internal status properties
             *
             * - VAR.POSITION +UNIT
             * - VAR.VELOCITY +UNIT
             * - VAR.HOME_KNOWN +LABEL
             * - VAR.MOVING
             * - VAR.ON_POSITIVE_LIMIT
             * - VAR.ON_NEGATIVE_LIMIT
             * - VAR.TRACE.INFO.TRACING
             * - VAR.TRACE.INFO.TRACED_VALUES
             * - VAR.UNIT +SELECT
             */
            void addProperties();

            /**
             * @brief Calculate the completion percent.
             *
             * @param _cmd the command name which appears in the completion bar
             * @param _asynch the call back object
             */
            void completion(std::string _cmd,
                            Basda::DeviceAsync & = Basda::Device::s_async);

            /**
             * @brief Checks if the motion is complete.
             *
             * This method collect the MOTION_COMPLETE flags of all motors.
             *
             * The following property will indicate the motion completeness
             *
             * - VAR.MOTION_COMPLETE
             *
             * @param _motion returns which motor is in motion
             * @return true if all motor have completed its motion
             */
            bool isMotionComplete(Nice::BitSet &_motion);

            /**
             * @brief Resets the motion complete flag.
             *
             * This method set back the motion complete flag.
             *
             * The following property is used
             *
             * - VAR.MOTION_COMPLETE
             */
//            void setMotionComplete(Nice::BitSet _bs);
            void setMotionComplete(bool _complete);

            void setIsReachable(const bool _isReachable);

            /**
             * @brief This method resets the fatal error.
             */
            void resetFatalError();

            /**
             * @brief This method fit, validates and buffers the external profile.
             *
             * @param _date - the start date when the trajectory should start
             * @param _positionSequence - the position sequence in steps
             */
            void generateExternalProfile(const Nice::Date &_date,
                                               const Nice::NPoint &_positionSequence);
            void shinsGenerateExternalProfile(const Nice::Date &_date, const Nice::NPoint &_positionSequence);

//            void resetMotionError();

//            /**
//            * @brief This method resets the fatal error.
//            *
//            * @todo implementation
//            */
//            void resetFatalError();

            /**
             * @brief This member keeps all connection to the MoCon. The key is
             *        the connection address.
             *
             */
            std::map<std::string, MPIACoreProtocolPtr> m_protocol;

            /**
             * @brief This member keeps all card objects. The key is the
             *        connection ID which is composed by the connection address,
             *        the card number and the module number.
             */
            std::map<std::string, MoConCardPtr> m_card;

            /**
             * @brief This member keeps all module objects. The key is the
             *        connection ID which is composed by the connection address,
             *        the card number and the module number.
             */
            std::map<std::string, MoConModulePtr> m_module;

            /**
             * @brief This member keeps all chat objects. The original
             *        Nice::Chat::Line object can be exchanged with a
             *        Chat::LineMock object to simulate the MoCon behavior.
             *
             */
            std::map<std::string, Nice::ChatLinePtr> m_chat;

            unsigned int m_externalProfileSize;

            /**
             * @brief Keeps the last external profile info value to reduce the
             *        number of log messages.
             */
            int m_externalProfileInfo;

            bool m_isReachable;

            Nice::Completion m_completion;

            Nice::NPoint m_targetPositions;

            Nice::NPoint m_startPosition;
            Nice::NPoint m_currentPosition;

            bool m_extended;

//            Basda::ValueStartMode m_startMode;

//            Nice::BitSet m_profileUploadSuccessful;

            Nice::Mutex m_mutex;

//            Nice::Time m_blockSize;
    };

    /**
     * @brief Definition of the smart pointer of this class.
     */
    typedef IceUtil::Handle<MoConNDevice> MoConNDevicePtr;
}

//            /**
//            * @brief This method add the following internal command properties
//            *
//            * - CMD.moveAbs
//            * - CMD.moveRel
//            * - CMD.moveHome
//            * - CMD.traceTimeBased
//            * - CMD.traceEventBased
//            * - CMD.externalProfile
//            * - CMD.testCommand
//            * - CMD.timeOffset
//            * - CMD.Stop +LABEL +NOPROG +AUTOSYNC
//            * - CMD.Abort +LABEL +NOPROG +AUTOSYNC
//            * - CMD.getPosition +LABEL +NOPROG +AUTOSYNC
//            * - CMD.terminal +ADVANCED
//            * - CMD.synchronizeTime
//            * - CMD.getCurrentTime
//            */
//             void addCommandInterface();

//            /**
//            * @brief This method lock the motor controller card for an exclusive interface access.
//            *
//            * The MPIA electronic rack can keep up to 8 motor controller cards, which can control up to 8 motors each. The N-Device keeps the motor controller card object of each motor in order to configure the motor and to programm the motor controller card. Different clients that are using different motors on the same card have to share the motor controller card object. To programm the motor controller a set of commands have to be called in a certain order. Thereby must be sure that no other client can interrput the current programming and the execution of the programmed command. Hence this shared object has to be locked first for an exclusive access and unlocked when the programming and the execution is done.
//            *
//            * The _command parameter is necessary to identify which command argument property tree has to be used to identify which motor controller card has to be locked. At the moment the command threads MoConNDeviceTimeBasedTraceThread and MoConNDeviceEventBasedTraceThread are using this method. The current implementation of this command identifies which modules are selected at the command properties and locks the corresponding cards.
//            *
//            * @param _command the command name as string
//            */
//             void lockCard(std::string &_command);

//            /**
//            * @brief This method unlock the card.
//            *
//            * The motor controller card is locked for an exclusive access till the unlockCard() method is called. At the moment the command threads MoConNDeviceTimeBasedTraceThread and MoConNDeviceEventBasedTraceThread are using this method.
//            */
//             void unlockCard();

//            /**
//            * @brief This is a temporary implementation of a terminal, which allows to send MoCon commands directly to the MoCon via the card object.
//            *
//            * The terminal is a special interface that allows to send strings directly to the motor controller. The advantage is that the MoCon commands can be checked without to use the NDevice implementation. Also new MoCon commands can be used directly, which are still not implemented.
//            *
//            * @note This method is just for testing whether the motor controller is working correctly. That helps to distinguish whether the failure comes from the software implementation or from the motor controller itself. The terminal interface is not thought to use it as standard interface.
//            *
//            * Usage:
//            * The MoCon command will be passed via the completion argument to the method. The action member of the completion argument is taken to store the MoCon command string. It will be extracted and sent to the motor controller.
//            *
//            * @code
//            *   Nice::Completion c;               //create a completion object
//            *   Nice::Terminal chat;              //create a terminal object
//            *   std::string str;
//            *   chat.setType(Nice::OUTGOING);     //define the message type Nice::OUTGOING / NICE::INCOMMING
//            *   chat.setCommand(command);         //store the command
//            *   chat.setComment(comment);         //store a comment - its just a note what you are doing
//            *   c = Nice::Completion().exec();    //set the completion state to EXEC
//            *   std::stringstream ss;
//            *   ss << chat;                       //convert the terminal object in a string
//            *   str = ss.str();
//            *   c.setAction(0, str);              //set the terminal string as action in the completion object
//            *   BridgeItem::set( c );             //set the completion state to the terminal property in order to execute the command string
//            * @endcode
//            *
//            * Command Syntax:
//            * module_name mocon_cmd [mocon_parameter]
//            * The module name is the name defined in the configuration file. The motor controller command is the same defined in Core/CommandID.h MoCon/CommandID.h. The paramter are optional and have the same syntax like described in the MoCon programmers manual.
//            *
//            * Example to move the motor to the absolute position 1000 [steps]:
//            * X 124 1000
//            *
//            * @note The execution of this terminal command can be done only when the ADVANCED attribute of the CMD.terminal property is set to true.
//            * @note The terminal execute the entered command on by one. Therefore the card object can not be locked in advanced in order to execute commands in a certain order. The terminal locks the card for one command and unlock the card immediatelly after the command execution. The terminal doesn't make sure that no other clients interrupt the programming of the motor controller.
//            */
//             void terminal(const Nice::Completion & _c);

//            /**
//            * @brief This method add the command properties of the trace command
//            *
//            * A complex property tree extend the command threads MoConNDeviceTimeBasedTraceThread and MoConNDeviceEventBasedTraceThread. The property trees are the command arguments which have to be defined. This method create the command property tree and predefined it with with default values based on the configuration files.
//            *
//            * @param _command the command name as string
//            * @param _timeBasedTrace - a flag to distinguish between the MoConNDeviceTimeBasedTraceThread and MoConNDeviceEventBasedTraceThread
//            *
//            * @todo write down the command property tree and create a new class maybe
//            */
//             void addTraceCommandProperties(std::string &_command, bool _timeBasedTrace);

//            /**
//            * @brief This method programm the motor controller card for the impending time based trace.
//            *
//            * This method prepare the motor controller card for the impending time base trace and set the sample rate, the number of samples and the sample mode at the motor controller card as well as the sample type for the selected motor at the corresponding motor module.
//            *
//            * @return number of samples
//            * @todo create a new class maybe
//            */
//             int configureTimeBasedTrace();

//            /**
//            * @brief This method returns true if one of the selected card is configured to use the rolling buffer mode.
//            *
//            * This method is used to switch between the progress bar and the busy indicator of the completion bar.
//            *
//            * @return true if one of the selected card is configured to use the rolling buffer mode.
//            */
//             bool getTimeBasedRollingBuffer();

//            /**
//            * @brief This is the command interface of the synchronizeTime() method and keep the client informed about the current completion state.
//            *
//            * @param _c the completion state which keep the client informed about the current execution state.
//            *
//            * @see synchronizeTime
//            */
//             void getReferenceTime( const Nice::Completion &_c );

//            /**
//            * @brief This is the command interface of the getCurrentTime() method and keep the client informed about the current completion state.
//            *
//            * @param _c the completion state which keep the client informed about the current execution state.
//            *
//            * @see getReferenceTime
//            */
//             void getCurrentTime( const Nice::Completion &_c );

//            /**
//            * @brief This method starts the time based trace.
//            *
//            * To start the time based trace the motor controller card has to be configured first. The sample type, the sample rate, the sample number and the sample mode has to be defined. The trace buffer can be cleared to be sure that no other process has allocated the buffer. All these card configuration will be done by calling the configureTimeBasedTrace() method.
//            */
//             void timeBasedTraceStart();

//            /**
//            * @brief This method stops the time based trace.
//            */
//             void timeBasedTraceStop();

//            /**
//            * @brief This methods clear and freed the data buffer of the time based trace at motor controller card.
//            */
//             void clearTimeBasedTraceBuffer();

//            /**
//            * @brief This method receive the traced data and updates the completion bar.
//            *
//            * This method will send a request to the MoCon to return the collected data. It uses the property
//            *
//            * CMD.traceTimeBased.BLOCK_SIZE
//            *
//            * to divide the collected data in blocks. The trace data blocks will be read one by one. In the meantime the completion bar will be updated based on the block size and the number of samples.
//            *
//            * @param _completion the pointer to the completion bar object.
//            *
//            * @see MoConModule::getTraceData
//            * @see MoConModule::receiveTraceData
//            */
//             void getTimeBasedTraceData(Nice::Completion &_completion);

//            /**
//            * @brief This method program the motor controller card for the impending event based trace.
//            *
//            * This method prepare the motor controller card for the impending event base trace and set the sample rate at the motor controller card as well as the sample type for the selected motor at the corresponding motor module.
//            */
//             void configureEventBasedTrace();

//            /**
//            * @brief This method starts the event based trace.
//            *
//            * To start the event based trace the motor controller card has to be configured first. The sample type and the sample mode has to be defined. The trace buffer can be cleared to be sure that no other process has allocated the buffer. All these card configuration will be done by calling the configureEventBasedTrace() method.
//            * The trace data will be returned as an event message.
//            */
//             void eventBasedTraceStart();

//            /**
//            * @brief This method stops the event based trace.
//            */
//             void eventBasedTraceStop();

//            /**
//            * @brief This method returns the current status of the time based trace.
//            *
//            * It updates the sample mode property, the status if the trace is still running, the status if a buffer overflow was detected and the number of already logged data of each motor module.
//            *
//            * The device will logically add the TRACING property of each motor module and store it in
//            * - VAR.TRACE.INFO.TRACING
//            *
//            * The equation is:
//            *
//            * TRACING = motor 1 TRACING OR motor 2 TRACING OR motor N TRACING
//            *
//            * The following property shows the number of traced values.
//            * - VAR.TRACE.INFO.TRACED_VALUES
//            *
//            * @return the trace info
//            */
//             int getTraceInfo();

//            /**
//            * @brief This method waits till an event is received.
//            */
//             void waitForEvent();

//            /**
//            * @brief This method converts the given trajectory to a motor controller profile.
//            *
//            * The calculated position sequence and the command parameter TIME_RESOLUTION, SAMPLES_PER_SEGMENT and MAX_ERROR are passed to the module method Basda::MoConModule::convertTrajectoryToProfile() where it is converted to the MoCon profile.
//            *
//            * The command parameter are properties of the command property itself.
//            * - CMD.externalProfile.MOD.NAME_OF_THE_MODULE.TIME_RESOLUTION
//            * - CMD.externalProfile.MOD.NAME_OF_THE_MODULE.SAMPLES_PER_SEGMENT
//            * - CMD.externalProfile.MOD.NAME_OF_THE_MODULE.MAX_ERROR
//            *
//            * Usage:
//            * @code
//            *    Nice::JointPtr cfg = config()->node("MOCON.SVC.DEV.1.CMD");
//            *    double dDuration = 120;     //in sec
//            *    double dPeriod = 60;        //in sec
//            *    double dAmp = 10;           //in mm
//            *    double dPhase = 0;          //rad
//            *    double dSegmentLength=1.;   //The maximum segment length is 1 seconds
//            *    int nSampling=100;          //Samples representing a segment with maximum length
//            *
//            *    double dTimeRes = dSegmentLength / nSampling;
//            *    std::vector< double > posSeqX = GenerateSineTraj(dDuration, dPeriod, dAmp, dPhase, dSegmentLength, nSampling);
//            *
//            *    cfg->node ( "externalProfile.MOD.X.POSITION_SEQUENCE")->set< std::vector< double > >(posSeqX);
//            *    cfg->node ( "externalProfile.MOD.X.SAMPLES_PER_SEGMENT")->set< unsigned int >(nSampling);
//            *    cfg->node ( "externalProfile.MOD.X.MAX_ERROR")->set< unsigned int >(0);
//            *    cfg->node ( "externalProfile.MOD.X.TIME_RESOLUTION")->set< double >(dTimeRes);
//            *    cfg->node ( "externalProfile.MOD.X.ACTIVATE")->set< bool >( true );
//            *
//            *    std::vector< Nice::PropertyPtr > cmd;
//            *    Nice::Barrier* barrier = new Nice::Barrier;
//            *    cmd.clear();
//            *    barrier->clear();
//            *    cmd.push_back( cfg->leaf("externalProfile") );
//            *    barrier->addCommand(cmd[0]);
//            *    barrier->exec(Nice::Time::seconds(0));
//            * @endcode
//            *
//            * @param _positionsSequences its a map with the name of the motor and the position sequence in millimeter
//            *
//            * @see Basda::MoConModule::convertTrajectoryToProfile()
//            */
//             void convertTrajectoryToProfile(std::map<std::string, std::vector<double> > _positionsSequences);

//            /**
//            * @brief This method stops the external profile of the motors, those names are stored in the vector.
//            *
//            * @param _externalProfileModules a vector with the names of the motors that have to stop the running profile
//            */
//             void setExternalProfileStop(std::vector<std::string> _externalProfileModules);

//            /**
//            * @brief This method starts the external profile of the motors, which are stored in the vector.
//            *
//            * The MoCon starts the profile immediately when the start cycle value is set to -1.
//            *
//            * @param _externalProfileModules a vector with the names of the motors and the start cycle
//            */
//             void setExternalProfileStart(std::map<std::string, Nice::I64> _externalProfileModules);

//            /**
//            * @brief This method freed the allocated memory of the external profile.
//            *
//            * @param _externalProfileModules a vector with the names of the motors that memory have to be freed
//            */
//             void clearExternalProfileBuffer(std::vector<std::string> _externalProfileModules);

//            /**
//            * @brief This method tries to free the allocated memory of the external profile.
//            *
//            * @param _externalProfileModules a vector with the names of the motors that memory have to be freed
//            *
//            * @see Basda::MoConModule::tryClearExternalProfileBuffer
//            */
//             void tryClearExternalProfileBuffer(std::vector<std::string> _externalProfileModules);

//            /**
//            * @brief This method upload the external profile data.
//            *
//            * @param _externalProfileModules a vector with the names of the motors that profile have to be uploaded
//            **/
//             void uploadExternalProfile(std::vector<std::string> _externalProfileModules);

//            /**
//            * @brief This method returns the external profile size.
//            *
//            * @param _externalProfileModules a vector with the names of the motors that should return the profile size
//            *
//            * @return the profile size
//            **/
//             unsigned int getExternalProfileSize(std::vector<std::string> _externalProfileModules);

//            /**
//            * @brief This method returns the actual index of the external profile.
//            *
//            * @param _externalProfileModules a vector with the names of the motors that should return the profile info
//            *
//            * @return the current index of the profile
//            **/
//             unsigned int getExternalProfileInfo(std::vector<std::string> _externalProfileModules);

//            /**
//            * @brief This method is a temporary implementation of the terminal interface. It will parse the terminal command response.
//            *
//            * @param _module the module number
//            * @param _ret the command response string
//            * @param _c the completion state object
//            */
//             void parse(std::string _module, std::string _ret, Nice::Completion _c);

//            /**
//            * @brief member to store the command threads
//            */
//             Nice::ThreadPool m_cmdThreads;

//            /**
//            * @brief This member stores the thread of the move absolute command.
//            *
//            * It is used to convert the position argument of the move absolute command when the unit has changed.
//            */
//             Basda::MoConNDeviceMoveAbsThread *m_moveAbsThread;

//            /**
//            * @brief This member stores the thread of the move relative command.
//            *
//            * It is used to convert the position argument of the move relative command when the unit has changed.
//            */
//             Basda::MoConNDeviceMoveRelThread *m_moveRelThread;

//            /**
//            * @brief mutex member to control the method access.
//            */
//             Nice::Mutex m_mutex;

//            /**
//            * @brief member to store the selected cards to avoid to go several time through the tree.
//            */
//             std::set<std::string> m_selectedCards;

//            /**
//            * @brief member to store the selected modules to avoid to go several time through the tree.
//            */
//             std::set<std::string> m_selectedModules;

//            /**
//            * @brief This member is just to keep the information whether the home search is stopped. The home known flag will not be set.
//            */
//             bool m_stopped;

//            /**
//            * @brief This member is just to keep the information whether the home search is aborted. The home known flag will not be set.
//            */
//             bool m_aborted;

//            /**
//            * @brief This map keeps all card commands that can be called via the terminal.
//            *
//            * The module commands will be send directly to the MoCon. The MoCon will complain if the command doesn't exist.
//            * The terminal checks if the entered command is in this list and lock the card object if it is the case.
//            * The integer value indicate that this command is a card command, but it is not used.
//            * The reason for the usage of the map is the possibility to search for the command IDs in the map - its easier than a vector implementation :).
//            */
//             std::map<unsigned int, unsigned int> m_cardCmd;

