/*
Copyright 2008-2010 Gephi
Authors : Mathieu Bastian <mathieu.bastian@gephi.org>
Website : http://www.gephi.org
This file is part of Gephi.
Gephi is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
Gephi is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with Gephi. If not, see <http://www.gnu.org/licenses/>.
*/
package org.gephi.io.importer.plugin.file;
import java.io.LineNumberReader;
import java.io.Reader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import org.gephi.io.importer.api.ContainerLoader;
import org.gephi.io.importer.api.EdgeDraft;
import org.gephi.io.importer.api.ImportUtils;
import org.gephi.io.importer.api.Issue;
import org.gephi.io.importer.api.NodeDraft;
import org.gephi.io.importer.api.Report;
import org.gephi.io.importer.spi.FileImporter;
import org.gephi.utils.longtask.spi.LongTask;
import org.gephi.utils.progress.Progress;
import org.gephi.utils.progress.ProgressTicket;
import org.openide.util.NbBundle;
/**
*
* @author Mathieu Bastian
*/
public class ImporterDL implements FileImporter, LongTask {
//enum
private enum Format {
FULLMATRIX, EDGELIST1
};
//Architecture
private Reader reader;
private ContainerLoader container;
private Report report;
private ProgressTicket progressTicket;
private boolean cancel = false;
//Data
private Format format = Format.FULLMATRIX;
private Map<String, String> headerMap;
private int numNodes;
private int numMatricies;
private int dataLineStartDelta = -1;
public boolean execute(ContainerLoader container) {
this.container = container;
this.report = new Report();
LineNumberReader lineReader = ImportUtils.getTextReader(reader);
try {
importData(lineReader);
} catch (Exception e) {
throw new RuntimeException(e);
}
return !cancel;
}
private void importData(LineNumberReader reader) throws Exception {
Progress.start(progressTicket); //Progress
List<String> lines = new ArrayList<String>();
for (; reader.ready();) {
String line = reader.readLine();
if (line != null && !line.isEmpty()) {
lines.add(line);
}
}
if (lines.isEmpty() || (!lines.get(0).startsWith("DL") && !lines.get(0).startsWith("dl"))) {
report.logIssue(new Issue(NbBundle.getMessage(ImporterDL.class, "importerDL_error_firstline"), Issue.Level.CRITICAL));
}
headerMap = new HashMap<String, String>();
readHeaderLine(lines.get(0).substring(2));
int i = 1;
for (; i < lines.size(); i++) {
String line = lines.get(i).toLowerCase();
if (line.trim().endsWith("data:") || line.trim().endsWith("labels:")) {
break;
} else {
readHeaderLine(line);
}
}
computeHeaders();
if (lines.get(i).toLowerCase().trim().endsWith("labels:") && lines.size() > i + 1) {
readLabels(lines.get(++i));
}
int dataLineStart = -1;
for (; i < lines.size(); i++) {
String line = lines.get(i).toLowerCase();
if (line.trim().endsWith("data:")) {
dataLineStart = i + 1;
break;
}
}
if (dataLineStart == -1) {
report.logIssue(new Issue(NbBundle.getMessage(ImporterDL.class, "importerDL_error_nodata"), Issue.Level.SEVERE));
} else if (lines.size() > dataLineStart) {
dataLineStartDelta = dataLineStart + 1;
lines = lines.subList(dataLineStart, lines.size());
if (format.equals(Format.FULLMATRIX)) {
readeMatrixBlock(lines);
} else if (format.equals(Format.EDGELIST1)) {
readEdgelistBlock(lines);
}
}
}
private void readHeaderLine(String line) {
line = line.replaceAll(" = ", "=");
StringTokenizer firstLineTokenizer = new StringTokenizer(line, " ,;");
while (firstLineTokenizer.hasMoreTokens()) {
String tag = firstLineTokenizer.nextToken().toLowerCase();
if (tag.indexOf("=") != -1) {
headerMap.put(tag.substring(0, tag.indexOf("=")).trim(), tag.substring(tag.indexOf("=") + 1).trim());
} else {
//report.logIssue(new Issue(NbBundle.getMessage(ImporterDL.class, "importerDL_error_unknowntag", tag), Issue.Level.WARNING));
}
}
}
private void computeHeaders() {
//read format
String form = (String) headerMap.get("format");
if (form == null) {
report.logIssue(new Issue(NbBundle.getMessage(ImporterDL.class, "importerDL_error_formatmissing"), Issue.Level.INFO));
} else if (!form.equals("edgelist1") && !form.equals("fullmatrix")) {
report.logIssue(new Issue(NbBundle.getMessage(ImporterDL.class, "importerDL_error_badformat", form), Issue.Level.SEVERE));
} else if (form.equals("edgelist1")) {
format = Format.EDGELIST1;
} else if (form.equals("fullmatrix")) {
format = Format.FULLMATRIX;
}
// read number of nodes
try {
String nArg = (String) headerMap.get("n");
numNodes = Integer.parseInt(nArg);
} catch (Exception e) {
report.logIssue(new Issue(NbBundle.getMessage(ImporterDL.class, "importerDL_error_nmissing"), Issue.Level.SEVERE));
}
// read number matricies
String mats = (String) headerMap.get("nm");
if (mats != null) {
try {
numMatricies = Integer.parseInt(mats);
} catch (Exception e) {
report.logIssue(new Issue(NbBundle.getMessage(ImporterDL.class, "importerDL_error_mmissing"), Issue.Level.SEVERE));
}
} else {
numMatricies = 1;
}
}
private void readLabels(String labels) {
StringTokenizer labelkonizer = new StringTokenizer(labels, ",");
// check that there are the right number of labels
if (labelkonizer.countTokens() != numNodes) {
report.logIssue(new Issue(NbBundle.getMessage(ImporterDL.class, "importerDL_error_labelscount", labelkonizer.countTokens(), numNodes), Issue.Level.SEVERE));
}
int nodeCount = 0;
while (labelkonizer.hasMoreTokens()) {
String label = labelkonizer.nextToken();
nodeCount++;
NodeDraft nodeDraft = container.factory().newNodeDraft();
nodeDraft.setId("" + nodeCount);
nodeDraft.setLabel(label);
container.addNode(nodeDraft);
}
}
private void readeMatrixBlock(List<String> data) {
int startTime = 0;
for (int i = 0; i < data.size(); i++) {
int rowNum = 0;
for (; i < data.size() && !data.get(i).trim().equals("!"); i++) {
if (rowNum <= numNodes) {
readMatrixRow(data.get(i), i, rowNum, startTime, startTime + 1);
rowNum++;
} else {
report.logIssue(new Issue(NbBundle.getMessage(ImporterDL.class, "importerDL_error_matrixrowscount", rowNum, numNodes), Issue.Level.SEVERE));
break;
}
}
if (rowNum < numNodes) {
report.logIssue(new Issue(NbBundle.getMessage(ImporterDL.class, "importerDL_error_matrixrowscount2", rowNum, numNodes), Issue.Level.SEVERE));
}
startTime++;
}
if (startTime != numMatricies) {
report.logIssue(new Issue(NbBundle.getMessage(ImporterDL.class, "importerDL_error_matriciescount", startTime, numMatricies), Issue.Level.SEVERE));
}
}
private void readMatrixRow(String line, int pointer, int row, int startTime, int endTime) {
StringTokenizer rowkonizer = new StringTokenizer(line, " ");
int from = row + 1;
int to = 1;
double weight = 0;
while (rowkonizer.hasMoreTokens()) {
String toParse = (String) rowkonizer.nextToken();
if (to > numNodes) {
report.logIssue(new Issue(NbBundle.getMessage(ImporterDL.class, "importerDL_error_matrixentriescount", row, startTime, getLineNumber(pointer)), Issue.Level.SEVERE));
}
try {
weight = Double.parseDouble(toParse);
} catch (Exception e) {
report.logIssue(new Issue(NbBundle.getMessage(ImporterDL.class, "importerDL_error_weightparseerror", toParse, startTime, getLineNumber(pointer)), Issue.Level.SEVERE));
}
if (weight != 0) {
NodeDraft sourceNode = container.getNode("" + from);
NodeDraft targetNode = container.getNode("" + to);
EdgeDraft edgeDraft = null;
if (container.edgeExists(sourceNode, targetNode)) {
edgeDraft = container.getEdge(sourceNode, targetNode);
//dynamic
} else {
edgeDraft = container.factory().newEdgeDraft();
edgeDraft.setSource(sourceNode);
edgeDraft.setTarget(targetNode);
edgeDraft.setWeight((float) weight);
container.addEdge(edgeDraft);
}
}
to++;
}
}
private void readEdgelistBlock(List<String> data) {
int startTime = 0;
for (int i = 0; i < data.size(); i++) {
for (; i < data.size() && !data.get(i).trim().equals("!"); i++) {
readEdgelistRow(data.get(i), i, startTime, startTime + 1);
}
// increment the time step before starting next matrix
startTime++;
}
if (startTime != numMatricies) {
report.logIssue(new Issue(NbBundle.getMessage(ImporterDL.class, "importerDL_error_edgelistssetscount", startTime, numMatricies), Issue.Level.SEVERE));
}
}
private void readEdgelistRow(String row, int pointer, double startTime, double endTime) {
StringTokenizer rowkonizer = new StringTokenizer(row);
if (!rowkonizer.hasMoreTokens()) {
return;
}
// should have three entries, int from, int to, weight
String from = rowkonizer.nextToken();
if (!rowkonizer.hasMoreTokens()) {
return;
}
String to = rowkonizer.nextToken();
double weight = 1.0;
if (rowkonizer.hasMoreTokens()) {
String weightParse = rowkonizer.nextToken();
try {
weight = Double.parseDouble(weightParse);
} catch (Exception e) {
report.logIssue(new Issue(NbBundle.getMessage(ImporterDL.class, "importerDL_error_edgeparseweight", weightParse, getLineNumber(pointer)), Issue.Level.WARNING));
}
}
NodeDraft sourceNode = container.getNode(from);
NodeDraft targetNode = container.getNode(to);
EdgeDraft edgeDraft = null;
if (container.edgeExists(sourceNode, targetNode)) {
edgeDraft = container.getEdge(sourceNode, targetNode);
//dynamic
} else {
edgeDraft = container.factory().newEdgeDraft();
edgeDraft.setSource(sourceNode);
edgeDraft.setTarget(targetNode);
edgeDraft.setWeight((float) weight);
container.addEdge(edgeDraft);
}
}
private int getLineNumber(int pointer) {
return pointer + dataLineStartDelta;
}
public void setReader(Reader reader) {
this.reader = reader;
}
public ContainerLoader getContainer() {
return container;
}
public Report getReport() {
return report;
}
public boolean cancel() {
cancel = true;
return true;
}
public void setProgressTicket(ProgressTicket progressTicket) {
this.progressTicket = progressTicket;
}
}