/*
 * Copyright (c) 2021 the Eclipse Milo Authors
 *
 * This program and the accompanying materials are made
 * available under the terms of the Eclipse Public License 2.0
 * which is available at https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 */

package org.eclipse.milo.opcua.sdk.server.nodes;

import org.eclipse.milo.opcua.sdk.core.nodes.ReferenceTypeNode;
import org.eclipse.milo.opcua.sdk.core.nodes.ReferenceTypeNodeProperties;
import org.eclipse.milo.opcua.stack.core.AttributeId;
import org.eclipse.milo.opcua.stack.core.types.builtin.LocalizedText;
import org.eclipse.milo.opcua.stack.core.types.builtin.NodeId;
import org.eclipse.milo.opcua.stack.core.types.builtin.QualifiedName;
import org.eclipse.milo.opcua.stack.core.types.builtin.unsigned.UInteger;
import org.eclipse.milo.opcua.stack.core.types.enumerated.NodeClass;
import org.jetbrains.annotations.Nullable;

public class UaReferenceTypeNode extends UaNode implements ReferenceTypeNode {

    private Boolean isAbstract;
    private Boolean symmetric;
    private LocalizedText inverseName;

    public UaReferenceTypeNode(
        UaNodeContext context,
        NodeId nodeId,
        QualifiedName browseName,
        LocalizedText displayName,
        LocalizedText description,
        UInteger writeMask,
        UInteger userWriteMask,
        Boolean isAbstract,
        Boolean symmetric,
        LocalizedText inverseName) {

        super(context, nodeId, NodeClass.ReferenceType,
            browseName, displayName, description, writeMask, userWriteMask);

        this.isAbstract = isAbstract;
        this.symmetric = symmetric;
        this.inverseName = inverseName;
    }


    @Override
    public Boolean getIsAbstract() {
        return (Boolean) filterChain.getAttribute(this, AttributeId.IsAbstract);
    }

    @Override
    public Boolean getSymmetric() {
        return (Boolean) filterChain.getAttribute(this, AttributeId.Symmetric);
    }

    @Override
    public LocalizedText getInverseName() {
        return (LocalizedText) filterChain.getAttribute(this, AttributeId.InverseName);
    }

    @Override
    public void setIsAbstract(Boolean isAbstract) {
        filterChain.setAttribute(this, AttributeId.IsAbstract, isAbstract);
    }

    @Override
    public void setSymmetric(Boolean symmetric) {
        filterChain.setAttribute(this, AttributeId.Symmetric, symmetric);
    }

    @Override
    public void setInverseName(LocalizedText inverseName) {
        filterChain.setAttribute(this, AttributeId.InverseName, inverseName);
    }

    @Override
    public synchronized Object getAttribute(AttributeId attributeId) {
        switch (attributeId) {
            case IsAbstract:
                return isAbstract;

            case Symmetric:
                return symmetric;

            case InverseName:
                return inverseName;

            default:
                return super.getAttribute(attributeId);
        }
    }

    @Override
    public synchronized void setAttribute(AttributeId attributeId, Object value) {
        switch (attributeId) {
            case IsAbstract:
                isAbstract = (Boolean) value;
                break;

            case Symmetric:
                symmetric = (Boolean) value;
                break;

            case InverseName:
                inverseName = (LocalizedText) value;
                break;

            default:
                super.setAttribute(attributeId, value);
                return; // prevent firing an attribute change
        }

        fireAttributeChanged(attributeId, value);
    }

    /**
     * Get the value of the NodeVersion Property, if it exists.
     *
     * @return the value of the NodeVersion Property, if it exists.
     * @see ReferenceTypeNodeProperties#NodeVersion
     */
    @Nullable
    public String getNodeVersion() {
        return getProperty(ReferenceTypeNodeProperties.NodeVersion).orElse(null);
    }

    /**
     * Set the value of the NodeVersion Property.
     * <p>
     * A PropertyNode will be created if it does not already exist.
     *
     * @param nodeVersion the value to set.
     * @see ReferenceTypeNodeProperties#NodeVersion
     */
    public void setNodeVersion(String nodeVersion) {
        setProperty(ReferenceTypeNodeProperties.NodeVersion, nodeVersion);
    }

}
