/******************************************************************************
 TestVarList.cc

							The TestVarList Class

	This class implements the simplest possible variable list for testing
	the parser.

	BASE CLASS = JVariableList

	Copyright © 1995 by John Lindal. All rights reserved.

 ******************************************************************************/

#include "TestVarList.h"
#include <jParseFunction.h>
#include <JString.h>
#include <iostream.h>
#include <jStreamUtil.h>
#include <jMath.h>
#include <string.h>
#include <jGlobals.h>
#include <jAssert.h>

static const JString kUnknownValueSymbol = "?";

/******************************************************************************
 Constructor

	file format:
		{
		N <name> <value>
		N <name>[array size] <values>
		}
		*

 ******************************************************************************/

TestVarList::TestVarList()
	:
	JVariableList()
{
	TestVarListX();
}

TestVarList::TestVarList
	(
	istream& input
	)
	:
	JVariableList()
{
	TestVarListX();

	input >> ws;
	while (input.peek() != '*')
		{
		JCharacter type;
		input >> type >> ws;
		if (type == 'N')
			{
			JString name = JReadUntilws(input);
			if (name.GetLastCharacter() != ']')
				{
				JFloat value;
				input >> value;
				AddNumericVar(name, value);
				}
			else
				{
				const JSize nameLen = name.GetLength();
				JIndex bracketIndex;
				const JBoolean foundBracket = name.LocateSubstring("[", &bracketIndex);
				assert( foundBracket && bracketIndex < nameLen-1 );
				const JString sizeStr = name.GetSubstring(bracketIndex+1, nameLen-1);
				name.RemoveSubstring(bracketIndex, nameLen);
				JSize arraySize;
				const JBoolean isNumber = sizeStr.ConvertToUInt(&arraySize);
				assert( isNumber );
				TVLNArray values(arraySize);
				for (JIndex i=1; i<= arraySize; i++)
					{
					JFloat value;
					input >> value;
					values.AppendElement(value);
					}
				AddNumericArray(name, values);
				}
			}
		else
			{
			JString errorStr = "Unsupported variable type 'x'";
			errorStr.SetCharacter(errorStr.GetLength()-1, type);
			(JGetUserNotification())->ReportError(errorStr);
			JIgnoreUntil(input, '\n');
			}
		input >> ws;
		}
	JIgnoreUntil(input, '\n');
}

// private

void
TestVarList::TestVarListX()
{
	itsNumericNames = new JPtrArray<JString>;
	assert( itsNumericNames != NULL );

	itsNumericValues = new JArray<JFloat>;
	assert( itsNumericValues != NULL );

	itsNumericArrays = new JPtrArray<TVLNArray>;
	assert( itsNumericArrays != NULL );

	InstallOrderedSet(itsNumericNames);
}

/******************************************************************************
 Destructor

 ******************************************************************************/

TestVarList::~TestVarList()
{
	itsNumericNames->DeleteAll();
	delete itsNumericNames;

	delete itsNumericValues;

	itsNumericArrays->DeleteAll();
	delete itsNumericArrays;
}

/******************************************************************************
 AddNumericVar

 ******************************************************************************/

JBoolean
TestVarList::AddNumericVar
	(
	const JCharacter*	name,
	const JFloat		value
	)
{
	JIndex index;
	if (JNameValid(name) && !ParseVariableName(name, strlen(name), &index))
		{
		JString* varName = new JString(name);
		assert( varName != NULL );
		itsNumericNames->Append(varName);
		itsNumericValues->AppendElement(value);
		itsNumericArrays->AppendElement(static_cast<TVLNArray*>(NULL));
		return kTrue;
		}
	else
		{
		return kFalse;
		}
}

/******************************************************************************
 AddNumericArray

 ******************************************************************************/

JBoolean
TestVarList::AddNumericArray
	(
	const JCharacter*	name,
	const TVLNArray&	values
	)
{
	if (JNameValid(name))
		{
		JString* varName = new JString(name);
		assert( varName != NULL );
		itsNumericNames->Append(varName);
		itsNumericValues->AppendElement(0.0);
		TVLNArray* newArray = new TVLNArray(values);
		assert( newArray != NULL );
		itsNumericArrays->AppendElement(newArray);
		return kTrue;
		}
	else
		{
		return kFalse;
		}
}

/******************************************************************************
 Virtual functions for TestVarList class

	Not inline because they are virtual

 ******************************************************************************/

/******************************************************************************
 GetVariableName

 ******************************************************************************/

const JString&
TestVarList::GetVariableName
	(
	const JIndex index
	)
	const
{
	return *(itsNumericNames->NthElement(index));
}

void
TestVarList::GetVariableName
	(
	const JIndex	index,
	JString*		name,
	JString*		subscript
	)
	const
{
	const JString* fullName = itsNumericNames->NthElement(index);
	const JSize fullLen     = fullName->GetLength();

	JIndex subStart;
	if (fullName->LocateSubstring("_", &subStart) &&
		1 < subStart && subStart < fullLen)
		{
		*name = fullName->GetSubstring(1, subStart-1);
		*subscript = fullName->GetSubstring(subStart+1, fullLen);
		}
	else
		{
		*name = *fullName;
		subscript->Clear();
		}
}

/******************************************************************************
 IsNumeric

 ******************************************************************************/

JBoolean
TestVarList::IsNumeric
	(
	const JIndex index
	)
	const
{
	return kTrue;
}

/******************************************************************************
 IsDiscrete

 ******************************************************************************/

JBoolean
TestVarList::IsDiscrete
	(
	const JIndex index
	)
	const
{
	return kFalse;
}

/******************************************************************************
 IsArray

 ******************************************************************************/

JBoolean
TestVarList::IsArray
	(
	const JIndex index
	)
	const
{
	return JConvertToBoolean( itsNumericArrays->NthElement(index) != NULL );
}

/******************************************************************************
 ArrayIndexValid

 ******************************************************************************/

JBoolean
TestVarList::ArrayIndexValid
	(
	const JIndex variableIndex,
	const JIndex elementIndex
	)
	const
{
	return JConvertToBoolean(
			elementIndex == 1 ||
			(IsArray(variableIndex) &&
			 (itsNumericArrays->NthElement(variableIndex))->IndexValid(elementIndex)));
}

/******************************************************************************
 ValueIsKnown

 ******************************************************************************/

JBoolean
TestVarList::ValueIsKnown
	(
	const JIndex variableIndex,
	const JIndex elementIndex
	)
	const
{
	return kTrue;
}

/******************************************************************************
 GetUnknownValueSymbol

 ******************************************************************************/

const JString&
TestVarList::GetUnknownValueSymbol
	(
	const JIndex index
	)
	const
{
	return kUnknownValueSymbol;
}

/******************************************************************************
 GetNumericValue

 ******************************************************************************/

JBoolean
TestVarList::GetNumericValue
	(
	const JIndex	variableIndex,
	const JIndex	elementIndex,
	JFloat*			value
	)
	const
{
	TVLNArray* values = itsNumericArrays->NthElement(variableIndex);
	if (values == NULL && elementIndex == 1)
		{
		*value = itsNumericValues->GetElement(variableIndex);
		return kTrue;
		}
	else if (values != NULL && values->IndexValid(elementIndex))
		{
		*value = values->GetElement(elementIndex);
		return kTrue;
		}
	else
		{
		return kFalse;
		}
}

JBoolean
TestVarList::GetNumericValue
	(
	const JIndex	variableIndex,
	const JIndex	elementIndex,
	JComplex*		value
	)
	const
{
	JFloat x;
	if (GetNumericValue(variableIndex, elementIndex, &x))
		{
		*value = x;
		return kTrue;
		}
	else
		{
		return kFalse;
		}
}

/******************************************************************************
 SetNumericValue

 ******************************************************************************/

void
TestVarList::SetNumericValue
	(
	const JIndex	variableIndex,
	const JIndex	elementIndex,
	const JFloat	value
	)
{
	assert( 0 /* TestVarList::SetNumericValue() is not supported */ );
}

void
TestVarList::SetNumericValue
	(
	const JIndex	variableIndex,
	const JIndex	elementIndex,
	const JComplex&	value
	)
{
	assert( 0 /* TestVarList::SetNumericValue() is not supported */ );
}

/******************************************************************************
 GetDiscreteValue

 ******************************************************************************/

JIndex
TestVarList::GetDiscreteValue
	(
	const JIndex variableIndex,
	const JIndex elementIndex
	)
	const
{
	return 1;
}

/******************************************************************************
 GetDiscreteValueCount

 ******************************************************************************/

JSize
TestVarList::GetDiscreteValueCount
	(
	const JIndex index
	)
	const
{
	return 0;
}

/******************************************************************************
 GetDiscreteValueName

 ******************************************************************************/

const JString&
TestVarList::GetDiscreteValueName
	(
	const JIndex variableIndex,
	const JIndex valueIndex
	)
	const
{
	return kUnknownValueSymbol;
}

/******************************************************************************
 SetDiscreteValue

 ******************************************************************************/

void
TestVarList::SetDiscreteValue
	(
	const JIndex variableIndex,
	const JIndex elementIndex,
	const JIndex valueIndex
	)
{
	assert( 0 /* TestVarList::SetDiscreteValue() is not supported */ );
}
