package org.ourfilesystem.simpleui;

/*
OurFileSystem is a peer2peer file sharing program.
Copyright (C) 2012  Robert Gass

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.

*/

import java.awt.EventQueue;

import javax.swing.BoxLayout;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPopupMenu;
import javax.swing.JTabbedPane;
import javax.swing.ListSelectionModel;
import javax.swing.SpinnerListModel;

import java.awt.BorderLayout;
import javax.swing.JPanel;
import java.awt.GridBagLayout;
import javax.swing.JLabel;

import java.awt.GridBagConstraints;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Date;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.swing.JTextField;

import org.ourfilesystem.com.ComConnectionImpl;
import org.ourfilesystem.com.ConnectionUpdateInterface;
import org.ourfilesystem.com.OFSConnector;
import org.ourfilesystem.com.OFSServerSocket;
import org.ourfilesystem.com.SignatureRequestInterface;
import org.ourfilesystem.core.Core;
import org.ourfilesystem.core.AutoUpdater;
import org.ourfilesystem.core.EventInterface;
import org.ourfilesystem.db.DataBaseComImpl;
import org.ourfilesystem.db.LocalFileReference;
import org.ourfilesystem.db.LocalPost;
import org.ourfilesystem.db.Peer;
import org.ourfilesystem.db.StorageImpl2;
import org.ourfilesystem.db.TimeImpl;
import org.ourfilesystem.postcodec.PostDecoded;
import org.ourfilesystem.security.CryptoComImpl;
import org.ourfilesystem.security.CryptoDataBaseImpl;
import org.ourfilesystem.simpleui.DownloadsTableModel.DLRow;
import org.ourfilesystem.ui.db.DBImpl;
import org.ourfilesystem.utilities.FileUtils;
import org.ourfilesystem.utilities.Licenses;
import org.ourfilesystem.filehander.FileHandler;
import org.ourfilesystem.filehander.FileReturnInterface;

import javax.swing.JButton;
import javax.swing.JTable;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.table.TableColumn;
import javax.swing.table.TableModel;
import javax.swing.table.TableRowSorter;
import javax.swing.JCheckBox;
import net.miginfocom.swing.MigLayout;
import javax.swing.JSpinner;

public class SimpleGUI implements EventInterface, SignatureRequestInterface, FileReturnInterface {

	//TODO: Save window sizes and split locations.
	
	//TODO: Make international 
	//TODO: Partially connected peers?
	//TODO: Add a nice way to reply to a post.  Quoting the past message.  Adding "Re: to the subject.
	//             Keeping the existing string values.
	//             Add a reply button to the view post dialog and the popup menu.  Reference
	//             the same file, but then the user can attach a new file.
	//TODO: Add a search option to search for all replies to a post.
	//             This can be done by searching for the "Re: and the subject line."
	//TODO: Add configuration/settings menu option and dialog
	//             Add threads to periodically update posts.  Have adjustable in the settings configs.
	//             Allow us to set the downloads directory in the settings/config.
	//             Allow default options to overwrite files of the same name or create new file name.
	//             Set max storage size and allow to delete old file references.
	//             Set max file storage and allow to delete older posts.
	//             Set default download priority.
	//TODO: Low priority: Possibly display messages related to each other somehow?  As in replies?
	
	
	//DONE: Mark peers as "bad".  Show bad peers in peers table.  Test to make sure
	//         bad peer cannot connect.
	//DONE: Do not show "Sign" request dialog for bad peers.
	//DONE: Make all other tables sortable.
	//DONE: Do not mark self as bad.
	//DONE: Selected bad peer gets put into database twice.
	//DONE: Connections windows does not properly show that peer conections are closed after marking bad.
	
	//DONE: Add an option to the post/search templates for strings with specific values to pick from.
	//             Make sure it allows for multi-selection.
	//DONE: Make search results table sortable. 
	//DONE: Add note about peer port being different than the <url>:<port> in the form for proxy
	//DONE: Change label in identity tab from url/ip to url/ip:port 
	//DONE: Add nickname to connection list.
	//DONE: Add rank to the search results table.
	//DONE: When displaying the peer nickname put a substring of the peer identifier in () after it
	//DONE: Remove generate new identity.
	//DONE: Make comments searchable.  The best way to simply not use the native comment field
	//           for posts.  Instead make comment a key with a single large value.  Have post form
	//           handle comment key specially to display as scrollable text pane.
	//DONE: Make file size human readable in posts table and downloads table.
	//DONE: Display file size in the posts table.
	//DONE: Add date to post display dialog.
	//DONE: Someone can make a post that sets a file as a duplicate of another, but if the search
	//             parameters don't yeild the duplicate, then it won't be excluded as a duplicate.
	//DONE: Figure out why multiple requests are issued to one peer when doing an update.
	//             peer0 had 3, peer1 had 1 after an update posts request.
	//			   This appears to be from missing parts, but why are there missing parts!
	//             I suspect this was due to closing the program in the middle of a download
	//             while it was making a lot of posts quickly for each part downloaded, and
	//             we lost a sequence value after it was reserved but then not saved.  The
	//             fix is to pick and save sequence numbers as the posts are actually saved.
	//DONE: For large new posts we need to see a progress bar, or indication to wait.
	//DONE: Fix event listeners to use swing event threads.
	//DONE: For new post dialog make sure we can see large file names.
	//DONE: Add a locking file that will tell if you already have an instance running.
	//DONE: Make sure we don't infinitely request connections to a peer.
	//DONE: Make note of the priority direction in the GUI. (lower number is higher priority)
	//DONE: Only update updated rows in the table.  When we update the whole table we loose the selection.
	//DONE: Fix problem where the current download gets dorked up when closing/openning program.
	//DONE: Restart downloads on resume.
	//DONE: Figure out why priority isn't working.
	//DONE: Add nickname to signature request window.
	//DONE: Need to make sure we don't get spammed by signature requests.
	//      For example, right now if a peer tries to update posts the other peer gets infinately
	//      spammed.
	//DONE: We need to be able to exclude files that have any given post with the exclude value.
	//DONE: Figure out why requests are reissued when a connection is closed.  It's like theres
	//             idle pending connections that get reissued when the connection is closed.
	//DONE: add an exclude string values.  For example, exclude ones marked as bad/corrupt.
	//DONE: Figure out why when we make a new post of a large file it's not recognizing it properly
	//             as a multi-part file.
	//DONE: Add an option to the search results pop-up menu to download a file.
	//DONE: Add column table names to the search results table. 
	//DONE: Make buttons to update messages sense we removed the other post tab.
	//DONE: Make pop-up menu option to download selected files in search table.
	//DONE: Remove File tab (at some point, or move somewhere for debug).
	//DONE: Make download status tab.
	//DONE: Why do we get posts twice on receiving peer.  Check if we already have post before saving in SearchDB
	//CANNOTDO: Open post from downloads tab.  We don't get the Post data in the model.
	//DONE: Make sure New Post dialg is not visible on startup.
	//DONE: Why don't re recongnize that we downloaded all pieces on shutdown?
	//DONE: Do not show proxy dialog on every restart.
	//DONE: Make a dialog to display posts that have been downloaded.
	//CLOSE: Add a column to the search results table to indicate if you already have the file.
	//          > Not doing this because we don't have a database reference to check if we
	//          > really have the whole file.  The only thing we might be able to check is if
	//          > we have a file with that name in the dl dir.
	//DONOTDO: Re-submit requests on pending connections (in case a connection isn't working)
	//           Under the covers we just close the connection and pending requests are re-dispatched.

	private JFrame frame;
	private JTextField textField;
	
	private NetworkConfigDialog ProxyDialog;
	private JCheckBox AutoSigCheckBox;
	
	private ComConnectionImpl Com;
	private Core Core;
	private String BaseDir;
	private File DownloadDir;
	private int Port;
	private AutoUpdater AutoUpdater;
	
	private PeerTable PeerTable;
	private ConnectionsTable ConTable;
	private BadPeerDialog BadDialog;
	
	private StorageImpl2 Store;
	private DBImpl SearchDB;
	private ExpandedPostTableModel ExpPostTable;
	private FileHandler FHandler;
	
	private JTextField textField_2;
	private JTable table;
	private JTable table_1;
	private JPopupMenu SearchPopup;
	private JPopupMenu PeerPopup;
	
	private JTextField textField_3;
	private JTable table_4;
	
	private SearchPanel SearchPanel;
	
	private NewExpandedPostDialog NewPostDialog;
	private ExpandedPostDialog PostDialog;
	private OFSSettings Settings;
	
	private DownloadsTableModel DownloadModel; 
	private JTable DownloadsTable;
	private JPopupMenu DownloadMenu;
	
	private HashSet<Peer> SignaturesRequested;
	
	private File ChooserDir;
	
	public class ProgressDots implements Runnable {
		private boolean Run;
		public ProgressDots() {
			Run = true;
			Thread t = new Thread(this);
			t.start();
		}
		@Override
		public void run() {
			System.out.println();
			System.out.println("Please wait.");
			while (Run) {
				DoDot();
			}
			System.out.println();
			System.out.println("Thanks, have fun!");
		}
		public synchronized void DoDot() {
			System.out.print(".");
			try {
				wait(500);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		public synchronized void close() {
			Run = false;
			notify();
		}
	}
	
	public void InitPeer(OFSServerSocket server, OFSConnector con, boolean editlocation) {
		if (Core == null || Com == null) {
			
			ProgressDots dots = new ProgressDots();
			
			Core = new Core();
			//Get the port value here, so we can open the socket to the right port.
			Store = new StorageImpl2(BaseDir);
			Peer p = Store.getMyPeerData();
			CryptoDataBaseImpl sec = new CryptoDataBaseImpl();
			TimeImpl time = new TimeImpl();
			DataBaseComImpl comdb = new DataBaseComImpl(Core);
			comdb.setStore(Store);
			comdb.addEventInterface(this);
			comdb.addEventInterface(SearchDB);
			comdb.setSecurity(sec);
			comdb.setTime(time);
			CryptoComImpl cryptcom = new CryptoComImpl();
			Com = new ComConnectionImpl(Core, comdb, cryptcom, this, BaseDir + File.separator + "tmp", server, con, Settings.isAutoSign());

			Core.setComConnector(Com);
			Core.setComDataBase(comdb);
			Core.addEventInterface(this);
			Core.addEventInterface(SearchDB);
			Core.setSecurity(sec);
			Core.setUserDataBase(Store);
			Core.setTime(time);

			FHandler = new FileHandler(BaseDir + File.separator + "searchdb.dat", BaseDir + File.separator + "tmp", Core, this);		
			Core.addEventInterface(FHandler);
			comdb.addEventInterface(FHandler);

			if (p == null) {
				System.out.println("WARNING: No peer data was found.  Generating new keys.");
				Core.generateNewKeys();
			}
			AutoUpdater = new AutoUpdater(Core, 
					Settings.isAutoUpdatePeers(), 
					Settings.getPeerUpdatePeriod(),
					Settings.isAutoUpdatePosts(),
					Settings.getPostUpdatePeriod());

			initialize(editlocation);
			
			dots.close();
			frame.setVisible(true);
			FHandler.Go();
		}
	}
	
	/**
	 * Launch the application.
	 */
	public static void main(String[] args) {
		if (args.length != 1) {
			System.out.println("The SimpleGUI requires one argument.");
			System.out.println("<basedir>");
			System.exit(1);
		}
		System.out.println(Licenses.getLicense());
		final String basedir = args[0];
		try {
			VersionUpdater.update(basedir);
			EventQueue.invokeLater(new Runnable() {
				public void run() {
					try {
						new SimpleGUI(basedir);
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
			});
		} catch (Exception e1) {
			System.out.println("ERROR: There was a problem upgrading. :(");
			System.out.println("You can email the following stack trace to: robertgass@gmail.com");
			e1.printStackTrace();
		}
	}

	/**
	 * Create the application.
	 */
	public SimpleGUI(String basedir) {
		ChooserDir = new File(".");
		SignaturesRequested = new HashSet<Peer>();
		BaseDir = basedir;
		DownloadDir = new File(BaseDir + File.separator + "downloads");
		DownloadDir.mkdirs();
		final File lockfile = new File(BaseDir + File.separator + "lock.dat");
		if (lockfile.exists()) {
			System.out.println("ERROR: Delete: " + lockfile + " to restart.");
			System.exit(1);
		}
		else {
			try {
				lockfile.createNewFile();
				Runtime.getRuntime().addShutdownHook(new Thread() {
					public void run() {
						lockfile.delete();
					}
				});
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		Settings = new OFSSettings(BaseDir);
		SearchDB = new DBImpl(basedir + File.separator + "search.dat");
		FHandler = new FileHandler(basedir + File.separator + "filedb.dat", 
									  basedir + File.separator + "tmp", 
									  Core, this);

		ProxyDialog = new NetworkConfigDialog(this, basedir);
		// Uncomment to use gui editor
		//initialize(false);
	}

	public void addLocalPost(Object message, Object fileref) {
		Core.addLocalPost(message, fileref);
	}
	
	public void insertFile(File fileref, PostDecoded post) {
		if (fileref.isFile()) {
			FHandler.insertFile(fileref, post);
		}
		if (fileref.isDirectory()) {
			File flist[] = fileref.listFiles();
			for (int cnt = 0; cnt < flist.length; cnt++) {
				insertFile(flist[cnt], post);
			}
		}
	}
	
	/**
	 * Initialize the contents of the frame.
	 */
	private void initialize(boolean editlocation) {
		PostDialog = new ExpandedPostDialog(this);
		
		frame = new JFrame();
		frame.setBounds(100, 100, 850, 700);
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.getContentPane().setLayout(new BorderLayout(0, 0));
		
		JTabbedPane tabbedPane = new JTabbedPane(JTabbedPane.TOP);
		frame.getContentPane().add(tabbedPane);
		
		JPanel panel = new JPanel();
		tabbedPane.addTab("Identity", null, panel, null);
		GridBagLayout gbl_panel = new GridBagLayout();
		gbl_panel.columnWidths = new int[]{0, 0, 0, 0, 0};
		gbl_panel.rowHeights = new int[]{0, 28, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
		gbl_panel.columnWeights = new double[]{0.0, 0.0, 1.0, 0.0, Double.MIN_VALUE};
		gbl_panel.rowWeights = new double[]{0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, Double.MIN_VALUE};
		panel.setLayout(gbl_panel);
		
		JLabel lblIpurl = new JLabel("IP/URL:Port");
		GridBagConstraints gbc_lblIpurl = new GridBagConstraints();
		gbc_lblIpurl.anchor = GridBagConstraints.NORTHEAST;
		gbc_lblIpurl.insets = new Insets(0, 0, 5, 5);
		gbc_lblIpurl.gridx = 1;
		gbc_lblIpurl.gridy = 1;
		panel.add(lblIpurl, gbc_lblIpurl);
		
		textField = new JTextField();
		GridBagConstraints gbc_textField = new GridBagConstraints();
		gbc_textField.fill = GridBagConstraints.HORIZONTAL;
		gbc_textField.insets = new Insets(0, 0, 5, 5);
		gbc_textField.gridx = 2;
		gbc_textField.gridy = 1;
		panel.add(textField, gbc_textField);
		textField.setColumns(10);
		textField.setEditable(editlocation);
		
		JLabel lblIntroduction = new JLabel("Introduction");
		GridBagConstraints gbc_lblIntroduction = new GridBagConstraints();
		gbc_lblIntroduction.anchor = GridBagConstraints.EAST;
		gbc_lblIntroduction.insets = new Insets(0, 0, 5, 5);
		gbc_lblIntroduction.gridx = 1;
		gbc_lblIntroduction.gridy = 2;
		panel.add(lblIntroduction, gbc_lblIntroduction);
		
		textField_2 = new JTextField();
		GridBagConstraints gbc_textField_2 = new GridBagConstraints();
		gbc_textField_2.insets = new Insets(0, 0, 5, 5);
		gbc_textField_2.fill = GridBagConstraints.HORIZONTAL;
		gbc_textField_2.gridx = 2;
		gbc_textField_2.gridy = 2;
		panel.add(textField_2, gbc_textField_2);
		textField_2.setColumns(10);
		
		JLabel lblNickname = new JLabel("Nickname");
		GridBagConstraints gbc_lblNickname = new GridBagConstraints();
		gbc_lblNickname.anchor = GridBagConstraints.EAST;
		gbc_lblNickname.insets = new Insets(0, 0, 5, 5);
		gbc_lblNickname.gridx = 1;
		gbc_lblNickname.gridy = 3;
		panel.add(lblNickname, gbc_lblNickname);
		
		textField_3 = new JTextField();
		GridBagConstraints gbc_textField_3 = new GridBagConstraints();
		gbc_textField_3.insets = new Insets(0, 0, 5, 5);
		gbc_textField_3.fill = GridBagConstraints.HORIZONTAL;
		gbc_textField_3.gridx = 2;
		gbc_textField_3.gridy = 3;
		panel.add(textField_3, gbc_textField_3);
		textField_3.setColumns(10);
		
		JButton btnSaveChanges = new JButton("Save Changes");
		GridBagConstraints gbc_btnSaveChanges = new GridBagConstraints();
		gbc_btnSaveChanges.insets = new Insets(0, 0, 5, 5);
		gbc_btnSaveChanges.gridx = 2;
		gbc_btnSaveChanges.gridy = 6;
		panel.add(btnSaveChanges, gbc_btnSaveChanges);
		
		btnSaveChanges.setActionCommand("SAVESTUFF");
		btnSaveChanges.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				if (e.getActionCommand().equals("SAVESTUFF")) {
					String location = textField.getText();
					if (location != null && (!location.equals(""))) {
						Core.setMyLocation(location);
					}
					String intro = textField_2.getText();
					if (intro != null && (!intro.equals(""))) {
						Core.setMyIntroduction(intro);
					}
					String nick = textField_3.getText();
					if (nick != null && (!nick.equals(""))) {
						Core.setMyNickname(nick);
					}
				}
			}
		});
		
		JButton btnExportPeerIdenity = new JButton("Export Peer Idenity File");
		GridBagConstraints gbc_btnExportPeerIdenity = new GridBagConstraints();
		gbc_btnExportPeerIdenity.insets = new Insets(0, 0, 5, 5);
		gbc_btnExportPeerIdenity.gridx = 2;
		gbc_btnExportPeerIdenity.gridy = 7;
		panel.add(btnExportPeerIdenity, gbc_btnExportPeerIdenity);
		
		btnExportPeerIdenity.setActionCommand("EXPORT");
		btnExportPeerIdenity.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				if (e.getActionCommand().equals("EXPORT")) {
					JFileChooser chooser = new JFileChooser();
					chooser.setCurrentDirectory(ChooserDir);
					int returnVal = chooser.showSaveDialog(frame);
					if (returnVal == JFileChooser.APPROVE_OPTION) {
						System.out.println("You chose to open this file: " + chooser.getSelectedFile().getName());
						File f = chooser.getSelectedFile();
						Peer p = Core.getMyPeerData();
						if (p != null) {
							try {
								FileOutputStream fos = new FileOutputStream(f);
								FileUtils.writePeer(fos, p);
								fos.close();
							}
							catch (Exception ex) {
								ex.printStackTrace();
								JOptionPane.showMessageDialog(frame, "ERROR: Could not export your peer data. " + ex.getMessage());						
							}
						}
					}
					ChooserDir = chooser.getCurrentDirectory();
				}
			}
		});
		
		JButton btnImportAndSign = new JButton("Import and Sign Peer Idenity File");
		GridBagConstraints gbc_btnImportAndSign = new GridBagConstraints();
		gbc_btnImportAndSign.insets = new Insets(0, 0, 5, 5);
		gbc_btnImportAndSign.gridx = 2;
		gbc_btnImportAndSign.gridy = 8;
		panel.add(btnImportAndSign, gbc_btnImportAndSign);
		
		btnImportAndSign.setActionCommand("IMPORT");
		btnImportAndSign.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				if (e.getActionCommand().equals("IMPORT")) {
					JFileChooser chooser = new JFileChooser();
					chooser.setCurrentDirectory(ChooserDir);
					int returnVal = chooser.showOpenDialog(frame);
					if (returnVal == JFileChooser.APPROVE_OPTION) {
						System.out.println("You chose to open this file: " + chooser.getSelectedFile().getName());
						File f = chooser.getSelectedFile();
						try {
							FileInputStream fis = new FileInputStream(f);
							Peer p = FileUtils.readPeer(fis);
							fis.close();
							Core.signPeer(p);
							JOptionPane.showMessageDialog(frame, "Peer has been signed and can now join the network.");							
						}
						catch (Exception ex) {
							ex.printStackTrace();
							JOptionPane.showMessageDialog(frame, "ERROR: Could not sign the peer data. " + ex.getMessage());						
						}
					}
					ChooserDir = chooser.getCurrentDirectory();
				}
			}
		});
		
		JPanel panel_1 = new JPanel();
		tabbedPane.addTab("Peers", null, panel_1, null);
		panel_1.setLayout(new BorderLayout(0, 0));
		
		JScrollPane scrollPane = new JScrollPane();
		panel_1.add(scrollPane);
		
		PeerTable = new PeerTable();
		table = new JTable(PeerTable);
		table.setAutoCreateRowSorter(true);
		scrollPane.setViewportView(table);
				
		JPanel buttPan = new JPanel();
		panel_1.add(buttPan, BorderLayout.NORTH);
		JButton shwBadPeers = new JButton("Show Bad Peers");
		shwBadPeers.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg0) {
				BadDialog.setVisible(true);
			}
		});
		buttPan.add(shwBadPeers); //, BorderLayout.NORTH);
		
		JButton btnUpdatePeers = new JButton("Update Peers");
		buttPan.add(btnUpdatePeers); //, BorderLayout.NORTH);
		btnUpdatePeers.setActionCommand("UPDATEPEERS");
		btnUpdatePeers.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg0) {
				if (arg0.getActionCommand().equals("UPDATEPEERS")) {
					List<Peer> pl = Core.getPeerList();
					PeerTable.addAllPeers(pl);
					Core.updatePeers();
				}
			}
		});

		
		JPanel panel_2 = new JPanel();
		tabbedPane.addTab("Connections", null, panel_2, null);
		panel_2.setLayout(new BorderLayout(0, 0));
		
		JScrollPane scrollPane_1 = new JScrollPane();
		panel_2.add(scrollPane_1);
		
		ConTable = new ConnectionsTable();
		table_1 = new JTable(ConTable);
		table_1.setAutoCreateRowSorter(true);
		scrollPane_1.setViewportView(table_1);
		
		JPanel panel_6 = new JPanel();
		tabbedPane.addTab("Posts", null, panel_6, null);
		panel_6.setLayout(new BorderLayout(0, 0));
		
		JSplitPane splitPane_2 = new JSplitPane();
		splitPane_2.setOrientation(JSplitPane.VERTICAL_SPLIT);
		//splitPane_2.setDividerLocation(20.0D);
		panel_6.add(splitPane_2, BorderLayout.CENTER);
		
		//NOTE: The search.template will attempt to add menu items to the pop-up menu.
		SearchPopup = new JPopupMenu("Search/References");
		setupPopupMenu();
		
		ExpPostTable = new ExpandedPostTableModel(SearchDB);
		table_4 = new JTable(ExpPostTable);
		TableColumn col2 = table_4.getColumnModel().getColumn(0);
		col2.setCellRenderer(ExpPostTable.new DateCellRenderer());
		col2 = table_4.getColumnModel().getColumn(1);
		col2.setCellRenderer(ExpPostTable.new DateCellRenderer());

		TableRowSorter<TableModel> sorter = new TableRowSorter<TableModel>(ExpPostTable);
		sorter.setComparator(0, new Comparator<Date>() {
			@Override
			public int compare(Date arg0, Date arg1) {
				if (arg0 == null) return -1;
				if (arg1 == null) return 1;
				return arg0.compareTo(arg1);
			}
		});
		sorter.setComparator(1, new Comparator<Date>() {
			@Override
			public int compare(Date arg0, Date arg1) {
				if (arg0 == null) return -1;
				if (arg1 == null) return 1;
				return arg0.compareTo(arg1);
			}
		});
		sorter.setComparator(6, new Comparator<String>() {
			private long str2long(String v) {
				Pattern p = Pattern.compile("(\\d+)(\\w+)");
				Matcher m = p.matcher(v);
				long val = 0;
				if (m.find()) {
					val = Long.valueOf(m.group(1));
					String mu = m.group(2);
					if (mu.equals("KB")) {
						val *= 1024L;
					}
					if (mu.equals("MB")) {
						val *= 1024L * 1024L;
					}
					if (mu.equals("GB")) {
						val *= 1024L * 1024L * 1024L;
					}
				}
				return val;
			}
			@Override
			public int compare(String arg0, String arg1) {
				Long v0 = str2long(arg0);
				Long v1 = str2long(arg1);
				return v0.compareTo(v1);
			}
		});
		table_4.setRowSorter(sorter);
		table_4.setComponentPopupMenu(SearchPopup);
		JScrollPane expscroll = new JScrollPane(table_4);
		splitPane_2.setRightComponent(expscroll);
		//table_4.setRowSelectionAllowed(true);
		//table_4.setColumnSelectionAllowed(false);
		table_4.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
		table_4.addMouseListener(new MouseListener() {
			@Override
			public void mouseClicked(MouseEvent c) {
				if (!c.isPopupTrigger() && c.getClickCount() == 2) {
					int row = table_4.getSelectedRow();
					if (row >= 0) {
						int r = table_4.convertRowIndexToModel(row);
						PostDecoded pd = ExpPostTable.getPost(r);
						openPost(pd);
					}					
				}
			}
			@Override
			public void mouseEntered(MouseEvent arg0) {
			}

			@Override
			public void mouseExited(MouseEvent arg0) {
			}

			@Override
			public void mousePressed(MouseEvent arg0) {
			}
			@Override
			public void mouseReleased(MouseEvent arg0) {
			}
		});
		
		JPanel panel_7 = new JPanel();
		splitPane_2.setLeftComponent(panel_7);
		//panel_7.setLayout(new BorderLayout(0, 0));

		final JPanel testp = new JPanel();
		SearchPanel = new SearchPanel(this);
		try {
			File searchtemplate = new File(BaseDir + File.separator + "search.template");
			if (!searchtemplate.exists()) {
				WriteDefaultSearchTemplate.writeDefaultFile(searchtemplate);
			}
			SearchPanel.PopulatePanel(testp, searchtemplate);
		} catch (IOException e1) {
			e1.printStackTrace();
			System.exit(1);
		}
		
		List<Peer> bpl = Store.listBadPeers();
		Iterator<Peer> ip = bpl.iterator();
		while (ip.hasNext()) {
			Peer p = ip.next();
			SearchPanel.addExcludePeer(p);
		}

		BadDialog = new BadPeerDialog();
		BadDialog.setStore(Store);
		BadDialog.setSearchPanel(SearchPanel);
		BadDialog.update();
		
		PeerPopup = new JPopupMenu("Peer selection");
		JMenuItem exp = new JMenuItem("Exclude Selected Peers from Search");
		PeerPopup.add(exp);
		exp.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent a) {
				int rows[] = table.getSelectedRows();
				for (int cnt = 0; cnt < rows.length; cnt++) {
					int r = table.convertRowIndexToModel(rows[cnt]);
					Peer p = PeerTable.getPeer(r);
					if (p != null) {
						SearchPanel.addExcludePeer(p);
					}
				}
			}
		});
		JMenuItem inc = new JMenuItem("Include Selected Peers for Search");
		PeerPopup.add(inc);
		inc.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent a) {
				int rows[] = table.getSelectedRows();
				for (int cnt = 0; cnt < rows.length; cnt++) {
					int r = table.convertRowIndexToModel(rows[cnt]);
					Peer p = PeerTable.getPeer(r);
					if (p != null) {
						SearchPanel.addIncludePeer(p);
					}
				}
			}
		});
		JMenuItem del = new JMenuItem("Mark peer as Bad.");
		PeerPopup.add(del);
		del.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg0) {
				int rows[] = table.getSelectedRows();
				for (int cnt = 0; cnt < rows.length; cnt++) {
					int r = table.convertRowIndexToModel(rows[cnt]);
					Peer p = PeerTable.getPeer(r);
					if (p != null) {
						Core.setBadPeer(p);
					}
				}
				updatePeerTable();
				BadDialog.update();
			}
		});
		table.setComponentPopupMenu(PeerPopup);
		JPanel buttonpanel = new JPanel();
		panel_7.add(buttonpanel);
		JButton btnLoadSearchTemplate = new JButton("Load Search Template");
		buttonpanel.add(btnLoadSearchTemplate);
		btnLoadSearchTemplate.setActionCommand("LOADSEARCH");
		btnLoadSearchTemplate.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent a) {
				if (a.getActionCommand().equals("LOADSEARCH")) {
					JFileChooser chooser = new JFileChooser();
					chooser.setCurrentDirectory(ChooserDir);
					int returnVal = chooser.showOpenDialog(frame);
					if (returnVal == JFileChooser.APPROVE_OPTION) {
						System.out.println("You chose to open this file: " + chooser.getSelectedFile().getName());
						File f = chooser.getSelectedFile();
						try {
							SearchPanel.PopulatePanel(testp, f);
						} catch (IOException e) {
							JOptionPane.showMessageDialog(frame, "There was a problem with that template file.");							
							try {
								SearchPanel.PopulatePanel(testp, new File(BaseDir + File.separator + "search.template"));
							} catch (IOException e1) {
								e1.printStackTrace();
								System.exit(1);
							}							
							e.printStackTrace();
						}
					}
					ChooserDir = chooser.getCurrentDirectory();
				}
			}
		});
		JButton updatebut = new JButton("Update Posts");
		updatebut.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent a) {
				Core.updatePosts();
			}
		});
		buttonpanel.add(updatebut);
		
		panel_7.setLayout(new BoxLayout(panel_7, BoxLayout.PAGE_AXIS));
		
		File f = new File(BaseDir + File.separator + "newpost.template");
		if (!f.exists()) {
			try {
				WriteDefaultPostTemplate.writeDefaultFile(f);
			} catch (IOException e1) {
				e1.printStackTrace();
			}
		}
		NewPostDialog = new NewExpandedPostDialog(this, f.getPath(), BaseDir + File.separator + "tmp");
		JButton newpost = new JButton("New Post");
		newpost.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent a) {
				NewPostDialog.setVisible(true);
			}
		});
		buttonpanel.add(newpost);
				
		JScrollPane testscroll = new JScrollPane(testp);
		panel_7.add(testscroll);
		
		
		JButton btnSearch = new JButton("Search");
		panel_7.add(btnSearch);
		panel_7.getRootPane().setDefaultButton(btnSearch);
		btnSearch.requestFocus();
		btnSearch.setActionCommand("SEARCH");
		btnSearch.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg0) {
				if (arg0.getActionCommand().equals("SEARCH")) {
					ExpPostTable.setQueryResults(SearchPanel.doSearch(SearchDB));
				}
			}
		});

		splitPane_2.setDividerLocation(200);
		
		JPanel panel_3 = new JPanel();
		tabbedPane.addTab("Downloads", null, panel_3, null);
		panel_3.setLayout(new BorderLayout(0, 0));
		
		JScrollPane scrollPane_2 = new JScrollPane();
		panel_3.add(scrollPane_2);
		
		DownloadMenu = new JPopupMenu("Downloads");
		DownloadModel = new DownloadsTableModel();
		TableRowSorter<TableModel> dlsorter = new TableRowSorter<TableModel>(DownloadModel);
		dlsorter.setComparator(2, new Comparator<String>() {
			private long str2long(String v) {
				Pattern p = Pattern.compile("(\\d+)(\\w+)");
				Matcher m = p.matcher(v);
				long val = 0;
				if (m.find()) {
					val = Long.valueOf(m.group(1));
					String mu = m.group(2);
					if (mu.equals("KB")) {
						val *= 1024L;
					}
					if (mu.equals("MB")) {
						val *= 1024L * 1024L;
					}
					if (mu.equals("GB")) {
						val *= 1024L * 1024L * 1024L;
					}
				}
				return val;
			}
			@Override
			public int compare(String arg0, String arg1) {
				Long v0 = str2long(arg0);
				Long v1 = str2long(arg1);
				return v0.compareTo(v1);
			}
		});
		FHandler.setFileReturnInterface(DownloadModel);
		DownloadsTable = new JTable(DownloadModel);
		DownloadsTable.setRowSorter(dlsorter);
		DownloadsTable.setComponentPopupMenu(DownloadMenu);
		scrollPane_2.setViewportView(DownloadsTable);
		
		JPanel panel_4 = new JPanel();
		tabbedPane.addTab("Settings", null, panel_4, null);
		panel_4.setLayout(new MigLayout("", "[][grow]", "[][][][][][]"));
		
		JButton button = new JButton("Configure Network");
		button.setActionCommand("SOCKSCONFIG");
		panel_4.add(button, "cell 0 0");
		button.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg0) {
				if (arg0.getActionCommand().equals("SOCKSCONFIG")) {
					ProxyDialog.setVisible(true);
				}
			}
		});
		
		AutoSigCheckBox = new JCheckBox("Automatically sign for new peers");
		AutoSigCheckBox.setSelected(false);
		panel_4.add(AutoSigCheckBox, "cell 0 1");
		AutoSigCheckBox.setSelected(Settings.isAutoSign());
		
		final JCheckBox AutomatciallyUpdatePeers = new JCheckBox("Automatcially update peers");
		panel_4.add(AutomatciallyUpdatePeers, "cell 0 2");
		AutomatciallyUpdatePeers.setSelected(Settings.isAutoUpdatePeers());
		AutomatciallyUpdatePeers.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg0) {
				Settings.setAutoUpdatePeers(AutomatciallyUpdatePeers.isSelected());
				AutoUpdater.setAutoPeerUpdate(AutomatciallyUpdatePeers.isSelected());
			}
		});
		
		JLabel lblPeerUpdatePeriod = new JLabel("Peer Update Period");
		panel_4.add(lblPeerUpdatePeriod, "cell 0 3,alignx trailing");
		
		List<String> lst = new LinkedList<String>();
		lst.add("10m");
		lst.add("20m");
		lst.add("30m");
		lst.add("40m");
		lst.add("1h");
		lst.add("2h");
		lst.add("4h");
		lst.add("8h");
		lst.add("24h");
		SpinnerListModel mod = new SpinnerListModel(lst);
		final JSpinner PeerUpdatePeriod = new JSpinner(mod);
		panel_4.add(PeerUpdatePeriod, "cell 1 3");
		PeerUpdatePeriod.setValue(Settings.getPeerUpdatePeriodStr());
		PeerUpdatePeriod.addChangeListener(new ChangeListener() {
			@Override
			public void stateChanged(ChangeEvent arg0) {
				String sv = (String)PeerUpdatePeriod.getValue();
				Settings.setPeerUpdatePeriodStr(sv);
				AutoUpdater.setPeerUpdatePeriod(Settings.getPeerUpdatePeriod());
			}
		});
		
		final JCheckBox AutomaticallyUpdatePosts = new JCheckBox("Automatically update posts");
		panel_4.add(AutomaticallyUpdatePosts, "cell 0 4");
		AutomaticallyUpdatePosts.setSelected(Settings.isAutoUpdatePosts());
		AutomaticallyUpdatePosts.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				Settings.setAutoUpdatePosts(AutomaticallyUpdatePosts.isSelected());
				AutoUpdater.setAutoPostUpdate(AutomaticallyUpdatePosts.isSelected());
			}
		});
		
		JLabel lblPostUpdatePeriod = new JLabel("Post Update Period");
		panel_4.add(lblPostUpdatePeriod, "cell 0 5,alignx trailing");
		
		List<String> lst2 = new LinkedList<String>();
		lst2.add("10m");
		lst2.add("20m");
		lst2.add("30m");
		lst2.add("40m");
		lst2.add("1h");
		lst2.add("2h");
		lst2.add("4h");
		lst2.add("8h");
		lst2.add("24h");
		SpinnerListModel mod2 = new SpinnerListModel(lst2);
		final JSpinner PostUpdatePeriod = new JSpinner(mod2);
		PostUpdatePeriod.setValue(Settings.getPostUpdatePeriodStr());
		panel_4.add(PostUpdatePeriod, "cell 1 5");
		PostUpdatePeriod.addChangeListener(new ChangeListener() {
			@Override
			public void stateChanged(ChangeEvent e) {
				String sv = (String)PostUpdatePeriod.getValue();
				Settings.setPostUpdatePeriodStr(sv);
				AutoUpdater.setPostUpdatePeriod(Settings.getPostUpdatePeriod());
			}
		});
		
		AutoSigCheckBox.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg0) {
				if (AutoSigCheckBox.isSelected()) {
					int r = JOptionPane.showConfirmDialog(frame, "Are you really sure?  ALL peers on the network should agree!");
					if (r == JOptionPane.YES_OPTION) {
						Com.setAutoSign(true);
						Settings.setAutoSign(true);
					}
					else {
						AutoSigCheckBox.setSelected(false);
						Settings.setAutoSign(false);
						Com.setAutoSign(false);
					}
				}
				else {
					Settings.setAutoSign(false);
					Com.setAutoSign(false);					
				}
			}
		});
		TableColumn col = DownloadsTable.getColumnModel().getColumn(3);
		col.setCellRenderer(DownloadModel.new ProgressCellRenderer());
		
		setupDownloadsPopup();
		updateMyInfoDisplay();
		updatePeerTable();
		updatePostTable();
	}
	
	private void setupDownloadsPopup() {
		JMenuItem setpriority = new JMenuItem("Change Priority");
		DownloadMenu.add(setpriority);
		setpriority.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg0) {
				int rows[] = DownloadsTable.getSelectedRows();
				if (rows.length > 0) {
					Object vals[] = {
							0,
							1,
							2,
							3,
							4,
							5
					};
					Integer v = (Integer)JOptionPane.showInputDialog(frame, "Set the download priority\n" +
							"Higher values are downloaded first.", 
							"Download Priority", 
							JOptionPane.QUESTION_MESSAGE, null, 
							vals, 0);

					if (v != null) {
						for (int cnt = 0; cnt < rows.length; cnt++) {
							int r = DownloadsTable.convertRowIndexToModel(rows[cnt]);
							DLRow dl = DownloadModel.getRow(r);
							if (dl != null) {
								FHandler.setPriority(dl.SaveAs, v);
							}
						}
					}
				}
			}
		});
		JMenuItem pause = new JMenuItem("Pause Download.");
		DownloadMenu.add(pause);
		pause.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg0) {
				int rows[] = DownloadsTable.getSelectedRows();
				for (int cnt = 0; cnt < rows.length; cnt++) {
					int r = DownloadsTable.convertRowIndexToModel(rows[cnt]);
					DLRow dl = DownloadModel.getRow(r);
					if (dl != null) {
						FHandler.pauseFile(dl.SaveAs);
					}					
				}
			}
		});
		JMenuItem resume = new JMenuItem("Resume Download.");
		DownloadMenu.add(resume);
		resume.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent arg0) {
				int rows[] = DownloadsTable.getSelectedRows();
				for (int cnt = 0; cnt < rows.length; cnt++) {
					int r = DownloadsTable.convertRowIndexToModel(rows[cnt]);
					DLRow dl = DownloadModel.getRow(r);
					if (dl != null) {
						FHandler.resumeFile(dl.SaveAs);
					}
				}				
			}
		});
		JMenuItem remove = new JMenuItem("Remove from the list.");
		DownloadMenu.add(remove);
		remove.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				int rows[] = DownloadsTable.getSelectedRows();
				for (int cnt = 0; cnt < rows.length; cnt++) {
					int r = DownloadsTable.convertRowIndexToModel(rows[cnt]);
					DLRow dl = DownloadModel.getRow(r);
					if (dl != null) {
						FHandler.removeFile(dl.SaveAs);
					}
				}
				refreshDownloads();
			}
		});
	}
	
	private void openPost(PostDecoded pd) {
		String nick = "";
		Peer p = Store.getPeer(pd.getPost().getPost().getSignedDigest().getPeerIdentifier());
		if (p != null) {
			nick = p.getNickSig();
		}
		PostDialog.setPost(pd, nick);
		PostDialog.setVisible(true);
	}
	
	public void refreshDownloads() {
		DownloadModel.clearAll();
		FHandler.updateAllStatus();		
	}
	
	private void setupPopupMenu() {
		JMenuItem openPost = new JMenuItem("Open post.");
		openPost.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				int row = table_4.getSelectedRow();
				if (row >= 0) {
					int r = table_4.convertRowIndexToModel(row);
					PostDecoded pd = ExpPostTable.getPost(r);
					openPost(pd);
				}
			}
		});
		SearchPopup.add(openPost);
		JMenuItem download = new JMenuItem("Download selected.");
		download.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent a) {
				int i[] = table_4.getSelectedRows();
				for (int cnt = 0; cnt < i.length; cnt++) {
					int r = table_4.convertRowIndexToModel(i[cnt]);
					PostDecoded pd = ExpPostTable.getPost(r);
					requestDownload(pd);
				}
			}
		});
		SearchPopup.add(download);
		SearchPopup.addSeparator();
		JMenuItem searchforreference = new JMenuItem("Search for posts referencing selected.");
		searchforreference.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent a) {
				int rows[] = table_4.getSelectedRows();
				for (int cnt = 0; cnt < rows.length; cnt++) {
					int r = table_4.convertRowIndexToModel(rows[cnt]);
					PostDecoded pd = ExpPostTable.getPost(r);
					SearchPanel.addDirectReference(pd);
				}
			}
		});
		SearchPopup.add(searchforreference);
		JMenuItem postreference = new JMenuItem("Reply");
		postreference.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent a) {
				int rows[] = table_4.getSelectedRows();
				for (int cnt = 0; cnt < rows.length; cnt++) {
					int r = table_4.convertRowIndexToModel(rows[cnt]);
					PostDecoded pd = ExpPostTable.getPost(r);
					NewPostDialog.addReference(pd);
					NewPostDialog.setVisible(true);
				}
			}
		});
		SearchPopup.add(postreference);
		SearchPopup.addSeparator();
	}
	
	public void requestDownload(PostDecoded pd) {
		if (pd != null) {
			Set<String> filelst = pd.getStringKeySet(FileHandler.FILENAME);
			if (filelst != null && filelst.size() > 0) {
				String filename = filelst.iterator().next();
				File sf = new File(DownloadDir.getPath() + File.separator + filename);
				FHandler.requestFile(sf, pd, false, 0);
			}
			else {
				//TODO: Error about not finding the file name.
			}
		}		
	}
	
	public void resetPopupMenu() {
		SearchPopup.removeAll();
		setupPopupMenu();
	}
	
	public void addReference(final String ref) {
		JMenuItem mi = new JMenuItem("Search for " + ref + " of selected");
		mi.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				int rows[] = table_4.getSelectedRows();
				for (int cnt = 0; cnt < rows.length; cnt++) {
					int r = table_4.convertRowIndexToModel(rows[cnt]);
					PostDecoded pd = ExpPostTable.getPost(r);
					SearchPanel.addHasReference(ref, pd);
				}
			}
		});
		SearchPopup.add(mi);
		JMenuItem pi = new JMenuItem("Another is a " + ref + " of this");
		pi.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				int rows[] = table_4.getSelectedRows();
				for (int cnt = 0; cnt < rows.length; cnt++) {
					int r = table_4.convertRowIndexToModel(rows[cnt]);
					PostDecoded pd = ExpPostTable.getPost(r);
					NewPostDialog.addReference(ref, pd);
					NewPostDialog.setVisible(true);
				}
			}
		});		
		SearchPopup.add(pi);
	}
	
	public void setLocation(String str) {
		Core.setMyLocation(str);
		updateMyInfoDisplay();
	}
	
	private void updateMyInfoDisplay() {
		Peer p = Core.getMyPeerData();
		if (p != null) {
			String str = (String)p.getLocation();
			if (str != null) {
				textField.setText(str);
			}
			else {
				textField.setText("localhost:" + this.Port);
			}
			if (p.getIntroduction() != null) {
				textField_2.setText(p.getIntroduction());
			}
			if (p.getNickname() != null) {
				textField_3.setText(p.getNickname());
			}
		}
		else {
			textField.setText("localhost:" + this.Port);			
		}
	}
	
	private void updatePostTable() {
		//PostTable.addAllPosts(Core.getPosts(new Date(0L)));
	}
	
	private void updatePeerTable() {
		PeerTable.addAllPeers(Core.getPeerList());
	}

	@Override
	public void SignatureRequest(final Peer p) {
		boolean okforwindow = false;
		if (p != null && p.getLocation() != null && p.getIntroduction() != null) {
			synchronized (SignaturesRequested) {
				if (!SignaturesRequested.contains(p)) {
					okforwindow = true;
					SignaturesRequested.add(p);
				}
			}
		}
		if (okforwindow) {
			EventQueue.invokeLater(new Runnable() {
				public void run() {
					try {
						SignRequestDialog s = new SignRequestDialog(Core, p);
						s.setVisible(true);
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
			});			
		}
	}

	@Override
	public void newPostReceived(final LocalPost postlist) {
//		EventQueue.invokeLater(new Runnable() {
//			public void run() {
//				PostTable.addPost(postlist);
//			}
//		});					
	}

	@Override
	public void newPeerReceived(final Peer peerlist) {
		EventQueue.invokeLater(new Runnable() {
			public void run() {
				PeerTable.addPeer(peerlist);
			}
		});			
	}

	@Override
	public void newFileDownloaded(final LocalFileReference filelist) {
	}

	@Override
	public void connectionFailure(final Peer p) {
		EventQueue.invokeLater(new Runnable() {
			public void run() {
				ConTable.removeConnection(p);
			}
		});			
		
	}

	@Override
	public void downloadFailed(final Object dig) {
		
	}

	@Override
	public void downloadStatusUpdate(File saveas, String dig, long totalsize, long amountcomplete, int pending, boolean paused, boolean inprogress, int priority) {
		// TODO Auto-generated method stub
	}

	public JTable getDownloadsTable() {
		return DownloadsTable;
	}

	@Override
	public void connectionEvent(final ConnectionUpdateInterface con) {
		EventQueue.invokeLater(new Runnable() {
			public void run() {
				//ConTable.addNewConnection(p);
				ConTable.connectionUpdate(con);
			}
		});					
	}
	public JCheckBox getAutoSigCheckBox() {
		return AutoSigCheckBox;
	}
}
