001package org.nasdanika.html.model.html.gen;
002
003import java.io.InputStream;
004import java.util.Map;
005
006import org.eclipse.emf.common.notify.impl.AdapterImpl;
007import org.eclipse.emf.ecore.EObject;
008import org.json.JSONArray;
009import org.json.JSONObject;
010import org.nasdanika.common.Context;
011import org.nasdanika.common.Function;
012import org.nasdanika.common.ListCompoundSupplierFactory;
013import org.nasdanika.common.MapCompoundSupplierFactory;
014import org.nasdanika.common.Supplier;
015import org.nasdanika.common.SupplierFactory;
016import org.nasdanika.common.Util;
017import org.nasdanika.emf.EObjectAdaptable;
018import org.nasdanika.html.Tag;
019import org.nasdanika.ncore.EObjectProperty;
020import org.nasdanika.ncore.Property;
021
022public class ListSupplierFactoryAdapter extends AdapterImpl implements SupplierFactory<InputStream> {
023        
024        protected ListSupplierFactoryAdapter(org.nasdanika.ncore.List list) {
025                setTarget(list);
026        }
027
028        @Override
029        public Supplier<InputStream> create(Context ctx) {
030                SupplierFactory<JSONArray> jsf = createJsonArraySupplierFactory((org.nasdanika.ncore.List) getTarget());
031                Function<Object, String> toStringFunction = Function.fromFunction(Object::toString, "toString()", 1);
032                return jsf.create(ctx).then(toStringFunction).then(Util.TO_STREAM.create(ctx));
033        }
034        
035        /**
036         * Creates {@link SupplierFactory} of {@link JSONArray} from a list.
037         * The factory is aware of model classes in Ncore package. Model elements
038         * of unknown classes are adapted to SupplierFactory.  
039         * @return
040         */
041        public static SupplierFactory<JSONArray> createJsonArraySupplierFactory(org.nasdanika.ncore.List list) {
042                ListCompoundSupplierFactory<Object> elementsFactory = new ListCompoundSupplierFactory<>("Elements");
043                for (EObject element: list.getValue()) {
044                        if (element instanceof org.nasdanika.ncore.List) {
045                                elementsFactory.add(createJsonArraySupplierFactory((org.nasdanika.ncore.List) element));                                
046                        } else if (element instanceof org.nasdanika.ncore.Map) {
047                                elementsFactory.add(createJsonObjectSupplierFactory((org.nasdanika.ncore.Map) element));
048                        } else if (element instanceof org.nasdanika.ncore.Boolean) {
049                                elementsFactory.add(SupplierFactory.from(((org.nasdanika.ncore.Boolean) element).getValue(), "Boolean"));
050                        } else if (element instanceof org.nasdanika.ncore.Integer) {
051                                elementsFactory.add(SupplierFactory.from(((org.nasdanika.ncore.Integer) element).getValue(), "Integer"));
052                        } else if (element instanceof org.nasdanika.ncore.String) {
053                                elementsFactory.add(SupplierFactory.from(((org.nasdanika.ncore.String) element).getValue(), "String"));
054                        } else {
055                                elementsFactory.add(adaptToSupplierFactory(element));
056                        }
057                }
058
059                return elementsFactory.then(ListSupplierFactoryAdapter::createListToJsonArrayFunction);
060        }
061        
062        /**
063         * Attempts to adapt to {@link Tag} factory first using {@link SupplierFactory.Provider}. Then to InputStream factory and chains with toString factory. 
064         * @param obj
065         * @return
066         */
067        private static SupplierFactory<? extends Object> adaptToSupplierFactory(EObject obj) {
068                Provider provider = EObjectAdaptable.adaptTo(obj, Provider.class);
069                if (provider != null) {
070                        SupplierFactory<Tag> tagFactory = provider.getFactory(Tag.class);
071                        if (tagFactory != null) {
072                                return tagFactory;
073                        }
074                        
075                        SupplierFactory<InputStream> streamFactory = provider.getFactory(InputStream.class);
076                        if (streamFactory != null) {
077                                return streamFactory.then(Util.TO_STRING);
078                        }
079                }
080                
081                
082                return EObjectAdaptable.adaptToSupplierFactoryNonNull(obj, Object.class).then(Util.OBJECT_TO_STRING_FACTORY);
083        }
084
085        private static Function<java.util.List<Object>, JSONArray> createListToJsonArrayFunction(Context context) {
086                return Function.fromFunction(JSONArray::new, "List to JSON array", 1);
087        }
088
089        private static Function<java.util.Map<String, Object>, JSONObject> createMapToJsonObjectFunction(Context context) {
090                java.util.function.Function<Map<String, Object>, JSONObject> func = map -> {
091                        return new JSONObject(map);
092                };
093                return Function.fromFunction(func, "Map to JSON Object", 1);
094        }
095
096        /**
097         * Creates {@link SupplierFactory} of {@link JSONObject} from a map.
098         * The factory is aware of model classes in Ncore package. Model elements
099         * of unknown classes are adapted to SupplierFactory.  
100         * @return
101         */
102        public static SupplierFactory<JSONObject> createJsonObjectSupplierFactory(org.nasdanika.ncore.Map map) {
103                MapCompoundSupplierFactory<String,Object> entryFactory = new MapCompoundSupplierFactory<>("Entries");
104                for (Property element: map.getValue()) {
105                        if (element instanceof org.nasdanika.ncore.ListProperty) {
106                                entryFactory.put(element.getName(), createJsonArraySupplierFactory((org.nasdanika.ncore.List) element));                                
107                        } else if (element instanceof org.nasdanika.ncore.MapProperty) {
108                                entryFactory.put(element.getName(),createJsonObjectSupplierFactory((org.nasdanika.ncore.Map) element));
109                        } else if (element instanceof org.nasdanika.ncore.BooleanProperty) {
110                                entryFactory.put(element.getName(), SupplierFactory.from(((org.nasdanika.ncore.Boolean) element).getValue(), "Boolean"));
111                        } else if (element instanceof org.nasdanika.ncore.IntegerProperty) {
112                                entryFactory.put(element.getName(), SupplierFactory.from(((org.nasdanika.ncore.Integer) element).getValue(), "Integer"));
113                        } else if (element instanceof org.nasdanika.ncore.StringProperty) {
114                                entryFactory.put(element.getName(), SupplierFactory.from(((org.nasdanika.ncore.String) element).getValue(), "String"));
115                        } else if (element instanceof EObjectProperty) {
116                                entryFactory.put(element.getName(), adaptToSupplierFactory(((EObjectProperty) element).getValue()));
117                        } else {
118                                throw new UnsupportedOperationException("Unsupported property type: " + element);
119                        }
120                }
121
122                return entryFactory.then(ListSupplierFactoryAdapter::createMapToJsonObjectFunction);
123        }
124//
125//      /**
126//       * Creates {@link SupplierFactory} of {@link BiSupplier} from a property.
127//       * The factory is aware of model classes in Ncore package. Model elements
128//       * of unknown classes are adapted to SupplierFactory assuming that the result is InputStream.  
129//       * @return
130//       */
131//      public static SupplierFactory<BiSupplier<String, Object>> createPropertySupplierFactory(org.nasdanika.ncore.Property property) {
132//              throw new UnsupportedOperationException();
133//      }
134
135}
136