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.BorderLayout;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.util.Properties;

import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import net.miginfocom.swing.MigLayout;
import javax.swing.JLabel;
import javax.swing.JTextField;
import javax.swing.JCheckBox;

import org.ourfilesystem.com.OFSConnector;
import org.ourfilesystem.com.OFSI2PConnector;
import org.ourfilesystem.com.OFSI2PServerSocket;
import org.ourfilesystem.com.OFSServerSocket;
import org.ourfilesystem.com.SimpleServerSocket;
import org.ourfilesystem.com.SimpleConnector;
import javax.swing.JSeparator;

public class NetworkConfigDialog extends JDialog {
	private static final long serialVersionUID = 1L;
	
	private static String I2PKey       = "USEI2P";
	private static String ProxyAddrKey = "PROXYADDR";
	private static String ProxyPortKey = "PROXYPORT";
	private static String ProxyUseKey  = "PROXYUSE";
	private static String PeerPortKey  = "PEERPORT";
	
	private final JPanel contentPanel = new JPanel();
	private JTextField textField;
	private JTextField textField_1;
	private JCheckBox useproxy;
	
	private boolean SimpleStarted;
	private boolean I2PStarted;
	
	private boolean UseI2P;
	private boolean UseProxy;
	private String ProxyAddr;
	private int ProxyPort;
	private int PeerPort;
	
	private SimpleServerSocket SimpleServer;
	private SimpleConnector SimpleConnector;
	private OFSI2PServerSocket I2PServer;
	private OFSI2PConnector I2PConnector;
	
	private String BaseDir;
	
	private SimpleGUI GUI;
	
	private File ConfigFile;
	private JTextField peerPort;
	private JCheckBox UseI2PBox;
	
	private boolean LoadConfig() {
		boolean loadedok = false;
		Properties p = new Properties();
		if (ConfigFile.exists()) {
			try {
				FileInputStream fis = new FileInputStream(ConfigFile);
				p.load(fis);
				fis.close();
				loadedok = true;
			} catch (Exception e) {
				e.printStackTrace();
				throw new RuntimeException("Could not read the proxy configuration file!");
			}		
		}
		UseI2P = Boolean.valueOf(p.getProperty(I2PKey, "false"));
		UseProxy = Boolean.valueOf(p.getProperty(ProxyUseKey, "true"));
		ProxyAddr = p.getProperty(ProxyAddrKey, "127.0.0.1");
		ProxyPort = Integer.valueOf(p.getProperty(ProxyPortKey, "9050"));
		PeerPort = Integer.valueOf(p.getProperty(PeerPortKey, "9140"));
		return loadedok;
	}
	
	private void SaveConfig() {
		Properties p = new Properties();
		p.setProperty(I2PKey, Boolean.toString(UseI2P));
		p.setProperty(ProxyUseKey, Boolean.toString(UseProxy));
		p.setProperty(ProxyAddrKey, ProxyAddr);
		p.setProperty(ProxyPortKey, Integer.toString(ProxyPort));
		p.setProperty(PeerPortKey, Integer.toString(PeerPort));
		try {
			FileOutputStream fos = new FileOutputStream(ConfigFile);
			p.store(fos, "proxy configuration for ofs");
			fos.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	public OFSServerSocket getServerSocket() {
		if (SimpleServer == null) {
			try {
				SimpleServer = new SimpleServerSocket(new ServerSocket(PeerPort));
			} catch (IOException e) {
				e.printStackTrace();
			}
			return SimpleServer;
		}
		return SimpleServer;
	}
	
	public OFSConnector getConnector() {
		if (SimpleConnector == null) {
			SimpleConnector = new SimpleConnector(UseProxy, ProxyAddr, ProxyPort);
		}
		SimpleConnector.setProxyAddr(ProxyAddr);
		SimpleConnector.setUseProxy(UseProxy);
		SimpleConnector.setProxyPort(ProxyPort);
		return SimpleConnector;
	}

	/**
	 * Create the dialog.
	 */
	public NetworkConfigDialog(SimpleGUI gui, String bd) {
		GUI = gui;
		SimpleStarted = false;
		I2PStarted = false;
		BaseDir = bd;
		File basedir = new File(BaseDir);
		if (!basedir.exists()) {
			basedir.mkdirs();
		}
		ConfigFile = new File(BaseDir + File.separator + "proxy.cfg");
		boolean justgo = LoadConfig();
		
		setTitle("Network Configuration");
		setBounds(100, 100, 450, 300);
		getContentPane().setLayout(new BorderLayout());
		contentPanel.setBorder(new EmptyBorder(5, 5, 5, 5));
		getContentPane().add(contentPanel, BorderLayout.CENTER);
		contentPanel.setLayout(new MigLayout("", "[][grow]", "[][][][][][][][][][][]"));
		{
			UseI2PBox = new JCheckBox("Use I2P");
			contentPanel.add(UseI2PBox, "cell 1 2");
			UseI2PBox.setSelected(UseI2P);
		}
		{
			JSeparator separator = new JSeparator();
			contentPanel.add(separator, "cell 1 5");
		}
		{
			JLabel lblSocksProxyAddress = new JLabel("SOCKS Proxy address");
			contentPanel.add(lblSocksProxyAddress, "cell 0 6,alignx trailing");
		}
		{
			textField = new JTextField();
			contentPanel.add(textField, "cell 1 6,growx");
			textField.setColumns(10);
			textField.setText(getProxyAddr());
		}
		{
			JLabel lblSocksProxyPort = new JLabel("SOCKS Proxy Port");
			contentPanel.add(lblSocksProxyPort, "cell 0 7,alignx trailing");
		}
		{
			textField_1 = new JTextField();
			contentPanel.add(textField_1, "cell 1 7,growx");
			textField_1.setColumns(10);
			textField_1.setText(Integer.toString(getProxyPort()));
		}
		{
			useproxy = new JCheckBox("Enable SOCKS Proxy");
			useproxy.setSelected(isUseProxy());
			contentPanel.add(useproxy, "cell 1 8");
		}
		{
			JLabel lblPeerPort = new JLabel("Peer Port");
			contentPanel.add(lblPeerPort, "cell 0 9,alignx trailing");
		}
		{
			peerPort = new JTextField();
			contentPanel.add(peerPort, "cell 1 9,growx");
			peerPort.setColumns(10);
			peerPort.setText(Integer.toString(getPeerPort()));
		}
		setEditable();
		UseI2PBox.addChangeListener(new ChangeListener() {
			@Override
			public void stateChanged(ChangeEvent arg0) {
				setEditable();
			}
		});
		{
			JPanel buttonPane = new JPanel();
			buttonPane.setLayout(new FlowLayout(FlowLayout.RIGHT));
			getContentPane().add(buttonPane, BorderLayout.SOUTH);
			{
				JButton okButton = new JButton("OK");
				okButton.setActionCommand("OK");
				okButton.addActionListener(new ActionListener() {
					@Override
					public void actionPerformed(ActionEvent a) {
						go();
					}
				});
				buttonPane.add(okButton);
				getRootPane().setDefaultButton(okButton);
			}
		}
		if (justgo) {
			setVisible(false);
			go(); 
		}
		else { setVisible(true); }
	}
	
	private void setEditable() {
		useproxy.setEnabled(!UseI2PBox.isSelected());
		textField.setEditable(!UseI2PBox.isSelected());
		textField_1.setEditable(!UseI2PBox.isSelected());
		peerPort.setEditable(!UseI2PBox.isSelected());
	}
	
	private void go() {
		if (UseI2PBox.isSelected()) {
			UseI2P = true;
			goI2P();
		}
		else {
			UseI2P = false;
			if (!useproxy.isSelected()) {
				UseProxy = false;
				goSimple();
			}
			else {
				String addr = textField.getText();
				if (!addr.matches("\\S+")) {
					JOptionPane.showMessageDialog(contentPanel, "Improper proxy address.");
				}
				else {
					String portstr = textField_1.getText();
					if (!portstr.matches("\\d+")) {
						JOptionPane.showMessageDialog(contentPanel, "Proxy port must be a number.");
					}
					else {
						try {
							ProxyPort = Integer.valueOf(portstr);
							ProxyAddr = addr;
							UseProxy = true;
							goSimple();
						}
						catch (Exception e) {
							JOptionPane.showMessageDialog(contentPanel, "The proxy port seems to be invalid.");
						}
					}
				}
			}
		}
	}
	
	public void goI2P() {
		SaveConfig();
		if (!SimpleStarted) {
			if (I2PServer == null) {
				try {
					I2PServer = new OFSI2PServerSocket(BaseDir + File.separator + "i2pkey.dat");
					I2PConnector = (OFSI2PConnector) I2PServer.getOFSConnector();
					GUI.InitPeer(I2PServer, I2PConnector, false);
					GUI.setLocation(I2PServer.getMyLocation());
				} catch (Exception e) {
					e.printStackTrace();
					JOptionPane.showMessageDialog(contentPanel, "Sorry, I couldn't get I2P.  Did you install with I2P?");
				}
				I2PStarted = true;
			}
		}
		else {
			JOptionPane.showMessageDialog(contentPanel, "You will have to restart for your changes to take effect.");			
		}
		setVisible(false);
	}
	
	public void goSimple() {
		SaveConfig();
		if (!I2PStarted) {
			try {
				PeerPort = Integer.valueOf(peerPort.getText());
				if (SimpleServer == null) {
					SimpleServer = new SimpleServerSocket(new ServerSocket(PeerPort));
					SimpleConnector = new SimpleConnector(UseProxy, ProxyAddr, ProxyPort);
					GUI.InitPeer(SimpleServer, SimpleConnector, true);
				}
			}
			catch (Exception e) {
				JOptionPane.showMessageDialog(contentPanel, "The peer port seems to be invalid.");
				return;
			}
			SimpleConnector.setProxyAddr(ProxyAddr);
			SimpleConnector.setProxyPort(ProxyPort);
			SimpleConnector.setUseProxy(UseProxy);
			if (SimpleStarted) {
				JOptionPane.showMessageDialog(contentPanel, "If you have changed your peer port you will need to restart.");			
			}
			SimpleStarted = true;
		}
		else {
			JOptionPane.showMessageDialog(contentPanel, "You will have to restart for your changes to take effect.");			
		}
		setVisible(false);
	}

	public boolean isUseProxy() {
		return UseProxy;
	}

	public void setUseProxy(boolean useProxy) {
		UseProxy = useProxy;
	}

	public String getProxyAddr() {
		return ProxyAddr;
	}

	public void setProxyAddr(String proxyAddr) {
		ProxyAddr = proxyAddr;
	}

	public int getProxyPort() {
		return ProxyPort;
	}

	public void setProxyPort(int proxyPort) {
		ProxyPort = proxyPort;
	}

	public int getPeerPort() {
		return PeerPort;
	}
	
	public JCheckBox getUseI2PBox() {
		return UseI2PBox;
	}
}
