/*
* XLogo4Schools - A Logo Interpreter specialized for use in schools, based on XLogo by Loic Le Coq
* Copyright (C) 2013 Marko Zivkovic
* Contact Information: marko88zivkovic at gmail dot com
* This program 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 2 of the License, or (at your option)
* any later version. This program 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 this program; if not, write to the Free
* Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
* This Java source code belongs to XLogo4Schools, written by Marko Zivkovic
* during his Bachelor thesis at the computer science department of ETH Zurich,
* in the year 2013 and/or during future work.
* It is a reengineered version of XLogo written by Loic Le Coq, published
* under the GPL License at http://xlogo.tuxfamily.org/
* Contents of this file were entirely written by Marko Zivkovic
*/
package xlogo.storage;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.StringReader;
import java.util.Calendar;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import xlogo.storage.user.UserConfig;
import xlogo.storage.workspace.WorkspaceConfig;
public abstract class StorableDocument extends Storable {
/**
*
*/
private static final long serialVersionUID = 8218323197066522297L;
private static Logger logger = LogManager.getLogger(StorableDocument.class.getSimpleName());
/**
* Contents of the file
*/
private String text;
/**
* DEFINE TIME
*/
private Calendar lastSync;
/**
* When this was created or saved the last time using {@link #store()}.
* Other store methods will not affect the time.
* @return
*/
public Calendar getLastSync() {
return lastSync;
}
public StorableDocument() {
super();
text = "";
synced();
}
/**
* If this is not virtual, store the file in the source folder of the UserSpace,
* and it also stores a copy in the backup folder, if this is required by {@link WorkspaceConfig#getNumberOfBackups()}.
*/
@Override
public void store() {
synced();
super.store();
}
protected void synced() {
lastSync = Calendar.getInstance();
}
/**
*
* This is the counterpart to {@link #openFromAnyFile(UserConfig, File)}
* Save (export) to any file on the file system.
* This works, even if the file is declared virtual.
*/
@Override
public void storeCopyToFile(File file) throws IOException, IllegalArgumentException {
logger.trace("Storing copy of " + getFileName() + " to " + file.getAbsolutePath());
try {
mkParentDirs(file);
FileOutputStream f = new FileOutputStream(file);
BufferedOutputStream b = new BufferedOutputStream(f);
OutputStreamWriter osw = new OutputStreamWriter(b, "UTF8");
osw.write(getText());
osw.close();
b.close();
f.close();
}
catch (FileNotFoundException e1) {
e1.printStackTrace();
}
}
/**
* Deletes the current file path
*/
public void delete() {
if (isVirtual())
return;
File file = getFilePath();
if (file != null && file.exists())
file.delete();
}
public String getText() {
if (text == null)
text = generateText();
return text;
}
/**
* This is invoked in {@link getText()} when the current text string is currently not defined.
* Implement this to map your data to a string. This is the counterpart to {@link #parseText(BufferedReader)}.
* @return
*/
protected abstract String generateText();
/**
* Setting text will invalidate the current text.
* The new text is then parsed to the concrete document structure.
* If possible, use {@link #setTextFromReader(BufferedReader)} for performance reasons.
* @param text
*/
public void setText(String text) {
invalidateText();
if (text == null)
return;
String replIndent = text.replaceAll("\t", " ");
StringReader sr = new StringReader(replIndent);
BufferedReader br = new BufferedReader(sr);
parseText(br);
}
/**
* Whether the underlying text representation is the empty string
* @return
*/
public boolean isEmpty() {
return getText().equals("");
}
/**
* Setting text will invalidate the current text.
* The new text is then parsed to the concrete document structure.
* @param br
*/
public void setTextFromReader(BufferedReader br) {
invalidateText();
parseText(br);
}
protected abstract void parseText(BufferedReader text);
/**
* @return Whether the set text could be parsed without errors.
*/
public abstract boolean hasErrors();
/**
* Call this whenever the internal object structure has changed and it should be serialized first, using {@link #generateText()},
* when {@link #getText()} is called the next time.
*/
protected void invalidateText() {
this.text = null;
}
}