import OdbToolsApplic.*;           // The package containing our stubs.
import org.omg.CosNaming.*;  // HelloClient will use the naming service.
import org.omg.CORBA.*;      // All CORBA applications need these classes.
import java.io.*;
import java.util.StringTokenizer;

import java.net.InetAddress;


public class  OdbToolsClient {

   /**
    *   Legge un file in una stringa
    *
    *  @param fileName Nome del file da leggere
    */
   private static  String leggiFile(String fileName) {
      FileInputStream fis;
      String rv;
      byte buf[] = new byte[500];
      int buf_l;
      // ----
      rv = "";
      try{
	 fis = new FileInputStream(fileName);
	 while ((buf_l =  fis.read(buf)) >= 0) {
	    rv = rv + new String(buf).substring(0, buf_l);
	 }
	 fis.close();
      } catch(Exception e) {
	 System.out.println("ERROR : " + e);
	 e.printStackTrace(System.out);
      }  
      return rv;
   }

   /**
    *   Scrive il contenuto di una stringa in un file
    *
    *  @param fileName Nome del file in cui scrivere
    *  @param s        stringa da scrivere
    */
   private static  void scriviFile(String fileName, String s) {
      FileOutputStream fos;
      int buf_l;
      // ----
      try{
	 fos = new FileOutputStream(fileName);
	 fos.write(s.getBytes());
	 fos.close();
      } catch(Exception e) {
	 System.out.println("ERROR : " + e);
	 e.printStackTrace(System.out);
      }  
   }

   /**  
    *   main routine <br>
    *   <br>
    *
    *   Realizza un interprete di comandi interattivo
    *   attraverso il quale e' possibile testare tutte le possibilita'
    *   dell'oggetto server.
    *
    */
   public static void main(String args[])   {
      ORB orb;
      org.omg.CORBA.Object objRef;    // Get the root naming context
      NamingContext ncRef;
      NameComponent nc;
      OdbToolsFactory factoryObj;     // reference all'oggetto factory
      OdbTools myRef;                 // reference all'oggetto servant
      String hn;
      int i;
      String serverName = "odbt";
      // -----
      try{
	 //
	 // Create and initialize the ORB
	 System.out.println(" init string: ");
	 for (i=0; i<args.length; i++)
	   System.out.println("  " + args[i]);
	 System.out.println(" - Creating orb...");
	 orb = ORB.init(args, null);
	 //
	 // Get the root naming context
	 System.out.println(" - resolving naming...");
	 objRef = orb.resolve_initial_references("NameService");
	 System.out.println(" - narrowing naming object...");
	 ncRef = NamingContextHelper.narrow(objRef);
	 //
	 // Resolve the object reference in naming
	 System.out.println(" - search for ODB-Tools CORBA object...");
	 nc = new NameComponent(serverName, "");
	 System.out.println(" - creating path...");
	 NameComponent path[] = {nc};
	 System.out.println(" - narrowing ODB-Tools object...");
	 factoryObj = OdbToolsFactoryHelper.narrow(ncRef.resolve(path));
	 System.out.println(" - CORBA connection ok.");
	 // determino il nome dell'Host
	 try {
	    hn = "" + InetAddress.getLocalHost();
	 } catch(Exception e1) {
	    System.out.println(e1);
	    e1.printStackTrace(System.out);
	    hn = "Unknow Host";
	 }
	 myRef = factoryObj.newServant("DemoClient " + hn);
	 //
	 // Call the server object and print results
	 //
	 String sin = "";
	 char c;
	 BufferedReader bris = 
	    new BufferedReader(new InputStreamReader(System.in));
	 System.out.println(" -- type a command ('h' to get help) -- ");
	 while ( ! ( 
		    sin.equals("exit") || 
		    sin.equals("x") ||
		    sin.equals("quit") ||
		    sin.equals("q") 
		    ) ) {
	    if (sin.length() > 0) {
	       //
	       // Interpreto il comando in sin
	       //
	       sin = sin + " ";
	       if (sin.substring(0,1).equals("h") ) {
		  //
		  // Help
		  // 
		  //
		  System.out.println("\n - ODB-Tools CORBA first client -\n");
		  System.out.println("command allowed:");
		  System.out.println("  x (exit)    quit client");
		  System.out.println("  q (quit)    quit client");
		  System.out.println("  h (help)    this screen");
		  System.out.println("  m fileName  show local file content");
		  System.out.println("  n           create a new " +
				     "servant object");
		  System.out.println("  k           kill current " +
				     "servant object");
		  System.out.println("  t fileIn [fileOut] "+
				     "Traduce il file odl in olcd\n" +
		                     "              se specificato, "+
				     "scrive l'output in fileOut");
		  System.out.println("  v fileIn    "+
				     "Valida il file odl <fileIn>" );
		  System.out.println("  o fileOdl fileOql [fileOut] "+
				     "Ottimizza la query nel <fileOql>\n" +
				     "              sullo schema " +
				     "del file <fileOdl>\n" +
		                     "              se specificato, "+
				     "scrive l'output in fileOut");
		  System.out.println("  vs          "+
				     "Valida l'ultimo file Odl tradotto" );
		  System.out.println("  os q [fileOut] "+
				     "Ottimizza la query q sull'ultimo " +
				     "schema validato" );
	       } else if (sin.substring(0,1).equals("m") ) {
		  //
		  // more di un file
		  // 
		  //
		  //
		  // Devo estrarre i tocken dalla stringa "sin"
		  //
		  StringTokenizer st = new StringTokenizer(sin.substring(1));
		  String fileInputName;
		  // 
		  fileInputName = "";
		  if (st.hasMoreTokens()) {
		     fileInputName = st.nextToken();
		     //
		     // Copio in sin il contenuto del file specificato
		     //
		     String s = leggiFile( fileInputName );
		     //
		     // mostro s
		     //
		     System.out.println("file [" + fileInputName 
					+ "]: [\n" + s +"\n]");
		  }
	       } else if (sin.substring(0,1).equals("n")) {
		  //
		  //
		  // New Servant Object
		  // 
		  //
		  System.out.println("Requiring new Server Reference...\n");
		  myRef = factoryObj.newServant("Nuova Prova");
	       } else if (sin.substring(0,1).equals("k")) {
		  //
		  //
		  // Kill Servant Object
		  // 
		  //
		  System.out.println("Sending Kill request...\n");
		  myRef.killObject();
		  myRef = null;
	       } else if (sin.substring(0,1).equals("t") ) {
		  // 
		  // Traduttore   ODL  --> OLCD
		  // 
		  //
		  // Devo estrarre i tocken dalla stringa "sin"
		  //
		  StringTokenizer st = new StringTokenizer(sin.substring(1));
		  String fileInputName;
		  String fileOutputName;
		  String sout;
		  StringHolder olcd = new StringHolder();
		  // 
		  fileInputName = "";
		  if (st.hasMoreTokens()) {
		     fileInputName = st.nextToken();
		     //
		     // Copio in sin il contenuto del file specificato
		     //
		     String s = leggiFile( fileInputName );
		     sout = myRef.translate_Odl_Olcd(s, olcd);
		     s = sout + "\n\n -------- olcd ------- \n\n " 
			+ olcd.value;
		     //
		     // eventualmente scrivo il file di output
		     //
		     if (st.hasMoreTokens()) {
			fileOutputName = st.nextToken();
			scriviFile(fileOutputName, s);
		     } else 
			System.out.println("output: [\n" + s +"\n]");
		  }
	       } else if (sin.substring(0,2).equals("v ") ) {
		  // 
		  // Validatore
		  // 
		  //
		  // Devo estrarre i tocken dalla stringa "sin"
		  //
		  StringTokenizer st = new StringTokenizer(sin.substring(1));
		  String fileInputName;
		  String fileOutputName;
		  String sout;
		  StringHolder fc = new StringHolder();
		  // 
		  fileInputName = "";
		  if (st.hasMoreTokens()) {
		     fileInputName = st.nextToken();
		     //
		     // Copio in sin il contenuto del file specificato
		     //
		     String s = leggiFile( fileInputName );
		     sout = myRef.validate_Odl(s, fc);
		     s = sout 
			+ "\n\n -------- forma canonica ------- \n\n " 
			+ fc.value ;
		     System.out.println("output: [\n" + s +"\n]");
		  }
	       } else if (sin.substring(0,2).equals("vs") ) {
		  // 
		  // Validatore
		  // 
		  //
		  // Devo estrarre i tocken dalla stringa "sin"
		  //
		  StringTokenizer st = new StringTokenizer(sin.substring(1));
		  String fileOutputName;
		  String sout;
		  StringHolder fc = new StringHolder();
		  String s ;
		  // 
		  // Copio in sin il contenuto del file specificato
		  //
		  sout = myRef.validate_OdlSS(fc);
		  s = sout 
		     + "\n\n -------- forma canonica ------- \n\n " 
		     + fc.value ;
		  System.out.println("output: [\n" + s +"\n]");
	       } else if (sin.substring(0,2).equals("o ") ) {
		  // 
		  // Ottimizzatore di query   OQL  --> OQL
		  // 
		  //
		  // Devo estrarre i tocken dalla stringa "sin"
		  //
		  StringTokenizer st = new StringTokenizer(sin.substring(1));
		  String fileOdl = "";
		  String fileOql = "";
		  String fileOutputName = "";
		  StringHolder stdOut = new StringHolder();
		  String s ;
		  // 
		  if (st.hasMoreTokens()) {
		     fileOdl = st.nextToken();
		     if (st.hasMoreTokens()) {
			fileOql = st.nextToken();
			//
			// Copio in sin il contenuto del file specificato
			//
			s = myRef.optimize_Oql(leggiFile( fileOdl ),
						  leggiFile( fileOql ),
						  stdOut);
			s = stdOut.value + 
			   "\n\n -------- optimized OQL ------- \n\n " + 
			   s;
			//
			// eventualmente scrivo il file di output
			//
			if (st.hasMoreTokens()) {
			   fileOutputName = st.nextToken();
			   scriviFile(fileOutputName, s);
			} else 
			   System.out.println("output: [\n" + s +"\n]");
		     }
		  }
	       } else if (sin.substring(0,2).equals("os") ) {
		  // 
		  // Ottimizzatore di query   OQL  --> OQL
		  // su schema pre-esistente
		  // 
		  //
		  // Devo estrarre i tocken dalla stringa "sin"
		  //
		  StringTokenizer st = new StringTokenizer(sin.substring(2));
		  String fileOql = "";
		  String fileOutputName = "";
		  String s ;
		  // 
		  if (st.hasMoreTokens()) {
		     fileOql = st.nextToken();
		     //
		     // Copio in sin il contenuto del file specificato
		     //
		     s = myRef.optimize_OqlSS(leggiFile( fileOql ) );
		     s = "\n\n -------- optimized OQL ------- \n\n " + s;
		     //
		     // eventualmente scrivo il file di output
		     //
		     if (st.hasMoreTokens()) {
			fileOutputName = st.nextToken();
			scriviFile(fileOutputName, s);
		     } else 
			System.out.println("output: [\n" + s +"\n]");
		  }
	       } else {
		  System.out.println("* wrong command, type 'h' for help");
	       }
	    }
	    // leggo una nuova riga
	    System.out.print(">");
	    sin = bris.readLine();
	    // System.out.println(" - command: [" + sin + "]");
	 }
	 if (myRef != null) {
	    System.out.println("Sending Kill request...\n");
	    myRef.killObject();
	    myRef = null;
	 }
      } catch(Exception e) {
	 System.out.println("ERROR : " + e);
	 e.printStackTrace(System.out);
      }  
   }
}