#include <Neuron.h>
#include <QGraphicsTextItem>
#include <QTime>
#include <iostream>
#include <Utilities.h>
#include <math.h>

using namespace std;

Neuron::Neuron()
{
    this->type = HIDDEN;
    this->setPosition(0, 0);

    if(this->type == HBIAS || this->type == IBIAS)
    {
        this->weight = 1.0;
        this->output = 1.0;
    }
    else
    {
        this->weight = Utilities::randFloat(0.1, 1);
        if(weight < 0.01)
            weight = 0.01;
    }

    output = 0.0;
}

Neuron::Neuron(int type, float xPos, float yPos, float w)
{
    this->type = type;
    this->setPosition(xPos, yPos);

    if(this->type == HBIAS || this->type == IBIAS)
    {
        this->weight = 1.0;
        this->output = 1.0;
    }
    else if(w != 0.0)
    {
        this->weight = w;
    }
    else
    {
        this->weight = Utilities::randFloat(0.1, 1);
        if(weight < 0.01)
            weight = 0.01;
    }

    output = 0.0;
}

Neuron *Neuron::replace(int type, float xPos, float yPos, float w)
{
    return new Neuron(type, xPos, yPos, w);
}

void Neuron::setWeight(float w)
{
    weight = w;
}

Neuron::~Neuron()
{

}

void Neuron::draw(QGraphicsScene *s)
{
    QColor cColour;
    QString additionalText;
    QString weightText = QString("W: ");
    weightText.append(QString::number(this->weight));

    switch(this->type)
    {
    case INPUT:
        cColour = QColor(1, 0, 0);
        additionalText = QString("INPUT");
        break;
    case OUTPUT:
        cColour = QColor(0, 0, 1);
        additionalText = QString("OUTPUT");
        break;
    case HIDDEN:
        cColour = QColor(1, 0, 1);
        additionalText = QString("HIDDEN");
        break;
    case IBIAS:
        cColour = QColor(0, 1, 0);
        additionalText = QString("BIAS");
        break;
    case HBIAS:
        cColour = QColor(0, 1, 1);
        additionalText = QString("BIAS");
        break;
    }

    QBrush *brush = new QBrush(cColour);

    s->addEllipse(this->getPosition()[0], this->getPosition()[1], 30, 30, QPen(cColour), *brush);
    s->addText(additionalText)->setPos(this->getPosition()[0], this->getPosition()[1] - 30);
    s->addText(weightText)->setPos(this->getPosition()[0], this->getPosition()[1] + 30);
    wText = s->items().first();
}

void Neuron::setPosition(float x, float y)
{
    this->position[0] = x;
    this->position[1] = y;
}

void Neuron::setActivation(float biasValue, QList<float> inputValues, QList<float> inputWeights)
{
    activation = biasValue;

    for(int i = 0; i < inputValues.length(); i++)
    {
        activation += (inputWeights[i] * inputValues[i]);
    }
}

void Neuron::setOutput(float act)
{
    if(this->type == OUTPUT)
    {
        output = act;
    }
    else
    {
        output = tanh(act);
    }
}

void Neuron::calculateError(float value, float e)
{
    if(this->type == OUTPUT)
    {
        error = (e - output);
    }
    else
    {
        error = (e * weight) * (1 - (output * output));
    }
}

void Neuron::updateWeights(float learningRate, float error, float input)
{
  //  if(this->type == HBIAS || this->type == IBIAS)
   // {
        this->weight = weight + (learningRate * error * input);
   // }
   /* else
    {
        this->weight = weight + (learningRate * error * output);
    }*/
}

QGraphicsItem *Neuron::getWText()
{
    return this->wText;
}

void Neuron::setWeightText(QGraphicsScene *s)
{
    QString weightText = QString("W: ");
    weightText.append(QString::number(this->weight));
    s->addText(weightText)->setPos(this->getPosition()[0], this->getPosition()[1] + 30);
    wText = s->items().first();
}
