/*
 * Created on 1 Nov 2006
 * Created by Paul Gardner
 * Copyright (C) Azureus Software, Inc, All Rights Reserved.
 *
 * 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 */


package com.aelitis.azureus.core.networkmanager.admin;

import java.io.IOException;
import java.net.InetAddress;
import java.nio.channels.UnsupportedAddressTypeException;

import org.gudy.azureus2.core3.util.IndentWriter;

import com.aelitis.azureus.core.AzureusCore;
import com.aelitis.azureus.core.networkmanager.admin.impl.NetworkAdminImpl;

public abstract class 
NetworkAdmin 
{
	private static NetworkAdmin	singleton;
	
	public static final String PR_NETWORK_INTERFACES	= "Network Interfaces";
	public static final String PR_DEFAULT_BIND_ADDRESS	= "Default Bind IP";
	public static final String PR_AS					= "AS";
	
	public static final int			IP_PROTOCOL_VERSION_AUTO		= 0;
	public static final int			IP_PROTOCOL_VERSION_REQUIRE_V4	= 1;
	public static final int			IP_PROTOCOL_VERSION_REQUIRE_V6	= 2;
	
	public static final String[]	PR_NAMES = {
		PR_NETWORK_INTERFACES,
		PR_DEFAULT_BIND_ADDRESS,
		PR_AS
	};
	
	public static synchronized NetworkAdmin
	getSingleton()
	{
		if ( singleton == null ){
			
			singleton = new NetworkAdminImpl();
		}
		
		return( singleton );
	}

	public InetAddress getSingleHomedServiceBindAddress() {return getSingleHomedServiceBindAddress(IP_PROTOCOL_VERSION_AUTO);}
	
	/**
	 * @throws UnsupportedAddressTypeException when no address matching the v4/v6 requirements is found, always returns an address when auto is selected
	 */
	public abstract InetAddress 
	getSingleHomedServiceBindAddress(int protocolVersion) throws UnsupportedAddressTypeException;
	
	public abstract InetAddress[]
	getMultiHomedServiceBindAddresses(boolean forNIO);
	
	public abstract InetAddress
	getMultiHomedOutgoingRoundRobinBindAddress(InetAddress target);
	
	public abstract String
	getNetworkInterfacesAsString();
	
	public abstract InetAddress[]
	getAllBindAddresses(
		boolean	include_wildcard );

	public abstract InetAddress
	guessRoutableBindAddress();
	
		/**
		 * Returns the list of current addresses that can successfully be bound
		 * to with an ephemeral port
		 * @return
		 */
	
	public abstract InetAddress[]
	getBindableAddresses();
	
	public abstract int
	getBindablePort(
		int		preferred_port )
	
		throws IOException;
	
	public abstract boolean
	mustBind();
	
	public abstract boolean
	hasMissingForcedBind();
	
	public abstract NetworkAdminNetworkInterface[]
	getInterfaces();
	
	public abstract boolean
	hasIPV4Potential();

	public abstract boolean
	isIPV6Enabled();
	
	public boolean hasIPV6Potential() {return hasIPV6Potential(false);}
	
	public abstract boolean
	hasIPV6Potential(boolean forNIO);
	
	public abstract NetworkAdminProtocol[]
	getOutboundProtocols(
		AzureusCore azureus_core);
	
	public abstract NetworkAdminProtocol[]
	getInboundProtocols(
		AzureusCore azureus_core );
	
	public abstract NetworkAdminProtocol
	createInboundProtocol(
		AzureusCore 	azureus_core,
		int				type,
		int				port );
		
	public abstract InetAddress
	testProtocol(
		NetworkAdminProtocol	protocol )
	
		throws NetworkAdminException;
	
	public abstract NetworkAdminSocksProxy
	createSocksProxy(
		String		host,
		int			port,
		String		username,
		String		password );
	
	public abstract boolean
	isSocksActive();
	
	public abstract NetworkAdminSocksProxy[]
	getSocksProxies();
	
	public abstract NetworkAdminHTTPProxy
	getHTTPProxy();
	
	public abstract NetworkAdminNATDevice[]
	getNATDevices(
			AzureusCore azureus_core);
	
		/**
		 * Only call if the supplied address is believed to be the current public address
		 * @param address
		 * @return
		 * @throws NetworkAdminException
		 */
		 
	public abstract NetworkAdminASN
	lookupCurrentASN(
		InetAddress		address )
	
		throws NetworkAdminException;
	
	public abstract NetworkAdminASN
	getCurrentASN();
	
		/**
		 * ad-hoc query
		 * @param address
		 * @return
		 * @throws NetworkAdminException
		 */
	
	public abstract NetworkAdminASN
	lookupASN(
		InetAddress		address )
	
		throws NetworkAdminException;
	
	public abstract void
	lookupASN(
		InetAddress					address,
		NetworkAdminASNListener		listener );
	
	
	public abstract String
	classifyRoute(
		InetAddress					address );
	
	public abstract boolean
	canTraceRoute();
	
	public abstract void
	getRoutes(
		final InetAddress					target,
		final int							max_millis,
		final NetworkAdminRoutesListener	listener )
	
		throws NetworkAdminException;
	
	public abstract boolean
	canPing();
	
	public abstract void
	pingTargets(
		final InetAddress					target,
		final int							max_millis,
		final NetworkAdminRoutesListener	listener )
	
		throws NetworkAdminException;
	
	public abstract InetAddress
	getDefaultPublicAddress();
	
	public abstract InetAddress
	getDefaultPublicAddress(
		boolean	peek );
	
	public abstract InetAddress 
	getDefaultPublicAddressV6();
	
	public abstract InetAddress 
	getDefaultPublicAddressV6(
		boolean	peek );

	public abstract boolean	hasDHTIPV6();
	
	public abstract void
	addPropertyChangeListener(
		NetworkAdminPropertyChangeListener	listener );
	
	public abstract void
	addAndFirePropertyChangeListener(
		NetworkAdminPropertyChangeListener	listener );

	public abstract void
	removePropertyChangeListener(
		NetworkAdminPropertyChangeListener	listener );
	
	public abstract void
	runInitialChecks(
			AzureusCore azureus_core);
	
	public abstract void
	logNATStatus(
		IndentWriter		iw );
	
	public abstract void
	generateDiagnostics(
		IndentWriter		iw );
}
