package com.kreative.paint.document.undo;
import java.util.ArrayList;
import java.util.List;
public class History implements Undoable {
private int maxTransactions;
private List<Transaction> transactions;
private int transactionIndex;
private Transaction inProgress;
private List<HistoryListener> listeners;
public History() {
this.maxTransactions = 30;
this.transactions = new ArrayList<Transaction>();
this.transactionIndex = 0;
this.inProgress = null;
this.listeners = new ArrayList<HistoryListener>();
}
public void addHistoryListener(HistoryListener l) {
listeners.add(l);
}
public void removeHistoryListener(HistoryListener l) {
listeners.remove(l);
}
public HistoryListener[] getHistoryListeners() {
return listeners.toArray(new HistoryListener[listeners.size()]);
}
protected void notifyHistoryListeners(HistoryEvent e) {
switch (e.getID()) {
case HistoryEvent.TRANSACTION_LIMIT_CHANGED: for (HistoryListener l : listeners) l.transactionLimitChanged(e); break;
case HistoryEvent.TRANSACTION_BEGAN: for (HistoryListener l : listeners) l.transactionBegan(e); break;
case HistoryEvent.TRANSACTION_CONTINUED: for (HistoryListener l : listeners) l.transactionContinued(e); break;
case HistoryEvent.TRANSACTION_RENAMED: for (HistoryListener l : listeners) l.transactionRenamed(e); break;
case HistoryEvent.TRANSACTION_COMMITTED: for (HistoryListener l : listeners) l.transactionCommitted(e); break;
case HistoryEvent.TRANSACTION_ROLLED_BACK: for (HistoryListener l : listeners) l.transactionRolledBack(e); break;
case HistoryEvent.TRANSACTION_REDONE: for (HistoryListener l : listeners) l.transactionRedone(e); break;
case HistoryEvent.TRANSACTION_UNDONE: for (HistoryListener l : listeners) l.transactionUndone(e); break;
}
}
public synchronized int getMaxTransactions() {
return maxTransactions;
}
public synchronized void setMaxTransactions(int maxTransactions) {
this.maxTransactions = maxTransactions;
notifyHistoryListeners(new HistoryEvent(HistoryEvent.TRANSACTION_LIMIT_CHANGED, this, null, null));
}
public synchronized void add(Atom a) {
if (inProgress == null) {
System.err.println("Warning: Atomic operation performed with no Transaction in progress.");
inProgress = new Transaction(null);
notifyHistoryListeners(new HistoryEvent(HistoryEvent.TRANSACTION_BEGAN, this, inProgress, a));
}
inProgress.add(a);
notifyHistoryListeners(new HistoryEvent(HistoryEvent.TRANSACTION_CONTINUED, this, inProgress, a));
}
public synchronized void begin(String name) {
if (inProgress != null) {
String thisName = (name == null) ? "" : name;
String thatName = (inProgress.getName() == null) ? "" : inProgress.getName();
System.err.println("Warning: Transaction \"" + thisName + "\" began with another Transaction (\"" + thatName + "\") already in progress.");
if (!inProgress.isEmpty()) {
commit(inProgress);
notifyHistoryListeners(new HistoryEvent(HistoryEvent.TRANSACTION_COMMITTED, this, inProgress, null));
}
}
inProgress = new Transaction(name);
notifyHistoryListeners(new HistoryEvent(HistoryEvent.TRANSACTION_BEGAN, this, inProgress, null));
}
public synchronized void rename(String name) {
if (inProgress == null) {
System.err.println("Warning: Transaction renamed with no Transaction in progress.");
} else {
inProgress.setName(name);
notifyHistoryListeners(new HistoryEvent(HistoryEvent.TRANSACTION_RENAMED, this, inProgress, null));
}
}
public synchronized void commit() {
if (inProgress == null) {
System.err.println("Warning: Transaction committed with no Transaction in progress.");
} else {
if (!inProgress.isEmpty()) {
commit(inProgress);
notifyHistoryListeners(new HistoryEvent(HistoryEvent.TRANSACTION_COMMITTED, this, inProgress, null));
}
inProgress = null;
}
}
public synchronized void rollback() {
if (inProgress == null) {
System.err.println("Warning: Transaction rolled back with no Transaction in progress.");
} else {
if (!inProgress.isEmpty()) {
inProgress.undo();
notifyHistoryListeners(new HistoryEvent(HistoryEvent.TRANSACTION_ROLLED_BACK, this, inProgress, null));
}
inProgress = null;
}
}
private synchronized void commit(Transaction t) {
transactions.subList(transactionIndex, transactions.size()).clear();
transactions.add(t);
transactionIndex++;
if (maxTransactions > 0) {
while (transactions.size() > maxTransactions) {
transactions.remove(0);
transactionIndex--;
}
}
}
public synchronized boolean isInProgress() {
return (inProgress != null);
}
public synchronized boolean canRedo() {
return (inProgress == null && transactionIndex < transactions.size());
}
public synchronized String getRedoName() {
if (inProgress == null && transactionIndex < transactions.size()) {
return transactions.get(transactionIndex).getName();
} else {
return null;
}
}
@Override
public synchronized void redo() {
if (inProgress != null) {
String thatName = (inProgress.getName() == null) ? "" : inProgress.getName();
System.err.println("Warning: Redo called with a Transaction (\"" + thatName + "\") in progress.");
} else if (transactionIndex < transactions.size()) {
Transaction t = transactions.get(transactionIndex);
t.redo();
transactionIndex++;
notifyHistoryListeners(new HistoryEvent(HistoryEvent.TRANSACTION_REDONE, this, t, null));
}
}
public synchronized boolean canUndo() {
return (inProgress == null && transactionIndex > 0);
}
public synchronized String getUndoName() {
if (inProgress == null && transactionIndex > 0) {
return transactions.get(transactionIndex - 1).getName();
} else {
return null;
}
}
@Override
public synchronized void undo() {
if (inProgress != null) {
String thatName = (inProgress.getName() == null) ? "" : inProgress.getName();
System.err.println("Warning: Undo called with a Transaction (\"" + thatName + "\") in progress.");
} else if (transactionIndex > 0) {
transactionIndex--;
Transaction t = transactions.get(transactionIndex);
t.undo();
notifyHistoryListeners(new HistoryEvent(HistoryEvent.TRANSACTION_UNDONE, this, t, null));
}
}
public synchronized int getTransactionCount() {
return transactions.size();
}
public synchronized String getTransactionName(int i) {
return transactions.get(i).getName();
}
public synchronized int getTransactionIndex() {
return transactionIndex;
}
public synchronized void setTransactionIndex(int i) {
if (inProgress != null) {
String thatName = (inProgress.getName() == null) ? "" : inProgress.getName();
System.err.println("Warning: SetTransactionIndex called with a Transaction (\"" + thatName + "\") in progress.");
} else if (i < 0 || i > transactions.size()) {
throw new IllegalArgumentException("transactionIndex = " + i);
} else if (transactionIndex > i) {
while (transactionIndex > i) {
undo();
}
} else if (transactionIndex < i) {
while (transactionIndex < i) {
redo();
}
}
}
}