#include "hrdarth.h"
#include "glistker.h"
#include "disphnd.h"
#include "cgidbg.h"
#include "usercom.h"
#include "yacintfc.h"
#include "netlnk.h"
#include "dylist.h"

GenericList::GenericList (DisplayNodeStr& node, int disp_hand,int hex_flag,
	int read_integer):
	integer_read_flag(read_integer),
	the_hex_flag(hex_flag),
	TheNode(node),
	hex_mask(0xffffffff),
	BlockSize(node.GetBlockSize(0)),
	SampleSize(node.GetInLink(0)->GetElementSize()),
	DisplayHandle(disp_hand)
{
	// Rules 
	//	1. New block or element is not started unless it will fit.
	//	2. Blocks are enclosed with `{}' if their size is > 1
	//	3. Samples are enclosed with `()' if their size is 2
	//	4. Samples are enclosed with `[]' if their size is > 2
	//	5. Sample elements are spearated by ',' if sample size is 2.
	//	6. Left most index is goes from 0 - 9.

	LineCount = 10 ;
	if (TheArithType == ArithType::ArithDouble ) WordWidth = 16 ;
	else if (TheArithType == ArithType::ArithFloat) {
		if (the_hex_flag) WordWidth = 9 ;
		else WordWidth = 16 ;
	} else if (TheArithType == ArithType::ArithInt16) {
		hex_mask = 0xffff ;
		if (the_hex_flag) WordWidth = 5 ;
		WordWidth = 6 ;
	} else DbgError("GenericList::GenericList","bad type");
	NextWordIndex = 0 ;
	SampleStartChar = 0 ;
	SampleEndChar = ' ' ;
	SampleSeparate = ' ' ;
	if (SampleSize == 2) {
		SampleStartChar = '(' ;
		SampleEndChar = ')' ;
		SampleSeparate = ',' ;
	} else if (SampleSize > 2) {
		SampleStartChar = '[' ;
		SampleEndChar = ']' ;
	}
	BlockStartChar = SampleStartChar ;
	BlockEndChar = SampleEndChar ;
	if (BlockSize > 1) {
		BlockStartChar = '{' ;
		BlockEndChar = '}' ;
	}
	BlockIndex = 0 ;
	SampleIndex = 0 ;
	WordIndex = 0 ;
	StartLineOut = 0 ;
	CharactersPerWord = WordWidth + 1 ;
	if (SampleSize == 1) CharactersPerSample = CharactersPerWord ;
	else CharactersPerSample = CharactersPerWord * SampleSize + 1 ;
	CharactersPerBlock = CharactersPerSample * BlockSize ;
	CharIndex = 0 ;
	LineWidth = 79 ;
	if (BlockSize > 1) MainTypeName = "Block" ;
	else MainTypeName = "Sample" ;
	LineStart = 9 ;
	if (SampleSize > 1) if (CharactersPerSample <= LineWidth - LineStart) 
		LineStart -= 3 ;
	if (BlockSize > 1) if (CharactersPerBlock <= LineWidth - LineStart)  
		LineStart -= 3 ;
}

ErrCode GenericList::List(int32 NumBlocks)
{
	ErrCode Return ;
	for (int i = 0 ; i < NumBlocks; i++) {
		Return = WriteBlock() ;
		BlockIndex++ ;
		SampleIndex = 0 ;
		if (Return > OK) return Return ;
	}
	return OK ;
}

void GenericList::CheckHeaderLine()
{
	if (LineCount < 10) return ;
	DISPLAY_OUT << " " << MainTypeName << " " << BlockIndex ;
	if (BlockSize > 1) if (CharactersPerBlock > LineWidth-LineStart)
		DISPLAY_OUT << ", " <<
		BlockStartChar << "sample index in block " <<
		SampleIndex << BlockEndChar ;
	if (SampleSize > 1) if(CharactersPerSample > LineWidth-LineStart)
		DISPLAY_OUT << ", " <<
		SampleStartChar << "word index in sample " <<
		SampleIndex << SampleEndChar ;
	DISPLAY_OUT << "\n" ;
	LineCount = 0 ;
}

void GenericList::NewLine()
{
	DISPLAY_OUT << "\n" ;
	LineCount++ ;
	CharIndex = 0 ;
	NextWordIndex = 0 ;
	StartLineOut = 0 ;
}

void GenericList::CheckNewLineSample()
{
	if (NextWordIndex)
		if (CharIndex + CharactersPerSample > LineWidth) NewLine();
}

void GenericList::CheckNewLineBlock()
{
	if (NextWordIndex) 
		if (CharIndex + CharactersPerBlock > LineWidth) NewLine();
}

void GenericList::CheckStartLineOut()
{
	if (StartLineOut) return ;
	StartLineOut = 1 ;
	DISPLAY_OUT << ' ' ;
	CharIndex++ ;
	DISPLAY_OUT.width(2);
	DISPLAY_OUT << (BlockIndex % 100) ;
	CharIndex+= 2 ;
	if (BlockSize > 1) if (CharactersPerBlock > LineWidth - LineStart)  {
		DISPLAY_OUT << ' ' ;
		CharIndex++ ;
		DISPLAY_OUT.width(2);
		DISPLAY_OUT << (SampleIndex % 100) ;
		CharIndex+=2 ;
	}
	if (SampleSize > 1) if (CharactersPerSample > LineWidth - LineStart) {
		DISPLAY_OUT << ' ' ;
		CharIndex++ ;
		DISPLAY_OUT.width(2);
		DISPLAY_OUT << (WordIndex % 100) ;
		CharIndex += 2;
	}
	DISPLAY_OUT << " " ;
	CharIndex+=1 ;
}

void GenericList::CheckSampleFit()
{
	CheckNewLineSample() ;
	CheckHeaderLine();
	CheckStartLineOut();
}


void GenericList::CheckBlockFit()
{
	CheckNewLineBlock();
	CheckHeaderLine();
	CheckStartLineOut();
}

void GenericList::CondOut(char c, char cc)
{
	if (cc) DISPLAY_OUT << cc ;
	else if (c) DISPLAY_OUT << c ;
	if (cc || c) CharIndex++ ;
}

ErrCode GenericList::WriteBlock()
{
	ErrCode Return ;
	CheckBlockFit();
	for (int j = 0 ; j < BlockSize; j++)  {
		char BlockBegin = 0 ;
		if (!j) BlockBegin = BlockStartChar ;
		char BlockEnd = 0 ;
		if (j == BlockSize -1) BlockEnd = BlockEndChar ;
		if ((Return = WriteSample(BlockBegin,BlockEnd)) > OK)
			return Return ;
		WordIndex = 0  ;
	}
	CheckNewLineBlock();
	return OK ;
}

void GenericList::WriteValue()
{
	MachWordCast val ;
	IntegerMachWord int_val ;
	if (integer_read_flag) int_val = TheNode.ReadInteger();
	else val =TheNode.ReadWord() ;
	DISPLAY_OUT.width(WordWidth) ;
	if (the_hex_flag) {
		if (!integer_read_flag) int_val = MachWord::convert_check(val);
		unsigned long v = int_val & hex_mask ;
		DISPLAY_OUT << hex << v << dec ;
	} else if (integer_read_flag) DISPLAY_OUT << int_val ;
	else DISPLAY_OUT << val ;
}

ErrCode GenericList::WriteSample(char BlockBegin, char BlockEnd)
{
	CheckSampleFit();
	CondOut(SampleStartChar,BlockBegin);
	for (int i = 0 ; i < SampleSize;i++) {
		WriteValue();
		CharIndex += WordWidth ;
		if (i < SampleSize-1) {
			DISPLAY_OUT << SampleSeparate ;
			CharIndex++ ;
		}
		WordIndex++ ;
		NextWordIndex++ ;
#ifdef INTERACTIVE
		if (State.IsError()) return FatalError ;
#endif
	}
	SampleIndex++ ;
	CondOut(SampleEndChar,BlockEnd);
	CheckNewLineSample();
	return OK ;
}



