package examples.io;

import java.io.*;
import java.util.*;
import weblogic.utils.*;
import weblogic.common.*;
import weblogic.io.common.*;
import javax.naming.*;
import weblogic.jndi.*;


/**
 * This example illustrates the use of the WebLogic File API.
 * FileBrowser is an interactive application that allows you
 * to browse through network-visible files on WebLogic Servers.
 * <p>
 * To run this example, first locate or start a WebLogic Server
 * that has a network-visible file system by setting the property
 * <tt>weblogic.io.fileSystem</tt> in your <tt>weblogic.properties</tt> file.
 * For example, to configure your WebLogic Server to offer
 * the native file system directory <i>/myserver/fullPath</i> as a network-visible 
 * file system named <i>myFiles</i>, set the property
 * <tt>weblogic.io.fileSystem.<i>myFiles</i>=<i>/myserver/fullPath</i>
 * in the WebLogic Server's <tt>weblogic.properties</tt> file.
 * <p>
 * After compiling this directory, you may call FileBrowser with one argument,
 * the URL of the server. It will then give you a list of the available 
 * file systems on that server and ask you to choose one.
 * <p>
 * You may also specify the file system as the second argument to FileBrowser.
 * If you do so, you may also specify the starting current directory as the
 * third argument. After FileBrowser displays the prompt (the current file 
 * system and the current directory) you may type any of the following commands:
 * <p>
 * <center>
 * <table border=1 cellpadding=5>
 * <th>Command<th>Use
 * <tr>
 * <td><font face="Courier New">cs URL [fileSystem [path]]
 * <td>Change server, file system, current directory
 * <tr>
 * <td><font face="Courier New">cf [fileSystem [path]]    
 * <td>Change file system, current directory
 * <tr>
 * <td><font face="Courier New">cd path                   
 * <td>Change current directory
 * <tr>
 * <td><font face="Courier New">s                         
 * <td>Print URL of current server
 * <tr>
 * <td><font face="Courier New">lf                        
 * <td>List file systems on current server
 * <tr>
 * <td><font face="Courier New">ls                        
 * <td>List entries in current directory
 * <tr>
 * <td><font face="Courier New">q                         
 * <td>quit
 * </table>
 * </center>
 * <p>
 * You may switch to the file system on the client by specifying the name #.
 * 
 * @author Copyright (c) 1997-98 by WebLogic, Inc. All Rights Reserved.
 * @author Copyright (c) 1999-2000 by BEA Systems, Inc. All Rights Reserved.
 */
public class FileBrowser {
  
  // The name FileBrowser uses to refer to the file system on the client
  private static final String LOCAL_FILE_SYSTEM_NAME = "#";
  
  // These five variables define the target of the FileBrowser;
  // which server, which file system, and which directory.
  private static String        currentServerURL;
  private static Context       currentContext;
  private static T3ServicesDef currentT3s;
  private static String        currentFileSystemName;
  private static T3FileSystem  currentFileSystem;
  private static T3File        currentDirectory;
  
  /**
   * Runs the FileBrowser example. Supply the URL of your
   * WebLogic Server and a fileSystemName and (optionally) a path
   * as the arguments.
   */
  public static void main(String[] argv) {
    if (argv.length == 0) {
      output("Usage: java example.io.FileBrowser WebLogicURL [fileSystemName [path]]");
      return;
    }
    
    output("**** WebLogic File System Browser ****");
    boolean initSuccess =
      setCurrentTarget(getArg(argv, 0, null),  // server URL
		       getArg(argv, 1, null),  // file system name
		       getArg(argv, 2, "")     // path
		       );
    if (!initSuccess) return;
    
    // Loop to process commands
    String commandLine;
    String args[] = null;
    String command;
    while (true) {
      // Get next command
      commandLine = input(currentFileSystemName + " " + currentDirectory.getPath() + ">");
      command = "";
      if (!commandLine.equals("")) {
	args = StringUtils.splitCompletely(commandLine, " ");
	command = args[0];
      }
      
      // Interpret command
      if (command.equals("cs")) { // Change server
	if (args.length > 1)
	  setCurrentTarget(getArg(args, 1, null),  // server URL
			   getArg(args, 2, null),  // file system name
			   getArg(args, 3, "")     // path
			   );
	else
	  output("Specify URL of the server");
      } 
      
      else if (command.equals("cf")) { // Change file system
	setCurrentFSD(currentT3s, 
		      getArg(args, 1, null),  // file system name
		      getArg(args, 2, "")     // path
		      );
      } 
      
      else if (command.equals("cd")) { // Change directory
	setCurrentDir(currentFileSystem,
		      currentDirectory,
		      getArg(args, 1, "")      // path
		      );
      } 
      
      else if (command.equals("s")) { // Print current server
	output(currentServerURL);
      } 
      
      else if (command.equals("lf")) {  // List file systems on current server
	listFileSystems(currentT3s);
      } 
      
      else if (command.equals("ls")) { // List files in current directory
	listFiles(currentDirectory);
      } 
      
      else if (command.equals("q")) { // Quit
	try {
	  currentContext.close();
	} catch (Exception e) {};
	break;
      } 
      
      else {
	output("FileBrowser Commands");
	output("  cs URL [fileSystem [path]] - change server, file system, current directory");
	output("  cf [fileSystem [path]]     - change file system, current directory");
	output("  cd path                    - change current directory");
	output("  s                          - print URL of current server");
	output("  lf                         - list file systems on current server");
	output("  ls                         - list entries in current directory");
	output("  q                          - quit");
	output("The file system on the client is named " + LOCAL_FILE_SYSTEM_NAME);
      }
    }
  }
  
  /**
   * Attempts to set the five variables that define the target of the
   * FileBrowser.  Connects to the server at serverURL and then calls
   * setCurrentFSD, passing in fileSystemName and path. If everything
   * succeeds, sets currentContext, currentT3s and currentServerURL.
   */
  private static boolean setCurrentTarget(String serverURL, String fileSystemName, String path) { 
    // Connect to the server
    try {
      Context newCtx;
      Hashtable env = new Hashtable();
      env.put(Context.PROVIDER_URL, serverURL);
      env.put(Context.INITIAL_CONTEXT_FACTORY, 
              weblogic.jndi.WLInitialContextFactory.class.getName());
      newCtx = new InitialContext(env);
      T3ServicesDef newT3s = (T3ServicesDef)newCtx.lookup("weblogic.common.T3Services");
      
      output("Connected to WebLogic Server at " + serverURL);
      
      // Set the current file system and directory
      if (!setCurrentFSD(newT3s, fileSystemName, path)) {
        try { 
          newCtx.close();
        } catch (Exception e) {};
        return false;
      }
      
      // Everything was successful.  Make the new target current.
      try {currentContext.close();} catch (Exception e) {};
      currentT3s = newT3s;
      currentContext = newCtx;
      currentServerURL = serverURL;
      return true;
      
    } catch (Exception e) {
      output("Unable to connect to WebLogic Server at URL " + serverURL);
      output(e.toString());
      return false;
    }
    
  }
  
  /**
   * Attempts to set three of the five variables that define the
   * target of the FileBrowser.  If fileSystemName is null, prompts
   * the user to select a file system. Gets that file system and then
   * calls setCurrentDir, passing in path. If everything succeeds,
   * sets currentFileSystemName and currentFileSystem.
   */
  private static boolean setCurrentFSD(T3ServicesDef t3s, String fileSystemName, String path) {
    // Get the file system name if needed
    if (fileSystemName == null) {
      output("Available file systems");
      Vector fsl = listFileSystems(t3s);
      if (fsl == null)
	return false;
      if (fsl.size() == 0) {
	output("none");
	output("Displaying local file system " + LOCAL_FILE_SYSTEM_NAME + " on client");
	fileSystemName = LOCAL_FILE_SYSTEM_NAME;
      } else if (fsl.size() == 1) {
	fileSystemName = (String) fsl.elementAt(0);
      } else {
	String response = input("Choose one by number:");
	int index;
	try {
	  index = Integer.valueOf(response).intValue();
	} catch (NumberFormatException e) {
	  output("Invalid format: type in a number between 1 and " + fsl.size());
	  return false;
	}
	if (index > 0 && index <= fsl.size()) 
	  fileSystemName = (String) fsl.elementAt(index-1);
	else {
	  output("Index out of range: type in a number between 1 and " + fsl.size());
	  return false;
	}
      }
    }
    
    // Get the file system
    String nameToUse = fileSystemName;
    if (fileSystemName.equals(LOCAL_FILE_SYSTEM_NAME))
      nameToUse = ""; // The local file system is actually obtained by using the empty String
    T3FileSystem fileSystem;
    try {
      fileSystem = t3s.io().getFileSystem(nameToUse);
    } catch (T3Exception e) {
      output("Unknown file system " + fileSystemName);
      return false;
    }
    
    // Set the current directory
    if (!setCurrentDir(fileSystem, null, path))
      return false;
    
    // Everything was successful.  Make the new file system current.
    currentFileSystemName = fileSystemName;
    currentFileSystem = fileSystem;
    return true;
  }
  
  /**
   * Attempts to set one of the five variables that define the target
   * of the FileBrowser.  Gets the directory specified by path. If
   * oldDirectory is not null, does so as an extension of
   * oldDirectory. If everything succeeds, sets currentDirectory.
   */
  private static boolean setCurrentDir(T3FileSystem fileSystem, T3File oldDirectory, String path) {
    T3File directory;
    if (oldDirectory == null)
      directory = fileSystem.getFile(path);
    else
      directory = oldDirectory.extend(path);
    try {
      directory = fileSystem.getFile(directory.getCanonicalPath());
    } catch (Exception e) {
      output("Unable to get directory " + path);
      return false;
    }
    if (!directory.isDirectory()) {
      output(path + " is not a valid directory");
      return false;
    }
    // Everything was successful.  Make the new directory current.
    currentDirectory = directory;
    return true;
  }
  
  /**
   * Lists and returns the file systems on the given WebLogic Server.
   */
  private static Vector listFileSystems(T3ServicesDef t3s) {
    Enumeration fsl;
    try {
      fsl = t3s.io().listFileSystems();
    } catch (T3Exception e) {
      output("Unable to list file systems");
      return null;
    }
    String element;
    int count = 1;
    Vector result = new Vector();
    while (fsl.hasMoreElements()) {
      element = (String) fsl.nextElement();
      output((count++) + ") " + element);
      result.addElement(element);
    }
    return result;
  }
  
  /**
   * Lists the files in the given directory.
   */
  private static void listFiles(T3File directory) {
    String results[] = directory.list();
    for (int i=0; i<results.length; i++) {
      T3File file = directory.extend(results[i]);
      output((file.canWrite()?"w":"-") +
	     (file.canRead()?"r":"-")  +
	     (file.isFile()?" F":" D")   +
	     adjustLong(file.length(), 12) + " " +
	     results[i]);
    }
  }
  
  /**
   * Helper function for listFiles. Prepares a long value for printing
   * by padding it in front with enough spaces to give it length width.
   */
  private static String adjustLong(long value, int width) {
    String valueString = (new Long(value)).toString();
    int padSize = width - valueString.length();
    StringBuffer buf = new StringBuffer(padSize);
    for (int i=0; i<padSize; i++)
      buf.append(' ');
    return buf + valueString;
  }
  
  private static BufferedReader is = new BufferedReader(new InputStreamReader(System.in));
  
  /**
   * After printing a prompt, reads a line of text.
   */
  private static String input(String prompt) { 
    System.out.print(prompt);
    try {
      return is.readLine();
    } catch (IOException e) {
      throw new Error("Error reading input: " + e.toString());
    }
  }
  
  /**
   * Prints a line of output.
   */
  private static void output(String message) {
    System.out.println(message);
  }
  
  /**
   * If array of Strings args is at least of length index, returns
   * the value at index. If not, returns the defaultValue.
   */
  private static String getArg(String[] args, int index, String defaultValue) {
    if (args.length > index)
      return args[index];
    else
      return defaultValue;
  }
  
}
