package share;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Map;
import ui.misc.files.MultiNamedFileTableModel;
import common.ClientServerProtocol;
import common.connection.ConnectionWriterInterface;
import common.files.AbstractFileTable;
import common.files.FileDigest;
import common.files.MultiNamedFile;
import common.files.NamedFile;
import common.files.SerializableFile;
import connection.server.ConnectionStateAdapter;
import connection.server.ServerConnection;
public class SharedFilesTable extends AbstractFileTable
{
private HashMap<FileDigest, LinkedList<File>> filePaths;
private MultiNamedFileTableModel tableModel;
private SharedFilesListenerInterface listener;
public SharedFilesTable()
{
super();
filePaths = new HashMap<FileDigest, LinkedList<File>>();
tableModel = new MultiNamedFileTableModel();
listener = new NullSharedFilesListener();
new ConnectionListener();
}
public synchronized void add(NamedFile file, File path)
{
super.addEntry(file);
if (!filePaths.containsKey(file.getHashData()))
{
filePaths.put(file.getHashData(), new LinkedList<File>());
}
filePaths.get(file.getHashData()).add(path);
}
public synchronized void remove(NamedFile file, File path)
{
super.removeName(file);
filePaths.get(file.getHashData()).remove(path);
if (filePaths.get(file.getHashData()).isEmpty())
{
filePaths.remove(file.getHashData());
}
}
public synchronized FileInputStream openFile(SerializableFile file)
throws IOException
{
Collection<File> paths = filePaths.get(file.getHashData());
for (File path : paths)
{
try
{
return new FileInputStream(path);
}
catch (IOException ignored)
{
}
}
throw new IOException();
}
public void setListener(SharedFilesListenerInterface listener)
{
this.listener = listener;
}
public void unsetListener()
{
listener = new NullSharedFilesListener();
}
private class ConnectionListener extends ConnectionStateAdapter
{
private ServerUpdater updater;
public void onConnected(ServerConnection newConnection)
{
super.onConnected(newConnection);
updater = new ServerUpdater(newConnection);
setListener(updater);
}
public void onDisconnected()
{
super.onDisconnected();
unsetListener();
}
}
public MultiNamedFileTableModel getTableModel()
{
return tableModel;
}
public void sendToServer(ServerConnection connection) throws IOException
{
HashMap<FileDigest, MultiNamedFile> table = acquireData();
for (Map.Entry<FileDigest, MultiNamedFile> entry : table.entrySet())
{
sendFile(connection, entry.getValue());
}
releaseData();
}
private void sendFile(ServerConnection connection, final MultiNamedFile file)
{
int protocolId = ClientServerProtocol.PROTOCOL_FILES;
int opcode = ClientServerProtocol.Files.OP_ADD_FILE;
connection.send(protocolId, opcode, new ConnectionWriterInterface()
{
public void run(ObjectOutputStream os) throws IOException
{
os.writeObject(file);
}
});
}
public boolean hasFile(SerializableFile file)
{
HashMap<FileDigest, MultiNamedFile> table = acquireData();
boolean result = table.containsKey(file.getHashData());
releaseData();
return result;
}
public String getFirstNameOf(SerializableFile file)
{
HashMap<FileDigest, MultiNamedFile> table = acquireData();
String name = table.get(file.getHashData()).getFirstName();
releaseData();
return name;
}
public Collection<String> getNamesFor(SerializableFile file)
{
HashMap<FileDigest, MultiNamedFile> table = acquireData();
HashSet<String> results = new HashSet<String>(table.get(file.getHashData())
.getNames());
releaseData();
return results;
}
public Collection<MultiNamedFile> query(Collection<String> keywords)
{
// TODO: use regular expressions?
LinkedList<MultiNamedFile> results = new LinkedList<MultiNamedFile>();
HashMap<FileDigest, MultiNamedFile> data = acquireData();
for (MultiNamedFile file : data.values())
{
checkFile(file, keywords, results);
}
releaseData();
return results;
}
private void checkFile(MultiNamedFile file, Collection<String> keywords,
Collection<MultiNamedFile> results)
{
Collection<String> names = new LinkedList<String>(file.getNames());
filterNames(names, keywords);
if (!names.isEmpty())
{
results.add(new MultiNamedFile(file, names));
}
}
private void filterNames(Collection<String> names, Collection<String> keywords)
{
Iterator<String> iterator = names.iterator();
while (iterator.hasNext())
{
if (!fileNameMatches(iterator.next(), keywords))
{
iterator.remove();
}
}
}
private boolean fileNameMatches(String name, Collection<String> keywords)
{
String lowerCaseName = name.toLowerCase();
boolean matches = true;
for (String keyword : keywords)
{
matches &= lowerCaseName.contains(keyword.toLowerCase());
if (!matches)
{
break;
}
}
return matches;
}
protected void onAdd(MultiNamedFile file)
{
tableModel.add(file);
listener.onAdd(file);
}
protected void onUpdate(MultiNamedFile file)
{
tableModel.fireTableDataChanged();
}
protected void onRemove(SerializableFile file)
{
tableModel.remove(file);
listener.onRemove(file);
}
}