// $Id: MELXmlParser.h,v 1.4 2003/03/19 16:49:24 fukasawa Exp $

//=============================================================================
/**
 *  @file    MELXmlParse.h
 *
 *  @author  Fukasawa Mitsuo
 *
 *
 *    Copyright (C) 2001-2002 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 MELXMLPARSER_H
#define MELXMLPARSER_H

#include "ace/streams.h"
#include "ace/OS.h"
#include <string>
#include <vector>
using namespace std;
#include "xercesc/util/PlatformUtils.hpp"
#include "xercesc/util/XMLString.hpp"
#include "xercesc/util/XMLUniDefs.hpp"
#include "xercesc/dom/DOMException.hpp"
#include "xercesc/parsers/XercesDOMParser.hpp"
#include "xercesc/dom/DOM.hpp"
#include "MELMemory.h"
#if _XERCES_VERSION >= 20200              // version-2.2.0 support namespace
using namespace XERCES_CPP_NAMESPACE;
#endif

typedef XercesDOMParser  DOMParser;

//-----------------------------------------------------------------------------
// Difinition of reading block infomation.
//-----------------------------------------------------------------------------
struct MelReadBlock
{
    PLCDevice * m_plc;
    long      m_top;
    size_t    m_datalen;
    u_short * m_bufp;
    size_t    m_words;

    MelReadBlock() : m_plc(NULL), m_top(0), m_datalen(0), m_bufp(NULL),
                     m_words(0) {}
    MelReadBlock(PLCDevice * plc) : m_plc(plc), m_top(0), m_bufp(NULL) {
            m_datalen = plc->size(); m_words = plc->words();
        }
    MelReadBlock(const MelReadBlock& rhs) {
            m_plc = rhs.m_plc; m_top = rhs.m_top;
            m_bufp = rhs.m_bufp;
            const_cast<MelReadBlock&>(rhs).m_bufp = NULL;
            m_datalen = rhs.m_datalen; m_words = rhs.m_words;
        }
    ~MelReadBlock() {}

    MelReadBlock operator=(const MelReadBlock& rhs) {
            if (this == &rhs)
                return *this;
            m_plc = rhs.m_plc; m_top = rhs.m_top;
            m_bufp = rhs.m_bufp;
            const_cast<MelReadBlock&>(rhs).m_bufp = NULL;
            m_datalen = rhs.m_datalen; m_words = rhs.m_words;
            return *this;
        }
};

//-----------------------------------------------------------------------------
struct MelReadBlocks
{
    bool     m_multi;               // As true, blocks are multi-device
    size_t   m_words;               //
    u_short * m_buftop;
    vector<MelReadBlock> m_blocks;

    MelReadBlocks() : m_multi(true), m_words(0), m_buftop(NULL) {}
    MelReadBlocks(const MelReadBlocks& rhs) {
            m_multi = rhs.m_multi;
            m_blocks = rhs.m_blocks;
            m_buftop = rhs.m_buftop;
            const_cast<MelReadBlocks&>(rhs).m_buftop = NULL;
            m_words = rhs.m_words;
        }
    ~MelReadBlocks() {
            if (m_buftop != NULL)
                free(m_buftop);
        }

    MelReadBlocks& operator=(const MelReadBlocks& rhs) {
            if (this == &rhs)
                return *this;
            m_multi = rhs.m_multi;
            m_blocks = rhs.m_blocks;
            m_buftop = rhs.m_buftop;
            const_cast<MelReadBlocks&>(rhs).m_buftop = NULL;
            m_words = rhs.m_words;
            return *this;
        }

};

//-----------------------------------------------------------------------------
// Definition of MELSEC Register.
//-----------------------------------------------------------------------------
struct MelsecMemoryInfo
{
    ACE_TCHAR m_name[16];
    int    m_memtype;
    int    m_devcode;
    size_t m_maxsize;
    size_t m_size;

//
    MelsecMemoryInfo(): m_memtype(0), m_devcode(0), m_maxsize(0), m_size(0) {
            m_name[0] = '\0';
        }
    MelsecMemoryInfo(const MelsecMemoryInfo& rhs) {
            m_memtype = rhs.m_memtype;
            memmove(m_name, rhs.m_name, sizeof(m_name));
            m_devcode = rhs.m_devcode;
            m_maxsize = rhs.m_maxsize;
            m_size = rhs.m_size;
        }
    ~MelsecMemoryInfo() {}
    MelsecMemoryInfo& operator=(const MelsecMemoryInfo& rhs) {
            if (this == &rhs)
                return *this;
            m_memtype = rhs.m_memtype;
            memmove(m_name, rhs.m_name, sizeof(m_name));
            m_devcode = rhs.m_devcode;
            m_maxsize = rhs.m_maxsize;
            m_size = rhs.m_size;
            return *this;
        }

    size_t nameq() { return sizeof(m_name); }
};


//-----------------------------------------------------------------------------
// XML parser class which defined MELSEC registers.
//-----------------------------------------------------------------------------
class BEE_Export MELXmlParser
{
    friend class MELDeviceManager;
    friend class MELDeviceServer;

public:
    MELXmlParser(const char * xmlFile = NULL) : m_cycle(10) {
            m_xmlFile = (xmlFile == NULL) ? "" : xmlFile;
        }
    ~MELXmlParser() {}

    int init(const char * xmlFile = NULL);
    int fini();
    int parse(MELDeviceManager * melmngr);
    int cycle() { return m_cycle; }

    static MELXmlParser * instance();

protected:
    int parseElements(MELDeviceManager * melmngr, DOMNode * node);
    int parseDevicesElm(DOMNode * node);
    int parseDeviceElement(DOMNode * node);
    int parseCycleElement(DOMNode * node);
    int parseLogSizeElement(DOMNode * node, MelsecMemoryInfo& melmem);
    int parseReadBlocksElm(DOMNode * node);
    int parseReadBlockElm(DOMNode * node, MelReadBlocks& readBlock,
                          int& maxblock);
    int parseReadDeviceElm(DOMNode * node, MelReadBlock& rblocks);

// member variables
protected:
    string m_xmlFile;
    int    m_cycle;

    vector<MelsecMemoryInfo> m_melsecs;
    vector<MelReadBlocks>    m_readers;
};


// ---------------------------------------------------------------------------
//  This is a simple class that lets us do easy (though not terribly efficient)
//  trancoding of XMLCh data to local code page for display.
// ---------------------------------------------------------------------------
#ifndef DEFINED_STRX
#define DEFINED_STRX

class StrX
{
public :
    // -----------------------------------------------------------------------
    //  Constructors and Destructor
    // -----------------------------------------------------------------------
    StrX(const XMLCh* const toTranscode)
    {
        // Call the private transcoding method
        fLocalForm = XMLString::transcode(toTranscode);
    }

    ~StrX()
    {
        delete [] fLocalForm;
    }


    // -----------------------------------------------------------------------
    //  Getter methods
    // -----------------------------------------------------------------------
    const char* localForm() const
    {
        return fLocalForm;
    }

private :
    // -----------------------------------------------------------------------
    //  Private data members
    //
    //  fLocalForm
    //      This is the local code page form of the string.
    // -----------------------------------------------------------------------
    char*   fLocalForm;
};

inline bool operator==(const char * s, const StrX& token)
{
    return (strcmp(token.localForm(), s) == 0);
}

inline bool operator!=(const char * s, const StrX& token)
{
    return (strcmp(token.localForm(), s) != 0);
}

#endif /* DEFINED_STRX */

#endif  // MELXMLPARSER_H
