001package org.javasimon.console.json;
002
003import org.javasimon.console.reflect.Getter;
004import org.javasimon.console.reflect.GetterFactory;
005import org.javasimon.console.text.Stringifier;
006import org.javasimon.console.text.StringifierFactory;
007
008import java.io.IOException;
009import java.io.Writer;
010import java.util.ArrayList;
011import java.util.HashMap;
012import java.util.List;
013import java.util.Map;
014
015/**
016 * JavaScript Object.
017 *
018 * @author gquintana
019 */
020public class ObjectJS extends AnyJS {
021
022        private List<Attribute> attributes;
023        private Map<String, Attribute> attributesByName;
024
025        public ObjectJS() {
026                this.attributes = new ArrayList<>();
027                this.attributesByName = new HashMap<>();
028        }
029
030        public void setAttribute(String name, AnyJS value) {
031                assert name != null;
032                assert value != null;
033                Attribute attribute = attributesByName.get(name);
034                if (attribute == null) {
035                        attribute = new Attribute(name, value);
036                        attributes.add(attribute);
037                        attributesByName.put(name, attribute);
038                } else {
039                        attribute.value = value;
040                }
041        }
042
043        public <T> void setSimpleAttribute(String name, T value, Stringifier<T> stringifier) {
044                SimpleJS propertyJS = new SimpleJS<>(value, stringifier);
045                setAttribute(name, propertyJS);
046        }
047
048        public AnyJS getAttribute(String name) {
049                assert name != null;
050                Attribute attribute = attributesByName.get(name);
051                return attribute == null ? null : attribute.value;
052        }
053
054        @Override
055        public void write(Writer writer) throws IOException {
056                writer.write("{");
057                boolean first = true;
058                for (Attribute attribute : attributes) {
059                        if (first) {
060                                first = false;
061                        } else {
062                                writer.write(",");
063                        }
064                        writeString(writer, attribute.name);
065                        writer.write(":");
066                        attribute.value.write(writer);
067                }
068                writer.write("}");
069        }
070
071        @SuppressWarnings("unchecked")
072        public static ObjectJS create(Object o, StringifierFactory stringifierFactory) {
073                if (o == null) {
074                        return null;
075                } else {
076                        ObjectJS objectJS = new ObjectJS();
077                        // Export properties using reflection
078                        for (Getter getter : GetterFactory.getGetters(o.getClass())) {
079                                String propertyName = getter.getName();
080                                Stringifier propertyStringifier = stringifierFactory.getStringifier(getter.getType(), getter.getSubType());
081                                if (propertyStringifier != null) {
082                                        Object propertyValue = getter.get(o);
083                                        objectJS.setSimpleAttribute(propertyName, propertyValue, propertyStringifier);
084                                }
085                        }
086                        return objectJS;
087                }
088        }
089
090        /** Export Simon attribute map as a JS object. */
091        private static class Attribute {
092
093                private final String name;
094                private AnyJS value;
095
096                public Attribute(String name, AnyJS value) {
097                        this.name = name;
098                        this.value = value;
099                }
100
101                @Override
102                public boolean equals(Object obj) {
103                        if (obj == null) {
104                                return false;
105                        }
106                        if (getClass() != obj.getClass()) {
107                                return false;
108                        }
109                        final Attribute other = (Attribute) obj;
110                        if ((this.name == null) ? (other.name != null) : !this.name.equals(other.name)) {
111                                return false;
112                        }
113                        return true;
114                }
115
116                @Override
117                public int hashCode() {
118                        return this.name == null ? 0 : this.name.hashCode();
119                }
120        }
121}