package com.example.Models.Expressions;

import com.example.Exceptions.BaseException;
import com.example.Models.Program.IDictionary;
import com.example.Models.Program.IHeap;
import com.example.Models.Types.IType;
import com.example.Models.Types.IntegerType;
import com.example.Models.Values.IntegerValue;
import com.example.Models.Values.IValue;

public class ArithmeticExpression implements IExpression {
    private IExpression left;
    private IExpression right;
    private char operator;

    public ArithmeticExpression(char operator,IExpression left, IExpression right) {
        this.left = left;
        this.right = right;
        this.operator = operator;
    }

    public IValue evaluate(IDictionary<String, IValue> table, IHeap heap) throws BaseException {
        IValue leftValue = left.evaluate(table, heap);
        IValue rightValue = right.evaluate(table, heap);

        if (leftValue.getType().equals(new IntegerType())) {
            int leftInt = ((IntegerValue)leftValue).getValue();

            if (rightValue.getType().equals(new IntegerType())) {
                int rightInt = ((IntegerValue)rightValue).getValue();

                switch (operator) {
                    case '+':
                        return new IntegerValue(leftInt + rightInt);
                    case '-':
                        return new IntegerValue(leftInt - rightInt);
                    case '*':
                        return new IntegerValue(leftInt * rightInt);
                    case '/':
                        if (rightInt == 0) {
                            throw new BaseException("Division by zero!");
                        }
                        return new IntegerValue(leftInt / rightInt);
                    default:
                        throw new BaseException("Invalid operator!");
                }
            } else {
                throw new BaseException("Second operand is not an integer!");
            }
        } else {
            throw new BaseException("First operand is not an integer!");
        }
    }

    public IExpression copy() {
        return new ArithmeticExpression(operator, left.copy(), right.copy());
    }

    public String toString() {
        return left.toString() + " " + operator + " " + right.toString();
    }

    public IType typeCheck(IDictionary<String, IType> typeTable) throws BaseException {
        IType type1, type2;
        type1 = left.typeCheck(typeTable);
        type2 = right.typeCheck(typeTable);
        if (type1.equals(new IntegerType())) {
            if (type2.equals(new IntegerType())) {
                return new IntegerType();
            } else {
                throw new BaseException("Second operand is not an integer!");
            }
        } else {
            throw new BaseException("First operand is not an integer!");
        }
    }
}
