/*
 * Copyright (c) 2019 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.delegates;

import java.util.ArrayList;
import java.util.List;

import org.eclipse.milo.opcua.sdk.core.AccessLevel;
import org.eclipse.milo.opcua.sdk.core.nodes.VariableNode;
import org.eclipse.milo.opcua.sdk.server.OpcUaServer;
import org.eclipse.milo.opcua.sdk.server.UaNodeManager;
import org.eclipse.milo.opcua.sdk.server.api.NodeManager;
import org.eclipse.milo.opcua.sdk.server.nodes.AttributeContext;
import org.eclipse.milo.opcua.sdk.server.nodes.UaNode;
import org.eclipse.milo.opcua.sdk.server.nodes.UaNodeContext;
import org.eclipse.milo.opcua.sdk.server.nodes.UaVariableNode;
import org.eclipse.milo.opcua.stack.core.Identifiers;
import org.eclipse.milo.opcua.stack.core.NamespaceTable;
import org.eclipse.milo.opcua.stack.core.UaException;
import org.eclipse.milo.opcua.stack.core.types.builtin.DataValue;
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.Variant;
import org.testng.annotations.Test;

import static org.testng.Assert.assertEquals;

public class AttributeDelegateChainTest {

    @Test
    public void testCreate() throws Exception {
        List<String> list = new ArrayList<>();

        AttributeDelegate delegate = AttributeDelegateChain.create(
            new AttributeDelegate() {
                @Override
                public DataValue getValue(AttributeContext context, VariableNode node) throws UaException {
                    list.add("root");
                    return node.getValue();
                }
            },
            parent -> new DelegatingAttributeDelegate(parent) {
                @Override
                public DataValue getValue(AttributeContext context, VariableNode node) throws UaException {
                    list.add("child1");
                    return super.getValue(context, node);
                }
            },
            parent -> new DelegatingAttributeDelegate(parent) {
                @Override
                public DataValue getValue(AttributeContext context, VariableNode node) throws UaException {
                    list.add("child2");
                    return super.getValue(context, node);
                }
            },
            parent -> new DelegatingAttributeDelegate(parent) {
                @Override
                public DataValue getValue(AttributeContext context, VariableNode node) throws UaException {
                    list.add("child3");
                    return super.getValue(context, node);
                }
            }
        );

        UaNodeManager nodeManager = new UaNodeManager();

        UaNodeContext context = new UaNodeContext() {
            @Override
            public OpcUaServer getServer() {
                return null;
            }

            @Override
            public NodeManager<UaNode> getNodeManager() {
                return nodeManager;
            }

            @Override
            public NamespaceTable getNamespaceTable() {
                return new NamespaceTable();
            }
        };

        UaVariableNode node = new UaVariableNode.UaVariableNodeBuilder(context)
            .setNodeId(NodeId.NULL_VALUE)
            .setAccessLevel(AccessLevel.READ_WRITE)
            .setBrowseName(QualifiedName.NULL_VALUE)
            .setDisplayName(LocalizedText.NULL_VALUE)
            .setDataType(Identifiers.String)
            .setTypeDefinition(Identifiers.BaseDataVariableType)
            .build();

        node.setValue(new DataValue(new Variant("foo")));

        DataValue value = delegate.getValue(new AttributeContext(null, null), node);
        assertEquals(value.getValue().getValue(), "foo");

        assertEquals(list.get(0), "child3");
        assertEquals(list.get(1), "child2");
        assertEquals(list.get(2), "child1");
        assertEquals(list.get(3), "root");
    }

}
