/*!
 * \file ClientAPIForMathPluginManagement.h
 *
 * \author Roger James
 * \date 13th November 2013
 *
 */

#pragma once

#include "basedevice.h"
#include "baseclient.h"

#include <string>
#include <vector>
#include <pthread.h>

namespace INDI
{
namespace AlignmentSubsystem
{
/*!
 * \class ClientAPIForMathPluginManagement
 * \brief This class provides the client API for driver side math plugin management. It communicates
 * with the driver via the INDI properties interface.
 */
class ClientAPIForMathPluginManagement
{
    public:
        /// \brief Virtual destructor
        virtual ~ClientAPIForMathPluginManagement() {}

        typedef std::vector<std::string> MathPluginsList;

        // Public methods

        /*!
             * \brief Return a list of the names of the available math plugins.
             * \param[out] AvailableMathPlugins Reference to a list of the names of the available math plugins.
             * \return False on failure
             */
        bool EnumerateMathPlugins(MathPluginsList &AvailableMathPlugins);

        /// \brief Initialise the API
        /// \param[in] BaseClient Pointer to the INDI:BaseClient class
        void Initialise(INDI::BaseClient *BaseClient);

        /** \brief Process new device message from driver. This routine should be called from within
             the newDevice handler in the client. This routine is not normally called directly but is called by
             the ProcessNewDevice function in INDI::Alignment::AlignmentSubsystemForClients which filters out calls
             from unwanted devices. TODO maybe hide this function.
                \param[in] DevicePointer A pointer to the INDI::BaseDevice object.
            */
        void ProcessNewDevice(INDI::BaseDevice *DevicePointer);

        /** \brief Process new property message from driver. This routine should be called from within
             the newProperty handler in the client. This routine is not normally called directly but is called by
             the ProcessNewProperty function in INDI::Alignment::AlignmentSubsystemForClients which filters out calls
             from unwanted devices. TODO maybe hide this function.
                \param[in] PropertyPointer A pointer to the INDI::Property object.
            */
        void ProcessNewProperty(INDI::Property *PropertyPointer);

        /** \brief Process new switch message from driver. This routine should be called from within
             the newSwitch handler in the client. This routine is not normally called directly but is called by
             the ProcessNewSwitch function in INDI::Alignment::AlignmentSubsystemForClients which filters out calls
             from unwanted devices. TODO maybe hide this function.
                \param[in] SwitchVectorProperty A pointer to the INDI::ISwitchVectorProperty.
            */
        void ProcessNewSwitch(ISwitchVectorProperty *SwitchVectorProperty);

        /*!
             * \brief Selects, loads and initialises the named math plugin.
             * \param[in] MathPluginName The name of the required math plugin.
             * \return False on failure.
             */
        bool SelectMathPlugin(const std::string &MathPluginName);

        /*!
             * \brief Re-initialises the current math plugin.
             * \return False on failure.
             */
        bool ReInitialiseMathPlugin();

    private:
        // Private methods

        bool SetDriverBusy();
        bool SignalDriverCompletion();
        bool WaitForDriverCompletion();

        // Private properties

        INDI::BaseClient *BaseClient;
        pthread_cond_t DriverActionCompleteCondition;
        pthread_mutex_t DriverActionCompleteMutex;
        bool DriverActionComplete;
        INDI::BaseDevice *Device;
        INDI::Property *MathPlugins;
        INDI::Property *PluginInitialise;
};

} // namespace AlignmentSubsystem
} // namespace INDI
