package com.github.ferstl.depgraph.graph.style;

import java.io.IOException;
import java.util.Map;
import com.github.ferstl.depgraph.dot.AttributeBuilder;
import com.github.ferstl.depgraph.graph.NodeResolution;
import com.google.common.collect.ImmutableMap;
import com.google.gson.FieldNamingPolicy;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.TypeAdapter;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;

public class StyleConfiguration {

  NodeConfiguration defaultNode = new NodeConfiguration();
  EdgeConfiguration defaultEdge = new EdgeConfiguration();
  Map<String, NodeConfiguration> scopedNodes = ImmutableMap.of("compile", new NodeConfiguration(), "test", new NodeConfiguration());
  Map<NodeResolution, EdgeConfiguration> edgeTypes = ImmutableMap.of(NodeResolution.INCLUDED, new EdgeConfiguration(), NodeResolution.OMITTED_FOR_DUPLICATE, new EdgeConfiguration());


  public static void main(String[] args) {
    Gson gson = new GsonBuilder()
        .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_DASHES)
        .enableComplexMapKeySerialization()
        .registerTypeAdapter(NodeResolution.class, new TypeAdapter<NodeResolution>() {

          @Override
          public void write(JsonWriter out, NodeResolution value) throws IOException {
            out.value(value.name().replace('_', '-').toLowerCase());
          }

          @Override
          public NodeResolution read(JsonReader in) throws IOException {
            String value = in.nextString();
            return NodeResolution.valueOf(value.replace('-', '_').toUpperCase());
          }
        })
        .setPrettyPrinting()
        .create();

    System.out.println(gson.toJson(new StyleConfiguration()));
  }

  static class NodeConfiguration {

    AbstractNode shape = new Polygon();
    String color = "red";
    Font font = new Font();

    public void configureGlobally(AttributeBuilder builder) {
      builder.color(this.color);
      this.font.configureGlobally(builder);
    }
  }

  static class EdgeConfiguration {

    String style = "dotted";
    String color = "black";
    Font font = new Font();

    public void configureGlobally(AttributeBuilder builder) {
      builder
          .style(this.style)
          .color(this.color);

      this.font.configureGlobally(builder);
    }
  }

  static class Font {

    String color = "black";
    int size = 14;
    String name = "Helvetica";

    public void configureGlobally(AttributeBuilder builder) {
      builder
          .color(this.color)
          .fontSize(this.size)
          .fontName(this.name);
    }
  }

  abstract static class AbstractNode {

    final String type;
    String color = "black";
    String style = "rounded";
    Font defaultFont = new Font();
    Font groupIdFont = this.defaultFont;
    Font artifactIdFont;
    Font versionFont;
    Font scopeFont;

    AbstractNode(String type) {
      this.type = type;
    }

    public final void configureGlobally(AttributeBuilder builder) {
      builder.shape(this.type)
          .style(this.style)
          .color(this.color)
          .fontName(this.defaultFont.name)
          .fontSize(this.defaultFont.size)
          .fontColor(this.defaultFont.color);
    }

  }

  static class Polygon extends AbstractNode {

    int sides = 4;


    Polygon() {
      super("polygon");
    }

  }

  static class Ellipse extends AbstractNode {

    Ellipse() {
      super("ellipse");
    }
  }
}

@@ -66,24 +66,117 @@
 OException;%0A
+import java.io.InputStream;%0Aimport java.io.InputStreamReader;%0Aimport java.lang.reflect.Type;%0A
 import java.
@@ -443,32 +443,203 @@
 on.GsonBuilder;%0A
+import com.google.gson.JsonDeserializationContext;%0Aimport com.google.gson.JsonDeserializer;%0Aimport com.google.gson.JsonElement;%0Aimport com.google.gson.JsonParseException;%0A
 import com.googl
@@ -1939,110 +1939,1234 @@
    .
-setPrettyPrinting()%0A        .create();%0A%0A    System.out.println(gson.toJson(new StyleConfiguration()));
+registerTypeAdapter(AbstractNode.class, new JsonDeserializer%3CAbstractNode%3E() %7B%0A%0A          @Override%0A          public AbstractNode deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException %7B%0A            JsonElement type = json.getAsJsonObject().get(%22type%22);%0A            if (type == null) %7B%0A              throw new NullPointerException(%22Undefined shape type%22);%0A            %7D%0A%0A            switch (type.getAsString()) %7B%0A              case %22polygon%22:%0A                return context.deserialize(json, Polygon.class);%0A              case %22ellipse%22:%0A                return context.deserialize(json, Ellipse.class);%0A              default:%0A                throw new IllegalArgumentException(%22Unknown shape type: %22 + type.getAsString());%0A            %7D%0A          %7D%0A        %7D)%0A        .setPrettyPrinting()%0A        .create();%0A%0A    System.out.println(gson.toJson(new StyleConfiguration()));%0A%0A    try (InputStream is = ClassLoader.getSystemResourceAsStream(%22style.json%22)) %7B%0A      StyleConfiguration config = gson.fromJson(new InputStreamReader(is), StyleConfiguration.class);%0A      System.err.println(gson.toJson(config));%0A    %7D catch (IOException e) %7B%0A      throw new RuntimeException(e);%0A    %7D
 %0A  %7D

Implement deserializer for the shape types