#include <fstream>
#include <iostream>
#include <string>
#include <math.h>
#include "Token.h"
#include "Lexer.h"
#include "Parser.h"
#include "Tests/TestLexer.h"
#include "ContextManager.h"
#include "ASTInspector.h"
#include "Tests/tests.h"
#include "basic_native_functions.h"
#include <unistd.h>

using namespace std;

//Helper functions
void register_functions(ContextManager & context_manager)
{
	context_manager.context("global")->register_function("print", print);
	context_manager.context("global")->register_function("println", println);
	context_manager.context("global")->register_function("sin", s_sin);
	context_manager.context("global")->register_function("cos", s_cos);
	context_manager.context("global")->register_function("tan", s_tan);
	context_manager.context("global")->register_function("sleep", sleep);
	context_manager.context("global")->register_function("len", len);
}

string compute_indentation(int depth_level)
{
	string indent = "";
	for(int i=0; i< depth_level; i++)
	{
		indent += "    ";
	}
	return indent;
}

int how_depth_change(vector<Token> tokens)
{
	int change = 0;
	for (unsigned int i = 0; i < tokens.size(); i++)
	{
		if(tokens[i].value == "{") change++;
		else if(tokens[i].value == "}") change--;
	}
	return change;
}

void interactive()
{
	//Initialization
	Lexer lexer;

	ContextManager context_manager;
	register_functions(context_manager);

	Parser parser(&context_manager);
	ASTInspector inspector;
	vector<Token> tokens;

	string input;
	int level_of_depth = 0;
	string indentation = "";
	//Main loop of interactive mode
	while(true)
	{
		cout << ">> " + indentation;
		getline(cin, input);
		if(input == "quit()") break;
		tokens = lexer.parse_line(input);

		level_of_depth += how_depth_change(tokens);
		indentation = compute_indentation(level_of_depth);

		parser.add_tokens(tokens);

		//It executes when statements and braces are closed
		if(level_of_depth == 0) {
			parser.interpret();
			parser.program->execute_last();
			inspector.visit(parser.tree.root);
			cout << context_manager.get_top()->debug() << endl;
			//cout << parser.show_tokens();
			cout << inspector.get_report();
			inspector.forget_everything();
		}
	}
}

void execute_script(std::string name )
{
	Lexer lexer;
	ContextManager context_manager;
	register_functions(context_manager);
	Parser parser(&context_manager);

	vector<Token> tokens;
	string line;
	ifstream input_file (name);

	if (input_file.is_open())
	{
		while ( input_file.good() )
		{
			getline (input_file,line);
			tokens = lexer.parse_line(line);
			parser.add_tokens(tokens);
		}
		input_file.close();
	}
	parser.interpret();
	parser.program->execute();
}

/**
 * Main function resolves in which mode user want to run program
 * Modes are:
 * Interactive - it is run when no arguments are provided
 * Tests - "SenchaLang --test"
 * Script execution - if path provided
 */

int main(int argc, char *argv[])
{
	if(argc <= 1)
	{
		cout << "Sencha-lang interpreter, version 0.44" << endl;
		interactive();
	}
	else
	{
		std::string argument1 = argv[1];
		if(argument1 == "--test")
		{
			cout << "I'm running tests" << endl;
			run_tests();
		}
		else {
			execute_script(argument1);
		}
	}

	return 0;
}
