1 package net.sf.openrocket.preset;
3 import net.sf.openrocket.material.Material;
4 import net.sf.openrocket.motor.Manufacturer;
5 import net.sf.openrocket.rocketcomponent.ExternalComponent.Finish;
6 import net.sf.openrocket.rocketcomponent.Transition.Shape;
7 import net.sf.openrocket.unit.UnitGroup;
8 import net.sf.openrocket.util.BugException;
9 import net.sf.openrocket.util.TextUtil;
11 import java.io.ByteArrayOutputStream;
12 import java.io.DataOutputStream;
13 import java.security.MessageDigest;
14 import java.util.ArrayList;
15 import java.util.Arrays;
16 import java.util.Collections;
17 import java.util.Comparator;
18 import java.util.HashMap;
19 import java.util.List;
24 * A model for a preset component.
26 * A preset component contains a component class type, manufacturer information,
27 * part information, and a method that returns a prototype of the preset component.
29 * @author Sampo Niskanen <sampo.niskanen@iki.fi>
31 // FIXME - Implement clone.
32 public class ComponentPreset implements Comparable<ComponentPreset> {
34 private final TypedPropertyMap properties = new TypedPropertyMap();
36 private boolean favorite = false;
37 private String digest = "";
40 BODY_TUBE( new TypedKey<?>[] {
41 ComponentPreset.MANUFACTURER,
42 ComponentPreset.PARTNO,
43 ComponentPreset.DESCRIPTION,
44 ComponentPreset.INNER_DIAMETER,
45 ComponentPreset.OUTER_DIAMETER,
46 ComponentPreset.LENGTH} ),
48 NOSE_CONE( new TypedKey<?>[] {
49 ComponentPreset.MANUFACTURER,
50 ComponentPreset.PARTNO,
51 ComponentPreset.DESCRIPTION,
52 ComponentPreset.SHAPE,
53 ComponentPreset.AFT_OUTER_DIAMETER,
54 ComponentPreset.AFT_SHOULDER_DIAMETER,
55 ComponentPreset.LENGTH} ),
57 TRANSITION( new TypedKey<?>[] {
58 ComponentPreset.MANUFACTURER,
59 ComponentPreset.PARTNO,
60 ComponentPreset.DESCRIPTION,
61 ComponentPreset.SHAPE,
62 ComponentPreset.FORE_OUTER_DIAMETER,
63 ComponentPreset.FORE_SHOULDER_DIAMETER,
64 ComponentPreset.FORE_SHOULDER_LENGTH,
65 ComponentPreset.AFT_OUTER_DIAMETER,
66 ComponentPreset.AFT_SHOULDER_DIAMETER,
67 ComponentPreset.AFT_SHOULDER_LENGTH,
68 ComponentPreset.LENGTH} ),
70 TUBE_COUPLER( new TypedKey<?>[] {
71 ComponentPreset.MANUFACTURER,
72 ComponentPreset.PARTNO,
73 ComponentPreset.DESCRIPTION,
74 ComponentPreset.OUTER_DIAMETER,
75 ComponentPreset.INNER_DIAMETER,
76 ComponentPreset.LENGTH} ),
78 BULK_HEAD( new TypedKey<?>[] {
79 ComponentPreset.MANUFACTURER,
80 ComponentPreset.PARTNO,
81 ComponentPreset.DESCRIPTION,
82 ComponentPreset.OUTER_DIAMETER,
83 ComponentPreset.LENGTH} ),
85 CENTERING_RING( new TypedKey<?>[] {
86 ComponentPreset.MANUFACTURER,
87 ComponentPreset.PARTNO,
88 ComponentPreset.DESCRIPTION,
89 ComponentPreset.INNER_DIAMETER,
90 ComponentPreset.OUTER_DIAMETER,
91 ComponentPreset.LENGTH} ),
93 ENGINE_BLOCK( new TypedKey<?>[] {
94 ComponentPreset.MANUFACTURER,
95 ComponentPreset.PARTNO,
96 ComponentPreset.DESCRIPTION,
97 ComponentPreset.INNER_DIAMETER,
98 ComponentPreset.OUTER_DIAMETER,
99 ComponentPreset.LENGTH} );
101 TypedKey<?>[] displayedColumns;
103 Type( TypedKey<?>[] displayedColumns) {
104 this.displayedColumns = displayedColumns;
107 public List<Type> getCompatibleTypes() {
108 return compatibleTypeMap.get(Type.this);
111 public TypedKey<?>[] getDisplayedColumns() {
112 return displayedColumns;
115 private static Map<Type,List<Type>> compatibleTypeMap = new HashMap<Type,List<Type>>();
118 compatibleTypeMap.put( BODY_TUBE, Arrays.asList( BODY_TUBE, TUBE_COUPLER) );
119 compatibleTypeMap.put( TUBE_COUPLER, Arrays.asList( BODY_TUBE,TUBE_COUPLER) );
120 compatibleTypeMap.put( CENTERING_RING, Arrays.asList( CENTERING_RING, ENGINE_BLOCK ) );
121 compatibleTypeMap.put( NOSE_CONE, Arrays.asList( NOSE_CONE, TRANSITION));
126 public final static TypedKey<Manufacturer> MANUFACTURER = new TypedKey<Manufacturer>("Manufacturer", Manufacturer.class);
127 public final static TypedKey<String> PARTNO = new TypedKey<String>("PartNo",String.class);
128 public final static TypedKey<String> DESCRIPTION = new TypedKey<String>("Description", String.class);
129 public final static TypedKey<Type> TYPE = new TypedKey<Type>("Type",Type.class);
130 public final static TypedKey<Double> LENGTH = new TypedKey<Double>("Length", Double.class, UnitGroup.UNITS_LENGTH);
131 public final static TypedKey<Double> INNER_DIAMETER = new TypedKey<Double>("InnerDiameter", Double.class, UnitGroup.UNITS_LENGTH);
132 public final static TypedKey<Double> OUTER_DIAMETER = new TypedKey<Double>("OuterDiameter", Double.class, UnitGroup.UNITS_LENGTH);
133 public final static TypedKey<Double> FORE_SHOULDER_LENGTH = new TypedKey<Double>("ForeShoulderLength",Double.class, UnitGroup.UNITS_LENGTH);
134 public final static TypedKey<Double> FORE_SHOULDER_DIAMETER = new TypedKey<Double>("ForeShoulderDiameter",Double.class, UnitGroup.UNITS_LENGTH);
135 public final static TypedKey<Double> FORE_OUTER_DIAMETER = new TypedKey<Double>("ForeOuterDiameter", Double.class, UnitGroup.UNITS_LENGTH);
136 public final static TypedKey<Double> AFT_SHOULDER_LENGTH = new TypedKey<Double>("AftShoulderLength",Double.class, UnitGroup.UNITS_LENGTH);
137 public final static TypedKey<Double> AFT_SHOULDER_DIAMETER = new TypedKey<Double>("AftShoulderDiameter",Double.class, UnitGroup.UNITS_LENGTH);
138 public final static TypedKey<Double> AFT_OUTER_DIAMETER = new TypedKey<Double>("AftOuterDiameter", Double.class, UnitGroup.UNITS_LENGTH);
139 public final static TypedKey<Shape> SHAPE = new TypedKey<Shape>("Shape", Shape.class);
140 public final static TypedKey<Material> MATERIAL = new TypedKey<Material>("Material", Material.class);
141 public final static TypedKey<Finish> FINISH = new TypedKey<Finish>("Finish", Finish.class);
142 public final static TypedKey<Double> THICKNESS = new TypedKey<Double>("Thickness", Double.class, UnitGroup.UNITS_LENGTH);
143 public final static TypedKey<Boolean> FILLED = new TypedKey<Boolean>("Filled", Boolean.class);
144 public final static TypedKey<Double> MASS = new TypedKey<Double>("Mass", Double.class, UnitGroup.UNITS_MASS);
146 public final static Map<String, TypedKey<?>> keyMap = new HashMap<String, TypedKey<?>>();
148 keyMap.put(MANUFACTURER.getName(), MANUFACTURER);
149 keyMap.put(PARTNO.getName(), PARTNO);
150 keyMap.put(TYPE.getName(), TYPE);
151 keyMap.put(DESCRIPTION.getName(), DESCRIPTION);
152 keyMap.put(LENGTH.getName(), LENGTH);
153 keyMap.put(INNER_DIAMETER.getName(), INNER_DIAMETER);
154 keyMap.put(OUTER_DIAMETER.getName(), OUTER_DIAMETER);
155 keyMap.put(FORE_SHOULDER_LENGTH.getName(), FORE_SHOULDER_LENGTH);
156 keyMap.put(FORE_SHOULDER_DIAMETER.getName(), FORE_SHOULDER_DIAMETER);
157 keyMap.put(FORE_OUTER_DIAMETER.getName(), FORE_OUTER_DIAMETER);
158 keyMap.put(AFT_SHOULDER_LENGTH.getName(), AFT_SHOULDER_LENGTH);
159 keyMap.put(AFT_SHOULDER_DIAMETER.getName(), AFT_SHOULDER_DIAMETER);
160 keyMap.put(AFT_OUTER_DIAMETER.getName(), AFT_OUTER_DIAMETER);
161 keyMap.put(SHAPE.getName(), SHAPE);
162 keyMap.put(MATERIAL.getName(), MATERIAL);
163 keyMap.put(FINISH.getName(), FINISH);
164 keyMap.put(THICKNESS.getName(), THICKNESS);
165 keyMap.put(FILLED.getName(), FILLED);
166 keyMap.put(MASS.getName(), MASS);
169 public final static List<TypedKey<?>> orderedKeyList = Arrays.<TypedKey<?>>asList(
178 AFT_SHOULDER_DIAMETER,
180 FORE_SHOULDER_DIAMETER,
181 FORE_SHOULDER_LENGTH,
191 // package scope constructor to encourage use of factory.
196 * Convenience method to retrieve the Type of this ComponentPreset.
200 public Type getType() {
201 return properties.get(TYPE);
205 * Convenience method to retrieve the Manufacturer of this ComponentPreset.
208 public Manufacturer getManufacturer() {
209 return properties.get(MANUFACTURER);
213 * Convenience method to retrieve the PartNo of this ComponentPreset.
216 public String getPartNo() {
217 return properties.get(PARTNO);
220 public String getDigest() {
224 public boolean has(Object key) {
225 return properties.containsKey(key);
229 * Package scope so the ComponentPresetFactory can call it.
232 void putAll(TypedPropertyMap other) {
236 properties.putAll(other);
240 * Package scope so the ComponentPresetFactory can call it.
244 <T> void put( TypedKey<T> key, T value ) {
245 properties.put(key, value);
248 public <T> T get(TypedKey<T> key) {
249 T value = properties.get(key);
251 throw new BugException("Preset did not contain key " + key + " " + properties.toString());
256 public boolean isFavorite() {
260 public void setFavorite(boolean favorite) {
261 this.favorite = favorite;
265 public int compareTo(ComponentPreset p2) {
266 int manuCompare = this.getManufacturer().getSimpleName().compareTo(p2.getManufacturer().getSimpleName());
267 if ( manuCompare != 0 )
270 int partNoCompare = this.getPartNo().compareTo(p2.getPartNo());
271 return partNoCompare;
275 public String toString() {
276 return get(MANUFACTURER).toString() + " " + get(PARTNO);
279 public String preferenceKey() {
280 return get(MANUFACTURER).toString() + "|" + get(PARTNO);
284 * Package scope so the factory can call it.
286 void computeDigest() {
289 ByteArrayOutputStream bos = new ByteArrayOutputStream();
290 DataOutputStream os = new DataOutputStream(bos);
292 List<TypedKey<?>> keys = new ArrayList<TypedKey<?>>( properties.keySet());
294 Collections.sort(keys, new Comparator<TypedKey<?>>() {
296 public int compare( TypedKey<?> a, TypedKey<?> b ) {
297 return a.getName().compareTo(b.getName());
301 for ( TypedKey<?> key : keys ) {
303 Object value = properties.get(key);
305 os.writeBytes(key.getName());
307 if ( key.getType() == Double.class ) {
308 Double d = (Double) value;
310 } else if (key.getType() == String.class ) {
311 String s = (String) value;
313 } else if (key.getType() == Manufacturer.class ) {
314 String s = ((Manufacturer)value).getSimpleName();
316 } else if ( key.getType() == Finish.class ) {
317 String s = ((Finish)value).name();
319 } else if ( key.getType() == Type.class ) {
320 String s = ((Type)value).name();
322 } else if ( key.getType() == Boolean.class ) {
323 Boolean b = (Boolean) value;
325 } else if ( key.getType() == Material.class ) {
326 double d = ((Material)value).getDensity();
328 } else if ( key.getType() == Shape.class ) {
329 // FIXME - this is ugly to use the ordinal but what else?
330 int i = ((Shape)value).ordinal();
336 MessageDigest md5 = MessageDigest.getInstance("MD5");
337 digest = TextUtil.hexString(md5.digest( bos.toByteArray() ));
339 catch ( Exception e ) {
341 throw new BugException(e);