package com.example.Models.Statements;

import java.util.ArrayList;

import com.example.Exceptions.BaseException;
import com.example.Models.Expressions.IExpression;
import com.example.Models.Program.IDictionary;
import com.example.Models.Program.ProgramState;
import com.example.Models.Types.IType;
import com.example.Models.Types.IntegerType;
import com.example.Models.Values.IntegerValue;

import javafx.util.Pair;

public class CreateSemaphore implements IStatement{
    private String variable;
    private IExpression expressionValue;

    public CreateSemaphore(String variable, IExpression expressionValue) {
        this.variable = variable;
        this.expressionValue = expressionValue;
    }

    public IStatement copy() {
        return new CreateSemaphore(variable, expressionValue);
    }

    public String toString() {
        return "CreateSemaphore(" + variable + ", " + expressionValue + ")";
    }

    public ProgramState execute(ProgramState state) throws BaseException{
        var symbolTable = state.getSymbolTable();
        var semaphoreTable = state.getSemaphoreTable();
        synchronized(semaphoreTable){
            var expressionValue = this.expressionValue.evaluate(symbolTable, state.getHeap());
            if(!expressionValue.getType().equals(new IntegerType())){
                throw new BaseException("Expression is not of type IntegerValue.");
            }
            var expressionInt = ((IntegerValue)expressionValue).getValue();
            if(!symbolTable.contains(variable)){
                throw new BaseException("Variable not found in symbol table.");
            }
            var index = semaphoreTable.add(new Pair<Integer,ArrayList<Integer>>(expressionInt, new ArrayList<Integer>()));
            symbolTable.update(variable, new IntegerValue(index));
            return null;    
        }
    }

    public IDictionary<String, IType> typeCheck(IDictionary<String, IType> typeTable) throws BaseException{
        var typeExpression = expressionValue.typeCheck(typeTable);
        if(!typeExpression.equals(new IntegerType())){
            throw new BaseException("Expression is not of type IntegerValue.");
        }
        var typeVariable = typeTable.get(variable);
        if(!typeVariable.equals(new IntegerType())){
            throw new BaseException("Variable is not of type IntegerValue.");
        }
        return typeTable;
    }
}
