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

  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.

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


#include "RbmComponent.hpp"



//==============================================================================
RbmComponent::RbmComponent (const std::string &name, size_t id, size_t numVisibleX, size_t numVisibleY, size_t numHidden)
	: Layer(name, id, numVisibleX, numVisibleY, numHidden)
	, m_currWeightIndexToDraw(0)
	, DrawTraining(nullptr)
	, DrawReconstruction(nullptr)
	, DrawWeights(nullptr)
	, DrawHidden(nullptr)
{
	addAndMakeVisible (DrawTraining = new DrawComponent (numVisibleX, numVisibleY));
	DrawTraining->setListener(this);

	addAndMakeVisible (DrawHidden = new DrawComponent (numHidden, 1));
	DrawHidden->setListener(this);

	addAndMakeVisible (DrawReconstruction = new DrawComponent (numVisibleX, numVisibleY));
	addAndMakeVisible (DrawWeights = new DrawComponent (numVisibleX, numVisibleY, 0.5, 0.5));

	addAndMakeVisible (m_toggleEnable = new ToggleButton ("Enable layer"));
	m_toggleEnable->setTooltip (TRANS("Enable layer for up pass"));
	m_toggleEnable->setButtonText (TRANS("Enable"));
	m_toggleEnable->addListener (this);
	m_toggleEnable->setToggleState(true, NotificationType::dontSendNotification);
	redrawWeights();

	setSize (430, 130);
	resized();
	setBounds (16, 140*id+16, 430, 130);
}

RbmComponent::~RbmComponent()
{
	DrawTraining = nullptr;
	DrawReconstruction = nullptr;
	DrawWeights = nullptr;
	DrawHidden = nullptr;
}

//==============================================================================
void RbmComponent::paint (Graphics& g)
{
	g.fillAll (Colours::white);

	g.setColour (Colours::black);
	g.setFont (Font (15.00f, Font::plain));
	g.drawText (TRANS("Sigma"),
				32, 306, 80, 14,
				Justification::centred, true);

	g.setColour (Colours::black);
	g.setFont (Font (15.00f, Font::plain));
	g.drawText (TRANS("Lambda"),
				120, 306, 80, 14,
				Justification::centred, true);

	g.setColour (Colours::black);
	g.setFont (Font (15.00f, Font::plain));
	g.drawText (TRANS("Num. epochs"),
				32, 354, 80, 14,
				Justification::centred, true);

	g.setColour (Colours::black);
	g.setFont (Font (15.00f, Font::plain));
	g.drawText (TRANS("Alpha"),
				120, 354, 80, 14,
				Justification::centred, true);

	g.setColour (Colours::black);
	g.setFont (Font (15.00f, Font::plain));
	g.drawText (TRANS("Sparsity"),
				208, 306, 80, 14,
				Justification::centred, true);

	g.setColour (Colours::black);
	g.setFont (Font (15.00f, Font::plain));
	g.drawText (TRANS("Sigma decay"),
				296, 306, 96, 14,
				Justification::centred, true);

	g.setColour (Colours::black);
	g.setFont (Font (15.00f, Font::plain));
	g.drawText (TRANS("Weight decay"),
				296, 354, 96, 14,
				Justification::centred, true);

	g.setColour (Colours::black);
	g.setFont (Font (15.00f, Font::plain));
	g.drawText (TRANS("Momentum"),
				208, 354, 80, 14,
				Justification::centred, true);

	g.setColour (Colours::black);
	g.setFont (Font (15.00f, Font::plain));
	g.drawText (TRANS("Sparsity Alpha"),
				408, 306, 96, 14,
				Justification::centred, true);

	g.setColour (Colours::black);
	g.setFont (Font (15.00f, Font::plain));
	g.drawText (TRANS("Weight init"),
				408, 354, 96, 14,
				Justification::centred, true);

}

void RbmComponent::resized()
{
	DrawTraining->setBoundsRelative(0, 0, 100./430, 100./130);
	DrawReconstruction->setBoundsRelative(110./430, 0, 100./430, 100./130);
	DrawWeights->setBoundsRelative (220./430, 0, 100./430, 100./130);
	DrawHidden->setBoundsRelative (0, 110./130, 430./430, 20./130);
	m_toggleEnable->setBoundsRelative (330./430, 0, 80./430, 24./130);
}

void RbmComponent::mouseMove (const MouseEvent& e)
{
    //[UserCode_mouseMove] -- Add your code here...
    //[/UserCode_mouseMove]
}

void RbmComponent::mouseEnter (const MouseEvent& e)
{
    //[UserCode_mouseEnter] -- Add your code here...
    //[/UserCode_mouseEnter]
}

void RbmComponent::mouseExit (const MouseEvent& e)
{
    //[UserCode_mouseExit] -- Add your code here...
    //[/UserCode_mouseExit]
}

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

void RbmComponent::mouseDrag (const MouseEvent& e)
{
    //[UserCode_mouseDrag] -- Add your code here...
//	e.eventComponent->setCentrePosition(e.getPosition().x, e.getPosition().y);
	std::cout << "Mouse = " << e.x << "," << e.y << std::endl;
    //[/UserCode_mouseDrag]
}

void RbmComponent::mouseUp (const MouseEvent& e)
{
    //[UserCode_mouseUp] -- Add your code here...
    //[/UserCode_mouseUp]
}

void RbmComponent::mouseDoubleClick (const MouseEvent& e)
{
    //[UserCode_mouseDoubleClick] -- Add your code here...
    //[/UserCode_mouseDoubleClick]
}

void RbmComponent::mouseWheelMove (const MouseEvent& e, const MouseWheelDetails& wheel)
{
    //[UserCode_mouseWheelMove] -- Add your code here...
    //[/UserCode_mouseWheelMove]
}

void RbmComponent::onDraw(DrawComponent &obj)
{
	if (&obj == DrawHidden)
	{
		downPass(obj.getData());
	}
	if (&obj == DrawTraining)
	{
		upDownPass(obj.getData());
	}
}

void RbmComponent::buttonClicked(Button* buttonThatWasClicked)
{
	if (buttonThatWasClicked == m_toggleEnable)
	{
		bool state = buttonThatWasClicked->getToggleState();
		if (next)
		{
			RbmComponent *pComp = static_cast<RbmComponent*> (next);
			pComp->m_toggleEnable->setToggleState(state, NotificationType::sendNotification);
		}
		redrawReconstruction();
	}
}

void RbmComponent::redrawReconstruction()
{
	RbmComponent *pComp = static_cast<RbmComponent*> (root());
	pComp->upDownPass(pComp->DrawTraining->getData());

}

void RbmComponent::gibbs(const arma::mat& v)
{
	arma::mat r = v;
	for (int i=0; i < params().numGibbs; i++)
	{
		DrawHidden->getData() = toHiddenProbs(r);
		r = toVisibleProbs(DrawHidden->getData());
	}
	DrawReconstruction->getData() = r;
	DrawReconstruction->DrawData();
	DrawHidden->DrawData();
}

void RbmComponent::upPass(const arma::mat& v)
{
	DrawTraining->getData() = v;
	DrawTraining->DrawData();
	gibbs(v);
	if (next)
	{
		RbmComponent *pComp = static_cast<RbmComponent*> (next);
			pComp->upPass(DrawHidden->getData());
		}
	}

void RbmComponent::downPass(const arma::mat& h)
{
	DrawHidden->getData() = h;
	DrawHidden->DrawData();
	DrawReconstruction->getData() = toVisibleProbs(h);
	DrawReconstruction->DrawData();
	if (prev)
	{
		RbmComponent *pComp = static_cast<RbmComponent*> (prev);
		pComp->downPass(DrawReconstruction->getData());
	}
}

void RbmComponent::upDownPass(const arma::mat& v)
{
	DrawTraining->getData() = v;
	DrawTraining->DrawData();
	gibbs(v);
	if (next)
	{
		RbmComponent *pComp = static_cast<RbmComponent*> (next);
		if (pComp->m_toggleEnable->getToggleState())
		{
			pComp->upDownPass(DrawHidden->getData());
		}
		else
		{
			return;
		}
	}
	else if (prev)
	{
		if (prev)
		{
			RbmComponent *pComp = static_cast<RbmComponent*> (prev);
			pComp->downPass(DrawReconstruction->getData());
		}
	}

}

arma::mat RbmComponent::getConvolutedWeight(arma::mat const &w)
{
//	if (next)
//	{
//		arma::mat wc = w * next->w().t(); // * 1.0/sqrt((double)w.cols());
//		return static_cast<RbmComponent*>(next)->getConvolutedWeight(wc);
//	}
//	else
	{
		return w;
	}
	
}
void RbmComponent::redrawWeights()
{
	DrawWeights->getData() = getConvolutedWeight(w().col(m_currWeightIndexToDraw));
	DrawWeights->DrawData();
}

void RbmComponent::redrawWeights(size_t index)
{
	m_currWeightIndexToDraw = index;
	redrawWeights();
}

void RbmComponent::setTrainingData(arma::mat const& batch)
{
	RbmComponent *pComp = static_cast<RbmComponent*> (root());
	pComp->upDownPass(batch);
}
//[/MiscUserCode]


//==============================================================================
