/*
 * Copyright (c) 2002-2010 "Neo Technology,"
 *     Network Engine for Objects in Lund AB [http://neotechnology.com]
 *
 * This file is part of Neo4j.
 * 
 * Neo4j is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 * 
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
package org.neo4j.graphdb;

/**
 * A dynamically instantiated and named {@link RelationshipType}. This class is
 * a convenience implementation of <code>RelationshipType</code> that is
 * typically used when relationship types are created and named after a
 * condition that can only be detected at runtime.
 * <p>
 * If all relationship types are known at compile time, it's better to use the
 * relationship type enum idiom as outlined in {@link RelationshipType}.
 * <p>
 * It's very important to note that a relationship type is uniquely identified
 * by its name, not by any particular instance that implements this interface.
 * This means that the proper way to check if two relationship types are equal
 * is by invoking <code>equals()</code> on their {@link #name() names}, NOT by
 * using Java's identity operator (<code>==</code>) or <code>equals()</code> on
 * the relationship type instances. A consequence of this is that you can NOT
 * use relationship types in hashed collections such as
 * {@link java.util.HashMap HashMap} and {@link java.util.HashSet HashSet}.
 * <p>
 * However, you usually want to check whether a specific relationship
 * <i>instance</i> is of a certain type. That is best achieved with the
 * {@link Relationship#isType Relationship.isType} method, such as:
 * 
 * <pre>
 * <code>
 * {@link RelationshipType} type = DynamicRelationshipType.{@link #withName(String) withName}( "myname" );
 * if ( rel.{@link Relationship#isType(RelationshipType) isType}( type ) )
 * {
 *     ...
 * }
 * </code>
 * </pre>
 */
public final class DynamicRelationshipType implements RelationshipType
{
    private final String name;

    private DynamicRelationshipType( final String name )
    {
        if ( name == null )
        {
            throw new IllegalArgumentException( "A relationship type cannot "
                                                + "have a null name" );
        }
        this.name = name;
    }

    /**
     * Instantiates a new DynamicRelationshipType with the given name.
     * There's more information regarding relationship types over at
     * {@link RelationshipType}.
     * 
     * @param name the name of the dynamic relationship type
     * @return a DynamicRelationshipType with the given name
     * @throws IllegalArgumentException if name is <code>null</code>
     */
    public static DynamicRelationshipType withName( final String name )
    {
        return new DynamicRelationshipType( name );
    }

    /**
     * Returns the name of this relationship type. The name uniquely identifies
     * a relationship type, i.e. two different RelationshipType instances with
     * different object identifiers (and possibly even different classes) are
     * semantically equivalent if they have {@link String#equals(Object) equal}
     * names.
     * 
     * @return the name of the relationship type
     */
    public String name()
    {
        return this.name;
    }

    /**
     * Returns a string representation of this dynamic relationship type.
     * 
     * @return a string representation of this dynamic relationship type
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString()
    {
        return "DynamicRelationshipType[" + this.name() + "]";
    }

    /**
     * Implements the identity-based equals defined by {@link Object
     * java.lang.Object}. This means that this dynamic relationship type
     * instance will NOT be equal to other relationship types with the same
     * name. As outlined in the documentation for {@link RelationshipType
     * RelationshipType}, the proper way to check for equivalence between two
     * relationship types is to compare their {@link RelationshipType#name()
     * names}.
     * 
     * @return <code>true</code> if <code>other</code> is the same instance as
     *         this dynamic relationship type, <code>false</code> otherwise
     * @see java.lang.Object#equals(java.lang.Object)
     */
    @Override
    public boolean equals( final Object other )
    {
        return super.equals( other );
    }

    /**
     * Implements the default hash function as defined by {@link Object
     * java.lang.Object}. This means that if you put a dynamic relationship
     * instance into a hash-based collection, it most likely will NOT behave as
     * you expect. Please see the documentation of {@link #equals(Object)
     * equals} and the {@link DynamicRelationshipType class documentation} for
     * more details.
     * 
     * @return a hash code value for this dynamic relationship type instance
     * @see java.lang.Object#hashCode()
     */
    @Override
    public int hashCode()
    {
        return super.hashCode();
    }
}
