#include "Parser.h"
#include "iostream"

Parser::Parser(Context * context)
{
	this->context = context;
    error_message = "***ERRORS DURING PARSING***\n";
    report_message = "***PARSER REPORT***\n";
    position_in_stream = 0;
    in_statement = false;
    program = static_cast<ProgramNode *>(tree.root);
}


Parser::~Parser()
{
    //dtor
}

void Parser::erase_all()
{
	tree.delete_all_children();
	tree.root = new ProgramNode();
	error_message = "***ERRORS DURING PARSING***\n";
	report_message = "***PARSER REPORT***\n";
	position_in_stream = 0;
	in_statement = false;
	program = static_cast<ProgramNode *>(tree.root);


}
string Parser::show_tokens()
{
	string tokens = "";
	for (unsigned int i = 0; i < token_stream.size(); i++)
	{
		tokens += token_stream[i].value + " ";
	}
	return tokens;
}

void Parser::add_tokens(vector<Token> tokens)
{
	for (unsigned int i = 0; i < tokens.size(); i++)
	{
		token_stream.push_back(tokens[i]);
	}
}

void Parser::report(string s)
{
    report_message += s ;
}

void Parser::error(string s)
{
    error_message += s ;
}

bool Parser::read_next()
{
    if(position_in_stream < token_stream.size())
    {
        current_token = token_stream[position_in_stream];
        tok_value = current_token.get_value();
        position_in_stream++;
        return true;
    }
    else
    {
        current_token = Token(t_invalid_token, "");
        tok_value = current_token.get_value();
        return false;
    }
}

void Parser::interpret()
{
	read_next();
    while(tok_value!= "")
    {
    	program->add_statement(statement(program));
    }


}

bool Parser::peek(string s)
{
    return tok_value == s;
}

bool Parser::accept(string s)
{
    if(peek(s))
    {
        read_next();
        return true;
    }
    else return false;
}

bool Parser::expect(string s)
{
    if(!accept(s))
    {
        string error_message = "Error: expected ";
        error_message += s;
        error_message += " but received: " + tok_value + "\n";

        error(error_message);
        return false;
    }
    else return true;
}

bool Parser::is_type()
{

   if(tok_value == "def" || tok_value == "string" || tok_value == "num")
   {
        read_next();
        return true;
   }

    else
    {
    	return false;
    }
}

ASTStatement * Parser::statement(ASTNode * parent)
{
	BasicStatement * stat = new BasicStatement(parent);

    if(accept("{"))
    {
         while(!accept("}"))
         {
             stat = static_cast<BasicStatement * >(statement(parent));
         }
    }


    else if(is_type())
    {
    	DeclarationStatement * declaration = new DeclarationStatement(parent, context);
    	std::string identifier = tok_value;
    	report("Identifier: " + identifier + "\n");
    	read_next();

    	declaration->add_name(identifier);

    	if(accept("="))
    	{
    		ASTExpression * ae = expr(stat);
    		declaration->add_right_value(ae);

    		report(" := \n");
    		accept(";");
    	}

    	if(accept(";"))
    	{
    		report("Variable declaration\n");
    	}

    	if(expect("("))
    	{
    		int argc = 0;
    		while(tok_value != ")")
    		{
    			argc++;
    			is_type();
    			report("function argument: " + tok_value + "\n");
    			declaration->add_argument(tok_value);
    			read_next();
    			if(peek(")"))
    			{
    				break;
    			}
    			expect(",");
    		}
    		expect(")");

    		if(!accept(";"))
    		{
    			report("function body:\n");
    			declaration->add_body(statement(stat));
    			report("function definition\n");
    		}

    	}

    	delete stat;
    	return declaration;

    }
    else if(accept("if"))
    {
        //stuff
        //TODO implement that
    	return stat;
    }
    else if(accept("while"))
    {
        //similar stuff
    	return stat;
    }
    else if(accept("return"))
    {

        if(!peek(";"))
        {
            stat->add_expression(expr(stat));
        }
        expect(";");
        report("RETURN\n");
        return stat;

    }
    else
    {

    	stat->add_expression(expr(stat));
        while(!expect(";") && tok_value != "") read_next();
        return stat;

    }

    return stat;
}

ASTExpression * Parser::prim_expr(ASTNode * expression)
{
	ConstantExpression * ce;
	BasicExpression * be;
	//TODO add reference type to prims, syblol is now just a literal... and floats
	if(current_token.get_type() == t_integer)
	{
		report("Number: " + tok_value + "\n");

		ce = new ConstantExpression(expression, std::atoi(tok_value.c_str()));
		read_next();
	}
	else if(current_token.get_type() == t_literal)
	{

		report("Character literal: " + tok_value + "\n");
		ce = new ConstantExpression(expression, tok_value);
		read_next();
	}
	else if(current_token.get_type() == t_symbol)
	{
		report("variable: " + tok_value + "\n");
		SenchaObject variable;
		//TODO is it right?
		string name = current_token.value;

		variable = context->get(name);
		variable.name = name;
		ce = new ConstantExpression(expression, variable, name);
		read_next();
	}
	else if(accept("("))
	{
		report("( ");
		be = static_cast<BasicExpression *>(expr(expression));
		report(" ) ");
		expect(")");
		return be;
	}
	else
	{
		string error_message = "ERROR: unexpected primary expression " + tok_value + "\n";
		error(error_message);
		read_next();
		return new IncorrectExpression(expression, error_message);
	}

	return ce;
}

ASTExpression * Parser::postfix_expr(ASTNode * expression)
{
	//TODO implement postfix expression ASAP
	BasicExpression * be = new BasicExpression(expression);
    prim_expr(be);
    if(accept("["))
    {
       expr(be);
       expect("]");
       report(" [] ");

    }
    else if(accept("("))
    {
        if(!accept(")"))
        {
            expr(be);
            report("function argument\n");
            while(accept(","))
            {
                expr(be);
                report("function argument\n");
            }

            expect(")");
        }
        report("FUNC_CALL\n");
    }


    //TODO implement postfix_expression
    return be;
}

ASTExpression * Parser::mul_expr(ASTNode * expression)
{
	BasicExpression * be = new BasicExpression(expression);
	be->set_left_operand(prim_expr(be));
	    if(peek("*") || peek("/"))
	    {
	        if(accept("*"))
	        {
	        	be->set_operator("*");
	            report(" *\n");
	        } else if(accept("/"))
	        {
	        	be->set_operator("/");
	            report(" /\n");
	        }
	        be->set_right_operand(mul_expr(be));
	    }

	    if(be->oper == "")
	    {
	        ASTExpression * ae;
	        ae = static_cast<ASTExpression *>(be->children[0]);
	        ae->parent = expression;
	        delete be;
	        return ae;
	    }

	return be;
}

ASTExpression * Parser::add_expr(ASTNode * expression)
{
	BasicExpression * be = new BasicExpression(expression);
    be->set_left_operand(mul_expr(be));
    if(peek("+") || peek("-"))
    {
        if(accept("+"))
        {
            report(" +\n");
            be->set_operator("+");
        }
        else if(accept("-"))
        {
            report(" -\n");
            be->set_operator("-");
        }
        be->set_right_operand(add_expr(be));
    }

    if(be->oper == "")
    {
    	ASTExpression * ae;
    		        ae = static_cast<ASTExpression *>(be->children[0]);
    		        ae->parent = expression;
    		        delete be;
    		        return ae;
    }

    return be;
}

ASTExpression * Parser::rel_expr(ASTNode * expression)
{
	BasicExpression * be = new BasicExpression(expression);
	be->set_left_operand(add_expr(be));
    if(peek("<") || peek(">"))
    {
        if(accept("<"))
        {
        	be->set_operator("<");
        	report(" <\n");
        }
        else if (accept(">"))
        {
        	be->set_operator(">");
        	report(" >\n");
        }
        be->set_right_operand(rel_expr(be));
    }

    if(be->oper == "")
    {
    	ASTExpression * ae;
    	ae = static_cast<ASTExpression *>(be->children[0]);
    	ae->parent = expression;
    	delete be;
    	return ae;
    }


    return be;
}

ASTExpression * Parser::eq_expr(ASTNode * expression)
{
	BasicExpression * be = new BasicExpression(expression);
	be->set_left_operand(rel_expr(be));
    if(peek("==") || peek("!="))
    {
        if(accept("=="))
        {
        	be->set_operator("==");
            report("==\n");
        }
        else if(accept("!="))
        {
        	be->set_operator("!=");
            report("!=\n");
        }
        be->set_right_operand(eq_expr(be));
    }

    if(be->oper == "")
    {
    	ASTExpression * ae;
    	ae = static_cast<ASTExpression *>(be->children[0]);
    	ae->parent = expression;
    	delete be;
    	return ae;
    }

    return be;
}

ASTExpression * Parser::expr(ASTNode * expression)
{
	Assignment * assignment = new Assignment(expression, context);
	ASTExpression * left = eq_expr(assignment);

    if(accept("="))
    {
    	ASTExpression * right = expr(assignment);

    	assignment->add_lvalue(left);
    	assignment->add_rvalue(right);

        report(" :=\n");
        return assignment;
    }

    else
    {
    	left->parent = expression;
    	delete assignment;
    	return left;
    }

}
