package com.example.Models.Statements;

import com.example.Exceptions.BaseException;
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;

public class ReleaseStatement implements IStatement {
    private String var;

    public ReleaseStatement(String var) {
        this.var = var;
    }

    @Override
    public String toString() {
        return "release(" + this.var + ")";
    }

    @Override
    public ProgramState execute(ProgramState state) throws BaseException {
        var symbolTable = state.getSymbolTable();
        var semaphoreTable = state.getSemaphoreTable();
        synchronized(semaphoreTable){
            var stack = state.getStack();

            if(!symbolTable.contains(this.var)){
                throw new BaseException("Variable not found in symbol table.");
            }

            var index = symbolTable.get(this.var);
            if(!index.getType().equals(new IntegerType())){
                throw new BaseException("Variable not of the type Integer");
            }
            var indexValue = ((IntegerValue)index).getValue();
            if(!semaphoreTable.contains(indexValue)){
                throw new BaseException("Index not found in semaphore table.");
            }

            var value = semaphoreTable.get(indexValue);
            if(value.getValue().contains(state.id)){
                value.getValue().remove(state.id);
            }

            return null;
        }
    }

    @Override
    public IDictionary<String, IType> typeCheck(IDictionary<String, IType> typeTable) throws BaseException{
        var type = typeTable.get(this.var);
        if(!type.equals(new IntegerType())){
            throw new BaseException("Variable not of the type Integer");
        }
        return typeTable;
    }

    @Override
    public IStatement copy() {
        return new ReleaseStatement(this.var);
    }
}
