//
// $Header: https://svn.mpia.de/gulli/TwiceAsNice/branch/unstable/TwiceAsNice/basda-mocca/src/device/mocca/NDeviceDummy/NDeviceDummy.h 14057 2016-11-10 14:53:04Z mathar $
//
// Description:
//
//
// Author: Florian Briegel <briegel@mpia.de>, (C) 2006
//
// Copyright: See COPYING file that comes with this distribution
//
//

#pragma once

#include <config.h>
#include <Nice/Map.h>
#include <Nice/Time.h>
#include <Nice/Property.h>
#include <Nice/Util/Completion.h>
#include <Basda/Mocca/NDevice.h>

#include <ostream>

namespace Basda
{
    class MoccaNDeviceDummy : virtual public MoccaNDevice
    {
        public:
            MoccaNDeviceDummy(const Nice::JointPtr & _config);
            virtual ~MoccaNDeviceDummy();

            //! open device
            virtual void open();

            //! close device
            virtual void close();

            //! reset the device
            virtual void reset(Basda::DeviceAsync & = Basda::Device::s_async);

            //! version
            virtual void version();

            //! init the device
            virtual void init(Basda::DeviceAsync & = Basda::Device::s_async);

            //! deinit the device
            virtual void deinit(Basda::DeviceAsync & = Basda::Device::s_async);

            //! activate the device
            virtual void activate(DeviceAsync & = Basda::Device::s_async);

            //! deactivate the device
            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 _cardNo     the ID of the MPIA electronic card
             * @param _moduleNo   the ID of the device module
             * @param _selectID   the sub command ID
             * @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 _commandID,
                    std::string _cardNo,
                    std::string _moduleNo,
                    std::string _selectID,
                    std::string _parameter,
                    std::string _numberOfLines,
                    DeviceAsync & = 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 TAKE OVER THE RESPONSIBILITY OF THE
             * CORRECT ERROR HANDLING.
             * THE DRIVER DOES NOT HAVE THE CONTROL OVER THAT DEVICE ANY MORE.
             *
             * @return the raw response string
             *
             * @see chat
             */
            virtual std::string dontParse(DeviceAsync & = 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 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 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  optional: 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 _commandID,
                    std::string _cardNo,
                    std::string _moduleNo,
                    std::string _numberOfLines,
                    DeviceAsync & = s_async);

            virtual bool isReachable();

            virtual void prepareMoveSync(Nice::BitSet _motors);
            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 All motors of a device move to the absolute position.
             *
             * @param _positions a vector containing the motor name and the
             *                   absolute target position in millimeter
             */
            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 All motors of a device move to the relative position.
             *
             * @param _positions a vector containing the motor name and the
             *                   relative target position in millimeter
             */
            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 &_async = Basda::Device::s_async);
            virtual void moveRelativeWait(Basda::DeviceAsync & =
                    Basda::Device::s_async);

            /**
             * @brief All motors of a device move to the home position.
             */
            virtual void moveToHome(Basda::DeviceAsync &_async =
                    Basda::Device::s_async)
            {
                moveToHomeStart(_async);
                moveToHomeWait(_async);
            }
            virtual void moveToHomeStart(Basda::DeviceAsync & =
                    Basda::Device::s_async);
            virtual void moveToHomeWait(Basda::DeviceAsync & =
                    Basda::Device::s_async);

            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 a device move to the positive limit switch.
             */
            virtual void moveToLimit(const Nice::NPoint &_positions,
                    Basda::DeviceAsync &_async = Basda::Device::s_async)
            {
                moveToLimitStart(_positions, _async);
                moveToLimitWait(_async);
            }
            virtual void moveToLimitStart(const Nice::NPoint &_positions,
                    Basda::DeviceAsync & = Basda::Device::s_async);
            virtual void moveToLimitWait(Basda::DeviceAsync & =
                    Basda::Device::s_async);

            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);

            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 All motors of a device stop moving.
             */
            virtual void stop();

            /**
             * @brief All motors of a device abort the current movement.
             */
            virtual void abort();

            /**
             * @brief Returns the current positions of all motors.
             *
             */
            virtual Nice::NPoint getPosition();
            virtual Nice::NPoint getDeviceEncoderPosition();
            virtual Nice::NPoint getAbsoluteEncoderPosition();
            virtual Nice::NPoint getIncrementalEncoderPosition();

            virtual void setPosition(const Nice::NPoint &_position);

            /**
             * @brief Returns the current velocity of all motors.
             *
             */
            virtual Nice::NPoint getVelocity();

            /**
             * @brief Returns the basic settings of all motors.
             *
             * Depending of the implementation the basic settings could be:
             * motion profile, revolution, velocity, acceleration, deceleration
             * and jerk. Each basic settings is stored in a sequence.
             *
             * @return a sequence of all motors with a sequence of all basic settings
             */
            virtual Nice::SeqSeqDouble getBasicSettings();

            /**
             * @brief Set the velocity configuration parameter of all motors.
             *
             * @param _velocity a vector with the velocity of all motors. The
             *        order of the velocities is corresponding to the order of
             *        the motor names in the property tree (alphabetical).
             */
            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. The
             *        order of the accelerations is corresponding to the order of
             *        the motor names in the property tree (alphabetical).
             */
            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. The
             *        order of the decelerations is corresponding to the order of
             *        the motor names in the property tree (alphabetical).
             */
            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. The
             *        order of the jerks is corresponding to the order of
             *        the motor names in the property tree (alphabetical).
             */
            virtual void setJerkSetting(const Nice::NPoint &_jerk);

            /**
             * @brief Returns the current limit switch state of all motors.
             */
            virtual bool isAtLimit(Nice::NPoint &);

            /**
             * @brief Returns the motion flag of all motors.
             */
            virtual bool isMoving(Nice::BitSet &);

            virtual bool isAtHome(Nice::BitSet &);

            virtual void setLinkTimeout(Nice::Time _tcpConnectionTimeout);
            virtual Nice::SeqTime getLinkTimeout();
            virtual Nice::NPoint getReferenceTime();
            virtual Nice::NPoint getCurrentTime();

            virtual void checkMotionError();

            virtual void startExternalProfile(
                    const Nice::Date &_startDate,
                    const Nice::NPoint &_positionSequence,
                    unsigned int /*_frequency*/,
                    unsigned int _samplesPerSegment,
                    unsigned int _faultTolerance,
                    Basda::DeviceAsync &_async = Basda::Device::s_async);

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

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

            virtual void changeExternalProfile(
                    const Nice::Date &_date,
                    const Nice::NPoint &_positionSequenceBlocks);

            void prepareExternalProfile(const Nice::SeqSeqInt &_segmentsX,
                    const Nice::SeqSeqInt &_segmentsY,
                    Basda::DeviceAsync &_async = Basda::Device::s_async);

            void startExternalProfile(Basda::DeviceAsync &_async = Basda::Device::s_async);
            void shinsStartExternalProfile(Basda::DeviceAsync &_async = Basda::Device::s_async);

            virtual Nice::SeqBitSet getPositionSwitchStatus();

            virtual void dumpStatusInformation(Basda::DeviceAsync &_asynch,
                                               bool _compareParameter = false);

            virtual Nice::Completion getProgress();

            virtual void setCollision(Nice::SeqPoint _collisions);

        protected:

            void setIsReachable(const bool _isReachable);

            void startTimer(double _distance);

            void waitInternal(const std::string _s,
                    Basda::DeviceAsync & _async);

            Nice::NPoint m_maxPosition;
            Nice::NPoint m_minPosition;
            Nice::NPoint m_maxVelocity;
            Nice::NPoint m_minVelocity;
            Nice::NPoint m_limit;

            struct PositionBlock
            {
                    PositionBlock()
                    {
                        Nice::NPoint _home(1, 0.0);
                        home = _home;
                        start = _home;
                        current = _home;
                        target = _home;
                        resolutionCmdPosToEncPos = 1;
                    }

                    PositionBlock(Nice::NPoint &_home,
                            double _resolutionCmdPosToEncPos)
                    {
                        home = _home;
                        start = _home;
                        current = _home;
                        target = _home;
                        resolutionCmdPosToEncPos =
                                _resolutionCmdPosToEncPos;
                    }
                    Nice::NPoint home;
                    Nice::NPoint start;
                    Nice::NPoint current;
                    Nice::NPoint target;
                    double resolutionCmdPosToEncPos;
            };

            PositionBlock m_commandedPosition;
            PositionBlock m_absEncPosition;
            PositionBlock m_incEncPosition;

            Nice::NPoint m_referenceTime;

            bool m_isReachable;

            // these members are needed to compute the percentage of the completion
            Nice::Timer m_timer;
            Nice::Time m_duration;

            Nice::Time m_tcpConnectionTimeout;

            //Deprecated!
            std::string m_cardNo;
            std::string m_moduleNo;
            std::string m_commandID;
            bool m_inMotion;
            Nice::Mutex m_mutex;
    };

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

