// snfXCImgr.hpp
// Copyright (C) 2007 - 2009 ARM Research Labs, LLC.
// See www.armresearch.com for the copyright terms.
// XML Command Interface manager.
// This module uperates a TCP server to accept requests for scans, GBUdb
// operations, etc on behalf of an snf_EngineHandler.

#ifndef included_snfXCImgr_hpp
#define included_snfXCImgr_hpp

#include <string>
#include <queue>
#include "timing.hpp"
#include "threading.hpp"
#include "networking.hpp"
#include "snf_xci.hpp"

using namespace std;

// We need to know these exist ;-)

class snf_RulebaseHandler;                                                      // These exist.
class snf_EngineHandler;                                                        // These exist.

// Handy references and "standards"

static const string XCIErrorResponse =                                          // Unrecognized request error.
  "<snf><xci><error message=\'What was that?\'/></xci></snf>\n";

static const string XCIBadSetResponse =                                         // Empty GBUdb set command error.
  "<snf><xci><error message=\'No changes in set. Use test!\'/></xci></snf>\n";

// snfXCIServerCommandHandler Base Class for Server Command Processing.

class snfXCIServerCommandHandler {                                              // Server Command Handler Base Class.
  public:
    virtual string processXCIRequest(snf_xci& X);                               // Server provides a useful processor.
};

// snfXCIJob encapsulates a single XCI transaction.

class snfXCIJob {                                                               // Job Packet.
  public:
    string Request;                                                             // XCI formatted request.
    string Response;                                                            // XCI formatted response.
    int SetupTime;                                                              // Setup time so far in ms.
    void clear();                                                               // Clear the buffers.
};

// snfXCIJobProcessor encapsulates the logic to respond to an XCI request.

class snfXCIJobProcessor {                                                      // XCI job processor.
  private:
    snf_xci myXCI;                                                              // XCI interpreter.
    snf_RulebaseHandler* myHome;                                                // Rulebase to use.
    snf_EngineHandler* myEngine;                                                // Scanner (set up internally).

    bool isScanJob();                                                           // True if myXCI is a scan job.
    bool isGBUdbJob();                                                          // True if myXCI is a GBUdb job.
    bool isReportJob();                                                         // True if myXCI is a Report job.
    bool isCommandJob();                                                        // True if myXCI is a Command job.
    void processScan(snfXCIJob& J);                                             // Process a scan request.
    string processGBUdb();                                                      // Process a GBUdb request.
    string processStatusReport();                                               // Process a report request.

  public:
    snfXCIJobProcessor(snf_RulebaseHandler* H);                                 // Setup scanner.
    ~snfXCIJobProcessor();                                                      // Tear down scanner.
    void process(snfXCIJob& J);                                                 // Process a Job.
};

// ChannelJob encapsulates a Client Job while in the queue and how long it has
// been in the system (since created).

class ChannelJob {                                                              // Wraper for job queue.
  private:
    TCPClient* myClient;                                                        // We have a TCPClient.
    Timer Lifetime;                                                             // We have a timer.

  public:
    ChannelJob();                                                               // We can be blank but usually
    ChannelJob(TCPClient* C);                                                   // we are created like this.
    msclock Age();                                                              // How old is this job?
    TCPClient* Client();                                                        // What client does it hold?
};

// snfXCITCPChannel encapsulates the logic to queue and handle TCPClients for
// the XCI interface. The queued TCPClients each represent a single request.
// Each request is handled in turn by reading the request into an snfXCIJob,
// handing that snfXCIJob to an snfXCIJobProcessor, transmitting the result
// back to the TCPClient, closing the connection, and recycling the snfXCIJob
// object for the next round.

// snfXCITCPChannel shuts down when given a NULL TCPClient; This allows any
// jobs in queue to be handled before the thread stops. To shut down a channel
// { C->submit(NULL); C->join(); delete C; C = NULL;}

const int LineBufferSize = 256;                                                 // Line buffer size.

class snfXCITCPChannel : private Thread {                                       // TCPClient processor & queue.
  private:

    snf_RulebaseHandler* myHome;                                                // Rulebase handler.

    snfXCIJobProcessor Processor;                                               // XCI processor.
    snfXCIJob Job;                                                              // XCI Job buffer.

    volatile int LatestSize;                                                    // Queue Size Blinking Light.
    Mutex QueueMutex;                                                           // Serializes queue changes.
    ProductionGateway QueueGateway;                                             // Keeps track of give and take.
    queue<ChannelJob> JobQueue;                                                 // Queue of clients.
    void give(ChannelJob& J);                                                   // give a client to the queue.
    ChannelJob take();                                                          // take a client from the queue.

    char LineBuffer[LineBufferSize];                                            // Read Line Buffer.
    void readRequest(TCPClient* Client);                                        // Read Job.Request from Client.
    void writeResponse(TCPClient* Client);                                      // Write Job.Request from Client.

    void myTask();                                                              // Thread's main loop.

  public:

    snfXCITCPChannel(snf_RulebaseHandler* H, string N);                         // Create these with a home rulebase.
    ~snfXCITCPChannel();                                                        // Destroy them very carefully.
    int Size();                                                                 // Keep track of how full they are.
    void submit(TCPClient* C);                                                  // This is how we submit jobs.

    const static ThreadType Type;                                               // The thread's type.

    const static ThreadState XCI_Wait;
    const static ThreadState XCI_Read;
    const static ThreadState XCI_Process;
    const static ThreadState XCI_Write;
    const static ThreadState XCI_Close;
    const static ThreadState XCI_Clear;
    const static ThreadState XCI_Shutdown;

    //const static ThreadState ThreadInitialized;                                 // Constructed successfully.
};

// snfXCImgr encapsulates a service engine that takes XCI requests via TCP,
// performs the required actions, and returns an XCI response. It also checks
// to see if the configuration for the XCI interface has changed.

class snfXCImgr : private Thread {                                              // XCI manager.
  private:

    Mutex ChannelMutex;                                                         // Safety Channel Up/Down events.

    bool CFG_XCI_ON;                                                            // Is XCI turned on?
    int CFG_XCI_PORT;                                                           // What port we listen to?
    void checkCFG();                                                            // Checks the configuration.

    snf_RulebaseHandler* myHome;                                                // Rulebase handler to service.
    snfXCITCPChannel* C0;                                                       // XCI channel 0
    snfXCITCPChannel* C1;                                                       // XCI channel 1
    snfXCITCPChannel* C2;                                                       // XCI channel 2
    snfXCITCPChannel* C3;                                                       // XCI channel 3
    snfXCITCPChannel* BestAvailableChannel();                                   // Selects XCI channel w/ lowest queue.

    TCPListener* Listener;                                                      // XCI Listener.

    bool XCI_UP;                                                                // True if XCI is alive.
    void startup_Listener();                                                    // Listener startup function.
    void shutdown_Listener();                                                   // Listener shutdown function.
    void startup_XCI();                                                         // XCI startup function.
    void shutdown_XCI();                                                        // XCI shutdown function.

    bool TimeToStop;                                                            // True when shutting down.
    void myTask();                                                              // Main thread task.

    volatile int diagLoopCount;
    volatile int diagClientCount;

  public:

    snfXCImgr();                                                                // Construct with no home.
    ~snfXCImgr();                                                               // Destroy to shut down.

    void linkHome(snf_RulebaseHandler* Home);                                   // Link to Home and set up shop.
    int TotalQueue();                                                           // Return the total work queue size.
    void stop();                                                                // Called to shut down.

    int pollLoopCount();                                                        // Get diagnostic loop count.
    int pollClientCount();                                                      // Get diagnostic client count.

    const static ThreadType Type;                                               // The thread's type.

    const static ThreadState XCI_InitialConfig;                                 // Getting initial configuration.
    const static ThreadState XCI_InitialStartup;                                // Performing first startup.
    const static ThreadState XCI_CheckConfig;                                   // Checking configuration.
    const static ThreadState XCI_PollingListener;                               // Polling Listener for jobs.
    const static ThreadState XCI_SubmittingJob;                                 // Submitting a new job.
    const static ThreadState XCI_ListenerDown;                                  // Listener is down.
    const static ThreadState XCI_Stopping;                                      // XCImgr Exiting Big Loop

};

#endif
