1 package net.sf.openrocket.preset;
3 import java.io.ByteArrayOutputStream;
4 import java.io.DataOutputStream;
5 import java.security.MessageDigest;
6 import java.util.ArrayList;
7 import java.util.Collections;
8 import java.util.Comparator;
9 import java.util.HashMap;
10 import java.util.List;
13 import net.sf.openrocket.material.Material;
14 import net.sf.openrocket.motor.Manufacturer;
15 import net.sf.openrocket.rocketcomponent.BodyTube;
16 import net.sf.openrocket.rocketcomponent.ExternalComponent.Finish;
17 import net.sf.openrocket.rocketcomponent.NoseCone;
18 import net.sf.openrocket.rocketcomponent.Transition;
19 import net.sf.openrocket.rocketcomponent.Transition.Shape;
20 import net.sf.openrocket.unit.UnitGroup;
21 import net.sf.openrocket.util.BugException;
22 import net.sf.openrocket.util.TextUtil;
26 * A model for a preset component.
28 * A preset component contains a component class type, manufacturer information,
29 * part information, and a method that returns a prototype of the preset component.
31 * @author Sampo Niskanen <sampo.niskanen@iki.fi>
33 // FIXME - Implement clone.
34 public class ComponentPreset implements Comparable<ComponentPreset> {
36 private final TypedPropertyMap properties = new TypedPropertyMap();
38 private boolean favorite = false;
39 private String digest = "";
42 BODY_TUBE( new TypedKey<?>[] {
43 ComponentPreset.MANUFACTURER,
44 ComponentPreset.PARTNO,
45 ComponentPreset.OUTER_DIAMETER,
46 ComponentPreset.INNER_DIAMETER,
47 ComponentPreset.LENGTH} ),
49 NOSE_CONE( new TypedKey<?>[] {
50 ComponentPreset.MANUFACTURER,
51 ComponentPreset.PARTNO,
52 ComponentPreset.DESCRIPTION,
53 ComponentPreset.SHAPE,
54 ComponentPreset.OUTER_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.OUTER_DIAMETER,
64 ComponentPreset.LENGTH} ),
66 TUBE_COUPLER( new TypedKey<?>[] {
67 ComponentPreset.MANUFACTURER,
68 ComponentPreset.PARTNO,
69 ComponentPreset.OUTER_DIAMETER,
70 ComponentPreset.INNER_DIAMETER,
71 ComponentPreset.LENGTH} ),
73 BULK_HEAD( new TypedKey<?>[] {
74 ComponentPreset.MANUFACTURER,
75 ComponentPreset.PARTNO,
76 ComponentPreset.DESCRIPTION,
77 ComponentPreset.OUTER_DIAMETER,
78 ComponentPreset.LENGTH} );
80 Type[] compatibleTypes;
81 TypedKey<?>[] displayedColumns;
83 Type( TypedKey<?>[] displayedColumns) {
84 compatibleTypes = new Type[1];
85 compatibleTypes[0] = this;
86 this.displayedColumns = displayedColumns;
89 Type( Type[] t, TypedKey<?>[] displayedColumns ) {
91 compatibleTypes = new Type[t.length+1];
92 compatibleTypes[0] = this;
93 for( int i=0; i<t.length; i++ ) {
94 compatibleTypes[i+1] = t[i];
97 this.displayedColumns = displayedColumns;
100 public Type[] getCompatibleTypes() {
101 return compatibleTypes;
104 public TypedKey<?>[] getDisplayedColumns() {
105 return displayedColumns;
110 public final static TypedKey<Manufacturer> MANUFACTURER = new TypedKey<Manufacturer>("Manufacturer", Manufacturer.class);
111 public final static TypedKey<String> PARTNO = new TypedKey<String>("PartNo",String.class);
112 public final static TypedKey<String> DESCRIPTION = new TypedKey<String>("Description", String.class);
113 public final static TypedKey<Type> TYPE = new TypedKey<Type>("Type",Type.class);
114 public final static TypedKey<Double> LENGTH = new TypedKey<Double>("Length", Double.class, UnitGroup.UNITS_LENGTH);
115 public final static TypedKey<Double> INNER_DIAMETER = new TypedKey<Double>("InnerDiameter", Double.class, UnitGroup.UNITS_LENGTH);
116 public final static TypedKey<Double> OUTER_DIAMETER = new TypedKey<Double>("OuterDiameter", Double.class, UnitGroup.UNITS_LENGTH);
117 public final static TypedKey<Double> SHOULDER_LENGTH = new TypedKey<Double>("ShoulderLength", Double.class, UnitGroup.UNITS_LENGTH);
118 public final static TypedKey<Double> SHOULDER_DIAMETER = new TypedKey<Double>("ShoulderDiameter", Double.class, UnitGroup.UNITS_LENGTH);
119 public final static TypedKey<Double> FORE_SHOULDER_LENGTH = new TypedKey<Double>("ForeShoulderLength",Double.class, UnitGroup.UNITS_LENGTH);
120 public final static TypedKey<Double> FORE_SHOULDER_DIAMETER = new TypedKey<Double>("ForeShoulderDiameter",Double.class, UnitGroup.UNITS_LENGTH);
121 public final static TypedKey<Double> FORE_OUTER_DIAMETER = new TypedKey<Double>("ForeOuterDiameter", Double.class, UnitGroup.UNITS_LENGTH);
122 public final static TypedKey<Shape> SHAPE = new TypedKey<Shape>("Shape", Shape.class);
123 public final static TypedKey<Material> MATERIAL = new TypedKey<Material>("Material", Material.class);
124 public final static TypedKey<Finish> FINISH = new TypedKey<Finish>("Finish", Finish.class);
125 public final static TypedKey<Double> THICKNESS = new TypedKey<Double>("Thickness", Double.class, UnitGroup.UNITS_LENGTH);
126 public final static TypedKey<Boolean> FILLED = new TypedKey<Boolean>("Filled", Boolean.class);
127 public final static TypedKey<Double> MASS = new TypedKey<Double>("Mass", Double.class, UnitGroup.UNITS_MASS);
129 public final static Map<String, TypedKey<?>> keyMap = new HashMap<String, TypedKey<?>>();
131 keyMap.put(MANUFACTURER.getName(), MANUFACTURER);
132 keyMap.put(PARTNO.getName(), PARTNO);
133 keyMap.put(TYPE.getName(), TYPE);
134 keyMap.put(DESCRIPTION.getName(), DESCRIPTION);
135 keyMap.put(LENGTH.getName(), LENGTH);
136 keyMap.put(INNER_DIAMETER.getName(), INNER_DIAMETER);
137 keyMap.put(OUTER_DIAMETER.getName(), OUTER_DIAMETER);
138 keyMap.put(SHOULDER_LENGTH.getName(), SHOULDER_LENGTH);
139 keyMap.put(SHOULDER_DIAMETER.getName(), SHOULDER_DIAMETER);
140 keyMap.put(FORE_SHOULDER_LENGTH.getName(), FORE_SHOULDER_LENGTH);
141 keyMap.put(FORE_SHOULDER_DIAMETER.getName(), FORE_SHOULDER_DIAMETER);
142 keyMap.put(FORE_OUTER_DIAMETER.getName(), FORE_OUTER_DIAMETER);
143 keyMap.put(SHAPE.getName(), SHAPE);
144 keyMap.put(MATERIAL.getName(), MATERIAL);
145 keyMap.put(FINISH.getName(), FINISH);
146 keyMap.put(THICKNESS.getName(), THICKNESS);
147 keyMap.put(FILLED.getName(), FILLED);
148 keyMap.put(MASS.getName(), MASS);
151 // package scope constructor to encourage use of factory.
156 * Convenience method to retrieve the Type of this ComponentPreset.
160 public Type getType() {
161 return properties.get(TYPE);
165 * Convenience method to retrieve the Manufacturer of this ComponentPreset.
168 public Manufacturer getManufacturer() {
169 return properties.get(MANUFACTURER);
173 * Convenience method to retrieve the PartNo of this ComponentPreset.
176 public String getPartNo() {
177 return properties.get(PARTNO);
180 public String getDigest() {
184 public boolean has(Object key) {
185 return properties.containsKey(key);
189 * Package scope so the ComponentPresetFactory can call it.
192 void putAll(TypedPropertyMap other) {
196 properties.putAll(other);
200 * Package scope so the ComponentPresetFactory can call it.
204 <T> void put( TypedKey<T> key, T value ) {
205 properties.put(key, value);
208 public <T> T get(TypedKey<T> key) {
209 T value = properties.get(key);
211 throw new BugException("Preset did not contain key " + key + " " + properties.toString());
216 public boolean isFavorite() {
220 public void setFavorite(boolean favorite) {
221 this.favorite = favorite;
225 public int compareTo(ComponentPreset p2) {
226 int manuCompare = this.getManufacturer().getSimpleName().compareTo(p2.getManufacturer().getSimpleName());
227 if ( manuCompare != 0 )
230 int partNoCompare = this.getPartNo().compareTo(p2.getPartNo());
231 return partNoCompare;
235 public String toString() {
236 return get(MANUFACTURER).toString() + " " + get(PARTNO);
239 public String preferenceKey() {
240 return get(MANUFACTURER).toString() + "|" + get(PARTNO);
244 * Package scope so the factory can call it.
246 void computeDigest() {
249 ByteArrayOutputStream bos = new ByteArrayOutputStream();
250 DataOutputStream os = new DataOutputStream(bos);
252 List<TypedKey<?>> keys = new ArrayList<TypedKey<?>>( properties.keySet());
254 Collections.sort(keys, new Comparator<TypedKey<?>>() {
256 public int compare( TypedKey<?> a, TypedKey<?> b ) {
257 return a.getName().compareTo(b.getName());
261 for ( TypedKey<?> key : keys ) {
263 Object value = properties.get(key);
265 os.writeBytes(key.getName());
267 if ( key.getType() == Double.class ) {
268 Double d = (Double) value;
270 } else if (key.getType() == String.class ) {
271 String s = (String) value;
273 } else if (key.getType() == Manufacturer.class ) {
274 String s = ((Manufacturer)value).getSimpleName();
276 } else if ( key.getType() == Finish.class ) {
277 String s = ((Finish)value).name();
279 } else if ( key.getType() == Type.class ) {
280 String s = ((Type)value).name();
282 } else if ( key.getType() == Boolean.class ) {
283 Boolean b = (Boolean) value;
285 } else if ( key.getType() == Material.class ) {
286 double d = ((Material)value).getDensity();
288 } else if ( key.getType() == Shape.class ) {
289 // FIXME - this is ugly to use the ordinal but what else?
290 int i = ((Shape)value).ordinal();
296 MessageDigest md5 = MessageDigest.getInstance("MD5");
297 digest = TextUtil.hexString(md5.digest( bos.toByteArray() ));
299 catch ( Exception e ) {
300 throw new BugException(e);