/*
 * 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/McObject.cc,v 1.46 2002/12/02 12:31:30 akisada Exp $
 */
#include "McObject.h"
#include "MmObject.h"
#include "MmHeader.h"
#include "MmData.h"
#include "WObject.h"
#include "RObject.h"
#include "PControl.h"
#include "PcObject.h"
#include "PvOctets.h"
#include "ItPosition.h"
#include "DmObject.h"
#include <stdio.h>

MObject::MObject(CSTR s):CmToken(s),describer_(0) {}
MObject::~MObject() {delete describer_; describer_=0;}
uint32_t MObject::objectLength(const PObject*,const WObject*) const {return 0;}
uint16_t MObject::width() const {return 0;}
void MObject::postProcess(void*) {}
void MObject::stepPostion(ItPosition&) const{}
void MObject::compound(MObject*) {}
MvKeyword::MvKeyword(CSTR s,int32_t t):MObject(s),token_(t) {}
MvKeyword::~MvKeyword() {}
bool MObject::icvUpdate(const PaObject&,PvOctets*) const {return false;}

PObject* MObject::tokenObject(int,CSTR) const {return 0;}

//must return error *Control 
bool MObject::generate(WControl& c,WObject* w_self,OCTBUF& buf) const {
	if(w_self){
		const PObject* p = w_self->rgenerate();
		return p ? p->generate(c,w_self,buf) : geneAuto(c,w_self,buf);}
	return c;}
bool MObject::generate_child(WControl& c,WObject* w_self,OCTBUF& buf) const {
	if(w_self){
		WObject* n=0;
		for(n=w_self->nextChild();n!=0;n=w_self->nextChild(n)) {
			WObject* w=(WObject*)n;
			w->generate(c,buf);}
		}
	return c;}

bool MObject::geneAuto(WControl& c,WObject*,OCTBUF&) const {return c;}
bool MObject::geneFix(WControl& c,WObject*,OCTBUF&) const {return c;}
bool MObject::encodeNumber(WControl&,const ItPosition&,OCTBUF&,const PvNumber&) const {
	return false;}
bool MObject::encodeOctets(WControl&,const ItPosition&,OCTBUF&,const PvOctets&) const {
	return false;}
PvObject* MObject::geneAutoValue(WObject*) const {return 0;}
PvObject* MObject::evalAutoValue(WObject*) const {return 0;}

// COMPOSE/REVERSE
WObject* MObject::compose(WControl&,WObject*,const PObject*) const {return 0;}
RObject* MObject::reverse(RControl&,RObject*,ItPosition&,OCTBUF&) const {return 0;}
RObject* MObject::rreverse(RControl& c,RObject* rp,ItPosition& at,OCTBUF& s) const {
	ItPosition ml(objectLength(),width());
	if(at<ml) {c.set_error(1); return 0;}
	at-=ml;
	return reverse(c,rp,at,s);}
void MObject::composeList(WControl&,WObject*,const PObjectList&) const {}

bool MObject::check_decode_limit(const MObject* m_parent,
		const ItPosition& at,OCTBUF& buf,const ItPosition& size)const{
	uint32_t l=buf.length();
	ItPosition len(l,0);
	len-=at; len-=size;
	if(len.bytes()>=0) {return true;}//decodeable enough length
	fprintf(stderr,
		"err:unable decode %s size(%d,%d) ,in %s at(%d,%d)/size(%d)\n",
		string(),size.bytes(),size.bits(),
		(m_parent?m_parent->string():""),at.bytes(),at.bits(),l);
	return false;}

bool MObject::check_decode_alignment_requirement(const MObject* m_parent,
		const ItPosition& offset,const ItPosition& size)const{
	uint32_t X = alignment_requirement();
	return check_decode_alignment_requirement(m_parent,offset,size,X);}

bool MObject::check_decode_alignment_requirement(const MObject* m_parent,
	const ItPosition& offset,const ItPosition& size,uint32_t ali)const{
	uint32_t X = ali;
	uint32_t H = offset.bytes();	//offset from ParentTop
	uint32_t S = size.bytes();	//this size
	uint32_t pad = padcount_alignment_requirement(X,H,S);
	if(pad==0) {return true;}	//ok alignment requirement no need pad
	fprintf(stderr,
		"err:%s alignment requirement(%d) need %d pad in %s\n",
		string(),X,pad,(m_parent?m_parent->string():""));
	return false;}

//OVERWRITE ICV
bool MObject::overwrite_ICV(ICVControl&,
		const ItPosition&,OCTBUF&,const TObject*)const{
	return true;}//useless overwrite
		
///////////////////////////////////////////////////////////////////////////////
McObject::McObject(CSTR s):MObject(s),size_(),members_(16) {}
McObject::~McObject() {}

PObject* McObject::tokenObject(int l,CSTR f) const {
	return new PcObject(this,f,l);}

void McObject::member(MObject* m) {
	members_.add(m);
	m->compound(this);}

MObject* McObject::findMember(CSTR s) const {
	MObject* rtn=0;
	for(int i=0,imax=members_.size();i<imax&&!rtn;i++){
		MObject* mem = members_[i];
		rtn=mem->findMember(s);}
	return rtn;}

McObject* McObject::find(CSTR s) {
	McObject tmp(s);
	return (McObject*)set_.find(&tmp);}

MObject* McObject::findClassMember(CSTR c,CSTR m) {
	const McObject* cls=find(c);
	return cls!=0?cls->findMember(m):0;}

McObject* McObject::confirmed() {
	ItPosition i;
	members_.elementsPerformWith(
		(MObjectFunc)&MObject::postProcess,(void*)&i);
	size_=i;
	return this;}

void McObject::print() const {
	members_.elementsPerform((MObjectFunc)&MObject::print);}

// COMPOSE
WObject* McObject::compose(WControl& c,
		WObject* w_parent,const PObject* pc) const {
	WObject* w_self = composeWc(c,w_parent,pc);
	const PObjectList& pls = pc->members();
	members_compose(c,w_self,pls);
	return w_self;}

WObject* McObject::composeWc(WControl&,
		WObject* w_parent,const PObject* pc) const {
	return new WcObject(w_parent,this,pc);}

void McObject::members_compose(WControl& c,
		WObject* w_self,const PObjectList& pls)const{
	for(int i=0,imax=members_.size();i<imax;i++){
		MObject* mem = members_[i];
		mem->composeList(c,w_self,pls);
		if(!c)break;}
	}

// REVERSE
RObject* McObject::reverse(RControl& c,
		RObject* r_parent,ItPosition& at,OCTBUF& buf)const{
	//
	const MObject* m_parent = r_parent ? r_parent->meta() : 0;
	uint32_t length = length_for_reverse(c,at,buf);
	ItPosition size(length,0);
	if(!check_decode_limit(m_parent,at,buf,size)){
		c.set_error(1); return 0;}
	if(!check_decode_alignment_requirement(m_parent,at,size)){
		c.set_warning(3); /*return 0;*/}
	//
	OCTBUF* buf_self = buf.substr(at.bytes(),length);
	RObject* r_self = reverseRc(c,r_parent,at,buf_self);
	ItPosition memat; //new offset from buf_self
	members_reverse(c,r_self,memat,*buf_self);
	at.addBytes(length);
	return r_self;}

uint32_t McObject::length_for_reverse(RControl&,ItPosition&,OCTBUF&) const {
	return size_.bytes();}
uint32_t McObject::Layerlength_for_reverse(RControl&,ItPosition&,OCTBUF&) const{
	return 0;}

RObject* McObject::reverseRc(RControl&,
		RObject* r_parent,const ItPosition& at,PvObject* pv)const{
	return new RcObject(r_parent,this,at,pv);}

void McObject::members_reverse(RControl& c,
		RObject* r_self,ItPosition& memat,OCTBUF& buf_self)const{
	for(int i=0,imax=members_.size();i<imax;i++){
		MObject* mem = members_[i];
		mem->reverse(c,r_self,memat,buf_self);
		if(!c)break;}
	int32_t remainlen = buf_self.remainLength(memat.bytes());
	if(remainlen>0){//reverse length Needless data
		McNeedless* mless = McNeedless::instance();
		mless->reverse(c,r_self,memat,buf_self);
		}
	}

void MObject::describe(const PObject* o) const {
	DmObject* dm=describer();
	if(dm!=0) {dm->describe(this,o);}}

// GENERATE
bool McObject::generate(WControl& c,WObject* w_self,OCTBUF& buf) const {
	return generate_child(c,w_self,buf);}

//////////////////////////////////////////////////////////////////////////////
// Needless data (no token ,can not describe on PacketDefineFile)
McNeedless* McNeedless::instance_ = 0;
McNeedless* McNeedless::instance(){
	if(!instance_){instance_= new McNeedless("[Needless]");}
	return instance_;}

McNeedless::McNeedless(CSTR s):McObject(s) {
	member( new MmData( "data" ) );
	}
McNeedless::~McNeedless() {}

// COMPOSE/REVERSE
uint32_t McNeedless::length_for_reverse(
		RControl&,ItPosition& at,OCTBUF& buf) const{
	return buf.remainLength(at.bytes());}

RObject* McNeedless::reverse(RControl& c,
		RObject* r_parent,ItPosition& at,OCTBUF& buf)const{
	uint32_t remainlen = length_for_reverse(c,at,buf);
	RObject* rc = remainlen ? McObject::reverse(c,r_parent,at,buf) : 0;
	return rc;}//if remainlen==0 do not reverse


//////////////////////////////////////////////////////////////////////////////
// DictType VS McObject dict

TypevsMc::TypevsMc():type_(-1),Mc_(0){}
TypevsMc::TypevsMc(int32_t type,MObject* mc):type_(type),Mc_(mc){}

TypevsMcDict::TypevsMcDict():list_(),other_(0){}
TypevsMcDict::~TypevsMcDict(){
	for(int i=0,imax=list_.size();i<imax;i++){
		delete list_[i];}
	}
MObject* TypevsMcDict::find(const Con_DictType& DictType)const{
	/**/ if(DictType.uneffect())	return 0;
	else if(DictType.finish())	return McNeedless::instance();
	else if(DictType.other())	return other_;
	int32_t type = DictType.type();
	for(int i=0,imax=list_.size();i<imax;i++){
		TypevsMc* rec = list_[i];
		if(type==rec->type())	return rec->Mc();}
	return other_;}
MObject* TypevsMcDict::find_other()const{return other_;}
bool TypevsMcDict::contains(const MObject* mc)const{
	if(other_ && other_->containsMc(mc))return true;
	for(int i=0,imax=list_.size();i<imax;i++){
		TypevsMc* rec = list_[i];
		if(rec->Mc()->containsMc(mc))return true;}
	return false;}

bool TypevsMcDict::check(const Con_DictType &DictType) const {
	if(DictType.effect()) {
		int32_t type = DictType.type();

		for(int i = 0, imax = list_.size(); i< imax; i++) {
			TypevsMc *rec = list_[i];

			if(type == rec->type()) {
				return(true);
			}
		}
	}

	return(false);
}

void TypevsMcDict::add(int32_t type,MObject* mc){
	list_.append(new TypevsMc(type,mc));}
void TypevsMcDict::add_other(MObject* mc){
	other_=mc;}

implementCmList(TypevsMcList,TypevsMc);
implementCmSet(MObjectSet,MObject);
implementCmList(MObjectList,MObject);
int32_t MObject::tokenArray_[MObject::maxMetaToken_];
MObjectSet McObject::set_(64);


syntax highlighted by Code2HTML, v. 0.9.1