001    package de.deepamehta.plugins.topicmaps.model;
002    
003    import de.deepamehta.core.JSONEnabled;
004    import de.deepamehta.core.model.TopicModel;
005    import de.deepamehta.core.util.DeepaMehtaUtils;
006    
007    import org.codehaus.jettison.json.JSONObject;
008    
009    import java.awt.Point;
010    
011    import java.util.Map;
012    import 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     */
022    public 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                JSONObject topicmap = new JSONObject();
073                topicmap.put("info", topicmapTopic.toJSON());
074                topicmap.put("topics", DeepaMehtaUtils.objectsToJSON(topics.values()));
075                topicmap.put("assocs", DeepaMehtaUtils.objectsToJSON(assocs.values()));
076                return topicmap;
077            } catch (Exception e) {
078                throw new RuntimeException("Serialization failed (" + this + ")", e);
079            }
080        }
081    
082        @Override
083        public String toString() {
084            return "topicmap " + getId();
085        }
086    
087        // -------------------------------------------------------------------------------------------- Public Inner Classes
088    
089        // Note: there is a client-side equivalent in canvas_view.js (deepamehta-webclient plugin)
090        public class GridPositioning {
091    
092            // Settings
093            private final int GRID_DIST_X = 220;    // MAX_TOPIC_LABEL_WIDTH + 20 pixel padding
094            private final int GRID_DIST_Y = 80;
095            private final int START_X;
096            private final int START_Y = 50;
097            private final int MIN_Y = -9999;
098    
099            private final int canvasWidth;
100            private final int transX;
101    
102            private int gridX;
103            private int gridY;
104    
105            // --- Constructors ---
106    
107            public GridPositioning(int canvasWidth, int transX) {
108                this.canvasWidth = canvasWidth;
109                this.transX = transX;
110                START_X = 50 - transX;
111                //
112                Point startPos = findStartPostition();
113                gridX = startPos.x;
114                gridY = startPos.y;
115            }
116    
117            // --- Public Methods ---
118    
119            public Point nextPosition() {
120                Point pos = new Point(gridX, gridY);
121                advancePosition();
122                return pos;
123            }
124    
125            // --- Private Methods ---
126    
127            private Point findStartPostition() {
128                int maxY = MIN_Y;
129                for (TopicViewmodel topic : topics.values()) {
130                    if (topic.getY() > maxY) {
131                        maxY = topic.getY();
132                    }
133                }
134                int x = START_X;
135                int y = maxY != MIN_Y ? maxY + GRID_DIST_Y : START_Y;
136                return new Point(x, y);
137            }
138    
139            private void advancePosition() {
140                if (gridX + GRID_DIST_X + transX > canvasWidth) {
141                    gridX = START_X;
142                    gridY += GRID_DIST_Y;
143                } else {
144                    gridX += GRID_DIST_X;
145                }
146            }
147        }
148    }