package org.allmyinfo.opmeta.nodes.core;

import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

import org.allmyinfo.coordinator.Coordinator;
import org.allmyinfo.nodes.NodeId;
import org.allmyinfo.operation.BaseOperation;
import org.allmyinfo.operation.Operation;
import org.allmyinfo.operation.meta.BaseOperationDescriptorImpl;
import org.allmyinfo.operation.meta.BaseSimpleOperandDescriptor;
import org.allmyinfo.operation.meta.FactoryContext;
import org.allmyinfo.operation.meta.OperandDescriptor;
import org.allmyinfo.operation.meta.OperandReader;
import org.allmyinfo.operation.meta.OperandWriter;
import org.allmyinfo.operation.nodes.core.CoordinateNode;
import org.eclipse.jdt.annotation.NonNull;

public class CoordinateNodeDescriptor extends BaseOperationDescriptorImpl {
	private final Set<OperandDescriptor> operands;
	public final @NonNull OperandDescriptor nodeOperand = new BaseSimpleOperandDescriptor() {
		@Override
		public @NonNull String getName() {
			return CoordinateNode.OPERAND_NODE;
		}

		@Override
		protected @NonNull Class<?> getDataType() {
			return NodeId.class;
		}
	};
	public final @NonNull OperandDescriptor opOperand = new BaseSimpleOperandDescriptor() {
		@Override
		public @NonNull String getName() {
			return CoordinateNode.OPERAND_OPERATION;
		}

		@Override
		public boolean allowNull() {
			return true;
		}
	};
	public final Coordinator.@NonNull Reactor coordReactor;

	CoordinateNodeDescriptor(final Coordinator.@NonNull Reactor coordReactor) {
		this.coordReactor = coordReactor;
		final Set<OperandDescriptor> map = new HashSet<OperandDescriptor>();
		map.add(nodeOperand);
		map.add(opOperand);
		operands = Collections.unmodifiableSet(map);
	}

	@Override
	public @NonNull String getName() {
		return CoordinateNode.OPERATION;
	}

	@SuppressWarnings("null")
	@Override
	public @NonNull Set<OperandDescriptor> getOperands() {
		return operands;
	}

	@Override
	public @NonNull Operation getOperation(final @NonNull FactoryContext context,
			final @NonNull OperandReader reader) {
		context.setOperation(this);
		final Operation nodeOp = require(context, reader, nodeOperand);
		final Operation operation = require(context, reader, opOperand);
		return new CoordinateNode(nodeOp, operation, coordReactor);
	}

	@Override
	public void writeOperation(final @NonNull BaseOperation operation,
			final @NonNull OperandWriter writer) {
		final CoordinateNode castOp = (CoordinateNode) operation;
		writer.writeSimpleOperand(CoordinateNode.OPERAND_NODE, castOp.nodeOp);
		writer.writeSimpleOperand(CoordinateNode.OPERAND_OPERATION, castOp.operation);
	}
}
