/*
 * Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005 Yokogawa Electric Corporation,
 * YDC Corporation, IPA (Information-technology Promotion Agency, Japan).
 * All rights reserved.
 * 
 * Redistribution and use of this software in source and binary forms, with 
 * or without modification, are permitted provided that the following 
 * conditions and disclaimer are agreed and accepted by the user:
 * 
 * 1. Redistributions of source code must retain the above copyright 
 * notice, this list of conditions and the following disclaimer.
 * 
 * 2. Redistributions in binary form must reproduce the above copyright 
 * notice, this list of conditions and the following disclaimer in the 
 * documentation and/or other materials provided with the distribution.
 * 
 * 3. Neither the names of the copyrighters, the name of the project which 
 * is related to this software (hereinafter referred to as "project") nor 
 * the names of the contributors may be used to endorse or promote products 
 * derived from this software without specific prior written permission.
 * 
 * 4. No merchantable use may be permitted without prior written 
 * notification to the copyrighters. However, using this software for the 
 * purpose of testing or evaluating any products including merchantable 
 * products may be permitted without any notification to the copyrighters.
 * 
 * 
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHTERS, THE PROJECT AND 
 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING 
 * BUT NOT LIMITED THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
 * FOR A PARTICULAR PURPOSE, ARE DISCLAIMED.  IN NO EVENT SHALL THE 
 * COPYRIGHTERS, THE PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
 * CONTRACT,STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 
 * THE POSSIBILITY OF SUCH DAMAGE.
 *
 * $TAHI: v6eval/lib/Pz/McTCP.cc,v 1.7 2001/10/12 04:56:15 tanaka Exp $
 */
#include "McTCP.h"
#include "MmData.h"
#include "ItPosition.h"
#include "WObject.h"
#include "RObject.h"
#include "PControl.h"
#include "PvObject.h"
#include "PvOctets.h"

#define DEF_ALIGNMENT_TCP	4
#define DEF_LENGTH_ELEM_TCP	4

//////////////////////////////////////////////////////////////////////////////
#define SUPER	McUpper
McUpp_TCP* McUpp_TCP::instance_=0;
McTopHdr_TCP* McUpp_TCP::tophdr_=0;
McUpp_TCP::McUpp_TCP(CSTR key):SUPER(key) {instance_=this;}
McUpp_TCP::~McUpp_TCP() {if(instance_==this)instance_=0;}

// COMPOSE/REVERSE
uint32_t McUpp_TCP::length_for_reverse(
		RControl& c,ItPosition& at,OCTBUF& buf) const{
	uint32_t length = tophdr_->Layerlength_for_reverse(c,at,buf);
	return length;}

RObject* McUpp_TCP::reverse(RControl& c,
		RObject* r_parent,ItPosition& at,OCTBUF& buf)const{
	RObject* r_self = SUPER::reverse(c,r_parent,at,buf);
	if(!c.error()){
		Con_IPinfo* info = c.IPinfo();
		if(info)info->reverse_postUppChecksum(c,r_self);}
	return r_self;}

bool McUpp_TCP::generate(WControl& c,WObject* w_self,OCTBUF& buf) const {
	bool rtn = SUPER::generate(c,w_self,buf);
	if(!c.error()){
		Con_IPinfo* info = c.IPinfo();
		if(info)info->generate_postUppChecksum(c,buf,w_self);}
	return rtn;}
#undef SUPER

//----------------------------------------------------------------------------
#define SUPER	McHeader
McTopHdr_TCP::McTopHdr_TCP(CSTR key):SUPER(key),length_(0){}
McTopHdr_TCP::~McTopHdr_TCP(){}
uint32_t McTopHdr_TCP::alignment_requirement() const{
	return DEF_ALIGNMENT_TCP;}

// COMPOSE/REVERSE
uint32_t McTopHdr_TCP::length_for_reverse(
		RControl& c,ItPosition& at,OCTBUF& buf) const{
	if(!length_)return SUPER::length_for_reverse(c,at,buf);
	uint32_t valulen	= length_->value(at,buf);
	uint32_t length		= valulen*DEF_LENGTH_ELEM_TCP;
	return length;}

uint32_t McTopHdr_TCP::Layerlength_for_reverse(
			RControl&,ItPosition& at,OCTBUF& buf) const{
	return buf.remainLength(at.bytes());}

bool McTopHdr_TCP::HCGENE(DataOffset)(
			WControl& cntr,WObject* wmem,OCTBUF& buf) const{
	WObject* wc		= wmem->parent();	//TopHdr_TCP
	uint32_t reallen	= wc->size().bytes();
	uint32_t valulen	= reallen/DEF_LENGTH_ELEM_TCP;
	PvNumber def(valulen);
	return def.generate(cntr,wmem,buf);}
#undef SUPER


///////////////////////////////////////////////////////////////////////////////
#define SUPER	McOption
McOpt_TCP::McOpt_TCP(CSTR key):SUPER(key),kind_(0),length_(0){}
McOpt_TCP::~McOpt_TCP(){}

// COMPOSE/REVERSE
uint32_t McOpt_TCP::length_for_reverse(RControl& c,
		ItPosition& at,OCTBUF& buf) const{
	if(!length_)return SUPER::length_for_reverse(c,at,buf);
	uint32_t valulen	= length_->value(at,buf);
	uint32_t length		= valulen;
	return length;}

bool McOpt_TCP::HCGENE(Length)(WControl& cntr,WObject* wmem,OCTBUF& buf)const{
	WObject* wc		= wmem->parent();	//Opt_TCP
	uint32_t reallen	= wc->size().bytes();
	uint32_t valulen	= reallen;
	PvNumber def(valulen);
	return def.generate(cntr,wmem,buf);}

bool McOpt_TCP::overwrite_DictType(
		RControl& c,ItPosition& at,OCTBUF& buf)const{
	if(c.DictType().finish())return false;	//End of OptionList
	uint32_t limit = buf.remainLength(at.bytes());
	if(limit==0)return false;		//End of TCP Header
	//
	ItPosition tmpat=at;
	RObject* rkind = kind_->reverse(c,0,tmpat,buf);
	if(!rkind)return false;			//Type field decode error
	//
	const PvNumber* pv = (const PvNumber*)rkind->pvalue();
	uint32_t kindvalue = pv->value();
	c.DictType().type_Set(kindvalue);	//self Type set
	delete rkind;
	return true;}
#undef SUPER

///////////////////////////////////////////////////////////////////////////////
#define SUPER	McOpt_TCP

//----------------------------------------------------------------------------
McOpt_TCP_ANY::McOpt_TCP_ANY(CSTR key):SUPER(key){}
McOpt_TCP_ANY::~McOpt_TCP_ANY(){}

//----------------------------------------------------------------------------
McOpt_TCP_EndofOptionList::McOpt_TCP_EndofOptionList(CSTR key):SUPER(key){}
McOpt_TCP_EndofOptionList::~McOpt_TCP_EndofOptionList(){}

RObject* McOpt_TCP_EndofOptionList::reverse(RControl& c,
		RObject* r_parent,ItPosition& at,OCTBUF& buf)const{
	RObject* r_self = SUPER::reverse(c,r_parent,at,buf);
	c.DictType().finish_Set(); // nextType must finish
	return r_self;}

//----------------------------------------------------------------------------
McOpt_TCP_NoOperation::McOpt_TCP_NoOperation(CSTR key):SUPER(key){}
McOpt_TCP_NoOperation::~McOpt_TCP_NoOperation(){}

//----------------------------------------------------------------------------
#define DEF_ALIGNMENT_MaximumSegmentSize	2
McOpt_TCP_MaximumSegmentSize::McOpt_TCP_MaximumSegmentSize(CSTR key):
	SUPER(key){}
McOpt_TCP_MaximumSegmentSize::~McOpt_TCP_MaximumSegmentSize(){}

uint32_t McOpt_TCP_MaximumSegmentSize::alignment_requirement() const{
	return DEF_ALIGNMENT_MaximumSegmentSize;}

/////////////////////////////////////////////////////////////////////////////// // create options
#include "PvAutoItem.h"
#include "PvAction.h"

#define UN(n)		PvNumber::unique(n)
#define MUST()		PvMUSTDEF::must()
#define EVALANY()	new PvANY()
#define GENEHC(mc,cls,mem)	new PvHCgene(mc,(HCgenefunc)&cls::HCGENE(mem))
#define EVALHC(mc,cls,mem)	new PvHCeval(mc,(HCevalfunc)&cls::HCEVAL(mem))

#define LEXADD(classname,lexname) addCompound(classname::create(lexname))
void McOpt_TCP::create_options(){
	LEXADD(McOpt_TCP_ANY,			"Opt_TCP_ANY" );
	LEXADD(McOpt_TCP_EndofOptionList,	"Opt_TCP_EndofOptionList" );
	LEXADD(McOpt_TCP_NoOperation,		"Opt_TCP_NoOperation" );
	LEXADD(McOpt_TCP_MaximumSegmentSize,	"Opt_TCP_MaximumSegmentSize" );
	}

void McOpt_TCP::common_member(){
        int32_t Kind = optionType();
        kind_member(	new MmUint( "Kind",	8,	UN(Kind),UN(Kind) ) );
        length_member(	new MmUint( "Length",	8,
				GENEHC(this,McOpt_TCP,Length),	EVALANY() ) );
        }

McOpt_TCP_ANY* McOpt_TCP_ANY::create(CSTR key){
	McOpt_TCP_ANY* mc = new McOpt_TCP_ANY(key);
	mc->common_member();
	mc->member( new MmData( "data" ) );
	// dict
	MmOption_onTCP::add_other(mc);		//Hdr_TCP::option=
	return mc;}
#if 0
ANY(Unknown Type)
        +--------+--------+--------//--------+
        |Kind    | Length | data             |
        +--------+--------+--------//--------+
#endif

McOpt_TCP_EndofOptionList* McOpt_TCP_EndofOptionList::create(CSTR key){
	McOpt_TCP_EndofOptionList* mc = new McOpt_TCP_EndofOptionList(key);
        int32_t Kind = mc->optionType();
        mc->kind_member( new MmUint( "Kind",	8,	UN(Kind),UN(Kind) ) );
	// dict
	MmOption_onTCP::add(mc);		//Hdr_TCP::option=
	return mc;}
#if 0
End of Option List
        +--------+
        |00000000|
        +--------+
#endif

McOpt_TCP_NoOperation* McOpt_TCP_NoOperation::create(CSTR key){
	McOpt_TCP_NoOperation* mc = new McOpt_TCP_NoOperation(key);
        int32_t Kind = mc->optionType();
        mc->kind_member( new MmUint( "Kind",	8,	UN(Kind),UN(Kind) ) );
	// dict
	MmOption_onTCP::add(mc);		//Hdr_TCP::option=
	return mc;}
#if 0
No Operation
        +--------+
        |00000001|
        +--------+
#endif

McOpt_TCP_MaximumSegmentSize* McOpt_TCP_MaximumSegmentSize::create(CSTR key){
	McOpt_TCP_MaximumSegmentSize* mc =
		new McOpt_TCP_MaximumSegmentSize(key);
	mc->common_member();
	mc->member( new MmUint( "MaxSegSize",	16,	UN(0),UN(0) ) );
	// dict
	MmOption_onTCP::add(mc);		//Hdr_TCP::option=
	return mc;}
#if 0
Maximum Segment Size
	+--------+--------+---------+--------+
        |00000010|00000100|   max seg size   |
        +--------+--------+---------+--------+
#endif


///////////////////////////////////////////////////////////////////////////////
MmOption_onTCP::MmOption_onTCP(CSTR key):MmReference_More0(key,true) {}
MmOption_onTCP::~MmOption_onTCP() {}

void MmOption_onTCP::add(McOpt_TCP* mc){
	dict_.add(mc->optionType(),mc);}
void MmOption_onTCP::add_other(McOpt_TCP* mc){dict_.add_other(mc);}
TypevsMcDict MmOption_onTCP::dict_;

// REVERSE
bool MmOption_onTCP::overwrite_DictType(
		RControl& c,ItPosition& at,OCTBUF& buf)const{
	McOpt_TCP* any = (McOpt_TCP*)dict_.find_other();
	return any->overwrite_DictType(c,at,buf);}

///////////////////////////////////////////////////////////////////////////////


syntax highlighted by Code2HTML, v. 0.9.1