//generated by abstract-syntax-gen
package de.peeeq.wurstscript.jassAst;
import java.util.*;

@SuppressWarnings({"cast", "unused", "rawtypes"})
class JassFunctionImpl implements JassFunction{
    JassFunctionImpl(String name, JassSimpleVars params, String returnType, JassVars locals, JassStatements body, boolean isCompiletimeNative) {
        if (name == null)
            throw new IllegalArgumentException("Element name must not be null.");
        if (params == null)
            throw new IllegalArgumentException("Element params must not be null.");
        if (returnType == null)
            throw new IllegalArgumentException("Element returnType must not be null.");
        if (locals == null)
            throw new IllegalArgumentException("Element locals must not be null.");
        if (body == null)
            throw new IllegalArgumentException("Element body must not be null.");
        this.name = name;
        this.params = params;
        this.returnType = returnType;
        this.locals = locals;
        this.body = body;
        this.isCompiletimeNative = isCompiletimeNative;
        params.setParent(this);
        locals.setParent(this);
        body.setParent(this);
    }

    private Element parent;
    public Element getParent() { return parent; }
    public void setParent(Element parent) {
        if (parent != null && this.parent != null) {
            throw new Error("Cannot change parent of element " + this.getClass().getSimpleName() + ", as it is already used in another tree."
                + "Use the copy method to create a new tree or remove the tree from its old parent or set the parent to null before moving the tree. ");
        }
        this.parent = parent;
    }

    public void replaceBy(Element other) {
        if (parent == null)
            throw new RuntimeException("Node not attached to tree.");
        for (int i=0; i<parent.size(); i++) {
            if (parent.get(i) == this) {
                parent.set(i, other);
                return;
            }
        }
    }

    private String name;
    public void setName(String name) {
        if (name == null) throw new IllegalArgumentException();
        this.name = name;
    } 
    public String getName() { return name; }

    private JassSimpleVars params;
    public void setParams(JassSimpleVars params) {
        if (params == null) throw new IllegalArgumentException();
        this.params.setParent(null);
        params.setParent(this);
        this.params = params;
    } 
    public JassSimpleVars getParams() { return params; }

    private String returnType;
    public void setReturnType(String returnType) {
        if (returnType == null) throw new IllegalArgumentException();
        this.returnType = returnType;
    } 
    public String getReturnType() { return returnType; }

    private JassVars locals;
    public void setLocals(JassVars locals) {
        if (locals == null) throw new IllegalArgumentException();
        this.locals.setParent(null);
        locals.setParent(this);
        this.locals = locals;
    } 
    public JassVars getLocals() { return locals; }

    private JassStatements body;
    public void setBody(JassStatements body) {
        if (body == null) throw new IllegalArgumentException();
        this.body.setParent(null);
        body.setParent(this);
        this.body = body;
    } 
    public JassStatements getBody() { return body; }

    private boolean isCompiletimeNative;
    public void setIsCompiletimeNative(boolean isCompiletimeNative) {
        this.isCompiletimeNative = isCompiletimeNative;
    } 
    public boolean getIsCompiletimeNative() { return isCompiletimeNative; }

    public Element get(int i) {
        switch (i) {
            case 0: return params;
            case 1: return locals;
            case 2: return body;
            default: throw new IllegalArgumentException("Index out of range: " + i);
        }
    }
    public Element set(int i, Element newElem) {
        Element oldElem;
        switch (i) {
            case 0: oldElem = params; setParams((JassSimpleVars) newElem); return oldElem;
            case 1: oldElem = locals; setLocals((JassVars) newElem); return oldElem;
            case 2: oldElem = body; setBody((JassStatements) newElem); return oldElem;
            default: throw new IllegalArgumentException("Index out of range: " + i);
        }
    }

    @Override
    public void forEachElement(java.util.function.Consumer<? super Element> action) {
        action.accept(this.params);
        action.accept(this.locals);
        action.accept(this.body);
    }
    public int size() {
        return 3;
    }
    @Override public JassFunction copy() {
        JassFunction result = new JassFunctionImpl(name, (JassSimpleVars) this.params.copy(), returnType, (JassVars) this.locals.copy(), (JassStatements) this.body.copy(), isCompiletimeNative);
        return result;
    }

    @Override public JassFunction copyWithRefs() {
        JassFunction res = copy();
        return res;
    }

    @Override public void clearAttributes() {
        params.clearAttributes();
        locals.clearAttributes();
        body.clearAttributes();
        clearAttributesLocal();
    }
    @Override public void clearAttributesLocal() {
        zzattr_getLine_state = 0;
        zzattr_getProg_state = 0;
    }
    @Override public void accept(Visitor v) {
        v.visit(this);
    }
    @Override public <T> T match(JassFunctionOrNative.Matcher<T> matcher) {
        return matcher.case_JassFunction(this);
    }
    @Override public void match(JassFunctionOrNative.MatcherVoid matcher) {
        matcher.case_JassFunction(this);
    }

    @Override public <T> T match(JassScope.Matcher<T> matcher) {
        return matcher.case_JassFunction(this);
    }
    @Override public void match(JassScope.MatcherVoid matcher) {
        matcher.case_JassFunction(this);
    }

    @Override public <T> T match(Element.Matcher<T> matcher) {
        return matcher.case_JassFunction(this);
    }
    @Override public void match(Element.MatcherVoid matcher) {
        matcher.case_JassFunction(this);
    }

    @Override public String toString() {
        return "JassFunction(" + name + ", " +params + ", " +returnType + ", " +locals + ", " +body + ", " +isCompiletimeNative+")";
    }
    public boolean structuralEquals(Element e) {
        if (e instanceof JassFunction) {
            JassFunction o = (JassFunction) e;
            return java.util.Objects.equals(name, o.getName())
                && this.params.structuralEquals(o.getParams())
                && java.util.Objects.equals(returnType, o.getReturnType())
                && this.locals.structuralEquals(o.getLocals())
                && this.body.structuralEquals(o.getBody())
                && java.util.Objects.equals(isCompiletimeNative, o.getIsCompiletimeNative());
        } else {
            return false;
        }
    }
// circular = null
    private int zzattr_getLine_state = 0;
    private int zzattr_getLine_cache;
    /** */
    public int getLine() {
        if (zzattr_getLine_state == 0) {
            try {
                zzattr_getLine_state = 1;
                zzattr_getLine_cache = de.peeeq.wurstscript.frotty.jassValidator.LineMapAttr.getLine((JassFunction)this);
            } finally {
                zzattr_getLine_state = 0;
            }
            zzattr_getLine_state = 2;
        } else if (zzattr_getLine_state == 1) {
            throw new CyclicDependencyError(this, "getLine");
        }
        return zzattr_getLine_cache;
    }
// circular = null
    private int zzattr_getProg_state = 0;
    private JassProg zzattr_getProg_cache;
    /** */
    public JassProg getProg() {
        if (zzattr_getProg_state == 0) {
            try {
                zzattr_getProg_state = 1;
                zzattr_getProg_cache = de.peeeq.wurstscript.frotty.jassValidator.LineMapAttr.getProg((JassFunction)this);
            } finally {
                zzattr_getProg_state = 0;
            }
            zzattr_getProg_state = 2;
        } else if (zzattr_getProg_state == 1) {
            throw new CyclicDependencyError(this, "getProg");
        }
        return zzattr_getProg_cache;
    }
}