package Compiler;

import java.util.List;
/**
 * Classes for possible statements in the language
 */
abstract class Statement {

    /**
     * Class for the main function of the program
     */
    static class MainFunction extends Statement{
        MainFunction(Statement block){
            this.block = block;
        }

        final Statement block;

        @Override
        public String getStatmentType() {
            return "main";
        }
        
    }

    /**
     * Class for representing a function
     */
    static class Function extends Statement{
        Function(Token name,Statement block,List<Expression> arguments,List<String> argumentTypes,String returnType){
            this.block=block;
            this.arguments=arguments;
            this.returnType=returnType;
            this.argumentTypes=argumentTypes;
            this.name=name;
        }

        final Statement block;
        final List<Expression> arguments;
        final List<String> argumentTypes;
        final String returnType;
        final Token name;

        @Override
        public String getStatmentType() {
            return "function";
        } 
    }

    /**
     * Class for representing a function declaration 
     * needed for compiling to C
     */
    static class FunctionDeclaration extends Statement{
        FunctionDeclaration(Token name,List<String> argumentTypes,String returnType){
            this.returnType=returnType;
            this.argumentTypes=argumentTypes;
            this.name=name;
        }
        
        final List<String> argumentTypes;
        final String returnType;
        final Token name;

        @Override
        public String getStatmentType() {
            return "functionDec";
        } 
    }

    /**
     * Class for representing a return statement
     */
    static class ReturnStatement extends Statement{

        ReturnStatement(Expression returnValue){
            this.returnValue=returnValue;

        }
        final Expression returnValue;

        @Override
        public String getStatmentType() {
            return "return";
        }
        
    }

    /**
     * Class for representing a statement for an expression
     */
    static class ExpressionStatement extends Statement{
        ExpressionStatement(Expression expr){
            this.expr = expr;
        }


        final Expression expr;

        @Override
        public String getStatmentType() {
            return "exprStmt";
        }
    }

    /**
     * Class for representing a block of statements
     */
    static class BlockStatement extends Statement{
        BlockStatement(List<Statement> statements){
            this.statements=statements;
        }

        final List<Statement> statements;

        @Override
        public String getStatmentType() {
            return "block";
        }
        
    }

    /**
     * Class for representing an if statement
     */
    static class IfStatement extends Statement{
        IfStatement(Expression condition, Statement ifBlock,Statement elseBlock){
            this.condition=condition;
            this.ifBlock=ifBlock;
            this.elseBlock=elseBlock;
        }

        final Expression condition;
        final Statement ifBlock;
        final Statement elseBlock;

        @Override
        public String getStatmentType() {
            return "ifStmt";
        }
    }

    /**
     * Class for representing a do loop
     */
    static class DoStatement extends Statement{
        DoStatement(Expression variable, Expression start,Expression stop,Expression step,Statement codeBlock){
            this.variable=variable;
            this.start=start;
            this.stop=stop;
            this.step=step;
            this.codeBlock=codeBlock;

        }

        final Expression variable;
        final Expression start;
        final Expression stop;
        final Expression step;
        final Statement codeBlock;

        @Override
        public String getStatmentType() {
            return "doStmt";
        }
    }

    /**
     * Class for representing a do while loop
     */
    static class DoWhileStatement extends Statement{
        DoWhileStatement(Expression condition,Statement codeBlock){
            this.condition=condition;
            this.codeBlock=codeBlock;

        }

        final Expression condition;
        final Statement codeBlock;

        @Override
        public String getStatmentType() {
            return "dowhileStmt";
        }
    }

    /**
     * Class for representing a integer or real declaration
     * 
     */
    static class VariableDeclaration extends Statement{
        VariableDeclaration(Token name,String type){
            this.name=name;
            this.type=type;
        }


        final Token name;
        final String type;

        @Override
        public String getStatmentType() {
            return "varDec";
        }

    }

    /**
     * Class for representing a string variable declaration
     */
    static class StringDeclaration extends Statement{
        StringDeclaration(Token name,Expression length){
            this.name=name;
            this.length=length;
        }


        final Token name;
        final Expression length;

        @Override
        public String getStatmentType() {
            return "stringDec";
        }

    }

    /**
     * Class for representing an array declaration
     */
    static class ArrayDeclaration extends Statement{
        ArrayDeclaration(Token name,String type,List<Expression> dimensions){
            this.name=name;
            this.dimensions=dimensions;
            this.type=type;
        }

        final String type;
        final Token name;
        final List<Expression> dimensions;

        @Override
        public String getStatmentType() {
            return "arrayDec";
        }

    }

    /**
     * Class for representing a print statement
     */
    static class PrintStatement extends Statement{
        PrintStatement(List<Expression> exprList){
            this.exprList=exprList;
        }
        final List<Expression> exprList;

        @Override
        public String getStatmentType() {
            return "print";
        }
    }

    //Abstract function for getting the statement type
    public abstract String getStatmentType();
}