/*
  ==============================================================================

  This is an automatically generated GUI class created by the Introjucer!

  Be careful when adding custom code to these files, as only the code within
  the "//[xyz]" and "//[/xyz]" sections will be retained when the file is loaded
  and re-saved.

  Created with Introjucer version: 3.1.0

  ------------------------------------------------------------------------------

  The Introjucer is part of the JUCE library - "Jules' Utility Class Extensions"
  Copyright 2004-13 by Raw Material Software Ltd.

  ==============================================================================
*/

//[Headers] You can add your own extra header files here...
//[/Headers]

#include "IQPlaneComponent.h"


//[MiscUserDefs] You can add your own user definitions and misc code here...
//[/MiscUserDefs]

//==============================================================================
IQPlaneComponent::IQPlaneComponent (uint32 maxNumPoints)
    : m_maxNumPoints(maxNumPoints), m_numPoints(0)
{

    //[UserPreSize]
	m_pPointArray = new sym_err_t[maxNumPoints];
    //[/UserPreSize]

    setSize (400, 400);


    //[Constructor] You can add your own custom stuff here..
	m_numConst = 4;
	for (int i=0; i < NUM_TRACKER_POINTS; i++)
	{
		m_trackerPoints[i].isEnabled = 0;
	}
    //[/Constructor]
}

IQPlaneComponent::~IQPlaneComponent()
{
    //[Destructor_pre]. You can add your own custom destruction code here..
    //[/Destructor_pre]



    //[Destructor]. You can add your own custom destruction code here..
	delete(m_pPointArray);
	m_pPointArray = nullptr;
    //[/Destructor]
}

//==============================================================================
void IQPlaneComponent::paint (Graphics& g)
{
    //[UserPrePaint] Add your own custom painting code here..
    juce::Point<float> p;
	juce::Colour c;
	uint32_t i;
    //[/UserPrePaint]

    g.fillAll (Colours::black);

    //[UserPaint] Add your own custom painting code here..
	if (m_pPointArray != nullptr)
	{
		for (i=0; i < m_numPoints; i++)
		{
			p.setX(m_pPointArray[i].soft_sym.real);
			p.setY(m_pPointArray[i].soft_sym.imag);
			c = Colour(juce::Colours::white).interpolatedWith(Colour(juce::Colours::red), 20*dabs(m_pPointArray[i].err_mag)).interpolatedWith(Colour(juce::Colours::blue), 20*dabs(m_pPointArray[i].err_phi));
			g.setColour (c);
			drawCross(g, p, 7);
		}
	}
	m_numPoints = 0;
    g.setColour (juce::Colours::limegreen);
	g.setOpacity(0.5);

	drawReference(g, 4, 1.0, 11);

	for (i=0; i < NUM_TRACKER_POINTS; i++)
	{
		if (m_trackerPoints[i].isEnabled)
		{
			g.setColour (m_trackerPoints[i].color);
			drawCircle(g, m_trackerPoints[i].point, m_trackerPoints[i].size);
		}
	}
    //[/UserPaint]
}

void IQPlaneComponent::resized()
{
    //[UserResized] Add your own custom resize handling here..
    //[/UserResized]
}

void IQPlaneComponent::mouseDown (const MouseEvent& e)
{
    //[UserCode_mouseDown] -- Add your code here...
	(void)e;
    //[/UserCode_mouseDown]
}



//[MiscUserCode] You can add your own definitions of your custom methods or any other code here...
void IQPlaneComponent::receiverStatusChanged(ReceiverInterface *pReceiver)
{
	params_t params;

	params = pReceiver->getParams();

	m_numConst = (uint32_t)pow(2.0, params.numBitsPerSymbol);
}

void IQPlaneComponent::trackerPointEnable(uint32_t id, juce::Colour color, cpx_t pos, float size)
{
	m_trackerPoints[id].color = color;
	m_trackerPoints[id].isEnabled = 1;
	m_trackerPoints[id].point.setX(pos.real);
	m_trackerPoints[id].point.setY(pos.imag);
	m_trackerPoints[id].size = size;

}

void IQPlaneComponent::trackerPointDisable(uint32_t id)
{
	m_trackerPoints[id].isEnabled = 0;
}

void IQPlaneComponent::pointAdd(sym_err_t *pPoint, uint32_t numPoints)
{
	uint32_t i;
	uint32_t numFill;

	if (m_numPoints >= m_maxNumPoints)
		return;

	numFill = (uint32_t)dmin(m_maxNumPoints-m_numPoints, numPoints);
	for (i=0; i < numFill; i++)
	{
		m_pPointArray[m_numPoints++] = pPoint[i];
	}
}

float IQPlaneComponent::getScreenCoordX(float x)
{
	if (isnan(x) || isinf(x))
		return 0;

	if ((x > 1.0) || (x < -1.0))
		return 0;

	return (float)(getWidth()*(1.0 + x)/2);
}

float IQPlaneComponent::getScreenCoordY(float y)
{
	if (isnan(y) || isinf(y))
		return 0;

	if ((y > 1.0) || (y < -1.0))
		return 0;

	return (float)(getHeight()*(1.0 + y)/2);
}

void IQPlaneComponent::drawReference(Graphics& g, uint32_t numConst, float radius, float size)
{
	float step;
	float s;
	float i, q;
	float x, y;
	uint32_t xx, yy;
	uint32_t N;

	N = (uint32_t)(sqrt((float)numConst));
	s = (float)(radius/sqrt(2));

	step = 2*s/(N-1);

	i = -s;
	xx = N;
	while(xx--)
	{
		q = -s;
		yy = N;
		while(yy--)
		{
			x = getScreenCoordX(i);
			y = getScreenCoordY(q);
			g.drawEllipse(x-size/2, y-size/2, size, size, 1.5);
			q += step;
		}
		i += step;
	}
}

void IQPlaneComponent::drawCross(Graphics& g, juce::Point<float> point, float size)
{
	float x, y;

	x = getScreenCoordX(point.getX());
	y = getScreenCoordY(point.getY());

	g.drawLine(x-size/2, y+size/2, x+size/2, y-size/2, 1.f);
	g.drawLine(x+size/2, y+size/2, x-size/2, y-size/2, 1.f);
}

void IQPlaneComponent::drawCircle(Graphics& g, juce::Point<float> point, float size)
{
	float x, y;

	x = getScreenCoordX(point.getX());
	y = getScreenCoordY(point.getY());

	g.drawEllipse(x-size/2, y-size/2, size, size, 1.5);
}

//[/MiscUserCode]


//==============================================================================
#if 0
/*  -- Introjucer information section --

    This is where the Introjucer stores the metadata that describe this GUI layout, so
    make changes in here at your peril!

BEGIN_JUCER_METADATA

<JUCER_COMPONENT documentType="Component" className="IQPlaneComponent" componentName=""
                 parentClasses="public Component, public ReceiverStatusListener"
                 constructorParams="uint32 maxNumPoints" variableInitialisers="m_maxNumPoints(maxNumPoints), m_numPoints(0)"
                 snapPixels="8" snapActive="1" snapShown="1" overlayOpacity="0.330"
                 fixedSize="0" initialWidth="400" initialHeight="400">
  <METHODS>
    <METHOD name="mouseDown (const MouseEvent&amp; e)"/>
  </METHODS>
  <BACKGROUND backgroundColour="ff000000"/>
</JUCER_COMPONENT>

END_JUCER_METADATA
*/
#endif


//[EndFile] You can add extra defines here...
//[/EndFile]
