@SuppressWarnings({"PMD.NPathComplexity", "PMD.ExcessiveMethodLength"})
    public BExpressionLookupValue addLookupValue(final String name, final String value, final int[] lookupData2) {
        String valueMutable = value;
        BExpressionLookupValue newValue = null;
        Integer num = lookupNumbers.get(name);
        if (num == null) {
            if (lookupData2 != null) {
                // do not create unknown name for external data array
                return newValue;
            }

            // unknown name, create
            num = lookupValues.size();
            lookupNumbers.put(name, num);
            lookupNames.add(name);
            lookupValues.add(new BExpressionLookupValue[]{new BExpressionLookupValue("")
                    , new BExpressionLookupValue("unknown")});
            lookupHistograms.add(new int[2]);
            final int[] ndata = new int[lookupData.length + 1];
            System.arraycopy(lookupData, 0, ndata, 0, lookupData.length);
            lookupData = ndata;
        }

        // look for that value
        BExpressionLookupValue[] values = lookupValues.get(num);
        int[] histo = lookupHistograms.get(num);
        int i = 0;
        boolean bFoundAsterix = false;
        for (; i < values.length; i++) {
            final BExpressionLookupValue v = values[i];
            if (v.equals("*")) {
                bFoundAsterix = true;
            }
            if (v.matches(valueMutable)) {
                break;
            }
        }
        if (i == values.length) {
            if (lookupData2 != null) {
                // do not create unknown value for external data array,
                // record as 'unknown' instead
                lookupData2[num] = 1; // 1 == unknown
                if (bFoundAsterix) {
                    // found value for lookup *
                    try {
                        // remove some unused characters
                        valueMutable = valueMutable.replaceAll(",", ".");
                        valueMutable = valueMutable.replaceAll(">", "");
                        valueMutable = valueMutable.replaceAll("_", "");
                        valueMutable = valueMutable.replaceAll(" ", "");
                        valueMutable = valueMutable.replaceAll("~", "");
                        valueMutable = valueMutable.replace((char) 8217, '\'');
                        valueMutable = valueMutable.replace((char) 8221, '"');
                        if (valueMutable.indexOf("-") == 0) {
                            valueMutable = valueMutable.substring(1);
                        }
                        if (valueMutable.contains("-")) {
                            // replace eg. 1.4-1.6 m to 1.4m
                            // but also 1'-6" to 1'
                            // keep the unit of measure
                            final String tmp = valueMutable.substring(valueMutable.indexOf("-") + 1).replaceAll("[0-9.,-]", "");
                            valueMutable = valueMutable.substring(0, valueMutable.indexOf("-"));
                            if (valueMutable.matches("\\d+(\\.\\d+)?")) {
                                valueMutable += tmp;
                            }
                        }
                        valueMutable = valueMutable.toLowerCase(Locale.US);

                        // do some value conversion
                        if (valueMutable.contains("ft")) {
                            float feet = 0f;
                            int inch = 0;
                            final String[] sa = valueMutable.split("ft");
                            if (sa.length >= 1) {
                                feet = Float.parseFloat(sa[0]);
                            }
                            if (sa.length == 2) {
                                valueMutable = sa[1];
                                if (valueMutable.indexOf("in") > 0) {
                                    valueMutable = valueMutable.substring(0, valueMutable.indexOf("in"));
                                }
                                inch = Integer.parseInt(valueMutable);
                                feet += inch / 12f;
                            }
                            valueMutable = String.format(Locale.US, "%3.1f", feet * 0.3048f);
                        } else if (valueMutable.contains("'")) {
                            float feet = 0f;
                            int inch = 0;
                            final String[] sa = valueMutable.split("'");
                            if (sa.length >= 1) {
                                feet = Float.parseFloat(sa[0]);
                            }
                            if (sa.length == 2) {
                                valueMutable = sa[1];
                                if (valueMutable.indexOf("''") > 0) {
                                    valueMutable = valueMutable.substring(0, valueMutable.indexOf("''"));
                                }
                                if (valueMutable.indexOf("\"") > 0) {
                                    valueMutable = valueMutable.substring(0, valueMutable.indexOf("\""));
                                }
                                inch = Integer.parseInt(valueMutable);
                                feet += inch / 12f;
                            }
                            valueMutable = String.format(Locale.US, "%3.1f", feet * 0.3048f);
                        } else if (valueMutable.contains("in") || valueMutable.contains("\"")) {
                            float inch = 0f;
                            if (valueMutable.indexOf("in") > 0) {
                                valueMutable = valueMutable.substring(0, valueMutable.indexOf("in"));
                            }
                            if (valueMutable.indexOf("\"") > 0) {
                                valueMutable = valueMutable.substring(0, valueMutable.indexOf("\""));
                            }
                            inch = Float.parseFloat(valueMutable);
                            valueMutable = String.format(Locale.US, "%3.1f", inch * 0.0254f);
                        } else if (valueMutable.contains("feet") || valueMutable.contains("foot")) {
                            float feet = 0f;
                            final String s = valueMutable.substring(0, valueMutable.indexOf("f"));
                            feet = Float.parseFloat(s);
                            valueMutable = String.format(Locale.US, "%3.1f", feet * 0.3048f);
                        } else if (valueMutable.contains("fathom") || valueMutable.contains("fm")) {
                            final String s = valueMutable.substring(0, valueMutable.indexOf("f"));
                            final float fathom = Float.parseFloat(s);
                            valueMutable = String.format(Locale.US, "%3.1f", fathom * 1.8288f);
                        } else if (valueMutable.contains("cm")) {
                            final String[] sa = valueMutable.split("cm");
                            if (sa.length >= 1) {
                                valueMutable = sa[0];
                            }
                            final float cm = Float.parseFloat(valueMutable);
                            valueMutable = String.format(Locale.US, "%3.1f", cm / 100f);
                        } else if (valueMutable.contains("meter")) {
                            valueMutable = valueMutable.substring(0, valueMutable.indexOf("m"));
                        } else if (valueMutable.contains("mph")) {
                            final String[] sa = valueMutable.split("mph");
                            if (sa.length >= 1) {
                                valueMutable = sa[0];
                            }
                            final float mph = Float.parseFloat(valueMutable);
                            valueMutable = String.format(Locale.US, "%3.1f", mph * 1.609344f);
                        } else if (valueMutable.contains("knot")) {
                            final String[] sa = valueMutable.split("knot");
                            if (sa.length >= 1) {
                                valueMutable = sa[0];
                            }
                            final float nm = Float.parseFloat(valueMutable);
                            valueMutable = String.format(Locale.US, "%3.1f", nm * 1.852f);
                        } else if (valueMutable.contains("kmh") || valueMutable.contains("km/h") || valueMutable.contains("kph")) {
                            final String[] sa = valueMutable.split("k");
                            if (sa.length > 1) {
                                valueMutable = sa[0];
                            }
                        } else if (valueMutable.contains("m")) {
                            valueMutable = valueMutable.substring(0, valueMutable.indexOf("m"));
                        } else if (valueMutable.contains("(")) {
                            valueMutable = valueMutable.substring(0, valueMutable.indexOf("("));
                        }
                        // found negative maxdraft values
                        // no negative values
                        // values are float with 2 decimals
                        lookupData2[num] = 1000 + (int) (Math.abs(Float.parseFloat(valueMutable)) * 100f);
                    } catch (Exception e) {
                        // ignore errors
                        System.err.println("error for " + name + "  " + value /* original value */ + " trans " + valueMutable + " " + e.getMessage());
                        lookupData2[num] = 0;
                    }
                }
                return newValue;
            }

            if (i == 500) {
                return newValue;
            }
            // unknown value, create
            final BExpressionLookupValue[] nvalues = new BExpressionLookupValue[values.length + 1];
            final int[] nhisto = new int[values.length + 1];
            System.arraycopy(values, 0, nvalues, 0, values.length);
            System.arraycopy(histo, 0, nhisto, 0, histo.length);
            values = nvalues;
            histo = nhisto;
            newValue = new BExpressionLookupValue(valueMutable);
            values[i] = newValue;
            lookupHistograms.set(num, histo);
            lookupValues.set(num, values);
        }

        histo[i]++;

        // finally remember the actual data
        if (lookupData2 != null) {
            lookupData2[num] = i;
        } else {
            lookupData[num] = i;
        }
        return newValue;
    }
add a new lookup-value for the given name to the given lookupData array.
If no array is given (null value passed), the value is added to
the context-binded array. In that case, unknown names and values are
created dynamically.

@return a newly created value element, if any, to optionally add aliases
main/src/main/java/cgeo/geocaching/brouter/expressions/BExpressionContext.java