Add factory method which constructs a user material which uses a localizable key.
[debian/openrocket] / core / src / net / sf / openrocket / material / Material.java
1 package net.sf.openrocket.material;
2
3 import net.sf.openrocket.database.Databases;
4 import net.sf.openrocket.l10n.Translator;
5 import net.sf.openrocket.startup.Application;
6 import net.sf.openrocket.unit.Unit;
7 import net.sf.openrocket.unit.UnitGroup;
8 import net.sf.openrocket.util.MathUtil;
9
10 /**
11  * A class for different material types.  Each material has a name and density.
12  * The interpretation of the density depends on the material type.  For
13  * {@link Type#BULK} it is kg/m^3, for {@link Type#SURFACE} km/m^2.
14  * <p>
15  * Objects of this type are immutable.
16  * 
17  * @author Sampo Niskanen <sampo.niskanen@iki.fi>
18  */
19
20 public abstract class Material implements Comparable<Material> {
21         
22         private static final Translator trans = Application.getTranslator();
23
24         public enum Type {
25                 LINE("Line", UnitGroup.UNITS_DENSITY_LINE),
26                 SURFACE("Surface", UnitGroup.UNITS_DENSITY_SURFACE),
27                 BULK("Bulk", UnitGroup.UNITS_DENSITY_BULK);
28                 
29                 private final String name;
30                 private final UnitGroup units;
31                 
32                 private Type(String name, UnitGroup units) {
33                         this.name = name;
34                         this.units = units;
35                 }
36                 
37                 public UnitGroup getUnitGroup() {
38                         return units;
39                 }
40                 
41                 @Override
42                 public String toString() {
43                         return name;
44                 }
45         }
46         
47         
48         /////  Definitions of different material types  /////
49         
50         public static class Line extends Material {
51                 Line(String name, String key, double density, boolean userDefined) {
52                         super(name, key, density, userDefined);
53                 }
54
55                 @Override
56                 public Type getType() {
57                         return Type.LINE;
58                 }
59         }
60         
61         public static class Surface extends Material {
62                 
63                 Surface(String name, String key, double density, boolean userDefined) {
64                         super(name, key, density, userDefined);
65                 }
66
67                 @Override
68                 public Type getType() {
69                         return Type.SURFACE;
70                 }
71                 
72                 @Override
73                 public String toStorableString() {
74                         return super.toStorableString();
75                 }
76         }
77         
78         public static class Bulk extends Material {
79                 Bulk(String name, String key, double density, boolean userDefined) {
80                         super(name, key, density, userDefined);
81                 }
82
83                 @Override
84                 public Type getType() {
85                         return Type.BULK;
86                 }
87         }
88         
89         
90
91         private final String name;
92         private final String key;
93         private final double density;
94         private final boolean userDefined;
95         
96         
97         /**
98          * Constructor for materials.
99          * 
100          * @param name ignored when defining system materials.
101          * @param key ignored when defining user materials.
102          * @param density
103          * @param userDefined true if this is a user defined material, false if it is a system material.
104          */
105         private Material(String name, String key, double density, boolean userDefined) {
106                 if ( userDefined ) {
107                         this.key = "UserDefined."+name;
108                         this.name = name;
109                 } else {
110                         this.key = key;
111                         this.name = trans.get("Databases.materials." + key);
112                 }
113                 this.userDefined = userDefined;
114                 this.density = density;
115         }
116
117         public String getKey() {
118                 return key;
119         }
120         
121         public double getDensity() {
122                 return density;
123         }
124         
125         public String getName() {
126                 return name;
127         }
128         
129         public String getName(Unit u) {
130                 return name + " (" + u.toStringUnit(density) + ")";
131         }
132         
133         public boolean isUserDefined() {
134                 return userDefined;
135         }
136         
137         public abstract Type getType();
138         
139         @Override
140         public String toString() {
141                 return this.getName(this.getType().getUnitGroup().getDefaultUnit());
142         }
143         
144         
145         /**
146          * Compares this object to another object.  Material objects are equal if and only if
147          * their types, names and densities are identical.
148          */
149         @Override
150         public boolean equals(Object o) {
151                 if (o == null)
152                         return false;
153                 if (this.getClass() != o.getClass())
154                         return false;
155                 Material m = (Material) o;
156                 return ((m.name.equals(this.name)) && MathUtil.equals(m.density, this.density));
157         }
158         
159         
160         /**
161          * A hashCode() method giving a hash code compatible with the equals() method.
162          */
163         @Override
164         public int hashCode() {
165                 return name.hashCode() + (int) (density * 1000);
166         }
167         
168         
169         /**
170          * Order the materials according to their name, secondarily according to density.
171          */
172         @Override
173         public int compareTo(Material o) {
174                 int c = this.name.compareTo(o.name);
175                 if (c != 0) {
176                         return c;
177                 } else {
178                         return (int) ((this.density - o.density) * 1000);
179                 }
180         }
181         
182         
183         public static Material newSystemMaterial(Type type, String key, double density ) {
184                 switch (type) {
185                 case LINE:
186                         return new Material.Line(null, key, density, false);
187                         
188                 case SURFACE:
189                         return new Material.Surface(null,key, density, false);
190                         
191                 case BULK:
192                         return new Material.Bulk(null, key, density, false);
193                         
194                 default:
195                         throw new IllegalArgumentException("Unknown material type: " + type);
196                 }
197         }
198         
199         /**
200          * Return a new user defined material of the specified type.
201          */
202         public static Material newUserMaterial(Type type, String name, double density) {
203                 switch (type) {
204                 case LINE:
205                         return new Material.Line(name, null, density, true);
206                         
207                 case SURFACE:
208                         return new Material.Surface(name, null, density, true);
209                         
210                 case BULK:
211                         return new Material.Bulk(name, null, density, true);
212                         
213                 default:
214                         throw new IllegalArgumentException("Unknown material type: " + type);
215                 }
216         }
217         
218         /**
219          * Return a new user defined material of the specified type and localizable key.
220          */
221         public static Material newUserMaterialWithKey(Type type, String key, double density) {
222                 switch (type) {
223                 case LINE:
224                         return new Material.Line(null, key, density, true);
225                         
226                 case SURFACE:
227                         return new Material.Surface(null, key, density, true);
228                         
229                 case BULK:
230                         return new Material.Bulk(null, key, density, true);
231                         
232                 default:
233                         throw new IllegalArgumentException("Unknown material type: " + type);
234                 }
235         }
236         
237         
238         
239         public String toStorableString() {
240                 return getType().name() + "|" + key + "|" + name.replace('|', ' ') + '|' + density;
241         }
242         
243         
244         /**
245          * Return a material defined by the provided string.
246          * 
247          * @param str                   the material storage string.
248          * @param userDefined   whether the created material is user-defined.
249          * @return                              a new <code>Material</code> object.
250          * @throws IllegalArgumentException             if <code>str</code> is invalid or null.
251          */
252         public static Material fromStorableString(String str) {
253                 if (str == null)
254                         throw new IllegalArgumentException("Material string is null");
255                 
256                 String[] split = str.split("\\|");
257                 if (split.length < 3)
258                         throw new IllegalArgumentException("Illegal material string: " + str);
259                 
260                 Type type = null;
261                 String name = null;
262                 String key= null;
263                 String densityString;
264                 
265                 try {
266                         type = Type.valueOf(split[0]);
267                 } catch (Exception e) {
268                         throw new IllegalArgumentException("Illegal material string: " + str, e);
269                 }
270                 
271                 if ( split.length == 3 ) {
272                         name = split[1];
273                         densityString =split[2];
274                 } else {
275                         key = split[1];
276                         name = split[2];
277                         densityString=split[3];
278                 }
279                 
280                 
281                 double density;
282
283                 try {
284                         density = Double.parseDouble(densityString);
285                 } catch (NumberFormatException e) {
286                         throw new IllegalArgumentException("Illegal material string: " + str, e);
287                 }
288                 
289                 return Databases.findMaterial(type, key, name, density);
290         }
291         
292 }