// $Id: JGSpoolDB.h,v 1.1 2003/02/09 16:16:13 fukasawa Exp $

//=============================================================================
/**
 *  @file    JGSpoolDB.h
 *
 *  @author  Fukasawa Mitsuo
 *
 *
 *    Copyright (C) 2001-2003 BEE Co.,Ltd. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */
//=============================================================================

#ifndef JGSPOOLDB_H
#define JGSPOOLDB_H

#include "JGEquipment.h"
#include "JGMemoryMappedFile.h"
#include "JGLogTime.h"
#include "BS2BlockHeader.h"

class JGEquipment;
class JGVariable;

// Spooled message header
struct SpoolBlock
{
    enum { NAME_LENGTH = 128 };

    BCHAR          m_fname[NAME_LENGTH];
    size_t         m_size;
    JGLogTime      m_time;
    BS2BlockHeader m_mhead;

    //
    SpoolBlock() { memset(m_fname, 0, NAME_LENGTH); }
    SpoolBlock(const string& fname, const JGLogTime& logtm,
               const BS2BlockHeader& mhead) {
            memmove(m_fname, fname.c_str(), min(NAME_LENGTH-1, fname.size()));
            m_fname[NAME_LENGTH-1] = '\0';
            m_time = logtm;
            m_mhead = mhead;
        }
    SpoolBlock(const string& fname, const BS2BlockHeader& mhead) {
            memmove(m_fname, fname.c_str(), min(NAME_LENGTH-1, fname.size()));
            m_fname[NAME_LENGTH-1] = '\0';
            m_mhead = mhead;
        }
    SpoolBlock(const SpoolBlock& rhs) { copy(rhs); }
    SpoolBlock& operator=(const SpoolBlock& rhs) {
            if (this == &rhs)
                return *this;
            copy(rhs);
            return *this;
        }

    void copy(const SpoolBlock& rhs) {
            memmove(m_fname, rhs.m_fname, NAME_LENGTH);
            m_time = rhs.m_time;
            m_mhead = rhs.m_mhead;
        }

    void getMessageName(string& retName) {
            retName = m_fname;
        }
    int erase() {
            m_fname[0] = '\0'; m_size = 0; return 0;
        }
    bool deleted() {
            if (ACE_OS::strlen(m_fname) == 0 || m_size == 0) {
                return true;
            }
            return false;
        }
};

//
// Layout of spooled data storage (mmap)
//
//  +-------------------------+
//  |   Revision Number       | (24 bytes)
//  +-------------------------+
//  |     Block Count         | (4 bytes)
//  +-------------------------+
//  |     Block Size          | (4 bytes)
//  +-------------------------+
//  |  Current Top Position   | (4 bytes)
//  +-------------------------+
//  |  Current End Position   | (4 bytes)
//  +-------------------------+
//  |      Current Size       | (4 bytes)
//  +-------------------------+
//  |      Overwrite          | (4 bytes)
//  +-------------------------+
//  |                         |
//  |      Block data         |
//  =     (SpoolBlock)       =
//  |                         |
//  +-------------------------+
//
#define SPOOLED_REVISION       0
#define SPOOLED_BLOCK_COUNT    24
#define SPOOLED_BLOCK_SIZE     28
#define SPOOLED_CURRENT_TOP    32
#define SPOOLED_CURRENT_END    36
#define SPOOLED_CURRENT_SIZE   40
#define SPOOLED_OVERWRITE      44

struct SpoolHeader
{
    char m_revision[24];
    int  m_blockCount;
    int  m_blockSize;
    int  m_getnum;             // top position
    int  m_putnum;             // end position
    int  m_cursize;
    int  m_overwrite;
};

#define SPOOLED_DATA_TOP       (sizeof(SpoolHeader))

//
// JGSpoolDB
//
class JGSpoolDB : public JGMemoryMappedFile
{
public:
    JGSpoolDB();
    ~JGSpoolDB() {}
    int  init(JGEquipment * equip, const string& dir, size_t maxsize, bool ow);
    void fini();
    void dump() const;

    int  put(BYTE * datap, size_t size);
    int  get(BYTE*& datap, size_t& size);
    bool overwrite() const  { return (m_shd->m_overwrite) ? true : false; }
    void overwrite(bool ow) { m_shd->m_overwrite = (ow) ? 1 : 0; }
    int  purge();
    void   decsize() { if (m_shd->m_cursize > 0) m_shd->m_cursize--; }
    size_t cursize() const { return m_shd->m_cursize; }
    size_t maxsize() const { return m_shd->m_blockCount; }
    bool full() const {
            if (m_shd->m_overwrite) {
                return false;
            } else {
               return ((m_shd->m_cursize >= m_shd->m_blockCount) ? true : false);
            }
        }

private:
    int readHeader(SpoolHeader& buf);
    int overwrite_put(BYTE * datap, size_t size);
    int sequential_put(BYTE * datap, size_t size);
    int makeSpoolBlock(int putnum, BYTE * datap, size_t size,
                       SpoolBlock * spool);

// member variables
private:
    SpoolHeader * m_shd;

    vector<SpoolBlock *> m_blockTable; // vector of blocks
    SpoolBlock * m_top;                // data top address in mmap

    ACE_Thread_Mutex     m_splock;     // mutex for spooling/spooled
};


#endif
