Source code: org/metacosm/util/LongProperty.java
1 /*
2 Metacosm, an object-oriented network game framework
3 Copyright (C) 1999-2001 Metacosm Development Team
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19
20 package org.metacosm.util;
21
22 import java.util.List;
23 import java.util.ArrayList;
24 import java.util.Collections;
25 import java.util.Iterator;
26
27 /**
28 * A Property with long value.
29 * TODO: min and max values can be stored in a memory-friendly way.
30 * They aren't stored as two long or double * values but as a special immutable Interval
31 * object (in fact a * reference to this object). A hashtable links (min, max) couples to
32 * IntervalManager objects, so for a given interval, only one Interval exists.
33 */
34 public final class LongProperty extends Property {
35
36 /**
37 * LongProperty constructor without a specified interval.
38 * Interval is defined as encompassing all long values.
39 * @param name the name of property
40 * @param value the value of the property
41 * @throws IllegalArgumentException if name is null
42 */
43 public LongProperty(String name, long value) throws IllegalArgumentException {
44 this( name, value, Long.MIN_VALUE, Long.MAX_VALUE);
45 }
46
47 /**
48 * LongProperty constructor with a specified interval.
49 * @param name the name of the property
50 * @param value the value of the property
51 * @param min the min value of the interval
52 * @param max the max value of the interval
53 * @throws IllegalArgumentException if name is null, or if min and max values are not in the right order.
54 */
55 public LongProperty(String name, long value, long min, long max) throws IllegalArgumentException {
56 super(name);
57 if (min > max) {
58 throw new IllegalArgumentException();
59 }
60 interval = new LongInterval(min, max);
61 this.value = interval.boundedValue(value);
62 initialValue = this.value;
63 absList = Collections.synchronizedList(new ArrayList());
64 randomValues = Collections.synchronizedList(new ArrayList());
65 absModifier = null;
66 relDelta = 0;
67 valueIndex = -1;
68 }
69
70 /**
71 * Used by clone() to produce a property with the same name and value, and with
72 * the same shared interval.
73 */
74 private LongProperty(String name, long value, LongInterval interval) {
75 super(name);
76 this.interval = interval;
77 this.value = value;
78 initialValue = this.value;
79 absList = Collections.synchronizedList(new ArrayList());
80 randomValues = Collections.synchronizedList(new ArrayList());
81 absModifier = null;
82 relDelta = 0;
83 valueIndex = -1;
84 }
85
86 public Object getValue() {
87 return new Long(value);
88 }
89
90 public long getLongValue() {
91 return value;
92 }
93
94 public long getMinValue() {
95 return interval.getMin();
96 }
97
98 public long getMaxValue() {
99 return interval.getMax();
100 }
101
102 private void calculate() {
103 if (absModifier != null) {
104 if (valueIndex < 0) {
105 value = interval.boundedValue( ((Long)absModifier.getValue()).longValue() + relDelta);
106 } else {
107 value = interval.boundedValue( ((Long)randomValues.get( valueIndex)).longValue() + relDelta);
108 }
109 } else {
110 valueIndex = -1;
111 value = interval.boundedValue( initialValue + relDelta);
112 }
113 }
114
115 /**
116 * Applies an absolute modifier to the property.
117 * If the absolute modifier has the highest priority,
118 * property value is computed anew, and then bounded.
119 * @param absMod the absolute modifier to be applied
120 */
121 public synchronized void applyModifier(AbsoluteModifier absMod) {
122 if (absMod != null) {
123 Long randomValue = null;
124 if (absMod instanceof RandomAbsoluteModifier) {
125 randomValue = (Long)absMod.getValue();
126 randomValues.add( randomValue);
127 }
128 absList.add(absMod);
129 if (absModifier == null || (absMod.getPriority() > absModifier.getPriority())) {
130 absModifier = absMod;
131 if (randomValue != null) {
132 valueIndex = randomValues.size()-1;
133 }
134 calculate();
135 }
136 }
137 }
138
139 /**
140 * Applies a relative modifier to the property.
141 * Property value is computed anew, and then bounded.
142 * @param relMod the relative modifier to be applied
143 */
144 public synchronized void applyModifier(RelativeModifier relMod) {
145 if (relMod != null) {
146 relDelta += ((Long)relMod.getValue()).longValue();
147 calculate();
148 }
149 }
150
151 /**
152 * Removes an absolute modifier previously applied to the property.
153 * Absolute modifier list is updated, and a new absolute modifier
154 * is chosen according to priority. Property value is then computed anew.
155 * @param absMod the absolute modifier to be removed
156 */
157 public synchronized void removeModifier(AbsoluteModifier absMod) {
158 if (absList.remove(absMod) && absMod == absModifier) {
159 long maxPriority = Integer.MIN_VALUE;
160 absModifier = null;
161 int ramCpt = -1;
162 boolean isRam = false;
163 valueIndex = -1;
164 for (Iterator i = absList.iterator(); i.hasNext(); ) {
165 AbsoluteModifier current = ((AbsoluteModifier)i.next());
166 isRam = (current instanceof RandomAbsoluteModifier);
167 if (isRam) {
168 ++ramCpt;
169 }
170 int priority = current.getPriority();
171 if (priority > maxPriority) {
172 if (isRam) {
173 valueIndex = ramCpt;
174 } else {
175 valueIndex = -1;
176 }
177 maxPriority = priority;
178 absModifier = current;
179 }
180 }
181 calculate();
182 }
183 }
184
185 /**
186 * Removes a relative modifier previously applied to the property.
187 * Property value is computed anew, and then bounded.
188 * @param relMod the relative modifier to be removed
189 */
190 public synchronized void removeModifier(RelativeModifier relMod) {
191 if (relMod != null) {
192 relDelta -= ((Long)relMod.getValue()).longValue();
193 calculate();
194 }
195 }
196
197 public void save(java.io.OutputStream os) throws java.io.IOException {
198 // serialization for now
199 /*
200 new java.io.ObjectOutputStream( os).writeObject( this);
201 */
202 }
203
204 public void load(java.io.InputStream is) throws java.io.IOException {
205 // serialization for now
206 /*
207 java.io.ObjectInputStream ois = new java.io.ObjectInputStream( is);
208 try {
209 LongProperty lp = (LongProperty) ois.readObject();
210 this.value = lp.value;
211 this.initialValue = lp.initialValue;
212 this.absList = lp.absList;
213 this.maxPriority = lp.maxPriority;
214 this.relDelta = lp.relDelta;
215 this.interval = lp.interval;
216 } catch ( ClassNotFoundException e) {
217 throw new UnsupportedOperationException();
218 }
219 */
220 }
221
222 public String toString() {
223 StringBuffer sb = new StringBuffer( " " + value + " [" + interval.getMin() + "," + interval.getMax() + "]\n ");
224 sb.append("absModifier = " + absModifier + "\n initialValue = " + initialValue + "\n absList = ");
225 for (Iterator i = absList.iterator(); i.hasNext(); ) {
226 AbsoluteModifier am = (AbsoluteModifier)i.next();
227 sb.append( "(" + am + ") ");
228 }
229 sb.append("\n randomValues = ");
230 for (Iterator i = randomValues.iterator(); i.hasNext(); ) {
231 sb.append( i.next() + " ");
232 }
233 sb.append( "\n relDelta = " + relDelta + "\n valueIndex = " + valueIndex);
234 return new String(sb);
235 }
236
237 /**
238 * @return a new LongProperty with the same name, value and interval. Interval is
239 * the same shared object.
240 */
241 public Object clone() {
242 return new LongProperty(name, value, interval);
243 }
244
245 private long value;
246 private long initialValue;
247
248 /**
249 * AbsoluteModifiers list
250 */
251 private List absList;
252 /**
253 * RandomAbsoluteModifier values list
254 */
255 private List randomValues;
256 /**
257 * The first max priority AbsoluteModifier
258 */
259 private AbsoluteModifier absModifier;
260 /**
261 * RandomAbsoluteModifier value index (for the first max priority AbsoluteModifier)
262 * -1 if not a RandomAbsoluteModifier<br>
263 * >= 0 otherwise
264 */
265 int valueIndex;
266 /**
267 * RelativeModifiers final effect
268 */
269 private long relDelta;
270 /**
271 * Domain interval
272 */
273 private LongInterval interval;
274 }
275