#ifndef DEBUGSERVICEBASE_H
#define DEBUGSERVICEBASE_H

/**
 * @file DebugServiceBase.h
 * @brief Shared base class for DebugService and WebDebugService.
 *
 * Extracts all signal-management, command-handling and config logic that is
 * common to both the TCP/UDP transport (DebugService) and the HTTP/SSE
 * transport (WebDebugService), eliminating the previous code duplication.
 */

#include "ConfigurationDatabase.h"
#include "DataSourceI.h"
#include "DebugServiceI.h"
#include "FastPollingMutexSem.h"
#include "ReferenceContainer.h"
#include "ReferenceT.h"
#include "StreamString.h"

namespace MARTe {

/**
 * @brief Intermediate base class that holds all shared debugging logic.
 *
 * Inherits from ReferenceContainer (to be a MARTe2 Object) and DebugServiceI
 * (to expose the RT-path / control-path interface).  Transport subclasses
 * (DebugService, WebDebugService) inherit from this class and add only their
 * transport-specific threading and socket logic.
 */
class DebugServiceBase : public ReferenceContainer, public DebugServiceI {
public:
    friend class DebugServiceTest;

    DebugServiceBase();
    virtual ~DebugServiceBase();

    // =========================================================================
    // DebugServiceI RT-path overrides (shared implementation)
    // =========================================================================

    virtual DebugSignalInfo *RegisterSignal(void *memoryAddress,
                                            TypeDescriptor type,
                                            const char8 *name,
                                            uint8 numberOfDimensions = 0,
                                            uint32 numberOfElements = 1);

    virtual void ProcessSignal(DebugSignalInfo *signalInfo, uint32 size,
                               uint64 timestamp);

    virtual void RegisterBroker(DebugSignalInfo **signalPointers,
                                uint32 numSignals,
                                MemoryMapBroker *broker,
                                volatile bool *anyActiveFlag,
                                Vector<uint32> *activeIndices,
                                Vector<uint32> *activeSizes,
                                FastPollingMutexSem *activeMutex,
                                volatile bool *anyBreakFlag,
                                Vector<uint32> *breakIndices,
                                const char8 *gamName = NULL_PTR(const char8 *),
                                bool isOutput = false);

    virtual bool IsPaused()      const { return isPaused; }
    virtual void SetPaused(bool paused) { isPaused = paused; }
    virtual bool IsStepPending() const { return stepRemaining > 0u; }
    virtual void ConsumeStepIfNeeded(const char8 *gamName,
                                     const char8 *threadName = NULL_PTR(const char8 *));

    // =========================================================================
    // DebugServiceI control-path overrides (shared implementation)
    // =========================================================================

    virtual uint32 ForceSignal  (const char8 *name, const char8 *valueStr);
    virtual uint32 UnforceSignal(const char8 *name);
    virtual uint32 TraceSignal  (const char8 *name, bool enable, uint32 decimation = 1);
    virtual uint32 SetBreak     (const char8 *name, uint8 op, float64 threshold);
    virtual uint32 ClearBreak   (const char8 *name);
    virtual bool   IsInstrumented(const char8 *fullPath, bool &traceable, bool &forcable);
    virtual uint32 RegisterMonitorSignal(const char8 *path, uint32 periodMs);
    virtual uint32 UnmonitorSignal      (const char8 *path);

    // =========================================================================
    // Shared control-path methods (used by transport subclasses)
    // =========================================================================

    /**
     * @brief Parse and dispatch a debug command; write text response to @p out.
     *
     * Handles: TRACE, FORCE, UNFORCE, BREAK, PAUSE, RESUME, STEP, STEP_STATUS,
     *          VALUE, DISCOVER, TREE, INFO, LS, CONFIG, MONITOR, UNMONITOR,
     *          SERVICE_INFO, MSG.
     *
     * SERVICE_INFO delegates to GetServiceInfo() so each transport can fill in
     * its own port/state information.
     */
    void HandleCommand(const StreamString &cmdIn, StreamString &out);

    void GetStepStatus(StreamString &out);
    void GetSignalValue(const char8 *name, StreamString &out);
    void Discover      (StreamString &out);
    void InfoNode      (const char8 *path, StreamString &out);
    void ListNodes     (const char8 *path, StreamString &out);
    void ServeConfig   (StreamString &out);

    void SetFullConfig(ConfigurationDatabase &config);
    void RebuildConfigFromRegistry();

    // =========================================================================
    // Struct shared by both transports
    // =========================================================================

    struct MonitoredSignal {
        ReferenceT<DataSourceI> dataSource;
        uint32 signalIdx;
        uint32 internalID;
        uint32 periodMs;
        uint64 lastPollTime;
        uint32 size;
        StreamString path;
    };

    // =========================================================================
    // Constants
    // =========================================================================

    static const uint32 GET_VALUE_MAX_ELEMENTS = 256u;

    /**
     * @brief Pre-build DISCOVER and TREE response caches.
     *
     * Called automatically by SetFullConfig() once the application is fully
     * initialised.  After this point, DISCOVER and TREE are served from the
     * pre-built string with no mutex contention and no JSON generation cost.
     * Both caches are invalidated whenever a new signal is registered (which
     * normally only happens during broker init, before SetFullConfig).
     */
    void BuildDiscoverCache();
    void BuildTreeCache();

    // Number of signals per DISCOVER_PART TCP chunk.  Responses larger than
    // this are split so the Go client can start parsing immediately.
    static const uint32 DISCOVER_CHUNK_SIGNALS = 256u;

protected:
    // =========================================================================
    // Virtual hooks for transport subclasses
    // =========================================================================

    /**
     * @brief Fill the SERVICE_INFO response text (transport-specific).
     *
     * Called by HandleCommand when the SERVICE_INFO command is received.
     * The base implementation writes nothing; subclasses override to append
     * e.g. "OK SERVICE_INFO TCP_CTRL:8080 UDP_STREAM:8081 STATE:RUNNING\n".
     */
    virtual void GetServiceInfo(StreamString &out) = 0;

    /**
     * @brief Write back transport-specific config keys after RebuildConfigFromRegistry().
     *
     * Called at the end of RebuildConfigFromRegistry() so that port numbers
     * and other transport parameters that were read in Initialise() are
     * reflected back into fullConfig (ExportData on ReferenceContainers
     * doesn't re-emit config-file parameters).
     */
    virtual void RebuildTransportConfig() {}

    // =========================================================================
    // Shared protected helpers
    // =========================================================================

    void Step(uint32 n, const char8 *threadName = NULL_PTR(const char8 *));
    void UpdateBrokersActiveStatus();
    void UpdateBrokersBreakStatus();
    void PatchRegistry();

    uint32 ExportTree(ReferenceContainer *container, StreamString &json,
                      const char8 *pathPrefix);
    void   ExportTreeNode(const char8 *path, StreamString &out);
    void   EnrichWithConfig(const char8 *path, StreamString &json);
    static void JsonifyDatabase(ConfigurationDatabase &db, StreamString &json);

    // =========================================================================
    // Shared data members
    // =========================================================================

    Vector<DebugSignalInfo *> signals;
    Vector<SignalAlias>       aliases;
    Vector<BrokerInfo>        brokers;
    Vector<MonitoredSignal>   monitoredSignals;

    FastPollingMutexSem mutex;
    FastPollingMutexSem tracePushMutex;
    TraceRingBuffer     traceBuffer;

    volatile bool    isPaused;
    volatile uint32  stepRemaining;
    StreamString     pausedAtGam;
    StreamString     stepThreadFilter;

    ConfigurationDatabase fullConfig;
    bool manualConfigSet;

    // Pre-built response caches.  Guarded by mutex (brief lock for swap,
    // none needed for reads once cacheValid is true and construction is done).
    StreamString  discoverCache;   // full chunked DISCOVER_PART+DISCOVER payload
    StreamString  treeCache;       // full TREE payload including sentinel
    volatile bool discoverCacheValid;
    volatile bool treeCacheValid;
};

} // namespace MARTe

#endif // DEBUGSERVICEBASE_H
