package server;

import java.io.IOException;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.nio.channels.Channel;
import java.util.Vector;

import common.Common;
import common.CommonCmdLineParser;
import common.CommonOptions;

public class ServerCmdLineParser extends CommonCmdLineParser {
	private Option dnsAddr;
	private Option dnsPort;
	private Option fwdAddr;
	private Option fwdPort;
	private Option logFile;
	private Option idleTimeout;
	
	public ServerCmdLineParser() {
		dnsAddr = addStringOption("dns-address");
		dnsPort = addIntegerOption("dns-port");
		fwdAddr = addStringOption("forward-address");
		fwdPort = addIntegerOption("forward-port");
		logFile = addStringOption("log-file");
		idleTimeout = addIntegerOption("idle-timeout");
	}

	@SuppressWarnings("unchecked")
	public ServerOptions parseCmdLine(String args[]) {
		CommonOptions commonOpts = super.parseCmdLine(args);
		if (commonOpts == null) {
			return null;
		}
		try {
			ServerOptions result = new ServerOptions();
			result.domain = commonOpts.domain;
			result.mtu = commonOpts.mtu;
			result.logLevel = commonOpts.logLevel;
			Vector listenStrings = getOptionValues(dnsAddr);
			for (Object listenStringObj : listenStrings) {
				result.listenAddrs.add(InetAddress.getByName((String)listenStringObj));
			}
			result.listenPorts.addAll(getOptionValues(dnsPort));
			String forwardAddr = (String)getOptionValue(fwdAddr);
			if (forwardAddr != null) {
				result.forwardAddr = InetAddress.getByName(forwardAddr);
			}
			Integer forwardPort = (Integer)getOptionValue(fwdPort);
			if (forwardPort == null) {
				result.forwardPort = -1;
			} else {
				result.forwardPort = forwardPort;
			}
			Integer idleTimeout = (Integer)getOptionValue(this.idleTimeout);
			if (idleTimeout == null)
				result.idleTimeout = -1;
			else
				result.idleTimeout = idleTimeout;
			result.logFile = (String)getOptionValue(this.logFile);
					
			
			setDefaults(result);
			
			if (result.domain == null) {
				return null;
			}
			if (result.forwardPort <= 0) {
				return null;
			}
			
			return result;
		} catch (UnknownHostException e1) {
			e1.printStackTrace();
			return null;
		}
	}

	private static void setDefaults(ServerOptions result) throws UnknownHostException {
		
		if (result.forwardAddr == null) {
			result.forwardAddr = Inet4Address.getByAddress(new byte[]{ 127, 0, 0, 1});
		}
		if (result.mtu <= 0) {
			result.mtu = Common.DEFAULT_MTU;
		}

		// Check for any inherited channels
		Channel chan = null;
		try {
			chan = System.inheritedChannel();
		} catch (IOException e) {}
		
		// Only add the default if we haven't inherited a channel.
		if (chan == null)
		{
			if (result.listenPorts.size() == 0) {
				result.listenPorts.add(Common.DEFAULT_DNS_PORT);
			}
			if (result.listenAddrs.size() == 0) {
				result.listenAddrs.add(InetAddress.getByName(Server.DEFAULT_ADDR));
			}
		} else {
			// Don't log to stdout by default if there is a channel (it might be being redirected to the channel)
			if (result.logFile == null) {
				result.logFile = "/tmp/tcp-over-dns";
			}
		}
	}

	public void printUsage() {
		System.out.println("Usage: java -jar " + Server.SERVER_NAME + ".jar --domain tnl.example.com --forward-port N <options>");
		System.out.println("Available options:");
		System.out.println("--domain          a.b.com  The domain name that the tunnel is sitting behind.");
		System.out.println("                           This must match the client's domain argument.");
		System.out.println("--forward-port    portNum  The port of the service which we are exporting, it");
		System.out.println("                           will be provided through the tunnel to the clients.");
		System.out.println("--forward-address a.b.c.d  The address of the service which we are exporting,");
		System.out.println("                           Defaults to localhost.");
		System.out.println("--dns-port        portNum  The port on which the server should listen for dns");
		System.out.println("                           queries. Defaults to port " + Common.DEFAULT_DNS_PORT + ".");
		System.out.println("--dns-address     a.b.c.d  The address on which to listen for dns queries.");
		System.out.println("                           Defaults to all addresses.");
		System.out.println("--mtu             bytes    Set the udp maximum MTU. Defaults to " + Common.DEFAULT_MTU + ".");
		System.out.println("--log-level       0-5      The amount of information to display. Defaults to 3.");
		System.out.println("                           0: Display nothing.");
		System.out.println("                           1: Display errors.");
		System.out.println("                           2: Display errors, warnings.");
		System.out.println("                           3: Display errors, warnings, general information.");
		System.out.println("                           4: Spam.");
		System.out.println("                           5: Megaspam.");
	}
}
