/*! \file
Project: Device Interface 

 \copyright © 2000,2001,2002,2003 All Rights Reserved.

 SYSTEM:       DVS Type Level

 SUBSYSTEM:    Generic Dvs Type

 FILE:         DvsArchive.cpp

 \author       Gerald P. Wilson


  OVERVIEW
  ========

    This file contains the base implementation of the 
    DVS archive commend set.
     

  HISTORY
  ========
    
    17Mar03  wilson  Created

*/

/* Includes */
#include "DvsArchive.h"





/*! \fn DvsArchiveCmdDataEle::DvsArchiveCmdDataEle(void)
 *  \brief Constructor.
 *
 */
DvsArchiveCmdDataEle::DvsArchiveCmdDataEle(void)
{
    Clear();
}



/*! \fn void  DvsArchiveCmdDataEle::Clear(void)
 *  \brief Clear out old clip and operation data.
 *
 *   Renders the element unusable as a command (can't be mistaken for valid command)
 */
void  DvsArchiveCmdDataEle::Clear(void)
{
    valid = FALSE;
    memset(&info, 0, sizeof(ARCHIVE_CMD_DATA_ST));
    info.state = JOB_UDEF;
    info.op = NO_ARCHV_OP;
}

/*! \fn void  DvsArchiveCmdDataEle::operator = (ARCHIVE_CMD_DATA_ST& rData)
 *  \brief Copy Archive Data.
 *
 *  \param rData reference to a ARCHIVE_CMD_DATA_ST data source
 *
 *   Copies reference data to object and validates.
 */
void  DvsArchiveCmdDataEle::operator = (ARCHIVE_CMD_DATA_ST& rData)
{
    memcpy(&info, &rData, sizeof(ARCHIVE_CMD_DATA_ST));
    Validate();
}


/*! \fn void  DvsArchiveCmdDataEle::operator = (DvsArchiveCmdDataEle& rEle)
 *  \brief Copy constructor.
 *
 *  \param rEle reference to a DvsArchiveCmdDataEle source
 *
 *   Copies reference object to object
 */
void  DvsArchiveCmdDataEle::operator = (DvsArchiveCmdDataEle& rEle)
{
    if (&rEle != this)
    {
        valid = rEle.valid;
        info = rEle.info;
    }
}


/*! \fn bool  DvsArchiveCmdDataEle::Validate(void)
 *  \brief Non-authorative validation of object data.
 *
 *   Just verifies that the data is not blank but does no checking
 *   for valid data.
 */
bool  DvsArchiveCmdDataEle::Validate(void)
{
    valid = TRUE;
    if ((info.op == NO_ARCHV_OP) ||
        (strlen(info.src) == 0)  ||
        (strlen(info.dest) == 0) ||
        (strlen(info.clip.name) == 0))
    {
        valid = FALSE;
    }
    
    return valid;
}



/*! \fn void DvsArchiveCmdDataEle::IfJobId(int id)
 *  \brief Set Interface Job Id.
 *
 *  \param id  A number generated by the interface to uniquely 
 *             identify this job
 */
void DvsArchiveCmdDataEle::IfJobId(int id)
{
    info.ifJobId = id;
    info.valid |= IF_JOB_ID;     
}


/*! \fn void DvsArchiveCmdDataEle::DevioJobId(int id)
 *  \brief Set DevIo assigned Job Id.
 *
 *  \param id  A number generated by the Device I/O module 
 *             to uniquely identify this job
 */
void DvsArchiveCmdDataEle::DevioJobId(int id)
{
    info.devioJobId = id;
    info.valid |= DEVIO_JOB_ID;     
}


/*! \fn void DvsArchiveCmdDataEle::DeviceJobId(int id)
 *  \brief Set Device assigned Job Id.
 *
 *  \param id  A number generated by the controlled Device 
 *             to uniquely identify this job
 */
void DvsArchiveCmdDataEle::DeviceJobId(int id)
{
    info.deviceJobId.number = id;
    info.valid |= DEV_JOB_ID;
    info.deviceJIdNum = TRUE;
}


/*! \fn void DvsArchiveCmdDataEle::Op(DvsArchiveCmdOpEtype op)
 *  \brief Set archive job operation code.
 *
 *  \param op  A DvsArchiveCmdOpEtype specifying the desired operation
 *             Operation enums defined in DvsArchiveExt.h
 *   
 *   Sets the op member of object data.
 *   
 *   Type of argument assures a valid code.
 */
void DvsArchiveCmdDataEle::Op(DvsArchiveCmdOpEtype op)
{
    info.op = op;
    info.valid |= OP_INFO_ID;     
}


/*! \fn void DvsArchiveCmdDataEle::Source(const String host)
 *  \brief Set host name.
 *
 *  \param host The host name in the form of a String object
 *
 *   Copies a host name into the src member of object data
 *   The contents of host argument is not altered
 */
void DvsArchiveCmdDataEle::Source(const String host)
{
    memset(&info.src, 0, HOST_NAME_LEN);
    strncpy(info.src, (char*)*host, HOST_NAME_LEN);
    info.src[HOST_NAME_LEN] = '\0';
    info.valid |= SRC_ID;     
}


/*! \fn void DvsArchiveCmdDataEle::Source(const char* pHost)
 *  \brief Set host name.
 *
 *  \param host The host name in the form of a pointer to a character string
 *
 *   Copies a pHost name into the src member of object data
 *   The contents of pHost argument is not altered
 */
void DvsArchiveCmdDataEle::Source(const char* pHost)
{
    memset(&info.src, 0, HOST_NAME_LEN);
    strncpy(info.src, pHost, HOST_NAME_LEN);
    info.src[HOST_NAME_LEN] = '\0';
    info.valid |= SRC_ID;     
}


/*! \fn void DvsArchiveCmdDataEle::Destination(const String host)
 *  \brief Set host name.
 *
 *  \param host The host name in the form of a String object
 *
 *   Copies a host name into the dest member of object data
 *   The contents of host argument is not altered
 */
void DvsArchiveCmdDataEle::Destination(const String host)
{
    memset(&info.dest, 0, HOST_NAME_LEN);
    strncpy(info.dest, (char*)*host, HOST_NAME_LEN);
    info.dest[HOST_NAME_LEN] = '\0';
    info.valid |= DEST_ID;     
}


/*! \fn void DvsArchiveCmdDataEle::Destination(const char* pHost)
 *  \brief Set host name.
 *
 *  \param host The host name in the form of a pointer to a character string
 *
 *   Copies a pHost name into the dest member of object data
 *   The contents of pHost argument is not altered
 */
void DvsArchiveCmdDataEle::Destination(const char* pHost)
{
    memset(&info.dest, 0, HOST_NAME_LEN);
    strncpy(info.dest, pHost, HOST_NAME_LEN);
    info.dest[HOST_NAME_LEN] = '\0';
    info.valid |= DEST_ID;     
}


/*! \fn int DvsArchiveCmdDataEle::IfJobId(void) const
 *  \brief Get Interface job id.
 *
 *  \return Interface job id
 *          L_EPARM  if IF_JOB_ID bit not set in valid bitmap
 */
int DvsArchiveCmdDataEle::IfJobId(void) const
{
    if (ValidIfJobId())
        return info.ifJobId;
    else
        return L_EPARM;
}


/*! \fn int DvsArchiveCmdDataEle::DevioJobId(void) const
 *  \brief Get DevIo job id.
 *
 *  \return DevIo job id
 *          L_EPARM  if DEVIO_JOB_ID bit not set in valid bitmap
 */
int DvsArchiveCmdDataEle::DevioJobId(void) const
{
    if (ValidDevioJobId())
        return info.devioJobId;
    else
        return L_EPARM;
}


/*! \fn int DvsArchiveCmdDataEle::DeviceJobId(void) const
 *  \brief Get Device job id.
 *
 *  \return Device job id
 *          L_EPARM  if DEV_JOB_ID bit not set in valid bitmap or
 *                   the device id is a string.
 */
int DvsArchiveCmdDataEle::DeviceJobId(void) const
{
    if (ValidDeviceJobId() && DeviceJobIdIsNum())
        return info.deviceJobId.number;
    else
        return L_EPARM;
}


/*! \fn const char* DvsArchiveCmdDataEle::DeviceJobIdStr(void) const
 *  \brief Get Device job id string.
 *
 *  \return DevIo job id
 *          NULL  if DEV_JOB_ID bit not set in valid bitmap or
 *                   the device id is not a string.
 */
const char* DvsArchiveCmdDataEle::DeviceJobIdStr(void) const
{
    if (ValidDeviceJobId() && (!DeviceJobIdIsNum()))
        return info.deviceJobId.string;
    else
        return NULL;
}


/*! \fn int DvsArchiveCmdDataEle::Op(void)
 *  \brief Get archive job code.
 *
 *  \return The op member of object data.
 *          L_EPARM  if OP_INFO_ID bit not set in valid bitmap
 *   
 *  \note Return type is int.
 */
int DvsArchiveCmdDataEle::Op(void) const
{
    if (ValidOpCode())
        return info.op;
    else
        return L_EPARM;
}


/*! \fn const char* DvsArchiveCmdDataEle::Src(void) const
 *  \brief Get source device name.
 *
 *  \return Source device name
 *          NULL  if SRC_ID bit not set in valid bitmap
 */
const char* DvsArchiveCmdDataEle::Src(void) const
{
    if (ValidSrc())
        return info.src;
    else
        return NULL;
}


/*! \fn const char* DvsArchiveCmdDataEle::Dest(void) const
 *  \brief Get destination device name.
 *
 *  \return Destination device name
 *          NULL  if DEST_ID bit not set in valid bitmap
 */
const char* DvsArchiveCmdDataEle::Dest(void) const
{
    if (ValidDest())
        return info.dest;
    else
        return NULL;
}


/*! \fn const char* DvsArchiveCmdDataEle::Status(void) const
 *  \brief Get status string.
 *
 *  \return Status string
 *          NULL  if STATUS_MSG_ID bit not set in valid bitmap
 */
const char* DvsArchiveCmdDataEle::Status(void) const
{
    if (ValidStatus())
        return info.status;
    else
        return NULL;
}


/*! \fn const char* DvsArchiveCmdDataEle::Msg(void) const
 *  \brief Get generic message string.
 *
 *  \return Generic message string
 *          NULL  if GENERIC_MSG_ID bit not set in valid bitmap
 */
const char* DvsArchiveCmdDataEle::Msg(void) const
{
    if (ValidStatus())
        return info.msg;
    else
        return NULL;
}










/*! \fn DvsArchiveCmdList::DvsArchiveCmdList(int num_ele)
 *  \brief Constructor.
 *
 */
DvsArchiveCmdList::DvsArchiveCmdList(int num_ele, int lim)
      : list(num_ele), valid(FALSE), opid(1), no_active(0),
        pActive(NULL), ecount(num_ele), limit(0)
{
    // Is the Queue OK?
    if (!list)
/*<--*/ return;
    
   /*
    *  Enable the high water mark so we can see if ecount was
    *  a good guess.
    */
    list.EnableHWM();
    
    limit = lim;
    if (limit)
    {
        pActive = new AllocEle::EleSt*[limit];
        if (pActive != NULL)
        {
            for (int i=0; i::EleSt*[limit];
        if (pActive != NULL)
        {
            for (int i=0; i::EleSt *pEle = list.NewEle();

    if (pEle == NULL)
/*<--*/ return L_EMEM;

    // Initialize the embedded class
    pEle->item.Clear();
    pEle->item = rData;
    if (pEle->item.Valid())
    {
        pEle->hdr.id = opid++;

        // Put it in the queue
        list.Put(pEle);
/*<--*/ return pEle->hdr.id;
    }
    else
    {
        returnEle(pEle);
        return L_EPARM;
    }
}    
    

/*! \fn int DvsArchiveCmdList::Delete(int id)
 *  \brief Delete an archive job.
 *
 *  \param id - The id of job to delete
 *
 *  \return
 *     SUCCESS - Job deleted
 *     L_EPARM - Job not found
 */
int DvsArchiveCmdList::Delete(int id)
{
    AllocEle::EleSt *pEle = list.EachEle();
    while(pEle)
    {
        if (pEle->hdr.id == id)
        {
            // RETURN THE ITEM TO THE POOL!
            returnEle(pEle);
/*<--*/     return SUCCESS;
        }
        pEle = list.NextEle(pEle);
    }
    return L_EPARM;
}



/*! \fn ArchiveDataEle& DvsArchiveCmdList::Find(int id)
 *  \brief Find an archive job.
 *
 *  \param id - The id of job to find
 *
 *  \return 
 *      reference to job if found
 *      reference to default empty job
 */
DvsArchiveCmdDataEle& DvsArchiveCmdList::Find(int id)
{
    AllocEle::EleSt *pEle = list.EachEle();
    while(pEle)
    {
        if (pEle->hdr.id == id)
/*<--*/     return pEle->item;
        pEle = list.NextEle(pEle);
    }
    
    return notFound;
}    
    
    
/*! \fn int DvsArchiveCmdList::Find(ARCHIVE_CMD_DATA_ST& id)
 *  \brief Find an archive job.
 *
 *  \param id - A reference to a ArchiveDataEle to match
 *
 *  \return 
 *      int     - The id of the job
 *      L_EFAIL - Job not found
 */
int DvsArchiveCmdList::Find(ARCHIVE_CMD_DATA_ST& info)
{
    AllocEle::EleSt *pEle = list.EachEle();
    while(pEle)
    {
        ARCHIVE_CMD_DATA_ST *pData = (ARCHIVE_CMD_DATA_ST*)&pEle->item;
        if ((info.op == pData->op) &&
            (strcmp(info.src, pData->src) == 0)  &&
            (strcmp(info.dest, pData->dest) == 0) &&
            (strcmp(info.clip.name, pData->clip.name) == 0))
        {
/*<--*/     return pEle->hdr.id;
        }
        pEle = list.NextEle(pEle);
    }
    
    return L_EFAIL;
}    
    


/*! \fn DvsArchiveCmdDataEle* DvsArchiveCmdList::NextOp(void)
 *  \brief Return a pointer to cmd data if conditions permit.
 *
 *   If the number of operations in progress is less than the limit,
 *   and if there are operations in the queue, dequeue the next 
 *   operation and return a opinter to the data. 
 *
 *   \note REMEMBER to call CompleteOp() when the operation is complete.
 *
 *   \return pointer to data if operation is ready
 *           NULL if number of operations in progress is max or 
 *                queue is empty.
 */
AllocEle::EleSt* DvsArchiveCmdList::NextOp(void)
{
    AllocEle::EleSt *pData = NULL;
    
    if (no_active < limit)
    {
        AllocEle::EleSt *pEle = list.GetNext();
        if (pEle != NULL)
        {
            no_active++;
            AllocEle::EleSt **pPending = pActive;
            while(*pPending != NULL) pPending++;
            *pPending = pEle;
            pData = *pPending;
        }
    }
    
    return pData;
}



/*! \fn DvsArchiveCmdDataEle* DvsArchiveCmdList::NextOp(void)
 *  \brief Return a pointer to cmd data if conditions permit.
 *
 *   If the number of operations in progress is less than the limit,
 *   and if there are operations in the queue, dequeue the next 
 *   operation and return a opinter to the data. 
 *
 *   \note REMEMBER to call CompleteOp() when the operation is complete.
 *
 *   \return pointer to data if operation is ready
 *           NULL if number of operations in progress is max or 
 *                queue is empty.
 */
void DvsArchiveCmdList::CompleteOp(AllocEle::EleSt* op)
{
    AllocEle::EleSt **pPending = pActive;
    for(int i=0; i < limit; i++)
    {
        if (*pPending == op)
        {
            list.ReturnEle(*pPending);
            *pPending = NULL;
            return;
        }
        pPending++;
    }
}



/*! \fn AllocEle::EleSt* DvsArchiveCmdList::ActiveOp(int i)
 *  \brief Get a pointer to an active operation data.
 *
 *  \param i an index to use to search the active operation array
 *
 *   If the entry in the array of operations is not NULL, return the 
 *   pointer to the data. 
 *
 *   \return pointer to data if present
 *           NULL if empty.
 */
AllocEle::EleSt* DvsArchiveCmdList::ActiveOp(int i)
{
    return pActive[i];
}
             



/*! \fn void DvsArchiveCmdList::returnEle(AllocEle::EleSt *pDeleted)
 *  \brief Private resource management.
 *
 *   The DvsArchiveCmdList constructor allocates a number of elements which are 
 *   made available for use/reuse. As elements are used, they MUST be returned 
 *   to the pool. 
 *
 *   \note REMEMBER, the list will allocate elements as needed. If you
 *   don't return used elements, a memory leak will result.
 */
void DvsArchiveCmdList::returnEle(AllocEle::EleSt *pDeleted)
{
    // Clear out old data before returning element 
    pDeleted->hdr.id = 0;
    pDeleted->item.Clear();
    list.ReturnEle(pDeleted);
}