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.stream.file;
033
034import java.awt.Color;
035import java.io.IOException;
036import java.io.PrintWriter;
037import java.lang.reflect.Array;
038import java.util.HashMap;
039import java.util.Locale;
040
041import org.graphstream.graph.CompoundAttribute;
042
043/**
044 * File output for the DGS (Dynamic Graph Stream) file format.
045 */
046public class FileSinkDGS extends FileSinkBase {
047        // Attribute
048
049        /**
050         * A shortcut to the output.
051         */
052        protected PrintWriter out;
053
054        protected String graphName = "";
055
056        // Command
057
058        @Override
059        protected void outputHeader() throws IOException {
060                out = (PrintWriter) output;
061
062                out.printf("DGS004%n");
063
064                if (graphName.length() <= 0)
065                        out.printf("null 0 0%n");
066                else
067                        out.printf("\"%s\" 0 0%n", formatStringForQuoting(graphName));
068        }
069
070        @Override
071        protected void outputEndOfFile() throws IOException {
072                // NOP
073        }
074
075        public void edgeAttributeAdded(String graphId, long timeId, String edgeId,
076                        String attribute, Object value) {
077                edgeAttributeChanged(graphId, timeId, edgeId, attribute, null, value);
078        }
079
080        public void edgeAttributeChanged(String graphId, long timeId,
081                        String edgeId, String attribute, Object oldValue, Object newValue) {
082                out.printf("ce \"%s\" %s%n", formatStringForQuoting(edgeId),
083                                attributeString(attribute, newValue, false));
084        }
085
086        public void edgeAttributeRemoved(String graphId, long timeId,
087                        String edgeId, String attribute) {
088                out.printf("ce \"%s\" %s%n", formatStringForQuoting(edgeId),
089                                attributeString(attribute, null, true));
090        }
091
092        public void graphAttributeAdded(String graphId, long timeId,
093                        String attribute, Object value) {
094                graphAttributeChanged(graphId, timeId, attribute, null, value);
095        }
096
097        public void graphAttributeChanged(String graphId, long timeId,
098                        String attribute, Object oldValue, Object newValue) {
099                out.printf("cg %s%n", attributeString(attribute, newValue, false));
100        }
101
102        public void graphAttributeRemoved(String graphId, long timeId,
103                        String attribute) {
104                out.printf("cg %s%n", attributeString(attribute, null, true));
105        }
106
107        public void nodeAttributeAdded(String graphId, long timeId, String nodeId,
108                        String attribute, Object value) {
109                nodeAttributeChanged(graphId, timeId, nodeId, attribute, null, value);
110        }
111
112        public void nodeAttributeChanged(String graphId, long timeId,
113                        String nodeId, String attribute, Object oldValue, Object newValue) {
114                out.printf("cn \"%s\" %s%n", formatStringForQuoting(nodeId),
115                                attributeString(attribute, newValue, false));
116        }
117
118        public void nodeAttributeRemoved(String graphId, long timeId,
119                        String nodeId, String attribute) {
120                out.printf("cn \"%s\" %s%n", formatStringForQuoting(nodeId),
121                                attributeString(attribute, null, true));
122        }
123
124        public void edgeAdded(String graphId, long timeId, String edgeId,
125                        String fromNodeId, String toNodeId, boolean directed) {
126                edgeId = formatStringForQuoting(edgeId);
127                fromNodeId = formatStringForQuoting(fromNodeId);
128                toNodeId = formatStringForQuoting(toNodeId);
129
130                out.printf("ae \"%s\" \"%s\" %s \"%s\"%n", edgeId, fromNodeId,
131                                directed ? ">" : "", toNodeId);
132        }
133
134        public void edgeRemoved(String graphId, long timeId, String edgeId) {
135                out.printf("de \"%s\"%n", formatStringForQuoting(edgeId));
136        }
137
138        public void graphCleared(String graphId, long timeId) {
139                out.printf("cl%n");
140        }
141
142        public void nodeAdded(String graphId, long timeId, String nodeId) {
143                out.printf("an \"%s\"%n", formatStringForQuoting(nodeId));
144        }
145
146        public void nodeRemoved(String graphId, long timeId, String nodeId) {
147                out.printf("dn \"%s\"%n", formatStringForQuoting(nodeId));
148        }
149
150        public void stepBegins(String graphId, long timeId, double step) {
151                out.printf(Locale.US, "st %f%n", step);
152        }
153
154        // Utility
155
156        protected String formatStringForQuoting(String str) {
157                return str.replaceAll("(^|[^\\\\])\"", "$1\\\\\"");
158        }
159
160        protected String attributeString(String key, Object value, boolean remove) {
161                if (key == null || key.length() == 0)
162                        return null;
163
164                if (remove) {
165                        return String.format(" -\"%s\"", key);
166                } else {
167                        if (value != null && value.getClass().isArray())
168                                return String.format(" \"%s\":%s", key, arrayString(value));
169                        else
170                                return String.format(" \"%s\":%s", key, valueString(value));
171                }
172        }
173
174        protected String arrayString(Object value) {
175                if (value != null && value.getClass().isArray()) {
176                        StringBuilder sb = new StringBuilder();
177                        sb.append("{");
178
179                        if (Array.getLength(value) == 0)
180                                sb.append("\"\"");
181                        else
182                                sb.append(arrayString(Array.get(value, 0)));
183
184                        for (int i = 1; i < Array.getLength(value); ++i)
185                                sb.append(String
186                                                .format(",%s", arrayString(Array.get(value, i))));
187
188                        sb.append("}");
189                        return sb.toString();
190                } else {
191                        return valueString(value);
192                }
193        }
194
195        protected String valueString(Object value) {
196                if (value == null)
197                        return "\"\"";
198
199                if (value instanceof CharSequence) {
200                        if (value instanceof String)
201                                return String.format("\"%s\"",
202                                                formatStringForQuoting((String) value));
203                        else
204                                return String.format("\"%s\"", (CharSequence) value);
205                } else if (value instanceof Number) {
206                        Number nval = (Number) value;
207
208                        if (value instanceof Integer || value instanceof Short
209                                        || value instanceof Byte || value instanceof Long)
210                                return String.format(Locale.US, "%d", nval.longValue());
211                        else
212                                return String.format(Locale.US, "%f", nval.doubleValue());
213                } else if (value instanceof Boolean) {
214                        return String.format(Locale.US, "%b", ((Boolean) value));
215                } else if (value instanceof Character) {
216                        return String.format("\"%c\"", ((Character) value).charValue());
217                } else if (value instanceof Object[]) {
218                        Object array[] = (Object[]) value;
219                        int n = array.length;
220                        StringBuffer sb = new StringBuffer();
221
222                        if (array.length > 0)
223                                sb.append(valueString(array[0]));
224
225                        for (int i = 1; i < n; i++) {
226                                sb.append(",");
227                                sb.append(valueString(array[i]));
228                        }
229
230                        return sb.toString();
231                } else if (value instanceof HashMap<?, ?>
232                                || value instanceof CompoundAttribute) {
233                        HashMap<?, ?> hash;
234
235                        if (value instanceof CompoundAttribute)
236                                hash = ((CompoundAttribute) value).toHashMap();
237                        else
238                                hash = (HashMap<?, ?>) value;
239
240                        return hashToString(hash);
241                } else if (value instanceof Color) {
242                        Color c = (Color) value;
243                        return String.format("#%02X%02X%02X%02X", c.getRed(), c.getGreen(),
244                                        c.getBlue(), c.getAlpha());
245                } else {
246                        return String.format("\"%s\"", value.toString());
247                }
248        }
249
250        protected String hashToString(HashMap<?, ?> hash) {
251                StringBuilder sb = new StringBuilder();
252
253                sb.append("[ ");
254
255                for (Object key : hash.keySet()) {
256                        sb.append(attributeString(key.toString(), hash.get(key), false));
257                        sb.append(",");
258                }
259
260                sb.append(']');
261
262                return sb.toString();
263        }
264}