001/*
002 * Copyright 2006 - 2013
003 *     Stefan Balev     <stefan.balev@graphstream-project.org>
004 *     Julien Baudry    <julien.baudry@graphstream-project.org>
005 *     Antoine Dutot    <antoine.dutot@graphstream-project.org>
006 *     Yoann Pigné      <yoann.pigne@graphstream-project.org>
007 *     Guilhelm Savin   <guilhelm.savin@graphstream-project.org>
008 * 
009 * This file is part of GraphStream <http://graphstream-project.org>.
010 * 
011 * GraphStream is a library whose purpose is to handle static or dynamic
012 * graph, create them from scratch, file or any source and display them.
013 * 
014 * This program is free software distributed under the terms of two licenses, the
015 * CeCILL-C license that fits European law, and the GNU Lesser General Public
016 * License. You can  use, modify and/ or redistribute the software under the terms
017 * of the CeCILL-C license as circulated by CEA, CNRS and INRIA at the following
018 * URL <http://www.cecill.info> or under the terms of the GNU LGPL as published by
019 * the Free Software Foundation, either version 3 of the License, or (at your
020 * option) any later version.
021 * 
022 * This program is distributed in the hope that it will be useful, but WITHOUT ANY
023 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
024 * PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.
025 * 
026 * You should have received a copy of the GNU Lesser General Public License
027 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
028 * 
029 * The fact that you are presently reading this means that you have had
030 * knowledge of the CeCILL-C and LGPL licenses and that you accept their terms.
031 */
032package org.graphstream.ui.graphicGraph;
033
034import static org.graphstream.ui.graphicGraph.GraphPosLengthUtils.nodePosition;
035
036import java.util.ArrayList;
037import java.util.Collection;
038import java.util.Collections;
039import java.util.HashMap;
040import java.util.Iterator;
041
042import org.graphstream.graph.Edge;
043import org.graphstream.graph.Graph;
044import org.graphstream.graph.Node;
045import org.graphstream.stream.SourceBase.ElementType;
046import org.graphstream.ui.geom.Point3;
047import org.graphstream.ui.graphicGraph.stylesheet.Selector;
048
049/**
050 * Graphical node.
051 * 
052 * <p>
053 * A graphic node defines a position (x,y,z), a string label, and a style from
054 * the style sheet.
055 * </p>
056 * 
057 * @see GraphicGraph
058 */
059public class GraphicNode extends GraphicElement implements Node {
060        /**
061         * The position of the node. In graph units.
062         */
063        public double x, y, z;
064
065        public boolean positionned = false;
066
067        /**
068         * New graphic node.
069         * 
070         * @param id
071         *            The node identifier.
072         * @param attributes
073         *            The node attribute set (can be null).
074         */
075        public GraphicNode(GraphicGraph graph, String id,
076                        HashMap<String, Object> attributes) {
077                super(id, graph);
078
079                if (attributes != null)
080                        addAttributes(attributes);
081        }
082
083        @Override
084        public Selector.Type getSelectorType() {
085                return Selector.Type.NODE;
086        }
087
088        @Override
089        public double getX() {
090                return x;
091        }
092
093        @Override
094        public double getY() {
095                return y;
096        }
097
098        @Override
099        public double getZ() {
100                return z;
101        }
102
103        protected Point3 getPosition() {
104                return new Point3(x, y, z);
105        }
106
107        protected void moveFromEvent(double x, double y, double z) {
108                this.x = x;
109                this.y = y;
110                this.z = z;
111
112                if (!positionned) {
113                        positionned = true;
114                }
115
116                mygraph.graphChanged = true;
117                mygraph.boundsChanged = true;
118        }
119
120        @Override
121        public void move(double x, double y, double z) {
122                moveFromEvent(x, y, z);
123
124                if (mygraph.feedbackXYZ)
125                        setAttribute("xyz", x, y, z);
126        }
127
128        @Override
129        protected void attributeChanged(AttributeChangeEvent event,
130                        String attribute, Object oldValue, Object newValue) {
131                super.attributeChanged(event, attribute, oldValue, newValue);
132                char c = attribute.charAt(0);
133
134                if (attribute.length() > 2 && c == 'u' && attribute.charAt(1) == 'i'
135                                && attribute.startsWith("ui.sprite.")) {
136                        mygraph.spriteAttribute(event, this, attribute, newValue);
137                } else if ((event == AttributeChangeEvent.ADD || event == AttributeChangeEvent.CHANGE)) {
138                        if (attribute.length() == 1) {
139                                switch (c) {
140                                case 'x':
141                                        moveFromEvent(numberAttribute(newValue), y, z);
142                                        break;
143                                case 'y':
144                                        moveFromEvent(x, numberAttribute(newValue), z);
145                                        break;
146                                case 'z':
147                                        moveFromEvent(x, y, numberAttribute(newValue));
148                                        break;
149                                default:
150                                        break;
151                                }
152                        } else if (c == 'x'
153                                        && attribute.length() > 1
154                                        && attribute.charAt(1) == 'y'
155                                        && (attribute.length() == 2 || (attribute.length() == 3 && attribute
156                                                        .charAt(2) == 'z'))) {
157
158                                double pos[] = nodePosition(this);
159                                moveFromEvent(pos[0], pos[1], pos[2]);
160                        }
161                }
162
163                mygraph.listeners.sendAttributeChangedEvent(getId(), ElementType.NODE,
164                                attribute, event, oldValue, newValue);
165        }
166
167        /**
168         * Try to convert the object to a double.
169         * 
170         * @param value
171         *            The object to convert.
172         * @return The value.
173         */
174        protected double numberAttribute(Object value) {
175                if (value instanceof Number) {
176                        return ((Number) value).doubleValue();
177                } else if (value instanceof String) {
178                        try {
179                                return Double.parseDouble((String) value);
180                        } catch (NumberFormatException e) {
181                        }
182                } else if (value instanceof CharSequence) {
183                        try {
184                                return Double.parseDouble(((CharSequence) value).toString());
185                        } catch (NumberFormatException e) {
186                        }
187                }
188
189                return 0;
190        }
191
192        @Override
193        protected void removed() {
194                // NOP
195        }
196
197        // Node interface.
198
199        /**
200         * Not implemented.
201         */
202        public Iterator<Node> getBreadthFirstIterator() {
203                throw new RuntimeException("not implemented !");
204        }
205
206        /**
207         * Not implemented.
208         */
209        public Iterator<Node> getBreadthFirstIterator(boolean directed) {
210                throw new RuntimeException("not implemented !");
211        }
212
213        /**
214         * Not implemented.
215         */
216        public Iterator<Node> getDepthFirstIterator() {
217                throw new RuntimeException("not implemented !");
218        }
219
220        /**
221         * Not implemented.
222         */
223        public Iterator<Node> getDepthFirstIterator(boolean directed) {
224                throw new RuntimeException("not implemented !");
225        }
226
227        public int getDegree() {
228                ArrayList<GraphicEdge> edges = mygraph.connectivity.get(this);
229
230                if (edges != null)
231                        return edges.size();
232
233                return 0;
234        }
235
236        @SuppressWarnings("unchecked")
237        public <T extends Edge> T getEdge(int i) {
238                ArrayList<GraphicEdge> edges = mygraph.connectivity.get(this);
239
240                if (edges != null && i >= 0 && i < edges.size())
241                        return (T) edges.get(i);
242
243                return null;
244        }
245
246        @SuppressWarnings("unchecked")
247        public <T extends Edge> T getEdgeBetween(String id) {
248                if (hasEdgeToward(id))
249                        return (T) getEdgeToward(id);
250                else
251                        return (T) getEdgeFrom(id);
252        }
253
254        @SuppressWarnings("all")
255        public <T extends Edge> T getEdgeFrom(String id) {
256                return null;
257        }
258
259        @SuppressWarnings("unchecked")
260        public <T extends Edge> Iterator<T> getEdgeIterator() {
261                ArrayList<GraphicEdge> edges = mygraph.connectivity.get(this);
262
263                if (edges != null)
264                        return (Iterator<T>) edges.iterator();
265
266                return null;
267        }
268
269        @SuppressWarnings("all")
270        public Iterator<Edge> iterator() {
271                return (Iterator<Edge>) getEdgeIterator();
272        }
273
274        @SuppressWarnings("all")
275        public <T extends Edge> Iterable<T> getEachEdge() {
276                return (Iterable<T>) mygraph.connectivity.get(this);
277        }
278
279        @SuppressWarnings("all")
280        public <T extends Edge> Collection<T> getEdgeSet() {
281                return (Collection<T>) Collections
282                                .unmodifiableCollection(mygraph.connectivity.get(this));
283        }
284
285        @SuppressWarnings("all")
286        public <T extends Edge> T getEdgeToward(String id) {
287                ArrayList<? extends Edge> edges = mygraph.connectivity.get(this);
288
289                for (Edge edge : edges) {
290                        if (edge.getOpposite(this).getId().equals(id))
291                                return (T) edge;
292                }
293
294                return null;
295        }
296
297        @SuppressWarnings("all")
298        public <T extends Edge> Iterator<T> getEnteringEdgeIterator() {
299                return getEdgeIterator();
300        }
301
302        @SuppressWarnings("all")
303        public <T extends Edge> Iterable<T> getEachEnteringEdge() {
304                return getEdgeSet();
305        }
306
307        @SuppressWarnings("all")
308        public <T extends Edge> Collection<T> getEnteringEdgeSet() {
309                return (Collection<T>) Collections.unmodifiableCollection(getEdgeSet());
310        }
311
312        public Graph getGraph() {
313                return mygraph;
314        }
315
316        public String getGraphName() {
317                throw new RuntimeException("impossible with GraphicGraph");
318        }
319
320        public String getHost() {
321                throw new RuntimeException("impossible with GraphicGraph");
322        }
323
324        public int getInDegree() {
325                return getDegree();
326        }
327
328        @SuppressWarnings("all")
329        public <T extends Edge> Iterator<T> getLeavingEdgeIterator() {
330                return getEdgeIterator();
331        }
332
333        @SuppressWarnings("all")
334        public <T extends Edge> Iterable<T> getEachLeavingEdge() {
335                return getEdgeSet();
336        }
337
338        @SuppressWarnings("all")
339        public <T extends Edge> Collection<T> getLeavingEdgeSet() {
340                return (Collection<T>) Collections.unmodifiableCollection(getEdgeSet());
341        }
342
343        public Iterator<Node> getNeighborNodeIterator() {
344                return null;
345        }
346
347        public int getOutDegree() {
348                return getDegree();
349        }
350
351        public boolean hasEdgeBetween(String id) {
352                return (hasEdgeToward(id) || hasEdgeFrom(id));
353        }
354
355        public boolean hasEdgeFrom(String id) {
356                return false;
357        }
358
359        public boolean hasEdgeToward(String id) {
360                return false;
361        }
362
363        public boolean isDistributed() {
364                return false;
365        }
366
367        public void setGraph(Graph graph) {
368                throw new RuntimeException("impossible with GraphicGraph");
369        }
370
371        public void setGraphName(String newHost) {
372                throw new RuntimeException("impossible with GraphicGraph");
373        }
374
375        public void setHost(String newHost) {
376                throw new RuntimeException("impossible with GraphicGraph");
377        }
378
379        // XXX stubs for the new methods
380
381        public <T extends Edge> T getEdgeBetween(Node Node) {
382                // TODO Auto-generated method stub
383                return null;
384        }
385
386        public <T extends Edge> T getEdgeBetween(int index) {
387                // TODO Auto-generated method stub
388                return null;
389        }
390
391        public <T extends Edge> T getEdgeFrom(Node Node) {
392                // TODO Auto-generated method stub
393                return null;
394        }
395
396        public <T extends Edge> T getEdgeFrom(int index) {
397                // TODO Auto-generated method stub
398                return null;
399        }
400
401        public <T extends Edge> T getEdgeToward(Node Node) {
402                // TODO Auto-generated method stub
403                return null;
404        }
405
406        public <T extends Edge> T getEdgeToward(int index) {
407                // TODO Auto-generated method stub
408                return null;
409        }
410
411        public boolean hasEdgeBetween(Node node) {
412                // TODO Auto-generated method stub
413                return false;
414        }
415
416        public boolean hasEdgeBetween(int index) {
417                // TODO Auto-generated method stub
418                return false;
419        }
420
421        public boolean hasEdgeFrom(Node node) {
422                // TODO Auto-generated method stub
423                return false;
424        }
425
426        public boolean hasEdgeFrom(int index) {
427                // TODO Auto-generated method stub
428                return false;
429        }
430
431        public boolean hasEdgeToward(Node node) {
432                // TODO Auto-generated method stub
433                return false;
434        }
435
436        public boolean hasEdgeToward(int index) {
437                // TODO Auto-generated method stub
438                return false;
439        }
440
441        public <T extends Edge> T getEnteringEdge(int i) {
442                // TODO Auto-generated method stub
443                return null;
444        }
445
446        public <T extends Edge> T getLeavingEdge(int i) {
447                // TODO Auto-generated method stub
448                return null;
449        }
450}