package nfjs.jmdns;

import java.awt.BorderLayout;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.net.ConnectException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import javax.jmdns.ServiceEvent;
import javax.jmdns.ServiceInfo;
import javax.jmdns.ServiceListener;
import javax.swing.JEditorPane;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.SwingUtilities;

/*
 * A simple demo that shows searching for a particular mDNS service instance
 * pattern and responding to finding them.
 * 
 */
public class LocalHttpBrowser extends JFrame implements ServiceListener
{
	private JLabel statusLabel;
	
	private ZeroConfServiceLocator zcsl;
	private Set services;
	private JTabbedPane tabs;
	private Map nameURLMap = new HashMap();
	
	LocalHttpBrowser() {
		super( "Local _http._tcp.local. browser" );
		zcsl = new ZeroConfServiceLocator();
		zcsl.searchForService( "_http._tcp.local.", this );
		services = new HashSet();
		
		buildUI();
	}
	
	protected void buildUI() {
		JPanel panel = new JPanel( new BorderLayout() );
		tabs = new JTabbedPane();
		panel.add( tabs, BorderLayout.CENTER );
		statusLabel = new JLabel("Searching for HTTP instances...");
		panel.add( statusLabel, BorderLayout.SOUTH );
		getContentPane().add( panel );
	}
	
	protected void removeTab( String name ) {
		for( int i = 0; i < tabs.getComponentCount(); i++ ) {
			if( tabs.getTitleAt( i ).equals( name ) ) {
				tabs.remove( i );
				break;
			}
		}
	}
	
	protected void buildBrowser( String name, String url ) {

		try {
			JEditorPane displayPane = new JEditorPane();
			JScrollPane jsp = new JScrollPane( displayPane );
			displayPane.setEditable( false );
			tabs.add( name, jsp );

			boolean done = false;
			
			// Sometimes we might be alerted to the new service
			// before it is ready to serve up the goodies, plan
			// for failure and recover. n.b. We really shouldn't
			// be sleeping for up to 2 seconds on the UI thread
			// but it's fine enough for a demo.
			
			for( int i = 0; i < 10 && !done; i++ ) {
				try {
					displayPane.setPage( url );
					statusLabel.setText( "Searching for HTTP instances..." );
					done = true; 
				} catch( ConnectException ce ) {
					statusLabel.setText("Retrying connection to: " + url );
					try {
						Thread.sleep( 200 );
					} catch( InterruptedException ie ) {
					}
				}
			}

		} catch( Exception e ) {
			e.printStackTrace();
		}
	}


	/**
	 * @param args
	 */
	public static void main(String[] args) {

		LocalHttpBrowser lhb = new LocalHttpBrowser();
		lhb.setLocation( 200, 200 );
		lhb.addWindowListener( lhb.new BrowserWindowAdapter() );
		lhb.setSize( 300, 500 );
		lhb.show();
	}
	
	protected void addService( ServiceEvent event ) {
		ServiceInfo si = event.getInfo();
		final String name = event.getName();
		final String url;
		
		if( si == null ) {
			synchronized( nameURLMap ) {
				url = ( String ) nameURLMap.get( name );
				
				if( ( url == null ) || services.contains( url ) ) {
					return;
				}
			}
		
		} else {
			// Skip over any IPv6 addresses if we see any
			if( si.getHostAddress().indexOf(":") != -1 ) {
				return;
			}
			
			url = "http://" + si.getHostAddress() + ":" + si.getPort() + si.getPropertyString("path");
			
			synchronized( nameURLMap ) {
				if( services.contains( url ) ) {
					return;
				}
				
				nameURLMap.put( name, url );
				services.add( url );
			}
		}
		
		SwingUtilities.invokeLater( new Runnable() {
			public void run() {
				buildBrowser( name, url );
			}
		} );
	}
	

	public void serviceTypeAdded(ServiceEvent event) {
	}

	public void serviceAdded(ServiceEvent event) {
		// While this may seem like the right place to add the
		// tab, we have only been made aware of the service instance
		// it hasn't yet been resolved
		
		addService( event );
	}


	public void serviceRemoved(ServiceEvent event) {
		final String name = event.getName();
		
		synchronized( nameURLMap ) {
			String url = ( String ) nameURLMap.get( name );
			services.remove( url );
		}
		
		SwingUtilities.invokeLater( new Runnable() {
			public void run() {
				removeTab( name );
			}
		});
	}

	public void serviceResolved(ServiceEvent event) {
		addService( event );
	}
	
	class BrowserWindowAdapter extends WindowAdapter {

		public void windowClosing(WindowEvent arg0) {
			LocalHttpBrowser.this.zcsl.shutdown();
			System.exit( 0 );
		}
	}
}
