@Override
    public Feature decorate(Feature feature, KmlEncodingContext context) {
      Placemark pm = (Placemark) feature;
      // while it's possible to have more than one style object, GE will only paint
      // the first one
      Style style = pm.createAndAddStyle();
      List<Symbolizer> symbolizers = context.getCurrentSymbolizers();
      SimpleFeature sf = context.getCurrentFeature();
      if (symbolizers.size() > 0 && sf.getDefaultGeometry() != null) {
        // sort by point, text, line and polygon
        Map<Class, List<Symbolizer>> classified = classifySymbolizers(symbolizers);

        // if no point symbolizers, create a default one
        List<Symbolizer> points = classified.get(PointSymbolizer.class);
        if (points.size() == 0) {
          if (context.isDescriptionEnabled()) {
            setDefaultIconStyle(style, sf, context);
          }
        } else {
          org.geotools.styling.Style wholeStyle = context.getCurrentLayer().getStyle();
          IconProperties properties = IconPropertyExtractor.extractProperties(wholeStyle, sf);
          setIconStyle(style, wholeStyle, properties, context);
        }

        // handle label styles
        List<Symbolizer> texts = classified.get(TextSymbolizer.class);
        if (texts.size() == 0) {
          if (context.isDescriptionEnabled()) {
            setDefaultLabelStyle(style);
          }
        } else {
          // the XML schema allows only one text style, follow painter's model
          // and set the last one
          TextSymbolizer lastTextSymbolizer = (TextSymbolizer) texts.get(texts.size() - 1);
          setLabelStyle(style, sf, lastTextSymbolizer);
        }

        // handle line styles
        List<Symbolizer> lines = classified.get(LineSymbolizer.class);
        // the XML schema allows only one line style, follow painter's model
        // and set the last one
        if (lines.size() > 0) {
          LineSymbolizer lastLineSymbolizer = (LineSymbolizer) lines.get(lines.size() - 1);
          setLineStyle(style, sf, lastLineSymbolizer.getStroke());
        }

        // handle polygon styles
        boolean forceOutiline = lines.size() == 0;
        List<Symbolizer> polygons = classified.get(PolygonSymbolizer.class);
        if (polygons.size() > 0) {
          // the XML schema allows only one polygon style, follow painter's model
          // and set the last one
          PolygonSymbolizer lastPolygonSymbolizer =
              (PolygonSymbolizer) polygons.get(polygons.size() - 1);
          setPolygonStyle(style, sf, lastPolygonSymbolizer, forceOutiline);
        }
      }

      return feature;
    }
  public LineSymbolizerWrapper(Symbolizer symbolizer, RuleWrapper parent) {
    super(symbolizer, parent);

    LineSymbolizer lineSymbolizer = (LineSymbolizer) symbolizer;

    // offset
    Point2D offset = getOffset(lineSymbolizer);
    if (offset != null) {
      xOffset = String.valueOf(offset.getX());
      yOffset = String.valueOf(offset.getY());
    } else {
      xOffset = DEFAULT_OFFSET;
      yOffset = DEFAULT_OFFSET;
    }

    stroke = lineSymbolizer.getStroke();
    if (stroke != null) {
      Expression color = stroke.getColor();
      strokeColor = expressionToString(color);
      Expression width = stroke.getWidth();
      strokeWidth = expressionToString(width);
      Expression opacity = stroke.getOpacity();
      strokeOpacity = expressionToString(opacity);

      if (strokeColor == null) {
        strokeColor = DEFAULT_COLOR;
        stroke.setColor(ff.literal(DEFAULT_COLOR));
      }
      if (strokeOpacity == null) {
        strokeOpacity = DEFAULT_OPACITY;
        stroke.setOpacity(ff.literal(DEFAULT_OPACITY));
      }
      if (strokeWidth == null) {
        strokeWidth = DEFAULT_WIDTH;
        stroke.setWidth(ff.literal(DEFAULT_WIDTH));
      }

      strokeGraphicStroke = stroke.getGraphicStroke();
      if (strokeGraphicStroke != null) {
        List<GraphicalSymbol> graphicalSymbolsList = strokeGraphicStroke.graphicalSymbols();
        if (graphicalSymbolsList.size() > 0) {
          GraphicalSymbol graphicalSymbol = graphicalSymbolsList.get(0);
          if (graphicalSymbol instanceof ExternalGraphic) {
            strokeExternalGraphicStroke = (ExternalGraphic) graphicalSymbol;
          }
        }
      }

      // dash
      float[] dashArray = stroke.getDashArray();
      if (dashArray != null) {
        dash = getDashString(dashArray);
      } else {
        dash = ""; // $NON-NLS-1$
      }
      // dashoffset
      dashOffset = stroke.getDashOffset().evaluate(null, String.class);
      // line cap
      lineCap = stroke.getLineCap().evaluate(null, String.class);
      // line join
      lineJoin = stroke.getLineJoin().evaluate(null, String.class);

      hasStroke = true;
    } else {
      hasStroke = false;
    }
  }