/*	Copyright (C) 2003-2008 Free Electron Organization
	Any use of this software requires a license.  If a valid license
	was not distributed with this file, visit freeelectron.org. */


#include "data.pmh"

namespace fe
{
namespace data
{

t_layout_info::t_layout_info(void)
{
	m_id = 0;
	m_sent = false;
}


Scanner::Scanner(sp<Scope> spScope)
{
	m_nextLayoutID = 1;
	m_nextRGID = 1;
	m_nextAttrID = 1;
	m_sentAttrID = 0;
	m_spScannedRecords = new RecordGroup();
	m_spScope = spScope;
	m_spRecordGroupType =
		m_spScope->typeMaster()->lookupType<sp<RecordGroup> >();
	m_spRecordArrayType =
		m_spScope->typeMaster()->lookupType<sp<RecordArray> >();
	m_spRecordType =
		m_spScope->typeMaster()->lookupType<Record>();
	m_spWeakRecordType =
		m_spScope->typeMaster()->lookupType<WeakRecord>();

	m_spScope->trackReference(this,"Scanner::Scanner");
}

Scanner::~Scanner(void)
{
	if(m_spScope.isValid())
	{
		m_spScope->untrackReference(this);
	}
}

int Scanner::getID(sp<RecordGroup> spRG)
{
	int id;
	t_rg_id::iterator it = m_rgs.find(spRG);
	if(it == m_rgs.end())
	{
		feX(e_usage,
			"BinaryWriter::getID",
			"attempt to get id of unscanned record group");
	}
	else
	{
		id = it->second;
	}
	return id;
}

int Scanner::getID(sp<RecordArray> spRA)
{
	int id;
	t_ra_id::iterator it = m_ras.find(spRA);
	if(it == m_ras.end())
	{
		feX(e_usage,
			"BinaryWriter::getID",
			"attempt to get id of unscanned record array");
	}
	else
	{
		id = it->second;
	}
	return id;
}


void Scanner::setupSBIDs(sp<RecordGroup> spRG)
{
	U32 nextSBID = 1;
	for(RecordGroup::iterator it = spRG->begin(); it != spRG->end(); it++)
	{
		sp<RecordArray> spRA = *it;
		for(int i = 0; i < spRA->length(); i++)
		{
			m_sbs[spRA->idr(i)] = nextSBID++;
		}
	}
}


void Scanner::scan(sp<RecordGroup> spRG)
{
	if(!spRG.isValid())
	{
		return;
	}
	int id;
	t_rg_id::iterator it = m_rgs.find(spRG);
	if(it != m_rgs.end())
	{
		// already scanned
		return;
	}
	m_rgs[spRG] = m_nextRGID;
	id = m_nextRGID++;

	for(RecordGroup::iterator rgit = spRG->begin(); rgit != spRG->end(); rgit++)
	{
		sp<RecordArray> spRA = *rgit;
		scan(spRA->layout());
		//if(m_aID.check(spRA))
		//{
			deepscan(spRA);
		//}
	}
}

void Scanner::scan(sp<RecordArray> spRA)
{
	if(!spRA.isValid())
	{
		return;
	}
	int id;
	t_ra_id::iterator it = m_ras.find(spRA);
	if(it != m_ras.end())
	{
		// already scanned
		return;
	}
	m_ras[spRA] = m_nextRGID;
	id = m_nextRGID++;

	scan(spRA->layout());
	deepscan(spRA);
}

void Scanner::scan(sp<Layout> spLayout)
{
	if(m_layouts.find(spLayout) != m_layouts.end())
	{
		// already scanned
		return;
	}
	m_layouts[spLayout].m_id = m_nextLayoutID++;

	// scan Attributes
	spLayout->initialize();

	sp<Scope> spScope = m_spScope;
	if(spLayout->scope() != m_spScope)
	{
		spScope = spLayout->scope();
	}

	UWORD cnt = spScope->getAttributeCount();
	for(UWORD i = 0; i < cnt; i++)
	{
		if(spLayout->checkAttribute(i))
		{
			sp<BaseType> spBT = spScope->attribute(i)->type();
			if(spBT->getInfo().isValid())
			{
				if(spScope->attribute(i)->isSerialize())
				{
					scan(spScope->attribute(i), spScope);
				}
			}
		}
	}

}

void Scanner::scan(sp<Attribute> spAttribute, sp<Scope> spScope)
{
	if(m_attrs.find(spAttribute) != m_attrs.end())
	{
		// already scanned
		return;
	}
	m_attrArray.push_back(spAttribute);
	m_attrs[spAttribute].m_id = m_nextAttrID++;
	m_attrs[spAttribute].m_scope = spScope;
}


void Scanner::deepscan(sp<RecordArray> spRA)
{
	for(int i = 0; i < spRA->length(); i++)
	{
		scan(spRA->getRecord(i));
	}
}

void Scanner::scan(Record record)
{
	if(!record.isValid())
	{
		return;
	}
	sp<Scope> scope = m_spScope;
	if(record.layout()->scope() != m_spScope)
	{
		scope = record.layout()->scope();
	}
	if(m_spScannedRecords->find(record))
	{
		// already scanned
		return;
	}
	scan(record.layout());
	m_spScannedRecords->add(record);
	UWORD cnt = scope->getAttributeCount();
	for(UWORD i = 0; i < cnt; i++)
	{
		if(record.layout()->checkAttribute(i))
		{
			if(scope->attribute(i)->isSerialize())
			{
				sp<BaseType> spBT = scope->attribute(i)->type();
				if(spBT == m_spRecordGroupType)
				{
					sp<RecordGroup> *pspRG;
					void *instance = record.rawAttribute(i);
					pspRG = reinterpret_cast<sp<RecordGroup> *>(instance);
					scan(*pspRG);
				}
				else if(spBT == m_spRecordArrayType)
				{
					sp<RecordArray> *pspRA;
					void *instance = record.rawAttribute(i);
					pspRA = reinterpret_cast<sp<RecordArray> *>(instance);
					scan(*pspRA);
				}
				else if(spBT == m_spRecordType)
				{
					Record *pR;
					void *instance = record.rawAttribute(i);
					pR = reinterpret_cast<Record *>(instance);
					scan(*pR);
				}
				else if(spBT == m_spWeakRecordType)
				{
					WeakRecord *pR;
					void *instance = record.rawAttribute(i);
					pR = reinterpret_cast<WeakRecord *>(instance);
					scan(*pR);
				}
				else
				{
					/* NOOP */
				}
			}
		}
	}
}


} /* namespace */
} /* namespace */

