private PointSymbolizer CreatePointSymbolizer(NodePropertyValue[] properties)
    {
      PointSymbolizer symPoint = new PointSymbolizer();

      int pointType = properties[0].Name.StartsWith("point-") ? 0 : 1;
      bool isArrow = HasPropertyValue(properties, "marker-file", "shape://arrow");

      if (pointType == 1 && isArrow)
        pointType = 2;

      ExternalGraphicSymbol pointSymbol = null;
      MarkGraphicSymbol markSymbol = null;
      GlyphGraphicSymbol glyphSymbol = null;

      LabelPlacementInfo lpi = new LabelPlacementInfo();

      if (pointType == 0 || (!isArrow && HasProperty(properties ,"marker-file")))
      {
        pointSymbol = new ExternalGraphicSymbol();
        symPoint.Graphic.GraphicSymbols.Add(pointSymbol);
        lpi.Placement = "centroid";
        lpi.Symbolizer = (int)SymbolizerType.Point;
      }
      else if (pointType == 1)
      {
        markSymbol = new MarkGraphicSymbol();
        symPoint.Graphic.GraphicSymbols.Add(markSymbol);
        lpi.Symbolizer = (int)SymbolizerType.Marker;
      }
      else
      {
        glyphSymbol = new GlyphGraphicSymbol();
        symPoint.Graphic.GraphicSymbols.Add(glyphSymbol);
        lpi.Symbolizer = (int)SymbolizerType.Marker;
      }

      float width = 10F, height = 0F;
      NodePropertyValue pv = null;

      try
      {
        int nProps = properties.Length;

        for (int i = 0; i < nProps; i++)
        {
          pv = properties[i];

          if (pointType == 0)
          {
            switch (pv.Name)
            {
              case "point-file":
                pointSymbol.Path = ToPath(pv.Value);
                break;
              case "point-allow-overlap":
                symPoint.LabelBehaviour.AllowOverlap = Convert.ToBoolean(pv.Value);
                break;
              case "point-ignore-placement":
                symPoint.LabelBehaviour.CollisionDetectable = !Convert.ToBoolean(pv.Value);
                break;
              case "point-opacity":
                pointSymbol.Opacity = Convert.ToSingle(pv.Value);
                break;
              case "point-placement":
                lpi.Placement = pv.Value;
                break;
              case "point-transform":
                UnsupportedProperty(pv);
                break;
              case "point-comp-op":
                //UnsupportedProperty(pv.Name);
                AddProperty(symPoint, "comp-op", pv.Value);
                break;
            }
          }
          else
          {
            switch (pv.Name)
            {
              case "marker-file":
                if (pointSymbol != null)
                  pointSymbol.Path = ToPath(pv.Value);
                else if (glyphSymbol != null)
                {
                  if (FontUtility.IsFontInstalled("DejaVu Sans"))
                  {
                    glyphSymbol.TextStyle.Font.Name = "DejaVu Sans";
                    glyphSymbol.TextStyle.Font.Stretch = 1.2F;
                    glyphSymbol.Unicode = 8594;
                  }
                  else if (FontUtility.IsFontInstalled("Segoe UI"))
                  {
                    glyphSymbol.TextStyle.Font.Name = "Segoe UI";
                    glyphSymbol.Unicode = 2192;
                  }

                }
                break;
              case "marker-opacity":
                float value = Convert.ToSingle(pv.Value);
                if (pointSymbol != null)
                  pointSymbol.Opacity = value;
                else if (symPoint.Graphic != null)
                  symPoint.Graphic.Opacity /*markSymbol.Opacity*/ = value;

                if (value == 0.0F)
                  symPoint.Enabled = false;
                break;
              case "marker-line-color":
                Color clr = ColorUtility.FromHtml(pv.Value);
                if (markSymbol != null)
                  markSymbol.Stroke.Color = clr;
                else if (glyphSymbol != null)
                  glyphSymbol.TextStyle.Halo.Color = clr;
                break;
              case "marker-line-width":
                if (markSymbol != null)
                  markSymbol.Stroke.Width = Convert.ToSingle(pv.Value);
                else if (glyphSymbol != null)
                  glyphSymbol.TextStyle.Halo.Radius = Convert.ToSingle(pv.Value);
                break;
              case "marker-line-opacity":
                if (markSymbol != null)
                  markSymbol.Stroke.Opacity = Convert.ToSingle(pv.Value);
                else if (glyphSymbol != null)
                  glyphSymbol.TextStyle.Halo.Opacity = Convert.ToSingle(pv.Value);
                break;
              case "marker-placement":
                lpi.Placement = pv.Value;
                if ((glyphSymbol != null || markSymbol != null) && lpi.Placement.Equals("line"))
                  lpi.Placement = "line-point-pattern";
                break;
              case "marker-multi-policy":
                // TODO
                break;
              case "marker-type":
                markSymbol.WellKnownName = pv.Value;
                break;
              case "marker-width":
                width = Convert.ToSingle(pv.Value);
                if (glyphSymbol != null)
                  glyphSymbol.TextStyle.Font.Size = width;
                break;
              case "marker-height":
                height = Convert.ToSingle(pv.Value);
                break;
              case "marker-fill-opacity":
                if (markSymbol != null)
                  markSymbol.Fill.Opacity = Convert.ToSingle(pv.Value);
                else if (glyphSymbol != null)
                  glyphSymbol.TextStyle.Opacity = Convert.ToSingle(pv.Value);
                break;
              case "marker-fill":
                clr = ColorUtility.FromHtml(pv.Value);
                if (markSymbol != null)
                  markSymbol.Fill.Color = clr;
                else if (glyphSymbol != null)
                  glyphSymbol.TextStyle.Color = clr;
                break;
              case "marker-allow-overlap":
                symPoint.LabelBehaviour.AllowOverlap = Convert.ToBoolean(pv.Value);
                break;
              case "marker-ignore-placement":
                symPoint.LabelBehaviour.CollisionDetectable = !Convert.ToBoolean(pv.Value);
                break;
              case "marker-spacing":
                lpi.Properties.Add(new KeyValuePair<string, string>(pv.Name, pv.Value));
                break;
              case "marker-max-error":
                // TODO
                break;
              case "marker-transform":
                ApplySVGTransformation(symPoint.Graphic, pv.Value);
                break;
              case "marker-clip":
                symPoint.Clip = Convert.ToBoolean(pv.Value);
                break;
              case "marker-smooth":
                symPoint.Clip = Convert.ToBoolean(pv.Value);
                break;
              case "marker-geometry-transform":
                UnsupportedProperty(pv);
                break;
              case "marker-comp-op":
                UnsupportedProperty(pv);
                AddProperty(symPoint, "comp-op", pv.Value);
                break;
            }
          }
        }
      }
      catch (Exception ex)
      {
        ThrowParsingException(ex, pv);
      }

      if (height == 0F)
        height = width;

      if (markSymbol != null)
        markSymbol.Size = new SizeF(width, height);
      else if (glyphSymbol != null)
        symPoint.Graphic.Size = new SizeF(width, 6);

      symPoint.LabelPlacement = CreateLabelPlacement(lpi);

      return symPoint;
    }
    private PolygonSymbolizer CreatePolygonSymbolizer(NodePropertyValue[] properties)
    {
      PolygonSymbolizer symPolygon = new PolygonSymbolizer();
      symPolygon.Fill.Color = Color.Gray;
      symPolygon.Fill.Outlined = false;
      symPolygon.Clip = true;

      GraphicFill gFill = properties[0].Name.StartsWith("polygon-pattern-") ? new GraphicFill() : null;
      if (gFill != null)
      {
        symPolygon.Fill.GraphicFill = gFill;
        symPolygon.Fill.Opacity = 0.0F;
      }

      GeometryTransformInfo geomTrans = new GeometryTransformInfo();

      NodePropertyValue pv = null;

      try
      {
        int nProps = properties.Length;

        for (int i = 0; i < nProps; i++)
        {
          pv = properties[i];

          if (gFill != null)
          {
            switch (pv.Name)
            {
              case "polygon-pattern-file":
                ExternalGraphicSymbol egs = new ExternalGraphicSymbol();
                egs.Path = ToPath(pv.Value);
                gFill.GraphicSymbols.Add(egs);
                break;
              case "polygon-pattern-opacity":
                gFill.Opacity = Convert.ToSingle(pv.Value);
                break;
              case "polygon-pattern-comp-op":
                AddProperty(symPolygon, "comp-op", pv.Value);
                break;
            }
          }
          else
          {
            switch (pv.Name)
            {
              case "polygon-fill":
                Color clr = ColorUtility.FromHtml(pv.Value);
                symPolygon.Fill.Color = clr;
                if (clr.A != 255)
                  symPolygon.Fill.Opacity = clr.A / 255.0F;
                break;
              case "polygon-opacity":
                symPolygon.Fill.Opacity = Convert.ToSingle(pv.Value);
                break;
              case "polygon-gamma":
                UnsupportedProperty(pv);
                break;
              case "polygon-gamma-method":
                UnsupportedProperty(pv);
                break;
              case "polygon-clip":
                symPolygon.Clip = Convert.ToBoolean(pv.Value);
                break;
              case "polygon-comp-op":
                UnsupportedProperty(pv);
                AddProperty(symPolygon, "comp-op", pv.Value);
                break;
              case "polygon-simplify":
                geomTrans.Simplify = pv.Value;
                break;
              case "polygon-simplify-algorithm":
                geomTrans.SimplifyAlgorithm = pv.Value;
                break;
              case "polygon-smooth":
                geomTrans.Smooth = pv.Value;
                break;
              case "polygon-offset":
                geomTrans.Offset = pv.Value;
                break;
              case "polygon-geometry-transform":
                geomTrans.GeometryTransform = pv.Value;
                break;
            }
          }
        }
      }
      catch (Exception ex)
      {
        ThrowParsingException(ex, pv);
      }

      symPolygon.GeometryExpression = ToGeometryExpression(geomTrans);

      return symPolygon;
    }
    private GraphicTextSymbolizer CreateGraphicTextSymbolizer(NodePropertyValue[] properties)
    {
      GraphicTextSymbolizer symText = new GraphicTextSymbolizer();
      symText.Clip = true;
      symText.TextLayout.Alignment = TextAlignment.CenterAligned;
      ExternalGraphicSymbol gsImage = new ExternalGraphicSymbol();
      symText.Graphic.GraphicSymbols.Add(gsImage);

      GeometryTransformInfo geomTrans = new GeometryTransformInfo();

      LabelPlacementInfo lpi = new LabelPlacementInfo();
      lpi.Placement = "point";
      lpi.Symbolizer = (int)SymbolizerType.Shield;

      int blockIndex = -1;
      TextLayoutBlock textBlock = new TextLayoutBlock();
      string textTransform = null;
      int nProps = properties.Length;
      float text_dx = 0F, text_dy = 0F;

      NodePropertyValue pv = null;

      try
      {
        for (int i = 0; i < nProps; i++)
        {
          pv = properties[i];

          switch (pv.Name)
          {
            case "shield-name":
              if (pv.Value != null)
              {
                string textExpr = ToExpression(pv.Value);
                if (!string.IsNullOrEmpty(textTransform))
                  textExpr = GetTextTransform(textExpr, textTransform);
                textBlock.TextExpression = textExpr;

                blockIndex++;
                if (blockIndex > 0)
                  textBlock = new TextLayoutBlock();

                symText.TextLayout.Blocks.Add(textBlock);
              }
              break;
            case "shield-face-name":
              SetFontName(textBlock, pv.Value);
              break;
            case "shield-file":
              gsImage.Path = ToPath(pv.Value);
              break;
            case "shield-text-transform":
              if (string.IsNullOrEmpty(textBlock.TextExpression))
                textTransform = pv.Value;
              else
                textBlock.TextExpression = GetTextTransform(textBlock.TextExpression, pv.Value);
              break;
            case "shield-fill":
              textBlock.TextFormat.TextStyle.Color = ColorUtility.FromHtml(pv.Value);
              break;
            case "shield-text-opacity":
              textBlock.TextFormat.TextStyle.Opacity = Convert.ToSingle(pv.Value);
              break;
            case "shield-opacity":
              gsImage.Opacity = Convert.ToSingle(pv.Value);
              break;
            case "shield-size":
              textBlock.TextFormat.TextStyle.Font.Size = Convert.ToSingle(pv.Value);
              break;
            case "shield-halo-radius":
              textBlock.TextFormat.TextStyle.Halo.Radius = Convert.ToSingle(pv.Value);
              break;
            case "shield-halo-fill":
              Color clr = ColorUtility.FromHtml(pv.Value);
              textBlock.TextFormat.TextStyle.Halo.Color = clr;
              if (clr.A != 255)
                textBlock.TextFormat.TextStyle.Halo.Opacity = clr.A / 255.0F;
              break;
            case "shield-halo-opacity":
              textBlock.TextFormat.TextStyle.Halo.Opacity = Convert.ToSingle(pv.Value);
              break;
            case "shield-clip":
              symText.Clip = Convert.ToBoolean(pv.Value);
              break;
            case "shield-horizontal-alignment":
              // TODO
              break;
            case "shield-vertical-alignment":
              // TODO
              break;
            case "shield-justify-alignment":
              // TODO
              break;
            case "shield-transform":
              //TODO
              break;
            case "shield-wrap-width":
              textBlock.TextFormat.TextWrapping.MaxWidth = Convert.ToUInt32(pv.Value);
              textBlock.TextFormat.TextWrapping.Mode = Drawing.Text.TextWrapMode.WrapByMaxWidthPixels;
              break;
            case "shield-wrap-before":
              TextWrapping tw = textBlock.TextFormat.TextWrapping;
              if (tw.Characters == null)
                tw.Characters = new WrapCharacter[] { new WrapCharacter() };

              tw.Characters[0].WrapType = CharacterWrapType.Before;
              break;
            case "shield-wrap-character":
              TextWrapping tw2 = textBlock.TextFormat.TextWrapping;
              if (tw2.Characters == null)
                tw2.Characters = new WrapCharacter[] { new WrapCharacter() };

              tw2.Characters[0].Character = pv.Value;
              break;
            case "shield-character-spacing":
              textBlock.TextFormat.TextSpacing.CharacterSpacing = Convert.ToSingle(pv.Value);
              break;
            case "shield-line-spacing":
              textBlock.TextFormat.TextSpacing.Leading = Convert.ToSingle(pv.Value);
              break;
            case "shield-allow-overlap":
              symText.LabelBehaviour.AllowOverlap = Convert.ToBoolean(pv.Value);
              break;
            case "shield-min-distance":
              symText.LabelBehaviour.CollisionMeasures.Add(string.Format("MinimumDistance({0})", pv.Value));
              break;
            case "shield-avoid-edges":
              symText.LabelBehaviour.AvoidEdges = Convert.ToBoolean(pv.Value);
              break;
            case "shield-spacing":
              lpi.Properties.Add(new KeyValuePair<string, string>(pv.Name, pv.Value));
              break;
            case "shield-min-padding":
              UnsupportedProperty(pv);
              break;
            case "shield-placement-type":
              lpi.Properties.Add(new KeyValuePair<string, string>(pv.Name, pv.Value));
              break;
            case "shield-placements":
              lpi.Properties.Add(new KeyValuePair<string, string>(pv.Name, pv.Value));
              break;
            case "shield-text-dx":
              text_dx = Convert.ToSingle(pv.Value);
              break;
            case "shield-text-dy":
              text_dy = Convert.ToSingle(pv.Value);
              break;
            case "shield-dx":
              lpi.Properties.Add(new KeyValuePair<string, string>(pv.Name, pv.Value));
              break;
            case "shield-dy":
              lpi.Properties.Add(new KeyValuePair<string, string>(pv.Name, pv.Value));
              break;
            case "shield-comp-op":
              UnsupportedProperty(pv);
              break;
            default:
              break;
          }
        }
      }
      catch (Exception ex)
      {
        ThrowParsingException(ex, pv);
      }

      if (text_dx != 0F || text_dy != 0F)
        symText.Graphic.Size = new SizeF(text_dx, text_dy);

      ApplyTextBlockFormat(symText.TextLayout);
      symText.LabelPlacement = CreateLabelPlacement(lpi);
      if ("point".Equals(lpi.Placement))
        geomTrans.DisplacementX = geomTrans.DisplacementY = string.Empty;
      symText.GeometryExpression = ToGeometryExpression(geomTrans);

      return symText;
    }