/*
 *    Copyright 2004-2006 Intel Corporation
 * 
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 * 
 *        http://www.apache.org/licenses/LICENSE-2.0
 * 
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

#ifndef _OASYS_MARSHAL_SERIALIZE_H_
#define _OASYS_MARSHAL_SERIALIZE_H_

#include "Serialize.h"
#include "BufferedSerializeAction.h"
#include "../util/ExpandableBuffer.h"
#include "../util/CRC32.h"


namespace oasys {


/**
 * Marshal is a SerializeAction that flattens an object into a byte
 * stream.
 */
class Marshal : public BufferedSerializeAction {
public:
    /**
     * Constructor with a fixed-size buffer.
     */
    Marshal(context_t context, u_char* buf, size_t length, int options = 0);

    /**
     * Constructor with an expandable buffer.
     */
    Marshal(context_t context, ExpandableBuffer* buf, int options = 0);

    /**
     * Since the Marshal operation doesn't actually modify the
     * SerializableObject, define a variant of action() and process()
     * that allows a const SerializableObject* as the object
     * parameter.
     */
    int action(const SerializableObject* const_object)
    {
        SerializableObject* object = (SerializableObject*)const_object;
        return SerializeAction::action(object);
    }

    void process(const char* name, SerializableObject* const_object)
    {
        SerializableObject* object = (SerializableObject*)const_object;
        return SerializeAction::process(name, object);
    }

    // Virtual functions inherited from SerializeAction
    void end_action();

    void process(const char* name, u_int64_t* i);
    void process(const char* name, u_int32_t* i);
    void process(const char* name, u_int16_t* i);
    void process(const char* name, u_int8_t* i);
    void process(const char* name, bool* b);
    void process(const char* name, u_char* bp, u_int32_t len);
    void process(const char*            name, 
                 BufferCarrier<u_char>* carrier);
    void process(const char*            name,
                 BufferCarrier<u_char>* carrier,
                 u_char                 terminator);
    void process(const char* name, std::string* s);

private:
    bool add_crc_;
};


/**
 * Unmarshal is a SerializeAction that constructs an object's
 * internals from a flat byte stream.
 * 
 * INVARIANT: The length of the buffer must be the length of the serialized
 * buffer.
 */
class Unmarshal : public BufferedSerializeAction {
public:
    /**
     * Constructor
     */
    Unmarshal(context_t context, const u_char* buf, size_t length,
              int options = 0);

    // Virtual functions inherited from SerializeAction
    void begin_action();

    void process(const char* name, u_int64_t* i);
    void process(const char* name, u_int32_t* i);
    void process(const char* name, u_int16_t* i);
    void process(const char* name, u_int8_t* i);
    void process(const char* name, bool* b);
    void process(const char* name, u_char* bp, u_int32_t len);
    void process(const char*            name, 
                 BufferCarrier<u_char>* carrier);
    void process(const char*            name,
                 BufferCarrier<u_char>* carrier,
                 u_char                 terminator);
    void process(const char* name, std::string* s); 

private:
    bool has_crc_;
};


/**
 * MarshalSize is a SerializeAction that determines the buffer size
 * needed to run a Marshal action over the object.
 */
class MarshalSize : public SerializeAction {
public:
    /**
     * Constructor
     */
    MarshalSize(context_t context, int options = 0)
        : SerializeAction(Serialize::INFO, context, options), size_(0)
    {
    }

    /**
     * Again, we can tolerate a const object as well.
     */
    int action(const SerializableObject* const_object)
    {
        SerializableObject* object = (SerializableObject*)const_object;
        return SerializeAction::action(object);
    }
    
    void process(const char* name, SerializableObject* const_object)
    {
        SerializableObject* object = (SerializableObject*)const_object;
        return SerializeAction::process(name, object);
    }

    /** @return Measured size */
    size_t size() { return size_; }

    /// @{
    /// Static functions to simply return the serialized sizes. Called
    /// from the various process() variants.
    static u_int32_t get_size(u_int64_t*)           { return 8; }
    static u_int32_t get_size(u_int32_t*)           { return 4; }
    static u_int32_t get_size(u_int16_t*)           { return 2; }
    static u_int32_t get_size(u_int8_t*)            { return 1; }
    static u_int32_t get_size(bool*)                { return 1; }
    static u_int32_t get_size(u_char*, u_int32_t len)  { return len; }
    static u_int32_t get_size(std::string* s)       { return s->length() + 4; }
    /// @}
    
    /// @{
    /// Virtual functions inherited from SerializeAction
    void begin_action();
    void process(const char* name, u_int64_t* i);
    void process(const char* name, u_int32_t* i);
    void process(const char* name, u_int16_t* i);
    void process(const char* name, u_int8_t* i);
    void process(const char* name, bool* b);
    void process(const char* name, u_char* bp, u_int32_t len);
    void process(const char*            name, 
                 BufferCarrier<u_char>* carrier);
    void process(const char*            name,
                 BufferCarrier<u_char>* carrier,
                 u_char                 terminator);
    void process(const char* name, std::string* s);
    /// @}

private:
    size_t size_;
};

//////////////////////////////////////////////////////////////////////////////
/**
 * MarshalCopy: Copy one object to another using Marshal/Unmarshal.
 */
class MarshalCopy {
public:
    /// Copy method, returns the serialized size
    static u_int32_t copy(ExpandableBuffer* buf,
                          const SerializableObject* src,
                          SerializableObject* dst);
};

} // namespace oasys

#endif /* _OASYS_MARSHAL_SERIALIZE_H_ */

