class WindBarbsFactory implements MarkFactory {

    public Shape getShape(Graphics2D graphics, Expression symbolUrl, Feature feature) {

        // CHECKS
        // cannot handle a null url
        if (symbolUrl == null) {
            if (LOGGER.isLoggable(Level.FINE)) {
                LOGGER.fine("Provided null symbol to the WindBarbs Factory");
            }
            return null;
        }
        // cannot handle a null feature
        if (feature == null) {
            if (LOGGER.isLoggable(Level.FINE)) {
                LOGGER.fine("Provided null feature to the WindBarbs Factory");
            }
            return null;
        }

        //
        // START PARSING CODE
        //
        if (LOGGER.isLoggable(Level.FINE)) {
            LOGGER.fine("Trying to resolve symbol:" + symbolUrl.toString());
        }

        // evaluate string from feature to extract all values
        final String wellKnownName = symbolUrl.evaluate(feature, String.class);
        if (wellKnownName == null || wellKnownName.length() <= 0) {
            if (LOGGER.isLoggable(Level.FINE)) {
                LOGGER.fine("Unable to resolve symbol provided to WindBarbs Factory");
            }
            return null;
        }

        // //
        //
        // Basic Syntax
        //
        // //
        if (!wellKnownName.matches(WindBarbsFactory.WINDBARB_DEFINITION)) {
            if (LOGGER.isLoggable(Level.FINE)) {
                LOGGER.fine("Unable to resolve symbol: " + wellKnownName);
            }
            return null;
        }
        if (LOGGER.isLoggable(Level.FINE)) {
            LOGGER.fine("Resolved symbol " + wellKnownName);
        }

        // ok from now on we should have a real windbarb, let's lower the log level

        // //
        //
        // WindBarbs set
        //
        // //
        String windBarbName = null;
        Matcher matcher = WINDBARB_SET_PATTERN.matcher(wellKnownName);
        if (matcher.matches()) {
            try {
                windBarbName = matcher.group(2);
            } catch (Exception e) {
                if (LOGGER.isLoggable(Level.INFO)) {
                    LOGGER.log(Level.INFO, "Unable to parse windbarb set from string: "
                            + wellKnownName, e);
                }

                return null;
            }
        }
        if (windBarbName == null || windBarbName.length() <= 0) {
            if (LOGGER.isLoggable(Level.INFO)) {
                LOGGER.fine("Unable to parse windBarbName from string: " + wellKnownName);
            }
            return null;
        }
        if (LOGGER.isLoggable(Level.FINE)) {
            LOGGER.fine("Resolved windBarbName " + windBarbName);
        }

        // //
        //
        // Looking for speed
        //
        // //
        matcher = SPEED_PATTERN.matcher(wellKnownName);
        double speed = Double.NaN;
        if (matcher.matches()) {
            String speedString = "";
            try {
                speedString = matcher.group(2);
                speed = Double.parseDouble(speedString);
            } catch (Exception e) {
                if (LOGGER.isLoggable(Level.INFO)) {
                    LOGGER.log(Level.INFO, "Unable to parse speed from string: " + speedString, e);
                }
                return null;
            }
        } else {
            if (LOGGER.isLoggable(Level.INFO)) {
                LOGGER.fine("Unable to parse speed from string: " + wellKnownName);
            }
            return null;
        }

        // //
        //
        // Looking for unit value
        //
        // //
        String uom = null;// no default
        matcher = UNIT_PATTERN.matcher(wellKnownName);
        if (matcher.matches()) {
            uom = matcher.group(2);
        }
        if (uom == null || uom.length() <= 0) {
            if (LOGGER.isLoggable(Level.INFO)) {
                LOGGER.info("Unable to parse UoM from " + wellKnownName);
            }
            return null;
        }

        // so far so good
        if (LOGGER.isLoggable(Level.FINE)) {
            LOGGER.fine("WindBarbs name " + windBarbName + "with Speed " + speed + "[" + uom + "]");
        }

        // //
        //
        // Params
        //
        // //
        int index = wellKnownName.indexOf('?');
        if (index > 0) {
            final Map<String, String> params = new HashMap<String, String>();
            final String kvp = wellKnownName.substring(index + 1);
            String[] pairs = kvp.split("&");
            if (pairs != null && pairs.length > 0) {
                for (String pair : pairs) {
                    // split
                    String[] splitPair = pair.split("=");
                    if (splitPair != null && splitPair.length > 0) {
                        params.put(splitPair[0].toLowerCase(), splitPair[1]);
                    } else {
                        if (LOGGER.isLoggable(Level.FINE)) {
                            LOGGER.fine("Skipping pair " + pair);
                        }
                    }
                }

                // checks
                if (!params.isEmpty()) {
                    return getWindBarb(windBarbName, speed, uom, params);
                }
            }
        } else {
            // make sure we close with ] and nothing else after
            if (!wellKnownName.endsWith("]")) {
                if (LOGGER.isLoggable(Level.INFO)) {
                    LOGGER.info("The provided symbol may be missing a ? before the KVP part.");
                }
                return null;
            }
        }

        // //
        //
        // Get shape if possible
        //
        // //
        return getWindBarb(windBarbName, speed, uom);

    }

}