<?php
error_reporting(E_ALL);
include_once("node.class.php");
include_once("database.class.php");
include_once("singleStock.class.php");
include_once("stock.class.php");
include_once("oanda.php");

class neuralNetwork {

		const CURRENTTREND = 0;
		const MACD = 1;
		const RATEOFCHANGE = 2;
		const PASTPRICE = 3;
		const VOLUMESTATUS = 4;

		public $nodeSize;
		public $nodes = array();
		public $inputNodes = array();
		public $outputNodes = array();
		public $darkNodes = array();
		public $identifier;
		public $singleStock;
		public $stock;
		public $id;
		public $db;
		public $timeFrame;
		public $hourFrame;
		public $account;
		public $accountNumber;
		public $endTime;
		public $units;
		public $outputStatus = "false";
		public $weak_buy_weight;
		public $weak_sell_weight;
		public $strong_buy_weight;
		public $strong_sell_weight;

function __construct($identifier, $timeFrame, $hour, $startTime, $units){
		$this->db = new database();
		$this->stock = new stock($identifier, $hour, $startTime, $timeFrame, $units);
		$this->singleStock = new singleStock($identifier);
		$this->identifier = $identifier;
		$stmt = $this->db->db->prepare("INSERT INTO pairs (identifier, timeFrame, success) VALUES (:identifier, :timeFrame, :success)");
		$stmt->execute(array(':identifier' => $this->identifier, ':timeFrame' => $timeFrame, ':success' => false));
		$this->id = $this->db->db->lastInsertId();
		$this->timeFrame = $timeFrame;
		$this->hourFrame = $hour;
		$this->startTime = $this->endTime;
		$this->account = new oandaAPI();
		$this->accountNumber = 734010;
		$this->units = $units;
		$this->calculate_weights(); //need to actually implement in the code for that portion of it.
	}
public function nodes(){
	

	$this->nodes[neuralNetwork::CURRENTTREND]->assignNodeRandomize($this->randomizer());
	$this->nodes[neuralNetwork::MACD]->assignNodeRandomize($this->randomizer());
	$this->nodes[neuralNetwork::RATEOFCHANGE]->assignNodeRandomize($this->randomizer());
	$this->nodes[neuralNetwork::PASTPRICE]->assignNodeRandomize($this->randomizer());
	$this->nodes[neuralNetwork::VOLUMESTATUS]->assignNodeRandomize($this->randomizer());

	$this->nodes[neuralNetwork::CURRENTTREND]->assignNodeInput($this->stock->currentTrend);
	$this->nodes[neuralNetwork::MACD]->assignNodeInput($this->stock->macd);
	if(is_nan($this->stock->rateOfChange)){
		$this->stock->rateOfChange = 0;
	}

	$this->nodes[neuralNetwork::RATEOFCHANGE]->assignNodeInput($this->stock->rateOfChange);
	$this->nodes[neuralNetwork::PASTPRICE]->assignNodeInput($this->stock->pastPrice);
	$this->nodes[neuralNetwork::VOLUMESTATUS]->assignNodeInput($this->stock->volumeStatus);

	$this->nodes[neuralNetwork::CURRENTTREND]->assignNodeOutput();
	$this->nodes[neuralNetwork::MACD]->assignNodeOutput();
	$this->nodes[neuralNetwork::RATEOFCHANGE]->assignNodeOutput();
	$this->nodes[neuralNetwork::PASTPRICE]->assignNodeOutput();
	$this->nodes[neuralNetwork::VOLUMESTATUS]->assignNodeOutput();

	}
public function inputNodes(){
		return $this->inputNodes;
	}
// Need to output nodes 	
public function outputNodes(){
		return $this->outputNodes;
	}
private function randomizer(){
	$min = 0;
	$max = 1;
	$val = $min + mt_rand() / mt_getrandmax() * ($max - $min);
	return $val;
}
private function checkRandomizerU(){
}
// 	Time to randomize the Nodes
public function randomizeNodes(){
		foreach($this->nodes as $node){
			$node->assignNodeRandomize($this->randomizer());
		}
		foreach($this->nodes as $node){
			checkRandomizerU($node->getNodeRandomizer());
		}
	}
// 	Need this to access databse, set the valid system into database to store for future.
static public function correct(bool $correctData){
	$db = new database();
	$stmt = $db->db->prepare("UPDATE pairs SET success = true WHERE success = 0");
	$stmt->execute();
	}
// Need this to access to database, set the invalid system into database to store for future.
static public function incorrect(bool $incorrectData){
	$db = new database();
	$stmt = $db->db->prepare("UPDATE pairs SET success = false WHERE success = 0");
	$stmt->execute();
	}
// 	Calcuate the node size
public function calculateNodeSize($inputNodesSize){
	/*	$tempSize = ($inputNodesSize * 2);
		$tempSize += ($tempSize / 2);
		$tempSize += ($tempSize / 2 - 1);
		$tempSize += (($tempSize / 2) / 2);
		for($i = $tempSize; $i > 0; $i--){
			$tempSize += $i;
		} */
		$this->nodeSize = $inputNodesSize;
	}
// 	Need to clear out the nodes 
public function destroyNodes(){
		unset($this->inputNodes);
		unset($this->outputNodes);
		unset($this->nodes);
		$nodeSize = 0;
	}
public function calculate() {
	$this->loadInputNodes();
// 		Need to calculate the size of the appropiate node size
	$size = sizeof($this->nodes); 
// 		This allows us to calculate the number of nodes needed.
	$this->calculateNodeSize($size); 
// 		This will create the amount of nodes;
	$this->nodes();
//		This will create output
	$this->generateOutput();
}
private function generateOutput() {
	$finalOutput = 0;
	foreach($this->nodes as $n)
	{
		$finalOutput += $n->nodeOutput;
	}
	 // $finalOutput = $this->nodes[CURRENTTREND]->nodeOutput + $this->nodes[MACD]->nodeOutput + $this->nodes[RATEOFCHANGE]->nodeOutput + $this->nodes[PASTPRICE]->nodeOutput + $this->nodes[VOLUMESTATUS]->nodeOutput;
	$tempDecision = "none";
	if ($finalOutput > 0 && $finalOutput < $this->weak_buy_weight) {
		$tempDecision = "Buy";
		$this->account->placeMarketTrade($this->accountNumber, $this->identifier, "B", $this->units);

	} else if ($finalOutput >= $this->strong_buy_weight) {
		$tempDecision = "Strong Buy";
		$this->account->placeMarketTrade($this->accountNumber, $this->identifier, "SB", $this->units);

	} else if ($finalOutput < 0 && $finalOutput > $this->weak_sell_weight) {
		$tempDecision = "Short";
		$this->account->placeMarketTrade($this->accountNumber, $this->identifier, "S", $this->units);

	} else if ($finalOutput <= $this->strong_sell_weight) {
		$tempDecision = "Strong Short";
		$this->account->placeMarketTrade($this->accountNumber, $this->identifier, "SS", $this->units);

	}
	$outputArray = array("suggestion" => $tempDecision, "EntryPoint" => "Beta", "profitPoint" => "Beta", "strength" => abs(round($finalOutput, 1))*100, 'Predicted Value' => $finalOutput);
	echo json_encode($outputArray);
}
private function calculate_weights()
{
	//this actually needs to do something...
	$this->weak_buy_weight = 0.45;
	$this->weak_sell_weight = -0.45;
	$this->strong_buy_weight = 0.5;
	$this->strong_sell_weight = -0.5;
}
private function backTest(){
//	for($i = 0; $i < 500; $i++){
	//	$temp  = new stock($)
//	}
//	foreach($this->stock){
//
//	}
}

private function loadInputNodes(){
		for($i = 0; $i < 5; $i++){
			$this->nodes[] = new node();
		}
	//	$this->inputNodes[0]->nodeInput = $this->identifier;
}
private function setNodesRow($nodes){
		$tempCounter = $this->nodeSize;
		$currentNodeRow = 1;
		$sub = 0;
// 		Looping through the nodes getting rows correct (hopefully)
		foreach($nodes as $node){
			if($tempCounter < sizeof($this->inputNodes)){
				$node->setNodeRow($currentNodeRow);
			}
			else if($tempCounter == sizeof($this->inputNodes)){
				$node->setNodeRow($currentNodeRow);
				$currentNodeRow++;
			}
			else if($tempCounter < (sizeof($this->inputNodes) * 2)){
				$node->setNodeRow($currentNodeRow);
			}
			else if($tempCounter == (sizeof($this->inputNodes) * 2)){
				$node->setNodeRow($currentNodeRow);
				$currentNodeRow++;
			}
			else if($tempCounter <= (sizeof($this->inputNodes) * 2) + (sizeof($this->inputNodes) / 2)){
				$node->setNodeRow($currentNodeRow);
			}
			else if($tempCounter == (sizeof($this->inputNodes) * 2) + (sizeof($this->inputNodes) / 2)){
				$node->setNodeRow($currentNodeRow);
				$currentNodeRow++;
			}
			else if($tempCounter <= (sizeof($this->inputNodes) * 2) + (sizeof($this->inputNodes) / 2) - $sub){
				$node->setNodeRow($currentNodeRow);
			}
			else if($tempCounter == (sizeof($this->inputNodes) * 2) + (sizeof($this->inputNodes) / 2) - $sub){
				$node->setNodeRow($currentNodeRow);
				$sub++;
				$currentNodeRow++;
			}
			$tempCounter++;
		}
// 		End of the foreach statment
	}
// Be able to get an algorithim to be used more than once
private function setAlgo(int $algoId)
{

}
//Generate into an algorithim to be used more than once. (this can be automated as well.)
private function gen_algo(int $algoId)
{

}
//	END OF CLASS
}
?>