/*********************************************************************************
 J2DVectorData.cc

	BASE CLASS = JPlotDataBase

	Copyright @ 1998 by Glenn W. Bach. All rights reserved.

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

#include <J2DVectorData.h>
#include <jAssert.h>

/*********************************************************************************
 Constructor function (static)

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

JBoolean
J2DVectorData::Create
	(
	J2DVectorData**			plotData, 
	const JArray<JFloat>&	x, 
	const JArray<JFloat>&	y,
	const JArray<JFloat>&	vx, 
	const JArray<JFloat>&	vy,
	const JBoolean			listen
	)
{
	if (OKToCreate(x,y, vx,vy))
		{
		*plotData = new J2DVectorData(x,y, vx,vy, listen);
		assert( *plotData != NULL );
		return kTrue;
		}
	else
		{
		*plotData = NULL;
		return kFalse;
		}
}

/*********************************************************************************
 OKToCreate (static)

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

JBoolean
J2DVectorData::OKToCreate
	(
	const JArray<JFloat>& x, 
	const JArray<JFloat>& y,
	const JArray<JFloat>& vx, 
	const JArray<JFloat>& vy
	)
{
	return JI2B(x.GetElementCount()  == y.GetElementCount() &&
				y.GetElementCount()  == vx.GetElementCount() &&
				vx.GetElementCount() == vy.GetElementCount());
}

/*********************************************************************************
 Constructor (protected)

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

J2DVectorData::J2DVectorData
	(
	const JArray<JFloat>&	x,
	const JArray<JFloat>&	y,
	const JArray<JFloat>&	vx,
	const JArray<JFloat>&	vy,
	const JBoolean			listen
	)
	:
	JPlotDataBase(kVectorPlot)
{
	assert( OKToCreate(x,y, vx,vy) );

	itsData = new JArray<J2DVectorPoint>;
	assert( itsData != NULL );

	const JSize count = x.GetElementCount();
	SetElementCount(count);

	for (JIndex i=1; i<=count; i++)
		{
		itsData->AppendElement(
			J2DVectorPoint(x.GetElement(i),  y.GetElement(i),
						   vx.GetElement(i), vy.GetElement(i)));
		}

	if (listen)
		{
		itsOrigXData  = &x;
		itsOrigYData  = &y;
		itsOrigVXData = &vx;
		itsOrigVYData = &vy;

		ListenTo(itsOrigXData);
		ListenTo(itsOrigYData);
		ListenTo(itsOrigVXData);
		ListenTo(itsOrigVYData);
		}
	else
		{
		itsOrigXData  = NULL;
		itsOrigYData  = NULL;
		itsOrigVXData = NULL;
		itsOrigVYData = NULL;
		}
}

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

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

J2DVectorData::~J2DVectorData()
{
	delete itsData;
}

/*********************************************************************************
 GetElement (virtual)

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

void
J2DVectorData::GetElement
	(
	const JIndex	index,
	J2DDataPoint*	data
	)
	const
{
	const J2DVectorPoint pt = itsData->GetElement(index);
	data->x = pt.x;
	data->y = pt.y;
}

/*********************************************************************************
 GetElement (virtual)

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

void
J2DVectorData::GetElement
	(
	const JIndex	index,
	J2DVectorPoint*	data
	)
	const
{
	*data = itsData->GetElement(index);
}

/*********************************************************************************
 GetXRange (virtual)

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

void
J2DVectorData::GetXRange
	(
	JFloat* min, 
	JFloat* max
	)
	const
{
	const JSize count = itsData->GetElementCount();
	for (JIndex i=1; i<=count; i++)
		{
		const J2DVectorPoint pt = itsData->GetElement(i);
		const JFloat x2         = pt.x + pt.vx;

		if (pt.x < *min || i == 1)
			{
			*min = pt.x;
			}
		if (x2 < *min || i == 1)
			{
			*min = x2;
			}

		if (pt.x > *max || i == 1)
			{
			*max = pt.x;
			}
		if (x2 > *max || i == 1)
			{
			*max = x2;
			}
		}
}

/*********************************************************************************
 GetYRange (virtual)

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

JBoolean
J2DVectorData::GetYRange
	(
	const JFloat	xMin, 
	const JFloat	xMax,
	JFloat*			yMin, 
	JFloat*			yMax
	)
	const
{
	const JSize count = itsData->GetElementCount();
	for (JIndex i=1; i<=count; i++)
		{
		const J2DVectorPoint pt = itsData->GetElement(i);
		const JFloat y2         = pt.y + pt.vy;

		if (pt.y < *yMin || i == 1)
			{
			*yMin = pt.y;
			}
		if (y2 < *yMin || i == 1)
			{
			*yMin = y2;
			}

		if (pt.y > *yMax || i == 1)
			{
			*yMax = pt.y;
			}
		if (y2 > *yMax || i == 1)
			{
			*yMax = y2;
			}
		}

	return kTrue;
}

/*********************************************************************************
 IgnoreDataChanges

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

void 
J2DVectorData::IgnoreDataChanges()
{
	if (itsOrigXData != NULL)
		{
		StopListening(itsOrigXData);
		StopListening(itsOrigYData);
		StopListening(itsOrigVXData);
		StopListening(itsOrigVYData);
		}

	itsOrigXData  = NULL;
	itsOrigYData  = NULL;
	itsOrigVXData = NULL;
	itsOrigVYData = NULL;
}

/*********************************************************************************
 Receive

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

void
J2DVectorData::Receive
	(
	JBroadcaster*	sender, 
	const Message&	message
	)
{
	if (sender == const_cast<JArray<JFloat>*>(itsOrigXData) ||
		sender == const_cast<JArray<JFloat>*>(itsOrigYData) ||
		sender == const_cast<JArray<JFloat>*>(itsOrigVXData) ||
		sender == const_cast<JArray<JFloat>*>(itsOrigVYData))
		{
		UpdateData();
		Broadcast(CurveChanged());
		}
	else
		{
		JPlotDataBase::Receive(sender, message);
		}
}

/******************************************************************************
 ReceiveGoingAway (virtual protected)

	The given sender has been deleted.

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

void
J2DVectorData::ReceiveGoingAway
	(
	JBroadcaster* sender
	)
{
	if (sender == const_cast<JArray<JFloat>*>(itsOrigXData) ||
		sender == const_cast<JArray<JFloat>*>(itsOrigYData) ||
		sender == const_cast<JArray<JFloat>*>(itsOrigVXData) ||
		sender == const_cast<JArray<JFloat>*>(itsOrigVYData))
		{
		IgnoreDataChanges();
		}
	else
		{
		JPlotDataBase::ReceiveGoingAway(sender);
		}
}

/*********************************************************************************
 UpdateData (private)

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

void
J2DVectorData::UpdateData()
{
	if (itsOrigXData != NULL &&
		OKToCreate(*itsOrigXData,  *itsOrigYData,
				   *itsOrigVXData, *itsOrigVYData))
		{
		const JSize count = itsOrigXData->GetElementCount();
		SetElementCount(count);

		itsData->RemoveAll();
		for (JIndex i=1; i<=count; i++)
			{
			itsData->AppendElement(
				J2DVectorPoint(itsOrigXData->GetElement(i),
							   itsOrigYData->GetElement(i),
							   itsOrigVXData->GetElement(i),
							   itsOrigVYData->GetElement(i)));
			}
		}
}

#define JTemplateType J2DVectorPoint
#include <JArray.tmpls>
#undef JTemplateType
