/*
* Copyright 2011, 2014 Range Networks, Inc.
*
* This software is distributed under multiple licenses;
* see the COPYING file in the main directory for licensing
* information for this specific distribution.
*
* This use of this software may be subject to additional restrictions.
* See the LEGAL file in the main directory for details.

    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.
*/
#ifndef MSGBASE_H
#define MSGBASE_H 1
#include <iostream>
#include <stdlib.h>		// For size_t
#include "Defines.h"
#include "BitVector.h"
#include "ScalarTypes.h"
typedef const char *Type2Str(int);
const char *tohex(int);

// This is a package to help write downlink messages and message elements.
// (Note: A message element class is a helper class that writes part of a message,
// but is not a final class.)
// Also see Field<> and Field_z<> types.
// You write a single function writeCommon(), and this package uses it to instantiate the
// functions from MsgBase in your message class, namely:
//		void writeBody(BitVector &dest, size_t &wp)
//		void writeBody(BitVector &dest)
//		int length()
//		void text(std::ostream&os)
// To use:
// Step 1: For both message classes and message element classes:
// 		- Create a single function named: writeCommon(MsgCommon& dest)
//		which writes out the message using the functions defined in MsgCommon,
// 		or the macros: WRITE_ITEM, WRITE_FIELD, etc.
//		The primary output function is writeField()
// Step 2: Your message classes only (not message element classes)
//		need to define the functions above.  You can do this by inheriting from MsgBody,
//		or just writing these yourself.
//		For examples see class MsgBody or class RLCDownlinkMessage.

class MsgCommon
{
	public:
	size_t wp;
	MsgCommon() : wp(0) {}
	MsgCommon(size_t wwp) : wp(wwp) {}

	// Ignore this.  g++ emits the vtable and typeid in the translation unit where
	// the first virtual method (meeting certain qualifications) is defined, so we use this
	// dummy method to control that and put the vtables in MsgBase.cpp.
	// Do not change the order of these functions here or you will get inscrutable link errors.
	// What a foo bar language.
	virtual void _define_vtable() {}		// Must be the first function.

	// The primary function to write bitfields.
    virtual void writeField(
		uint64_t value, 		// The value to be output to the BitVector by write().
		unsigned len, 			// length in bits of value.
		const char *name=0, 	// name to be output by text() function; if not supplied,
								// then this var does not appear in the text()
		Type2Str cvt=0) = 0;	// optional function to translate value to a string in text().

	// This is used primarily to write variables of type Field or Field_z,
	// for which the width is defined in the type declaration.
    virtual void writeField(const ItemWithValueAndWidth&item, const char *name = 0) = 0;

	// Same as above, but an optional field whose presence is controlled by present.
    virtual void writeOptFieldLH(	// For fields whose presence is indicated by H, absence by L.
        uint64_t value, unsigned len, int present, const char*name = 0) = 0;
	// An alternative idiom to writeOptField01() is:
	// 		if (dst.write01(present)) writeField(value,len,name);
    virtual void writeOptField01(	// For fields whose presence is indicated by 1, absence by 0.
        uint64_t value, unsigned len, int present, const char*name = 0) = 0;
	virtual void writeH() {}
    virtual void writeL() {}
    virtual void write0() {}
    virtual void write1() {}
	virtual bool write01(bool present) {return present;}
	virtual void writeBitMap(bool*value,unsigned bitmaplen, const char*name) = 0;

	// getStream() returns the ostream for the text() function, or NULL for
	// length() or write() functions.  You can use it to make your function
	// do something special for text().
	virtual std::ostream* getStream() { return NULL; }
};

#define WRITE_ITEM(name) writeField(name,#name)
#define WRITE_OPT_ITEM01(name,opt) writeOptField01(name,name.getWidth(),opt,#name)

#define WRITE_FIELD(name,width) writeField(name,width,#name)
#define WRITE_OPT_FIELD01(name,width,opt) writeOptField01(name,width,opt,#name)
#define WRITE_OPT_FIELDLH(name,width,opt) writeOptFieldLH(name,width,opt,#name)
class MsgCommonWrite : public MsgCommon {
	BitVector& mResult;
	public:
	void _define_vtable();
	MsgCommonWrite(BitVector& wResult) : mResult(wResult)  {}
	MsgCommonWrite(BitVector& wResult, size_t &wp) : MsgCommon(wp), mResult(wResult)  {}
	void writeField(uint64_t value, unsigned len, const char * name=0, Type2Str =0);
    void writeField(const ItemWithValueAndWidth&item, const char *name = 0);

	void write0() { writeField(0,1); }
	void write1() { writeField(1,1); }
	bool write01(bool present) { writeField(present,1); return present; }
	void writeH();
	void writeL();

	// Write an Optional Field controlled by an initial L/H field.
	void writeOptFieldLH(uint64_t value, unsigned len, int present, const char * name);

	// Write an Optional Field controlled by an initial 0/1 field.
	void writeOptField01(uint64_t value, unsigned len, int present, const char * name);

	// Write a bitmap.
	void writeBitMap(bool*value,unsigned bitmaplen, const char*name);
};

class MsgCommonLength : public MsgCommon {
	public:
	void _define_vtable();
    void writeH() { wp++; }
    void writeL() { wp++; }
    void write0() { wp++; }
    void write1() { wp++; }
	bool write01(bool present) { wp++; return present;}
    void writeField(uint64_t, unsigned len, const char* =0, Type2Str =0) { wp+=len; }
    //virtual void writeField(const ItemWithValueAndWidth&item, const char *name= 0) { wp = item.getWidth(); }
    virtual void writeField(const ItemWithValueAndWidth&item, const char *) { wp = item.getWidth(); }
    void writeOptFieldLH(uint64_t, unsigned len, int present, const char*) {
		wp++; if (present) wp += len;
	}
    void writeOptField01(uint64_t, unsigned len, int present, const char*) {
		wp++; if (present) wp += len;
	}
	void writeBitMap(bool*,unsigned bitmaplen, const char*) { wp+=bitmaplen; }
};

class MsgCommonText : public MsgCommon {
    std::ostream& mos;
    public:
	void _define_vtable();
    MsgCommonText(std::ostream &os) : mos(os) { }

    void writeField(const ItemWithValueAndWidth&item, const char *name = 0) {
        if (name) { mos << " " << name << "=(" << item.getValue() << ")"; }
	}
    void writeField(uint64_t value, unsigned, const char*name=0, Type2Str cvt=0) {
        if (name) {
			mos << " " << name << "=";
			if (cvt) { mos << cvt(value); } else { mos << value; }
		}
    }

    void writeOptFieldLH(uint64_t value, unsigned, int present, const char*name = 0) {
        if (name && present) { mos << " " << name << "=(" << value << ")"; }
    }

    void writeOptField01(uint64_t value, unsigned, int present, const char*name = 0) {
        if (name && present) { mos << " " << name << "=(" << value << ")"; }
    }
	void writeBitMap(bool*value,unsigned bitmaplen, const char*name);
	std::ostream* getStream() { return &mos; }
};


// This is the base class for the message, that defines the functions that use MsgCommon.
/***
class MsgBody {
	public:
	virtual void writeCommon(MsgCommon &dest) const = 0;

	void writeOptional01(MsgCommon &dest, bool control) const {
		if (control) {
			dest.write1();
			writeCommon(dest);
		} else {
			dest.write0();
		}
	}

	void writeBody(BitVector &vdst, size_t &wwp) const {
		MsgCommonWrite dest(vdst,wwp);
		writeCommon(dest);
		wwp = dest.wp;
	}
	void writeBody(BitVector &vdst) const {
		MsgCommonWrite dest(vdst);
		writeCommon(dest);
	}
	int lengthBodyBits() const {
		MsgCommonLength dest;
		writeCommon(dest);
		return dest.wp;
	}
	void textBody(std::ostream&os) const {
		MsgCommonText dest(os);
		writeCommon(dest);
	}
};
***/

/***
#define INHERIT_MSG_BASE \
	void write(BitVector &dest, size_t &wp) { MsgBase::write(dest,wp); } \
	void write(BitVector &dest) { MsgBase::write(dest); } \
	int length() { return MsgBase::length(); } \
	void text(std::ostream&os) const { MsgBase::text(os); }
***/
	
#endif
