// Near Infinity - An Infinity Engine Browser and Editor
// Copyright (C) 2001 - 2005 Jon Olav Hauglid
// See LICENSE.txt for license information
package org.infinity.util;
import java.util.ArrayList;
import java.util.List;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import org.infinity.resource.AbstractStruct;
import org.infinity.resource.AddRemovable;
import org.infinity.resource.HasAddRemovable;
import org.infinity.resource.StructEntry;
public final class StructClipboard
{
public static final int CLIPBOARD_EMPTY = 0;
public static final int CLIPBOARD_VALUES = 1;
public static final int CLIPBOARD_ENTRIES = 2;
private static StructClipboard clip;
private final List<ChangeListener> listeners = new ArrayList<ChangeListener>();
private final List<StructEntry> contents = new ArrayList<StructEntry>();
private Class<? extends StructEntry> contentsClass;
private boolean hasValues = true;
public static synchronized StructClipboard getInstance()
{
if (clip == null)
clip = new StructClipboard();
return clip;
}
private static void pasteSubStructures(AbstractStruct targetStruct, List<? extends StructEntry> substructures)
{
for (int i = 0; i < substructures.size(); i++) {
AddRemovable pasteEntry = (AddRemovable)substructures.get(i);
if (pasteEntry instanceof HasAddRemovable) {
AbstractStruct pasteStruct = (AbstractStruct)pasteEntry;
List<AddRemovable> subsubstructures = pasteStruct.removeAllRemoveables();
targetStruct.addDatatype(pasteEntry);
pasteSubStructures(pasteStruct, subsubstructures);
}
else
targetStruct.addDatatype(pasteEntry);
}
}
private StructClipboard()
{
}
@Override
public String toString()
{
StringBuffer sb = new StringBuffer();
for (int i = 0; i < contents.size(); i++) {
StructEntry datatype = contents.get(i);
sb.append(datatype.getName()).append(": ").append(datatype.toString()).append('\n');
}
return sb.toString();
}
public void addChangeListener(ChangeListener listener)
{
listeners.add(listener);
}
public void clear()
{
contents.clear();
contentsClass = null;
fireStateChanged();
}
public void copy(AbstractStruct struct, int firstIndex, int lastIndex)
{
contents.clear();
contentsClass = struct.getClass();
try {
for (int i = firstIndex; i <= lastIndex; i++) {
StructEntry entry = struct.getField(i);
contents.add((StructEntry)entry.clone());
}
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
hasValues = false;
fireStateChanged();
}
public void copyValue(AbstractStruct struct, int firstIndex, int lastIndex)
{
contents.clear();
hasValues = true;
contentsClass = struct.getClass();
try {
for (int i = firstIndex; i <= lastIndex; i++) {
StructEntry entry = struct.getField(i);
contents.add((StructEntry)entry.clone());
}
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
fireStateChanged();
}
public void cut(AbstractStruct struct, int firstIndex, int lastIndex)
{
contents.clear();
contentsClass = struct.getClass();
try {
for (int i = firstIndex; i <= lastIndex; i++) {
StructEntry entry = struct.getField(i);
contents.add((StructEntry)entry.clone());
}
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
hasValues = false;
for (int i = firstIndex; i <= lastIndex; i++)
struct.removeDatatype((AddRemovable)struct.getField(firstIndex), true);
fireStateChanged();
}
public int getContentType(AbstractStruct struct)
{
if (contents.isEmpty())
return CLIPBOARD_EMPTY;
if (hasValues) {
if (struct.getClass().equals(contentsClass))
return CLIPBOARD_VALUES;
else
return CLIPBOARD_EMPTY;
}
else {
if (struct.getClass().equals(contentsClass))
return CLIPBOARD_ENTRIES;
AddRemovable[] targetClasses;
try {
targetClasses = ((HasAddRemovable)struct).getAddRemovables();
} catch (Exception e) {
return CLIPBOARD_EMPTY;
}
if (targetClasses == null)
targetClasses = new AddRemovable[0];
for (int i = 0; i < contents.size(); i++) {
Class<? extends StructEntry> c = contents.get(i).getClass();
boolean found = false;
for (final AddRemovable targetClass : targetClasses) {
if (targetClass != null && c.equals(targetClass.getClass()))
found = true;
}
if (!found)
return CLIPBOARD_EMPTY;
}
return CLIPBOARD_ENTRIES;
}
}
public int paste(AbstractStruct targetStruct)
{
int lastIndex = 0;
try {
for (int i = 0; i < contents.size(); i++) {
AddRemovable pasteEntry = (AddRemovable)contents.get(i).clone();
if (pasteEntry instanceof HasAddRemovable) {
((HasAddRemovable)pasteEntry).getAddRemovables();
List<AddRemovable> substructures = ((AbstractStruct)pasteEntry).removeAllRemoveables();
lastIndex = targetStruct.addDatatype(pasteEntry);
pasteSubStructures((AbstractStruct)pasteEntry, substructures);
}
else
lastIndex = targetStruct.addDatatype(pasteEntry);
}
} catch (Exception e) {
e.printStackTrace();
}
return lastIndex;
}
public int pasteValue(AbstractStruct struct, int index)
{
for (int i = 0; i < contents.size(); i++) {
StructEntry oldEntry = struct.getField(index + i);
StructEntry newEntry = contents.get(i);
if (oldEntry.getClass() != newEntry.getClass() ||
oldEntry.getSize() != newEntry.getSize())
return 0;
}
try {
for (int i = 0; i < contents.size(); i++) {
StructEntry oldEntry = struct.getField(index + i);
StructEntry newEntry = (StructEntry)contents.get(i).clone();
newEntry.copyNameAndOffset(oldEntry);
struct.setListEntry(index + i, newEntry);
}
} catch (CloneNotSupportedException e) {
e.printStackTrace();
return 0;
}
return contents.size();
}
public void removeChangeListener(ChangeListener listener)
{
listeners.remove(listener);
}
private void fireStateChanged()
{
ChangeEvent event = new ChangeEvent(this);
for (int i = 0; i < listeners.size(); i++)
listeners.get(i).stateChanged(event);
}
}