View Javadoc
1   package org.opentrafficsim.road.od;
2   
3   import java.util.ArrayList;
4   import java.util.List;
5   
6   import org.djutils.exceptions.Throw;
7   import org.opentrafficsim.base.OtsRuntimeException;
8   
9   /**
10   * A category is a set of objects who's class belongs to a certain categorization. One {@code Category} object can specify to
11   * which subset of traffic between on origin and destination certain demand data belongs.
12   * <p>
13   * Copyright (c) 2013-2024 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
14   * BSD-style license. See <a href="https://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
15   * </p>
16   * @author <a href="https://github.com/averbraeck">Alexander Verbraeck</a>
17   * @author <a href="https://github.com/peter-knoppers">Peter Knoppers</a>
18   * @author <a href="https://github.com/wjschakel">Wouter Schakel</a>
19   */
20  public class Category
21  {
22  
23      /** Empty category. */
24      public static final Category UNCATEGORIZED = new Category(Categorization.UNCATEGORIZED);
25  
26      /** Categorization. */
27      private final Categorization categorization;
28  
29      /** List of objects defining the category. */
30      private final List<Object> objects = new ArrayList<>();
31  
32      /**
33       * @param categorization categorization
34       */
35      private Category(final Categorization categorization)
36      {
37          Throw.whenNull(categorization, "Categorization may not be null.");
38          this.categorization = categorization;
39      }
40  
41      /**
42       * Constructor.
43       * @param categorization categorization
44       * @param object1 1st object
45       * @param objects other objects
46       * @throws IllegalArgumentException if the objects do not comply with the categorization
47       * @throws NullPointerException if any input is null
48       */
49      public Category(final Categorization categorization, final Object object1, final Object... objects)
50      {
51          this(categorization);
52          Throw.when(categorization.size() != objects.length + 1, IllegalArgumentException.class,
53                  "Objects do not comply with the categorization; bad number of objects.");
54          Throw.whenNull(object1, "Objects may not be null.");
55          Throw.when(!categorization.get(0).isAssignableFrom(object1.getClass()), IllegalArgumentException.class,
56                  "Objects do not comply with the categorization; object 1 is of type %s, should be %s.", object1.getClass(),
57                  categorization.get(0));
58          for (int i = 1; i < categorization.size(); i++)
59          {
60              Throw.whenNull(objects[i - 1], "Objects may not be null.");
61              Throw.when(!categorization.get(i).isAssignableFrom(objects[i - 1].getClass()), IllegalArgumentException.class,
62                      "Objects do not comply with the categorization; object %d is of type %s, should be %s.", i + 1,
63                      objects[i - 1].getClass(), categorization.get(i));
64          }
65          this.objects.add(object1);
66          for (Object object : objects)
67          {
68              this.objects.add(object);
69          }
70      }
71  
72      /**
73       * Returns the i'th object.
74       * @param i index of the object
75       * @return the i'th object
76       * @throws IndexOutOfBoundsException if index i is out of bounds
77       */
78      public final Object get(final int i)
79      {
80          Throw.when(i < 0 || i >= this.objects.size(), IndexOutOfBoundsException.class,
81                  "Index %d is out of range for categorization of size %d", i, this.objects.size());
82          return this.objects.get(i);
83      }
84  
85      /**
86       * Return categorization.
87       * @return categorization.
88       */
89      public final Categorization getCategorization()
90      {
91          return this.categorization;
92      }
93  
94      /**
95       * Returns the object of this category pertaining to the specified class from the category.
96       * @param clazz class from categorization to get the category object for
97       * @param <T> type of the object
98       * @return object of this category pertaining to the specified class from the category
99       */
100     @SuppressWarnings("unchecked")
101     public final <T> T get(final Class<T> clazz)
102     {
103         Throw.when(!this.categorization.entails(clazz), OtsRuntimeException.class,
104                 "Trying to get a categorization object by class, with the class not belonging to the categorization.");
105         for (Object obj : this.objects)
106         {
107             if (clazz.isAssignableFrom(obj.getClass()))
108             {
109                 return (T) obj; // assignable so safe
110             }
111         }
112         throw new OtsRuntimeException(
113                 "Categorization contains no object assignable to given class, even though the categorization entails the class.");
114     }
115 
116     @Override
117     public final int hashCode()
118     {
119         final int prime = 31;
120         int result = 1;
121         result = prime * result + ((this.categorization == null) ? 0 : this.categorization.hashCode());
122         result = prime * result + ((this.objects == null) ? 0 : this.objects.hashCode());
123         return result;
124     }
125 
126     @Override
127     public final boolean equals(final Object obj)
128     {
129         if (this == obj)
130         {
131             return true;
132         }
133         if (obj == null)
134         {
135             return false;
136         }
137         if (getClass() != obj.getClass())
138         {
139             return false;
140         }
141         Category other = (Category) obj;
142         if (this.categorization == null)
143         {
144             if (other.categorization != null)
145             {
146                 return false;
147             }
148         }
149         else if (!this.categorization.equals(other.categorization))
150         {
151             return false;
152         }
153         if (this.objects == null)
154         {
155             if (other.objects != null)
156             {
157                 return false;
158             }
159         }
160         else if (!this.objects.equals(other.objects))
161         {
162             return false;
163         }
164         return true;
165     }
166 
167     @Override
168     public final String toString()
169     {
170         return "Category [" + this.objects + "]";
171     }
172 
173 }