/*
 * Copyright (c) 2015-2018 Dzikoysk
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.panda_lang.panda.language.structure.statement.variable.assigners;

import org.panda_lang.panda.design.architecture.dynamic.Executable;
import org.panda_lang.panda.design.architecture.value.Value;
import org.panda_lang.panda.design.runtime.ExecutableBranch;
import org.panda_lang.panda.design.runtime.PandaRuntimeException;
import org.panda_lang.panda.language.structure.general.expression.Expression;
import org.panda_lang.panda.language.structure.prototype.scope.ClassScopeInstance;
import org.panda_lang.panda.design.architecture.prototype.field.PrototypeField;
import org.panda_lang.panda.design.architecture.prototype.field.StaticValue;

public class FieldAssigner implements Executable {

    private final PrototypeField field;
    private final Expression instanceExpression;
    private final Expression valueExpression;

    public FieldAssigner(Expression instanceExpression, PrototypeField field, Expression valueExpression) {
        this.instanceExpression = instanceExpression;
        this.field = field;
        this.valueExpression = valueExpression;
    }

    @Override
    public void execute(ExecutableBranch branch) {
        int memoryIndex = field.getFieldIndex();

        if (memoryIndex == -1) {
            throw new PandaRuntimeException("Invalid memory pointer, variable may not exist");
        }

        if (field.isStatic()) {
            StaticValue staticValue = StaticValue.of(valueExpression.getExpressionValue(branch));
            field.setStaticValue(staticValue);
            return;
        }

        Value instance = instanceExpression.getExpressionValue(branch);

        if (instance == null) {
            throw new PandaRuntimeException("Instance is not defined");
        }

        if (!(instance.getObject() instanceof ClassScopeInstance)) {
            throw new PandaRuntimeException("Cannot get field value of external object");
        }

        ClassScopeInstance pandaInstance = (ClassScopeInstance) instance.getObject();
        branch.instance(pandaInstance.toValue());

        Value value = valueExpression.getExpressionValue(branch);

        if (value.isNull() && !field.isNullable()) {
            throw new PandaRuntimeException("Cannot assign null to variable '" + field.getName() + "' without nullable modifier");
        }

        if (!field.isMutable() && pandaInstance.getVariables()[memoryIndex] != null) {
            throw new PandaRuntimeException("Cannot change value of immutable variable '" + field.getName() + "'");
        }

        pandaInstance.getFieldValues()[memoryIndex] = value;
    }

    @Override
    public String toString() {
        return instanceExpression.getReturnType().getClassName() + "@f_memory[" + field.getFieldIndex() + "] << " + valueExpression.toString();
    }

}
@@ -2066,16 +2066,492 @@
 anch));%0A
+%0A            if ((staticValue.getValue() == null %7C%7C staticValue.getValue().isNull()) && !field.isNullable()) %7B%0A                throw new PandaRuntimeException(%22Cannot assign null to static field '%22 + field.getName() + %22' without nullable modifier%22);%0A            %7D%0A%0A            if (!field.isMutable() && field.getStaticValue() != null) %7B%0A                throw new PandaRuntimeException(%22Cannot change value of immutable static field '%22 + field.getName() + %22'%22);%0A            %7D%0A%0A
         
@@ -3302,24 +3302,22 @@
 null to 
-variable
+field 
  '%22 + fi
@@ -3540,24 +3540,21 @@
 mutable 
-variable
+field
  '%22 + fi

Apply mutability and nullability to static fields