All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.helger.graph.impl.DirectedGraphNode Maven / Gradle / Ivy

There is a newer version: 9.5.5
Show newest version
/**
 * Copyright (C) 2014-2016 Philip Helger (www.helger.com)
 * philip[at]helger[dot]com
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.helger.graph.impl;

import java.util.function.Consumer;

import javax.annotation.Nonnegative;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.concurrent.NotThreadSafe;

import com.helger.commons.ValueEnforcer;
import com.helger.commons.annotation.ReturnsMutableCopy;
import com.helger.commons.collection.CollectionHelper;
import com.helger.commons.collection.ext.CommonsArrayList;
import com.helger.commons.collection.ext.CommonsHashSet;
import com.helger.commons.collection.ext.CommonsLinkedHashMap;
import com.helger.commons.collection.ext.CommonsLinkedHashSet;
import com.helger.commons.collection.ext.ICommonsList;
import com.helger.commons.collection.ext.ICommonsOrderedMap;
import com.helger.commons.collection.ext.ICommonsOrderedSet;
import com.helger.commons.collection.ext.ICommonsSet;
import com.helger.commons.state.EChange;
import com.helger.commons.string.ToStringGenerator;
import com.helger.graph.IMutableDirectedGraphNode;
import com.helger.graph.IMutableDirectedGraphRelation;

/**
 * Default implementation if the {@link IMutableDirectedGraphNode} interface
 *
 * @author Philip Helger
 */
@NotThreadSafe
public class DirectedGraphNode extends AbstractBaseGraphObject implements IMutableDirectedGraphNode
{
  private ICommonsOrderedMap  m_aIncoming;
  private ICommonsOrderedMap  m_aOutgoing;

  public DirectedGraphNode ()
  {
    this (null);
  }

  public DirectedGraphNode (@Nullable final String sID)
  {
    super (sID);
  }

  public final boolean isDirected ()
  {
    return true;
  }

  public void addIncomingRelation (@Nonnull final IMutableDirectedGraphRelation aNewRelation)
  {
    ValueEnforcer.notNull (aNewRelation, "NewRelation");
    ValueEnforcer.isTrue (aNewRelation.getTo () == this, "Passed incoming relation is not based on this node");
    if (m_aIncoming != null)
    {
      if (m_aIncoming.containsKey (aNewRelation.getID ()))
        throw new IllegalArgumentException ("The passed relation (" +
                                            aNewRelation +
                                            ") is already contained as an incoming relation");

      // check if the relation from-node is already contained
      for (final IMutableDirectedGraphRelation aRelation : m_aIncoming.values ())
        if (aRelation.getFrom () == aNewRelation.getFrom ())
          throw new IllegalArgumentException ("The from-node of the passed relation (" +
                                              aNewRelation +
                                              ") is already contained");
    }
    else
    {
      m_aIncoming = new CommonsLinkedHashMap<> ();
    }

    // Add!
    m_aIncoming.put (aNewRelation.getID (), aNewRelation);
  }

  public boolean hasIncomingRelations ()
  {
    return m_aIncoming != null && m_aIncoming.isNotEmpty ();
  }

  @Nonnegative
  public int getIncomingRelationCount ()
  {
    return m_aIncoming == null ? 0 : m_aIncoming.size ();
  }

  public boolean isIncomingRelation (@Nullable final IMutableDirectedGraphRelation aRelation)
  {
    return m_aIncoming != null && aRelation != null && aRelation.equals (m_aIncoming.get (aRelation.getID ()));
  }

  @Nonnull
  @ReturnsMutableCopy
  public ICommonsList  getAllIncomingRelations ()
  {
    return m_aIncoming == null ? new CommonsArrayList<> () : new CommonsArrayList<> (m_aIncoming.values ());
  }

  public void forEachIncomingRelation (@Nonnull final Consumer  aConsumer)
  {
    ValueEnforcer.notNull (aConsumer, "Consumer");
    if (m_aIncoming != null)
      m_aIncoming.forEachValue (aConsumer);
  }

  @Nonnull
  public EChange removeIncomingRelation (@Nonnull final IMutableDirectedGraphRelation aRelation)
  {
    return aRelation == null || m_aIncoming == null ? EChange.UNCHANGED : m_aIncoming.removeObject (aRelation.getID ());
  }

  @Nonnull
  public EChange removeAllIncomingRelations ()
  {
    if (!hasIncomingRelations ())
      return EChange.UNCHANGED;
    m_aIncoming = null;
    return EChange.CHANGED;
  }

  public boolean isFromNode (@Nullable final IMutableDirectedGraphNode aNode)
  {
    return getIncomingRelationFrom (aNode) != null;
  }

  @Nonnull
  @ReturnsMutableCopy
  public ICommonsSet  getAllFromNodes ()
  {
    final ICommonsSet  ret = new CommonsHashSet<> ();
    if (m_aIncoming != null)
      CollectionHelper.findAllMapped (m_aIncoming.values (), IMutableDirectedGraphRelation::getFrom, ret::add);
    return ret;
  }

  @Nullable
  public IMutableDirectedGraphRelation getIncomingRelationFrom (@Nullable final IMutableDirectedGraphNode aFromNode)
  {
    if (m_aIncoming != null && aFromNode != null)
      for (final IMutableDirectedGraphRelation aRelation : m_aIncoming.values ())
        if (aRelation.getFrom ().equals (aFromNode))
          return aRelation;
    return null;
  }

  public void addOutgoingRelation (@Nonnull final IMutableDirectedGraphRelation aNewRelation)
  {
    ValueEnforcer.notNull (aNewRelation, "NewRelation");
    ValueEnforcer.isTrue (aNewRelation.getFrom () == this, "Passed outgoing relation is not based on this node");
    if (m_aOutgoing != null)
    {
      if (m_aOutgoing.containsKey (aNewRelation.getID ()))
        throw new IllegalArgumentException ("The passed relation " +
                                            aNewRelation +
                                            " is already contained as an outgoing relation");
      // check if the relation to-node is already contained
      for (final IMutableDirectedGraphRelation aRelation : m_aOutgoing.values ())
        if (aRelation.getTo () == aNewRelation.getTo ())
          throw new IllegalArgumentException ("The to-node of the passed relation " +
                                              aNewRelation +
                                              " is already contained");
    }
    else
    {
      m_aOutgoing = new CommonsLinkedHashMap<> ();
    }

    // Add!
    m_aOutgoing.put (aNewRelation.getID (), aNewRelation);
  }

  public boolean hasOutgoingRelations ()
  {
    return m_aOutgoing != null && m_aOutgoing.isNotEmpty ();
  }

  @Nonnegative
  public int getOutgoingRelationCount ()
  {
    return m_aOutgoing == null ? 0 : m_aOutgoing.size ();
  }

  public boolean isOutgoingRelation (@Nullable final IMutableDirectedGraphRelation aRelation)
  {
    return m_aOutgoing != null && aRelation != null && aRelation.equals (m_aOutgoing.get (aRelation.getID ()));
  }

  @Nonnull
  @ReturnsMutableCopy
  public ICommonsList  getAllOutgoingRelations ()
  {
    return m_aOutgoing == null ? new CommonsArrayList<> () : new CommonsArrayList<> (m_aOutgoing.values ());
  }

  public void forEachOutgoingRelation (@Nonnull final Consumer  aConsumer)
  {
    ValueEnforcer.notNull (aConsumer, "Consumer");
    if (m_aOutgoing != null)
      m_aOutgoing.values ().forEach (aConsumer);
  }

  @Nonnull
  @ReturnsMutableCopy
  public ICommonsSet  getAllToNodes ()
  {
    final ICommonsSet  ret = new CommonsHashSet<> ();
    if (m_aOutgoing != null)
      CollectionHelper.findAllMapped (m_aOutgoing.values (), IMutableDirectedGraphRelation::getTo, ret::add);
    return ret;
  }

  @Nonnull
  public EChange removeOutgoingRelation (@Nonnull final IMutableDirectedGraphRelation aRelation)
  {
    return aRelation == null || m_aOutgoing == null ? EChange.UNCHANGED : m_aOutgoing.removeObject (aRelation.getID ());
  }

  @Nonnull
  public EChange removeAllOutgoingRelations ()
  {
    if (!hasOutgoingRelations ())
      return EChange.UNCHANGED;
    m_aOutgoing = null;
    return EChange.CHANGED;
  }

  public boolean isToNode (@Nullable final IMutableDirectedGraphNode aNode)
  {
    return getOutgoingRelationTo (aNode) != null;
  }

  @Nullable
  public IMutableDirectedGraphRelation getOutgoingRelationTo (@Nullable final IMutableDirectedGraphNode aToNode)
  {
    if (m_aOutgoing != null && aToNode != null)
      for (final IMutableDirectedGraphRelation aRelation : m_aOutgoing.values ())
        if (aRelation.getTo ().equals (aToNode))
          return aRelation;
    return null;
  }

  public boolean isConnectedWith (@Nullable final IMutableDirectedGraphNode aNode)
  {
    if (aNode == null)
      return false;
    return getIncomingRelationFrom (aNode) != null || getOutgoingRelationTo (aNode) != null;
  }

  @Nullable
  public IMutableDirectedGraphRelation getRelation (@Nullable final IMutableDirectedGraphNode aNode)
  {
    if (aNode == null)
      return null;
    final IMutableDirectedGraphRelation aIncoming = getIncomingRelationFrom (aNode);
    final IMutableDirectedGraphRelation aOutgoing = getOutgoingRelationTo (aNode);
    if (aIncoming != null && aOutgoing != null)
      throw new IllegalStateException ("Both incoming and outgoing relations between node '" +
                                       getID () +
                                       "' and '" +
                                       aNode.getID () +
                                       "' exist!");
    return aIncoming != null ? aIncoming : aOutgoing;
  }

  public boolean hasRelations ()
  {
    return hasIncomingOrOutgoingRelations ();
  }

  public boolean hasIncomingOrOutgoingRelations ()
  {
    return hasIncomingRelations () || hasOutgoingRelations ();
  }

  public boolean hasIncomingAndOutgoingRelations ()
  {
    return hasIncomingRelations () && hasOutgoingRelations ();
  }

  @Nonnegative
  public int getRelationCount ()
  {
    return getIncomingRelationCount () + getOutgoingRelationCount ();
  }

  @Nonnull
  @ReturnsMutableCopy
  public ICommonsOrderedSet  getAllRelations ()
  {
    final ICommonsOrderedSet  ret = new CommonsLinkedHashSet<> ();
    if (m_aIncoming != null)
      ret.addAll (m_aIncoming.values ());
    if (m_aOutgoing != null)
      ret.addAll (m_aOutgoing.values ());
    return ret;
  }

  public void forEachRelation (@Nonnull final Consumer  aConsumer)
  {
    forEachIncomingRelation (aConsumer);
    forEachOutgoingRelation (aConsumer);
  }

  @Nonnull
  @ReturnsMutableCopy
  public ICommonsOrderedSet  getAllRelationIDs ()
  {
    final ICommonsOrderedSet  ret = new CommonsLinkedHashSet<> ();
    if (m_aIncoming != null)
      ret.addAll (m_aIncoming.keySet ());
    if (m_aOutgoing != null)
      ret.addAll (m_aOutgoing.keySet ());
    return ret;
  }

  @Nonnull
  @ReturnsMutableCopy
  public ICommonsOrderedSet  getAllRelatedNodes ()
  {
    final ICommonsOrderedSet  ret = new CommonsLinkedHashSet<> ();
    if (m_aIncoming != null)
      for (final IMutableDirectedGraphRelation aRelation : m_aIncoming.values ())
        ret.add (aRelation.getFrom ());
    if (m_aOutgoing != null)
      for (final IMutableDirectedGraphRelation aRelation : m_aOutgoing.values ())
        ret.add (aRelation.getTo ());
    return ret;
  }

  @Nonnull
  @ReturnsMutableCopy
  public ICommonsOrderedSet  getAllRelatedNodeIDs ()
  {
    final ICommonsOrderedSet  ret = new CommonsLinkedHashSet<> ();
    if (m_aIncoming != null)
      for (final IMutableDirectedGraphRelation aRelation : m_aIncoming.values ())
        ret.add (aRelation.getFromID ());
    if (m_aOutgoing != null)
      for (final IMutableDirectedGraphRelation aRelation : m_aOutgoing.values ())
        ret.add (aRelation.getToID ());
    return ret;
  }

  @Nonnull
  public EChange removeAllRelations ()
  {
    EChange ret = EChange.UNCHANGED;
    ret = ret.or (removeAllIncomingRelations ());
    ret = ret.or (removeAllOutgoingRelations ());
    return ret;
  }

  @Override
  public boolean equals (final Object o)
  {
    return super.equals (o);
  }

  @Override
  public int hashCode ()
  {
    return super.hashCode ();
  }

  @Override
  public String toString ()
  {
    return ToStringGenerator.getDerived (super.toString ())
                            .append ("incomingIDs", m_aIncoming == null ? null : m_aIncoming.keySet ())
                            .append ("outgoingIDs", m_aOutgoing == null ? null : m_aOutgoing.keySet ())
                            .toString ();
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy