/*
 * %W% %E% Sun Microsystems, Inc.
 *
 * Copyright (c) 1998 Sun Microsystems, Inc. All Rights Reserved.
 *
 * Permission to use, copy, modify, and distribute this software
 * and its documentation for NON-COMMERCIAL purposes and without
 * fee is hereby granted provided that this copyright notice
 * appears in all copies. Please refer to the file "copyright.html"
 * for further important copyright and licensing information.
 *
 * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF
 * THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
 * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
 * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR
 * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
 * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
 */

import java.io.*;
import java.lang.*;
import java.net.*;
import java.util.*;
import java.rmi.*;

import net.jini.discovery.*;
import net.jini.event.*;
import net.jini.entry.Entry;
import net.jini.lookup.*;
import net.jini.lookup.entry.ServiceInfo;

import com.sun.jini.lookup.entry.BasicServiceType;

public class JiniPrintProxy implements Runnable {

    final static int	COMMAND_SOCKET = PrintRemote.SOCKET + 1;

    JiniPrintProxy	currentInstance = null;
    private ServiceTemplate servTmpl;
    private LookupDiscovery disco;
    
    private ServiceRegistrar lookup;                       
    private LookupLocator locator;    

    Socket		remoteSocket;
    Socket		commandSocket;
    ServerSocket	remoteServerSocket;
    ServerSocket	commandServerSocket;

    PrintRemote		service = null;
   
    public JiniPrintProxy() {
	Thread		thread;
	ServiceMatches	matches;

	if (currentInstance == null) {

	    currentInstance = this;

	    try {
		// Create new SecurityManager if none exists
		if (System.getSecurityManager()==null) {
		    System.setSecurityManager(new RMISecurityManager());
		}
	    } catch (Exception e) {
		System.out.println("lookup error: "+e);
		return;
	    }

	    // Create this new BasicServiceType for PrintService
	    BasicServiceType basicServiceType = new 
		BasicServiceType("PrintService");

	    Entry[] entry = new Entry[] { basicServiceType };

	    // Create a new ServiceTemplate for PrintService
	    servTmpl = new ServiceTemplate(null, new Class[0], entry);
 
	    // Error if ServiceTemplate not created correctly
	    if (servTmpl==null) {
		System.out.println("servTmpl is null");
		return;
	    }

	    System.out.println("JiniPrintProxy: Looking up lookup service");

	    try {
		locator = new LookupLocator("jini://talon.eng.sun.com");
		lookup = locator.getRegistrar();
       	
		if (lookup == null) 
		    System.out.println("JiniPrintProxy: lookup is null");

	    } catch (Exception e) {
		System.out.println("JiniPrintProxy locator error: "+e);
		return;
	    }

	    System.out.println("JiniPrintProxy: Checking for services");

	    try {
		// Lookup lookup services with timeout of 1000 milliseconds
		matches = lookup.lookup(servTmpl, 1000);

		System.out.println("JiniPrintProxy totalMatches: "+ 
				   matches.totalMatches+"\n");

		for (int i=0; i<matches.totalMatches; i++) {
		    System.out.println("serviceID="+
				       matches.items[i].serviceID);
		    System.out.println("service="+matches.items[i].service);
		    service = (PrintRemote)matches.items[i].service;

		    System.out.println("host: "+locator.getHost());
		    System.out.println("port: "+locator.getPort());    	    
		    System.out.println("");    	    
		}
    	    
	    } catch (Exception e) {
		try {
		    remoteSocket.close();
		} catch (Exception ex) {
		    ex.printStackTrace();
		}
		e.printStackTrace();
	    }
	}

	// Start separate thread for command socket
	thread = new Thread(this);
	thread.start();

	// Start remote socket
	activateRemoteSocket();
    }   

    private void activateRemoteSocket() {
	OutputStream	outputStream;
	ObjectOutputStream	objOutStream;

    	try {

	    remoteServerSocket = new ServerSocket(PrintRemote.SOCKET);
	     
	    // Loop to accept new connections and serve PrintRemote object
	    while (true) {
		System.out.println(">Waiting for remoteSocket request...");
		remoteSocket = remoteServerSocket.accept();
		outputStream = remoteSocket.getOutputStream();
		objOutStream = new ObjectOutputStream(outputStream);
		objOutStream.writeObject(service);
		System.out.println(">Remote object written...");
	    }
	
	} catch (Exception e) {
	    try {
		remoteSocket.close();
	    } catch (Exception ex) {
		ex.printStackTrace();
	    }
    	    e.printStackTrace();
    	}
    }

    private void activateCommandSocket() {
	InputStream inputStream;
	OutputStream outputStream;
	BufferedReader bufferedReader;
	BufferedWriter bufferedWriter;
	String command;
	String retStr;

    	try {

	    commandServerSocket = new ServerSocket(COMMAND_SOCKET);
	     
	    // Loop to accept new connections and serve PrintRemote object
	    while (true) {
		System.out.println(">Waiting for commandSocket request...");
		commandSocket = commandServerSocket.accept();
		System.out.println(">Accepted commandSocket request");
		inputStream = commandSocket.getInputStream();
		outputStream = commandSocket.getOutputStream();
		bufferedReader
		    = new BufferedReader(new InputStreamReader(inputStream));
		bufferedWriter
		    = new BufferedWriter(new OutputStreamWriter(outputStream));
		command = bufferedReader.readLine();
		System.out.println(">commandSocket command: "+command);
		retStr = executeCommand(command);
		System.out.println(">commandSocket retStr: "+retStr);
		if (retStr != null) {
		    System.out.println(">commandSocket writing retStr");
		    bufferedWriter.write(retStr, 0, retStr.length());
		    System.out.println(">commandSocket flushing retStr");
		    bufferedWriter.flush();
		    System.out.println(">commandSocket closing retStr");
		    bufferedWriter.close();
		}
	    }
	
	} catch (Exception e) {
	    try {
		commandSocket.close();
	    } catch (Exception ex) {
		ex.printStackTrace();
	    }
    	    e.printStackTrace();
    	}
    }

    private String executeCommand(String command) {
	StringTokenizer stringToken = new StringTokenizer(command, ":");
	String commandStr = null;
	String printerStr = null;
	String retStr = null;

	if (stringToken.hasMoreTokens()) {
	    commandStr = stringToken.nextToken();
	}

	if (commandStr != null) {

	    if (stringToken.hasMoreTokens()) {
		printerStr = stringToken.nextToken();
	    }
	    
	    if (printerStr != null) {
		try {
		    if (commandStr.equals("print")) {
			String fileStr = null;

			if (stringToken.hasMoreTokens()) {
			    fileStr = stringToken.nextToken();
			}		    
		    
			if (fileStr != null) {
			    retStr = service.print(printerStr, fileStr);
			}
		    } else if (commandStr.equals("checkQueue")) {
			if (printerStr != null) {
			    retStr = service.checkQueue(printerStr);
			}
		    }
		} catch (RemoteException e) {
		    e.printStackTrace();
		}
	    }
	}

	return(retStr);
    }

    public static void main (String[] args) {
	JiniPrintProxy jiniPrintProxy = new JiniPrintProxy();
    }

    public void run() {
	activateCommandSocket();
    }

}

