1 module dunitconversion.conversionfamily;
2 
3 import dunitconversion.linearfunction;
4 import dunitconversion.conversionrule;
5 import dunitconversion.tools;
6 
7 /**
8  * The ConversionFamily class is an internal class that provides
9  * a conversion by holding all of the conversion rules for a single family
10  */
11 class ConversionFamily {
12 
13     /**
14       * Constructs a family with empty base unit and family name
15       */
16     this() {
17 
18     }
19 
20     /**
21     * Constructs a family with the given base unit and family name
22     */
23     this(string baseUnit, string family) {
24         m_baseUnit = baseUnit;
25         m_family = family;
26     }
27 
28     /**
29      * Adds a conversion rule to convertor
30      * Params: rule = rule to add
31      */
32     void addConversionRule(ConversionRule rule) {
33         if (m_rules is null)
34         {
35             m_family = rule.family;
36             m_baseUnit = rule.baseUnit;
37         }
38         else
39         {
40             if (m_family != rule.family || m_baseUnit != rule.baseUnit)
41                 throw new Exception("Incorrect rule added to family");
42         }
43         m_rules[rule.unit] = rule;
44     }
45 
46     /**
47      * Converts from in unit to out unit
48      * Params:
49      *      inUnit = unit to convert from
50      *      outUnit = unit to convert to
51      * Returns: LinearFunction object containing conversion from in to out unit
52      */
53     LinearFunction convert(string inUnit, string outUnit) const {
54         if (m_rules is null)
55             throw new Exception("No conversion rules known for " ~ m_family ~ " family");
56 
57         if (inUnit == m_baseUnit && outUnit in m_rules)  // conversion from base unit to unit
58             return m_rules[outUnit].convertFunction;
59         if (inUnit in m_rules && outUnit == m_baseUnit)  // conversion from unit to base unit
60             return m_rules[inUnit].convertFunction.inversed();
61         
62         // conversion from one unit to another through the base unit if possible
63         if (inUnit !in m_rules || outUnit !in m_rules)  // one of the conversions is not present
64             throw new Exception("Conversion from " ~ inUnit ~ " to " ~ outUnit ~ " not found");
65         LinearFunction inToBase = m_rules[inUnit].convertFunction.inversed();
66         LinearFunction baseToOut = m_rules[outUnit].convertFunction;
67 
68         return combined(inToBase, baseToOut);
69     }
70 
71     /**
72      * Converts a given value from in unit to out unit
73      * Params:
74      *      value = value to convert
75      *      inUnit = unit to convert from
76      *      outUnit = unit to convert to
77      * Returns: value converted to
78      */
79     double convert(double value, string inUnit, string outUnit) const {
80         auto f = convert(inUnit, outUnit);
81         if (f.isValid())
82             return f.y(value);
83         return double.nan;
84     }
85 
86 protected:
87     ConversionRule [string] m_rules;    /// Key is a unit, it's assumed that all rules have the same base unit
88     string m_baseUnit;     /// Base unit for this family
89     string m_family;       /// Family name
90 }