View Javadoc
1   package org.opentrafficsim.simulationengine.properties;
2   
3   import java.util.ArrayList;
4   import java.util.Collections;
5   import java.util.Comparator;
6   import java.util.Iterator;
7   
8   /**
9    * Compound property.
10   * <p>
11   * Copyright (c) 2013-2015 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
12   * BSD-style license. See <a href="http://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
13   * <p>
14   * $LastChangedDate: 2016-04-05 01:45:04 +0200 (Tue, 05 Apr 2016) $, @version $Revision: 1874 $, by $Author: pknoppers $,
15   * initial version 30 dec. 2014 <br>
16   * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
17   */
18  public class CompoundProperty extends AbstractProperty<ArrayList<AbstractProperty<?>>>
19  {
20      /** Properties contained in this one. */
21      private ArrayList<AbstractProperty<?>> value;
22  
23      /** The shortName of the property. */
24      private String shortName;
25  
26      /** The description of the property. */
27      private String description;
28  
29      /** The property is read-only. */
30      private final Boolean readOnly;
31  
32      /**
33       * Construct a CompoundProperty.
34       * @param shortName String; the short name of the new CompoundProperty
35       * @param description String; description of the new CompoundProperty (may use HTML mark up)
36       * @param initialValue Integer; the initial value of the new CompoundProperty
37       * @param readOnly boolean; if true this CompoundProperty can not be altered
38       * @param displayPriority int; the display priority of the new CompoundProperty
39       */
40      public CompoundProperty(final String shortName, final String description,
41          final ArrayList<AbstractProperty<?>> initialValue, final boolean readOnly, final int displayPriority)
42      {
43          super(displayPriority);
44          this.shortName = shortName;
45          this.description = description;
46          this.value = null == initialValue ? new ArrayList<AbstractProperty<?>>() : initialValue;
47          this.readOnly = readOnly;
48      }
49  
50      /** {@inheritDoc} */
51      @Override
52      public final ArrayList<AbstractProperty<?>> getValue()
53      {
54          return new ArrayList<AbstractProperty<?>>(this.value);
55      }
56  
57      /** {@inheritDoc} */
58      @Override
59      public final String getShortName()
60      {
61          return this.shortName;
62      }
63  
64      /** {@inheritDoc} */
65      @Override
66      public final String getDescription()
67      {
68          return this.description;
69      }
70  
71      /** {@inheritDoc} */
72      @Override
73      public final void setValue(final ArrayList<AbstractProperty<?>> newValue) throws PropertyException
74      {
75          if (this.readOnly)
76          {
77              throw new PropertyException("Cannot modify a read-only CompoundProperty");
78          }
79          this.value = newValue;
80      }
81  
82      /** {@inheritDoc} */
83      @Override
84      public final boolean isReadOnly()
85      {
86          return this.readOnly;
87      }
88  
89      /**
90       * Find an embedded AbstractProperty that has a specified shortName. <br>
91       * Return the first matching one, or null if none of the embedded AbstractProperties has the specified name.
92       * @param name String; the name of the sought embedded AbstractProperty
93       * @return AbstractProperty&lt;?&gt;; the first matching embedded AbstractProperty or null if there is no embedded
94       *         AbstractProperty with the specified name
95       */
96      public final AbstractProperty<?> findByShortName(final String name)
97      {
98          // System.out.println("Searching property " + name);
99          Iterator<AbstractProperty<ArrayList<AbstractProperty<?>>>> i = this.iterator();
100         while (i.hasNext())
101         {
102             AbstractProperty<?> ap = i.next();
103             // System.out.println("Inspecting " + ap.getShortName());
104             if (ap.getShortName().equals(name))
105             {
106                 return ap;
107             }
108         }
109         return null;
110     }
111 
112     /**
113      * Add an AbstractProperty at a specified position.
114      * @param index int; the position where the AbstractProperty must be added
115      * @param ap AbstractProperty; the property to add
116      * @throws PropertyException when this CompoundProperty is read-only, or index is out of range
117      */
118     public final void add(final int index, final AbstractProperty<?> ap) throws PropertyException
119     {
120         if (this.readOnly)
121         {
122             throw new PropertyException("Cannot modify a read-only CompoundProperty");
123         }
124         if (index < 0 || index > this.value.size())
125         {
126             throw new PropertyException("index is out of range");
127         }
128         this.value.add(index, ap);
129     }
130 
131     /**
132      * Add an AbstractProperty at the end of the list.
133      * @param ap AbstractProperty; the property to add
134      * @throws PropertyException when this CompoundProperty is read-only
135      */
136     public final void add(final AbstractProperty<?> ap) throws PropertyException
137     {
138         add(this.value.size(), ap);
139     }
140 
141     /**
142      * Remove a sub property from this CompoundProperty.
143      * @param index int; the position of the sub property to remove
144      * @throws PropertyException when this CompoundProperty is read-only, or index is out of range
145      */
146     public final void remove(final int index) throws PropertyException
147     {
148         if (this.readOnly)
149         {
150             throw new PropertyException("Cannot modify a read-only CompoundProperty");
151         }
152         if (index < 0 || index >= this.value.size())
153         {
154             throw new PropertyException("index is out of range");
155         }
156         this.value.remove(index);
157     }
158 
159     /**
160      * Return the number of sub properties of this CompoundProperty.
161      * @return int; the number of sub properties of this CompoundProperty
162      */
163     public final int size()
164     {
165         return this.value.size();
166     }
167 
168     /**
169      * Return the sub property at a specified index.
170      * @param index int; the index of the property to retrieve
171      * @return AbstractProperty; the sub property at the specified index
172      * @throws PropertyException when index is out of range
173      */
174     public final AbstractProperty<?> get(final int index) throws PropertyException
175     {
176         if (index < 0 || index >= this.value.size())
177         {
178             throw new PropertyException("index is out of range");
179         }
180         return this.value.get(index);
181     }
182 
183     /**
184      * Return the sub-items in display order.
185      * @return ArrayList&lt;AbstractProperty&lt;?&gt;&gt;; the sub-items in display order
186      */
187     public final ArrayList<AbstractProperty<?>> displayOrderedValue()
188     {
189         ArrayList<AbstractProperty<?>> result = new ArrayList<AbstractProperty<?>>(this.value);
190         final ArrayList<AbstractProperty<?>> list = this.value;
191         Collections.sort(result, new Comparator<AbstractProperty<?>>()
192         {
193 
194             @Override
195             public int compare(final AbstractProperty<?> arg0, final AbstractProperty<?> arg1)
196             {
197                 int dp0 = arg0.getDisplayPriority();
198                 int dp1 = arg1.getDisplayPriority();
199                 if (dp0 < dp1)
200                 {
201                     return -1;
202                 }
203                 else if (dp0 > dp1)
204                 {
205                     return 1;
206                 }
207                 int i0 = list.indexOf(arg0);
208                 int i1 = list.indexOf(arg1);
209                 if (i0 < i1)
210                 {
211                     return -1;
212                 }
213                 else if (i0 > i1)
214                 {
215                     return 1;
216                 }
217                 return 0;
218             }
219 
220         });
221         /*-
222         System.out.println("Sorted " + getShortName());
223         int pos = 0;
224         for (AbstractProperty<?> ap : result)
225         {
226             System.out.println(++pos + " - " + ap.getDisplayPriority() + ": " + ap.getShortName());
227         }
228          */
229         return result;
230     }
231 
232     /** {@inheritDoc} */
233     @Override
234     public final String htmlStateDescription()
235     {
236         StringBuilder result = new StringBuilder();
237         result.append("<table border=\"1\">");
238         result.append("<tr><th align=\"left\">" + getShortName() + "</th></tr>\n");
239         for (AbstractProperty<?> ap : displayOrderedValue())
240         {
241             result.append("<tr><td>&nbsp;&nbsp;&nbsp;&nbsp;" + ap.htmlStateDescription() + "</td></tr>\n");
242         }
243         result.append("</table>\n");
244         return result.toString();
245     }
246 
247     /**
248      * Remove a property from this CompoundProperty.
249      * @param removeMe AbstractProperty the property that must be removed
250      * @throws PropertyException when the supplied property cannot be removed (probably because it is not part of this
251      *             CompoundProperty)
252      */
253     public final void remove(final AbstractProperty<?> removeMe) throws PropertyException
254     {
255         if (!this.value.remove(removeMe))
256         {
257             throw new PropertyException("Cannot remove property " + removeMe);
258         }
259     }
260 
261     /** {@inheritDoc} */
262     @Override
263     public final AbstractProperty<ArrayList<AbstractProperty<?>>> deepCopy()
264     {
265         ArrayList<AbstractProperty<?>> copyOfValue = new ArrayList<AbstractProperty<?>>();
266         for (AbstractProperty<?> ap : this.value)
267         {
268             copyOfValue.add(ap.deepCopy());
269         }
270         return new CompoundProperty(this.shortName, this.description, copyOfValue, this.readOnly, getDisplayPriority());
271     }
272 
273 }