001package de.deepamehta.plugins.topicmaps.model;
002
003import de.deepamehta.core.JSONEnabled;
004import de.deepamehta.core.model.TopicModel;
005import de.deepamehta.core.util.DeepaMehtaUtils;
006
007import org.codehaus.jettison.json.JSONObject;
008
009import java.awt.Point;
010
011import java.util.Map;
012import java.util.logging.Logger;
013
014
015
016/**
017 * A topicmap viewmodel: a collection of topics and associations plus their view properties.
018 * <p>
019 * Features:
020 * - Serialization to JSON.
021 */
022public class TopicmapViewmodel implements JSONEnabled {
023
024    // ---------------------------------------------------------------------------------------------- Instance Variables
025
026    private TopicModel topicmapTopic;
027    private Map<Long, TopicViewmodel> topics;
028    private Map<Long, AssociationViewmodel> assocs;
029
030    private Logger logger = Logger.getLogger(getClass().getName());
031
032    // ---------------------------------------------------------------------------------------------------- Constructors
033
034    public TopicmapViewmodel(TopicModel topicmapTopic, Map<Long, TopicViewmodel> topics,
035                                                       Map<Long, AssociationViewmodel> assocs) {
036        this.topicmapTopic = topicmapTopic;
037        this.topics = topics;
038        this.assocs = assocs;
039    }
040
041    // -------------------------------------------------------------------------------------------------- Public Methods
042
043    public long getId() {
044        return topicmapTopic.getId();
045    }
046
047    // ---
048
049    public Iterable<TopicViewmodel> getTopics() {
050        return topics.values();
051    }
052
053    public Iterable<AssociationViewmodel> getAssociations() {
054        return assocs.values();
055    }
056
057    // ---
058
059    public TopicViewmodel getTopic(long id) {
060        return topics.get(id);
061    }
062
063    public AssociationViewmodel getAssociation(long id) {
064        return assocs.get(id);
065    }
066
067    // ---
068
069    @Override
070    public JSONObject toJSON() {
071        try {
072            return new JSONObject()
073                .put("info", topicmapTopic.toJSON())
074                .put("topics", DeepaMehtaUtils.toJSONArray(topics.values()))
075                .put("assocs", DeepaMehtaUtils.toJSONArray(assocs.values()));
076        } catch (Exception e) {
077            throw new RuntimeException("Serialization failed (" + this + ")", e);
078        }
079    }
080
081    @Override
082    public String toString() {
083        return "topicmap " + getId();
084    }
085
086    // -------------------------------------------------------------------------------------------------- Nested Classes
087
088    // Note: there is a client-side equivalent in canvas_view.js (deepamehta-webclient plugin)
089    public class GridPositioning {
090
091        // Settings
092        private final int GRID_DIST_X = 220;    // MAX_TOPIC_LABEL_WIDTH + 20 pixel padding
093        private final int GRID_DIST_Y = 80;
094        private final int START_X;
095        private final int START_Y = 50;
096        private final int MIN_Y = -9999;
097
098        private final int canvasWidth;
099        private final int transX;
100
101        private int gridX;
102        private int gridY;
103
104        // --- Constructors ---
105
106        public GridPositioning(int canvasWidth, int transX) {
107            this.canvasWidth = canvasWidth;
108            this.transX = transX;
109            START_X = 50 - transX;
110            //
111            Point startPos = findStartPostition();
112            gridX = startPos.x;
113            gridY = startPos.y;
114        }
115
116        // --- Public Methods ---
117
118        public Point nextPosition() {
119            Point pos = new Point(gridX, gridY);
120            advancePosition();
121            return pos;
122        }
123
124        // --- Private Methods ---
125
126        private Point findStartPostition() {
127            int maxY = MIN_Y;
128            for (TopicViewmodel topic : topics.values()) {
129                if (topic.getY() > maxY) {
130                    maxY = topic.getY();
131                }
132            }
133            int x = START_X;
134            int y = maxY != MIN_Y ? maxY + GRID_DIST_Y : START_Y;
135            return new Point(x, y);
136        }
137
138        private void advancePosition() {
139            if (gridX + GRID_DIST_X + transX > canvasWidth) {
140                gridX = START_X;
141                gridY += GRID_DIST_Y;
142            } else {
143                gridX += GRID_DIST_X;
144            }
145        }
146    }
147}