/*******************************************************************************
* This file is part of logisim-evolution.
*
* logisim-evolution is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* logisim-evolution 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with logisim-evolution. If not, see <http://www.gnu.org/licenses/>.
*
* Original code by Carl Burch (http://www.cburch.com), 2011.
* Subsequent modifications by :
* + Haute École Spécialisée Bernoise
* http://www.bfh.ch
* + Haute École du paysage, d'ingénierie et d'architecture de Genève
* http://hepia.hesge.ch/
* + Haute École d'Ingénierie et de Gestion du Canton de Vaud
* http://www.heig-vd.ch/
* The project is currently maintained by :
* + REDS Institute - HEIG-VD
* Yverdon-les-Bains, Switzerland
* http://reds.heig-vd.ch
*******************************************************************************/
package com.cburch.logisim.gui.log;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import com.cburch.logisim.data.Value;
class LogThread extends Thread implements ModelListener {
// file will be flushed with at least this frequency
private static final int FLUSH_FREQUENCY = 500;
// file will be closed after waiting this many milliseconds between writes
private static final int IDLE_UNTIL_CLOSE = 10000;
private Model model;
private boolean canceled = false;
private Object lock = new Object();
private PrintWriter writer = null;
private boolean headerDirty = true;
private long lastWrite = 0;
public LogThread(Model model) {
this.model = model;
model.addModelListener(this);
}
// Should hold lock and have verified that isFileEnabled() before
// entering this method.
private void addEntry(Value[] values) {
if (writer == null) {
try {
writer = new PrintWriter(new FileWriter(model.getFile(), true));
} catch (IOException e) {
model.setFile(null);
return;
}
}
Selection sel = model.getSelection();
if (headerDirty) {
if (model.getFileHeader()) {
StringBuilder buf = new StringBuilder();
for (int i = 0; i < sel.size(); i++) {
if (i > 0)
buf.append("\t");
buf.append(sel.get(i).toString());
}
writer.println(buf.toString());
}
headerDirty = false;
}
StringBuilder buf = new StringBuilder();
for (int i = 0; i < values.length; i++) {
if (i > 0)
buf.append("\t");
if (values[i] != null) {
int radix = sel.get(i).getRadix();
buf.append(values[i].toDisplayString(radix));
}
}
writer.println(buf.toString());
lastWrite = System.currentTimeMillis();
}
public void cancel() {
synchronized (lock) {
canceled = true;
if (writer != null) {
writer.close();
writer = null;
}
}
}
public void entryAdded(ModelEvent event, Value[] values) {
synchronized (lock) {
if (isFileEnabled())
addEntry(values);
}
}
public void filePropertyChanged(ModelEvent event) {
synchronized (lock) {
if (isFileEnabled()) {
if (writer == null) {
Selection sel = model.getSelection();
Value[] values = new Value[sel.size()];
boolean found = false;
for (int i = 0; i < values.length; i++) {
values[i] = model.getValueLog(sel.get(i)).getLast();
if (values[i] != null)
found = true;
}
if (found)
addEntry(values);
}
} else {
if (writer != null) {
writer.close();
writer = null;
}
}
}
}
private boolean isFileEnabled() {
return !canceled && model.isSelected() && model.isFileEnabled()
&& model.getFile() != null;
}
@Override
public void run() {
while (!canceled) {
synchronized (lock) {
if (writer != null) {
if (System.currentTimeMillis() - lastWrite > IDLE_UNTIL_CLOSE) {
writer.close();
writer = null;
} else {
writer.flush();
}
}
}
try {
Thread.sleep(FLUSH_FREQUENCY);
} catch (InterruptedException e) {
}
}
synchronized (lock) {
if (writer != null) {
writer.close();
writer = null;
}
}
}
public void selectionChanged(ModelEvent event) {
headerDirty = true;
}
}