package de.uni_hamburg.fs;

import collections.CollectionEnumeration;


/**
 * Represents a null value in the feature structure system.
 * This class is a singleton that wraps Java's null value as both a Type and a Node.
 * It implements special behavior for feature operations, where all feature requests
 * are either rejected or return null-specific responses.
 */
public class NullObject extends NoFeatureNode implements JavaType {

    /**
     * The singleton NullObject wraps a java null value as a Type and
     * at the same time as a node.
     */
    public final static NullObject INSTANCE = new NullObject();

    /**
     * Construct a new wrapper for the given Java Object.
     */
    private NullObject() {}

    @Override
    public Object getJavaObject() {
        return null;
    }

    @Override
    public int hashCode() {
        return 0;
    }

    @Override
    public boolean equals(Object that) {
        return that instanceof NullObject;
    }

    /**
     * Return the name of this Type.
     */
    @Override
    public String getName() {
        return "null";
    }

    /**
     * Return the qualified name of this Type.
     */
    @Override
    public String getFullName() {
        return "null";
    }

    @Override
    public boolean isApprop(Name featureName) {
        return false;
    }

    @Override
    public CollectionEnumeration appropFeatureNames() {
        return EmptyEnumeration.INSTANCE;
    }

    @Override
    public Type appropType(Name featureName) {
        throw new NoSuchFeatureException(featureName, this);
    }

    /**
     * Return whether this Type is extensional.
     */
    @Override
    public boolean isExtensional() {
        return true;
    }

    /**
     * Return whether this Type represents an instance.
     */
    @Override
    public boolean isInstanceType() {
        return true;
    }

    @Override
    public Type getInstanceType() {
        return this;
    }

    /**
     * Return whether this Type subsumes {@literal <that>} Type.
     * In other words, return whether this Type is more general than {@literal <that>} Type.
     */
    @Override
    public boolean subsumes(Type that) {
        return equals(that);
    }

    /**
     * Return the unification of this Type and {@literal <that>} Type.
     * this Type is not modified!
     */
    @Override
    public Type unify(Type that) throws UnificationFailure {
        // special case for other JavaObject:
        if (equals(that)) {
            return this;
        }
        return that.unify(this);
    }

    /**
     * Return whether this Type and {@literal <that>} Type are compatible.
     */
    @Override
    public boolean canUnify(Type that) {
        if (equals(that)) {
            return true;
        }
        return that.canUnify(this);
    }

    /**
     * Look for the most general common extensional supertype of this and {@literal <that>}.
     */
    @Override
    public Type mostGeneralExtensionalSupertype(Type that) {
        // TODO
        return null;
    }

    @Override
    public Type getType() {
        return this;
    }

    @Override
    public Node newNode() {
        return this;
    }

    @Override
    public Node duplicate() {
        return this; // no need to clone null!
    }
}