001package conexp.fx.core.xml;
002
003/*
004 * #%L
005 * Concept Explorer FX
006 * %%
007 * Copyright (C) 2010 - 2023 Francesco Kriegel
008 * %%
009 * This program is free software: you can redistribute it and/or modify
010 * it under the terms of the GNU General Public License as
011 * published by the Free Software Foundation, either version 3 of the
012 * License, or (at your option) any later version.
013 * 
014 * This program is distributed in the hope that it will be useful,
015 * but WITHOUT ANY WARRANTY; without even the implied warranty of
016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
017 * GNU General Public License for more details.
018 * 
019 * You should have received a copy of the GNU General Public
020 * License along with this program.  If not, see
021 * <http://www.gnu.org/licenses/gpl-3.0.html>.
022 * #L%
023 */
024
025import java.util.Collection;
026import java.util.Collections;
027import java.util.LinkedList;
028import java.util.List;
029import java.util.Map;
030import java.util.Set;
031import java.util.concurrent.ConcurrentHashMap;
032
033import org.jsoup.nodes.Element;
034
035import com.google.common.base.Function;
036import com.google.common.collect.Iterables;
037
038import conexp.fx.core.collections.Pair;
039
040public abstract class AbstractCompoundData extends Data<Map<String, Data<?>>> implements Map<String, Data<?>> {
041
042  private static final Function<Element, String> ELEMENT_TO_TEXT_FUNCTION = new Function<Element, String>() {
043
044    public final String apply(final Element element) {
045      return element.text();
046    }
047  };
048
049  public AbstractCompoundData(final Datatype type, final String key) {
050    super(type, key, new ConcurrentHashMap<String, Data<?>>());
051  }
052
053  public AbstractCompoundData(final Datatype type, final String key, final Map<String, Data<?>> value) {
054    super(type, key, new ConcurrentHashMap<String, Data<?>>(value));
055  }
056
057  public AbstractCompoundData(final Datatype type, final String key, final Element element, final Metadata metadata)
058      throws NullPointerException, IndexOutOfBoundsException {
059    super(type, key, readDataFromElement(element, metadata));
060  }
061
062  protected synchronized static final Map<String, Data<?>>
063      readDataFromElement(final Element element, final Metadata metadata) {
064    final Map<String, Data<?>> map = new ConcurrentHashMap<String, Data<?>>();
065    for (Map.Entry<String, Pair<Datatype, Metadata>> entry : metadata.getKeyDatatypeMap().entrySet()) {
066      final String key = entry.getKey();
067      final Datatype type = entry.getValue().first();
068      final Metadata _metadata = entry.getValue().second();
069      final Element data = JsoupUtil.firstElement(element, Key.toArray(key));
070      switch (type) {
071      case BOOLEAN:
072        map.put(key, new BooleanData(key, data.text()));
073        break;
074      case INTEGER:
075        map.put(key, new IntegerData(key, data.text()));
076        break;
077      case FLOAT:
078        map.put(key, new FloatData(key, data.text()));
079        break;
080      case STRING:
081        try {
082          map.put(key, new StringData(key, data.text()));
083        } catch (Exception e) {
084          System.err.println(data);
085          e.printStackTrace();
086        }
087        break;
088      case COMPOUND:
089        map.put(key, new CompoundData(key, data, entry.getValue().second()));
090        break;
091      case BOOLEAN_LIST:
092        map.put(key, new BooleanListData(key, _metadata.getSubkey(), null, readStringDataFromElement(data, _metadata)));
093        break;
094      case INTEGER_LIST:
095        map.put(key, new IntegerListData(key, _metadata.getSubkey(), null, readStringDataFromElement(data, _metadata)));
096        break;
097      case FLOAT_LIST:
098        map.put(key, new FloatListData(key, _metadata.getSubkey(), null, readStringDataFromElement(data, _metadata)));
099        break;
100      case STRING_LIST:
101        map.put(key, new StringListData(key, _metadata.getSubkey(), readStringDataFromElement(data, _metadata)));
102        break;
103      case COMPOUND_LIST:
104        map.put(key, new CompoundListData(key, _metadata.getSubkey(), data, _metadata));
105      case METADATA:
106      default:
107      }
108    }
109    return map;
110  }
111
112  protected static List<String> readStringDataFromElement(final Element element, final Metadata metadata) {
113    List<String> list = new LinkedList<String>();
114    for (String value : Iterables
115        .transform(JsoupUtil.childrenByTag(element, metadata.getSubkey()), ELEMENT_TO_TEXT_FUNCTION))
116      list.add(value);
117    return Collections.synchronizedList(list);
118  }
119
120  @Override
121  public final boolean isEmpty() {
122    return value.isEmpty();
123  }
124
125  @Override
126  public final int size() {
127    return value.size();
128  }
129
130  @Override
131  public final void clear() {
132    value.clear();
133  }
134
135  @Override
136  public final boolean containsKey(Object key) {
137    return value.containsKey(key);
138  }
139
140  @Override
141  public final boolean containsValue(Object value) {
142    return this.value.containsValue(value);
143  }
144
145  @Override
146  public final Data<?> get(Object key) {
147    return value.get(key);
148  }
149
150  @Override
151  public final Data<?> put(String key, Data<?> value) {
152    return this.value.put(key, value);
153  }
154
155  @Override
156  public final void putAll(Map<? extends String, ? extends Data<?>> m) {
157    value.putAll(m);
158  }
159
160  @Override
161  public final Data<?> remove(Object key) {
162    return value.remove(key);
163  }
164
165  @Override
166  public final Set<String> keySet() {
167    return value.keySet();
168  }
169
170  @Override
171  public final Collection<Data<?>> values() {
172    return value.values();
173  }
174
175  @Override
176  public final Set<Map.Entry<String, Data<?>>> entrySet() {
177    return value.entrySet();
178  }
179
180}