package de.gurkenlabs.litiengine.environment.tilemap.xml;

import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;

import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlValue;
import javax.xml.bind.annotation.adapters.XmlAdapter;

import de.gurkenlabs.litiengine.environment.tilemap.ICustomProperty;

public class CustomPropertyAdapter extends XmlAdapter<CustomPropertyAdapter.PropertyList, Map<String, ICustomProperty>> {
  private static final String STRING_TYPE = "string";
  @XmlAccessorType(XmlAccessType.FIELD)
  static class Property {
    @XmlAttribute
    String name;
    @XmlAttribute
    String type;
    @XmlAttribute
    String value;
    @XmlValue
    String contents;

    Property() {
    }

    Property(String name, String type) {
      this.name = name;
      this.type = type == null ? STRING_TYPE : type;
    }

    @SuppressWarnings("unused")
    private void afterUnmarshal(Unmarshaller u, Object parent) {
      if (this.type == null) {
        this.type = STRING_TYPE;
      }
    }

    @SuppressWarnings("unused")
    private void beforeMarshal(Marshaller m) {
      if (this.type.equals(STRING_TYPE)) {
        this.type = null;
      }
    }
  }

  @XmlAccessorType(XmlAccessType.FIELD)
  static class PropertyList {
    @XmlElement(name = "property")
    List<Property> properties;

    PropertyList() {
    }

    PropertyList(List<Property> properties) {
      this.properties = properties;
    }
  }

  @Override
  public Map<String, ICustomProperty> unmarshal(PropertyList v) {
    Map<String, ICustomProperty> map = new Hashtable<>(v.properties.size()); // use hashtable to reject null keys/values
    for (Property property : v.properties)
      map.put(property.name, new CustomProperty(property.type, property.value != null ? property.value : property.contents));
    return map;
  }

  @Override
  public PropertyList marshal(Map<String, ICustomProperty> v) {
    if (v.isEmpty()) {
      return null;
    }
    List<Property> list = new ArrayList<>(v.size());
    for (Map.Entry<String, ICustomProperty> entry : v.entrySet()) {
      ICustomProperty property = entry.getValue();
      String value = property.getAsString();
      Property saved = new Property(entry.getKey(), property.getType());
      if (value.contains("\n")) {
        saved.contents = value;
      } else {
        saved.value = value;
      }
      list.add(saved);
    }
    return new PropertyList(list);
  }
}

@@ -76,24 +76,54 @@
 .ArrayList;%0A
+import java.util.Collections;%0A
 import java.
@@ -138,16 +138,16 @@
 htable;%0A
-
 import j
@@ -788,16 +788,17 @@
 tring%22;%0A
+%0A
   @XmlAc
@@ -852,16 +852,48 @@
 Property
+ implements Comparable%3CProperty%3E
  %7B%0A    @
@@ -1511,24 +1511,311 @@
      %7D%0A    %7D
+%0A%0A    @Override%0A    public int compareTo(Property o) %7B%0A      if (o == null) %7B%0A        return 1;%0A      %7D%0A%0A      if (o.name == null && this.name == null) %7B%0A        return 0;%0A      %7D%0A%0A      if (this.name == null) %7B%0A        return -1;%0A      %7D%0A%0A      return this.name.compareTo(o.name);%0A    %7D
 %0A  %7D%0A%0A  @Xml
@@ -3010,21 +3010,50 @@
 saved);%0A
-
     %7D
+%0A%0A    Collections.sort(list);
 %0A    ret

Make sure that the custom properties are sorted.