001package systems.dmx.geomaps.model;
002
003import systems.dmx.core.JSONEnabled;
004import systems.dmx.core.RelatedTopic;
005import systems.dmx.core.Topic;
006import systems.dmx.core.model.TopicModel;
007import systems.dmx.core.service.CoreService;
008import systems.dmx.core.util.DMXUtils;
009
010import org.codehaus.jettison.json.JSONObject;
011
012import java.util.HashMap;
013import java.util.Iterator;
014import java.util.List;
015import java.util.Map;
016import java.util.logging.Logger;
017
018
019
020/**
021 * A geomap model: a collection of Geo Coordinate topic models.
022 * <p>
023 * Features:
024 * - load from DB (by constructor).
025 * - Serialization to JSON.
026 *
027 * ### TODO: rename to GeomapViewmodel
028 */
029public class Geomap implements Iterable<TopicModel>, JSONEnabled {
030
031    // ---------------------------------------------------------------------------------------------- Instance Variables
032
033    protected Topic geomapTopic;
034    protected Map<Long, TopicModel> geoCoords = new HashMap();
035
036    protected CoreService dmx;
037
038    private Logger logger = Logger.getLogger(getClass().getName());
039
040    // ---------------------------------------------------------------------------------------------------- Constructors
041
042    /**
043     * Loads a topicmap from the DB.
044     *
045     * ### TODO: pass geomap data instead of retrieving in constructor. Don't pass core service.
046     */
047    public Geomap(long geomapId, CoreService dmx) {
048        logger.info("Loading geomap " + geomapId);
049        // Note: a Geomap is not a DMXObject. So the JerseyResponseFilter's automatic
050        // child topic loading is not applied. We must load the child topics manually here.
051        this.geomapTopic = dmx.getTopic(geomapId).loadChildTopics();
052        this.dmx = dmx;
053        //
054        fetchGeoCoordinates();
055    }
056
057    // -------------------------------------------------------------------------------------------------- Public Methods
058
059    public long getId() {
060        return geomapTopic.getId();
061    }
062
063    // ### TODO: needed?
064    public boolean containsTopic(long geoCoordId) {
065        return geoCoords.get(geoCoordId) != null;
066    }
067
068    // ---
069
070    @Override
071    public JSONObject toJSON() {
072        try {
073            return new JSONObject()
074                .put("info", geomapTopic.toJSON())
075                .put("topics", DMXUtils.toJSONArray(geoCoords.values()));
076        } catch (Exception e) {
077            throw new RuntimeException("Serialization failed", e);
078        }
079    }
080
081    @Override
082    public Iterator<TopicModel> iterator() {
083        return geoCoords.values().iterator();
084    }
085
086    @Override
087    public String toString() {
088        return "geomap " + getId();
089    }
090
091    // ------------------------------------------------------------------------------------------------- Private Methods
092
093    private void fetchGeoCoordinates() {
094        for (Topic geoCoord : fetchGeoCoordinates(geomapTopic)) {
095            geoCoords.put(geoCoord.getId(), geoCoord.getModel());
096        }
097    }
098
099    private List<RelatedTopic> fetchGeoCoordinates(Topic geomapTopic) {
100        return DMXUtils.loadChildTopics(geomapTopic.getRelatedTopics("dmx.geomaps.geotopic_mapcontext",
101            "dmx.core.default", "dmx.topicmaps.topicmap_topic", "dmx.geomaps.geo_coordinate"));
102    }
103}