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.pajek;
033
034import java.util.ArrayList;
035import java.util.Locale;
036
037import org.graphstream.graph.implementations.AbstractElement.AttributeChangeEvent;
038import org.graphstream.stream.SourceBase.ElementType;
039import org.graphstream.stream.file.FileSourcePajek;
040import org.graphstream.util.parser.ParseException;
041import org.graphstream.util.parser.Token;
042
043public class PajekContext {
044        FileSourcePajek pajek;
045        String sourceId;
046
047        protected boolean directed = false;
048
049        protected String weightAttributeName = "weight";
050
051        public PajekContext(FileSourcePajek pajek) {
052                this.pajek = pajek;
053                this.sourceId = String.format("<Pajek stream %d>", System.currentTimeMillis());
054        }
055
056        protected void setDirected(boolean on) {
057                directed = on;
058        }
059
060        protected int addNodes(Token nb) throws ParseException {
061                int n = getInt(nb);
062
063                for (int i = 1; i <= n; ++i) {
064                        pajek.sendNodeAdded(sourceId, String.format("%d", i));
065                }
066
067                return n;
068        }
069
070        protected void addGraphAttribute(String attr, String value) {
071                pajek.sendAttributeChangedEvent(sourceId, sourceId, ElementType.GRAPH,
072                                attr, AttributeChangeEvent.ADD, null, value);
073        }
074
075        protected void addNodeLabel(String nb, String label) {
076                pajek.sendAttributeChangedEvent(sourceId, nb, ElementType.NODE,
077                                "ui.label", AttributeChangeEvent.ADD, null, label);
078        }
079
080        protected void addNodeGraphics(String id, NodeGraphics graphics) {
081                pajek.sendAttributeChangedEvent(sourceId, id, ElementType.NODE,
082                                "ui.style", AttributeChangeEvent.ADD, null, graphics.getStyle());
083        }
084
085        protected void addNodePosition(String id, Token x, Token y, Token z)
086                        throws ParseException {
087                Object pos[] = new Object[3];
088                pos[0] = (Double) getReal(x);
089                pos[1] = (Double) getReal(y);
090                pos[2] = z != null ? (Double) getReal(z) : 0;
091                
092                pajek.sendAttributeChangedEvent(sourceId, id, ElementType.NODE,
093                                "xyz", AttributeChangeEvent.ADD, null, pos);
094        }
095
096        protected String addEdge(String src, String trg) {
097                String id = String.format("%s_%s_%d", src, trg,
098                                (long) (Math.random() * 100000) + System.currentTimeMillis());
099
100                pajek.sendEdgeAdded(sourceId, id, src, trg, directed);
101
102                return id;
103        }
104
105        protected void addEdges(EdgeMatrix mat) {
106                int size = mat.size();
107                int edgeid = 0;
108
109                for (int line = 0; line < size; line++) {
110                        for (int col = 0; col < size; col++) {
111                                if (mat.hasEdge(line, col)) {
112                                        String id = String.format("%d_%d_%d", line + 1, col + 1,
113                                                        edgeid++);
114                                        if (mat.hasEdge(col, line)) {
115                                                pajek.sendEdgeAdded(sourceId, id,
116                                                                String.format("%d", line + 1),
117                                                                String.format("%d", col + 1), false);
118                                                mat.set(col, line, false);
119                                        } else {
120                                                pajek.sendEdgeAdded(sourceId, id,
121                                                                String.format("%d", line + 1),
122                                                                String.format("%d", col + 1), true);
123                                        }
124                                }
125                        }
126                }
127        }
128
129        protected void addEdgeWeight(String id, Token nb) throws ParseException {
130                pajek.sendAttributeChangedEvent(sourceId, id, ElementType.EDGE,
131                                weightAttributeName, AttributeChangeEvent.ADD, null, getReal(nb));
132        }
133
134        protected void addEdgeGraphics(String id, EdgeGraphics graphics) {
135                pajek.sendAttributeChangedEvent(sourceId, id, ElementType.EDGE,
136                                "ui.style", AttributeChangeEvent.ADD, null, graphics.getStyle());
137        }
138
139        protected static int getInt(Token nb) throws ParseException {
140                try {
141                        return Integer.parseInt(nb.image);
142                } catch (Exception e) {
143                        throw new ParseException(String.format("%d:%d: %s not an integer",
144                                        nb.beginLine, nb.beginColumn, nb.image));
145                }
146        }
147
148        protected static double getReal(Token nb) throws ParseException {
149                try {
150                        return Double.parseDouble(nb.image);
151                } catch (Exception e) {
152                        throw new ParseException(String.format("%d:%d: %s not a real",
153                                        nb.beginLine, nb.beginColumn, nb.image));
154                }
155        }
156
157        public static String toColorValue(Token R, Token G, Token B)
158                        throws ParseException {
159                double r = getReal(R);
160                double g = getReal(G);
161                double b = getReal(B);
162
163                return String.format("rgb(%d, %d, %d)", (int) (r * 255),
164                                (int) (g * 255), (int) (b * 255));
165        }
166}
167
168abstract class Graphics {
169        protected StringBuffer graphics = new StringBuffer();
170
171        public abstract void addKey(String key, String value, Token tk)
172                        throws ParseException;
173
174        public String getStyle() {
175                return graphics.toString();
176        }
177
178        protected double getReal(String nb, Token tk) throws ParseException {
179                try {
180                        return Double.parseDouble(nb);
181                } catch (Exception e) {
182                        throw new ParseException(String.format("%d:%d: %s not a real",
183                                        tk.beginLine, tk.beginColumn, nb));
184                }
185        }
186
187        protected int getInt(String nb, Token tk) throws ParseException {
188                try {
189                        return Integer.parseInt(nb);
190                } catch (Exception e) {
191                        throw new ParseException(String.format("%d:%d: %s not an integer",
192                                        tk.beginLine, tk.beginColumn, nb));
193                }
194        }
195}
196
197class NodeGraphics extends Graphics {
198        @Override
199        public void addKey(String key, String value, Token tk)
200                        throws ParseException {
201                if (key.equals("shape")) {
202                        graphics.append(String.format("shape: %s;", value));
203                } else if (key.equals("ic")) {
204                        graphics.append(String.format("fill-color: %s;", value));
205                } else if (key.equals("bc")) {
206                        graphics.append(String.format(
207                                        "stroke-color: %s; stroke-mode: plain;", value));
208                } else if (key.equals("bw")) {
209                        graphics.append(String.format(Locale.US, "stroke-width: %fpx;",
210                                        getReal(value, tk)));
211                } else if (key.equals("s_size")) {
212                        graphics.append(String.format(Locale.US, "size: %fpx;",
213                                        getReal(value, tk)));
214                } else if (key.equals("lc")) {
215                        graphics.append(String.format("text-color: %s;", value));
216                } else if (key.equals("fos")) {
217                        graphics.append(String.format("text-size: %d;", getInt(value, tk)));
218                } else if (key.equals("font")) {
219                        graphics.append(String.format("text-font: %s;", value));
220                }
221        }
222}
223
224class EdgeGraphics extends Graphics {
225        @Override
226        public void addKey(String key, String value, Token tk)
227                        throws ParseException {
228                if (key.equals("w")) {
229                        graphics.append(String.format(Locale.US, "size: %fpx;",
230                                        getReal(value, tk)));
231                } else if (key.equals("c")) {
232                        graphics.append(String.format("fill-color: %s;", value));
233                } else if (key.equals("s")) {
234                        double s = getReal(value, tk);
235                        graphics.append(String.format("arrow-size: %spx, %spx;", s * 5,
236                                        s * 3));
237                } else if (key.equals("l")) {
238                        // ?
239                } else if (key.equals("p")) {
240                        // ?
241                } else if (key.equals("lc")) {
242                        graphics.append(String.format("text-color: %s;", value));
243                } else if (key.equals("fos")) {
244                        graphics.append(String.format("text-size: %d;", getInt(value, tk)));
245                } else if (key.equals("font")) {
246                        graphics.append(String.format("text-font: %s;", value));
247                }
248        }
249}
250
251class EdgeMatrix {
252        // Line first, col second.
253        // Line = from node, col = to node.
254        protected boolean mat[][];
255
256        protected int curLine = 0;
257
258        public EdgeMatrix(int size) {
259                mat = new boolean[size][size]; // Horror !
260        }
261
262        public int size() {
263                return mat.length;
264        }
265
266        public boolean hasEdge(int line, int col) {
267                return mat[line][col];
268        }
269
270        public void set(int line, int col, boolean value) {
271                mat[line][col] = value;
272        }
273
274        public void addLine(ArrayList<String> line) {
275                if (curLine < mat.length) {
276                        if (line.size() == mat.length) {
277                                for (int i = 0; i < mat.length; i++) {
278                                        mat[curLine][i] = line.get(i).equals("1");
279                                }
280                                curLine++;
281                        } else if (line.size() == mat.length * mat.length) {
282                                int n = mat.length * mat.length;
283                                curLine = -1;
284                                for (int i = 0; i < n; i++) {
285                                        if (i % mat.length == 0)
286                                                curLine++;
287                                        mat[curLine][i - (curLine * mat.length)] = line.get(i)
288                                                        .equals("1");
289                                }
290                        }
291                }
292        }
293
294        @Override
295        public String toString() {
296                StringBuffer buffer = new StringBuffer();
297                for (int line = 0; line < mat.length; line++) {
298                        for (int col = 0; col < mat.length; col++) {
299                                buffer.append(String.format("%s ", mat[line][col] ? "1" : "0"));
300                        }
301                        buffer.append(String.format("%n"));
302                }
303
304                return buffer.toString();
305        }
306}