package com.sun.solarisinstall.panels;

//
// Copyright (c) 1996 Sun Microsystems, Inc., all rights reserved.
//

// FileAgent.java
//
// A library of function calls for the purpose of Merlin panels accessing
// the local filesystem without going through WizardState

import java.io.*;
import com.sun.wizards.core.*;

import java.util.Vector;

// FileAgent
//
public class FileAgent {
  static final int CLOSED = 0;
  static final int READY = 1;
  static final int READING = 2;
  static final int WRITING = 3;
  int state;

  String installDir = "/tmp";
  String baseDir = "/tmp";

  DataOutputStream out = null;
  BufferedReader inReader = null;

  // Constructor
  //
  public FileAgent() {
    super();
    state = READY;
  }


  // Finalizer
  //
  protected void finalize() throws FileAgentException, Throwable {
    if (state != CLOSED)
      close();			// Close connection
    super.finalize();
  }


  // Close
  //
  public void close () {
    // Finish any operations in progress
    try {
      if (state == READING)
	this.readClose();
      else if (state == WRITING)
	this.writeClose();
    } catch (FileAgentException ex) {}
   
    state = CLOSED;
  }

  public InputStream getInputStream(String filename) {
    filename = fixFilename(filename);
 
    InputStream f = null;
    try {
      f = (InputStream)new FileInputStream(filename);
      return (f);
    } catch (IOException e) {
      System.err.println("IO EXCEPTION opening " + filename);
      return (null);
    }
  }

  public OutputStream getOutputStream(String filename) {
    filename = fixFilename(filename);
 
    OutputStream f = null;
    try {
      f = (OutputStream) new FileOutputStream(filename);
      return (f);
    } catch (IOException e) {
      System.err.println("IO EXCEPTION opening " + filename);
      return (null);
    }
  }

  public void closeOutputStream(OutputStream f) {
    try {
      f.flush();
      f.close();
    } catch (IOException e) {
      System.err.println(e);
    }
  }

  public void closeInputStream(InputStream f) {
    try {
      f.close();
    } catch (IOException e) {
      System.err.println(e);
    }
  }


  // readOpen
  //
  // Prepares to read a file.  Must be performed before read
  //   filename: name of file to read
  //
  public void readOpen (String filename) throws FileAgentException {
    filename = fixFilename(filename);

    // Finish up other reads and writes
    switch (state) {
    case CLOSED:
      throw new FileAgentException ("No Connection");
    case READING:
      this.readClose();
      break;
    case WRITING:
      this.writeClose();
      break;
    }

    try {
      inReader = new BufferedReader(new InputStreamReader(new FileInputStream(filename)));
    } catch (IOException ex) {
      throw new FileAgentException("IOException: "+ex);
    }
    state = READING;
  }

  // readLine
  //
  // Reads and returns a line of data from the open file
  //
  public String readLine () throws FileAgentException {
    if (state != READING)
      throw new FileAgentException ("No file open");
    
    try {
      String line = inReader.readLine();
      return (line);
    } catch (IOException ex) {
      throw new FileAgentException("IOException: "+ex);
    }
  }


  // readClose
  //
  // Closes the file after reading
  //
  public void readClose () throws FileAgentException {
    if (state == READING) {
      try {
        if (inReader != null) {
          inReader.close();
	    inReader = null;
        }
      } catch (IOException ex) {
	throw new FileAgentException("IOException: "+ex);
      }
      state = READY;
    }
  }
  

  // writeOpen
  //
  // opens a file for writing
  //
  public void writeOpen (String filename) throws FileAgentException {
    filename = fixFilename(filename);

    switch (state) {
    case CLOSED:
      throw new FileAgentException ("No Connection");
    case READING:
      this.readClose();
      break;
    case WRITING:
      this.writeClose();
      break;
    }
    
    try {
      out = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(filename)));
    } catch (IOException ex) {
      throw new FileAgentException("IOException: "+ex);
    }
    state = WRITING;
  }


  // writeLine
  //
  // Writes a line to the open file
  //   line: string to write
  //
  public void writeLine (String line) throws FileAgentException {
    if (state != WRITING)
      throw new FileAgentException("No file open");

    try {
      out.writeBytes(line+"\n");
      // not necessary to flush until we finish writing
    } catch (IOException ex) {
      throw new FileAgentException("IOException: "+ex);
    }
  }


  // writeClose
  //
  // closes a file opened for writing
  //
  public void writeClose () throws FileAgentException {
    if (state == WRITING) {
      try {
        if (out != null) {
          out.flush();
          out.close();
          out = null;
        }
      } catch (IOException ex) {
	throw new FileAgentException("IOException: "+ex);
      }
      state = READY;
    }
  }

  
  // ls
  //
  // Gets a list of files in a directory and returns it in the form
  // of a vector of filenames
  //   dirname: directory to list
  //
  public Vector ls(String dirname) throws FileAgentException {
    Vector dir = new Vector();

    dirname = fixFilename(dirname);

    switch (state) {
    case CLOSED:
      throw new FileAgentException ("No Connection");
    case READING:
      this.readClose();
      break;
    case WRITING:
      this.writeClose();
      break;
    }
    state = READY;

    File f = new File(dirname);
    if (f.isDirectory()) {
      String[] s = f.list();
      for (int i=0; i < s.length; i++) {
        dir.addElement(s[i]);
      }
    }

    dir.trimToSize();		// Shorten to min. length
    return (dir);
  }

  
  // doesExist
  // 
  //   Returns true if the specified file exists; otherwise, returns false.
  //
  public boolean doesExist(String filename) throws FileAgentException {
    filename = fixFilename(filename);
    boolean exists = false;

    switch (state) {
    case CLOSED:
      throw new FileAgentException ("No Connection");
    case READING:
      this.readClose();
      break;
    case WRITING:
      this.writeClose();
      break;
    }
    state = READY;

    File f = new File(filename);
    return (f.exists());
  }


  // touch
  //
  // Creates an empty file of the specified filename.
  //
  public void touch(String fileName) throws FileAgentException {
    fileName = fixFilename(fileName);

    switch (state) {
    case CLOSED:
      throw new FileAgentException ("No Connection");
    case READING:
      this.readClose();
      break;
    case WRITING:
      this.writeClose();
      break;
    }
    state = WRITING;

    try {
      File file = new File(fileName);
      if (!file.exists()) {
        FileOutputStream fos = new FileOutputStream(file);
	  fos.close();
      } else {
        throw new FileAgentException("File already exists");
      }
    } catch (IOException ex) {
      throw new FileAgentException("IOException: "+ex);
    }
  }


  // cp
  //
  // Copies the contents of srcFile to destFile.
  //
  public void cp(String srcFile, String destFile) throws FileAgentException {
    srcFile = fixFilename(srcFile);
    destFile = fixFilename(destFile);
    if (Def.DEBUG)System.out.println("Copying " + srcFile + " to " + destFile);


    switch (state) {
    case CLOSED:
      throw new FileAgentException ("No Connection");
    case READING:
      this.readClose();
      break;
    case WRITING:
      this.writeClose();
      break;
    }
    state = WRITING;

    try {
      File src = new File(srcFile);
      File dest = new File(destFile);

      if (src.exists() && src.isFile()) {
        inReader = new BufferedReader(new InputStreamReader(new FileInputStream(src)));
        out = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(dest)));
	  
        String line;
        while ((line = inReader.readLine()) != null) {
          out.writeBytes(line+"\n");
        }

        inReader.close();
        out.flush();
        out.close();
        inReader = null;
        out = null;
      } else {
        throw new FileAgentException("File doesn't exist or is not a plain file");
      }
    } catch (IOException ex) {
      throw new FileAgentException("IOException: " + ex);
    }
  }


  // mkdir
  //
  // Creates a directory with the specified name
  //
  public void mkdir(String dirName) throws FileAgentException {
    dirName = fixFilename(dirName);

    switch (state) {
    case CLOSED:
      throw new FileAgentException ("No Connection");
    case READING:
      this.readClose();
      break;
    case WRITING:
      this.writeClose();
      break;
    }
    state = WRITING;

    try {
      File file = new File(dirName);
      file.mkdir();
    } catch (NullPointerException ex) {
      throw new FileAgentException("Empty directory name");
    }
  }


  // cp_r
  //
  // Recursively copies the contents of srcFile to destFile.
  //
  public void cpr(String srcFile, String destFile) throws FileAgentException {
    srcFile = fixFilename(srcFile);
    destFile = fixFilename(destFile);
    System.out.println("Copying (recursively) " + srcFile + " to " + destFile);


    switch (state) {
    case CLOSED:
      throw new FileAgentException ("No Connection");
    case READING:
      this.readClose();
      break;
    case WRITING:
      this.writeClose();
      break;
    }
    state = WRITING;

    File src = new File(srcFile);
    File dest = new File(destFile);
    if (src.exists() && (src.isFile() || src.isDirectory())) {
      MyRun r = new MyRun ("/usr/bin/cp -r "+srcFile+" "+destFile, true);
      if (r.getResult() != 0) {
        throw new FileAgentException("Destination file cannot be written.");
      }
    } else {
      throw new FileAgentException("File doesn't exist or is not a plain file");
    }
  }


  // rm
  //
  // Removes a file
  //   filename: file to remove
  //
  public void rm(String filename) throws FileAgentException {
    File deleted = new File(installDir+"/.deleted");
    filename = fixFilename(filename);

    switch (state) {
    case CLOSED:
      throw new FileAgentException ("No Connection");
    case READING:
      this.readClose();
      break;
    case WRITING:
      this.writeClose();
      break;
    }
    state = READY;

    try {
      File file = new File(filename);
      if (file.exists()) {
        file.renameTo(deleted); // Deletions cause security execption
      } else {
        throw new FileAgentException("File doesn't exist.");
      }
    } catch (NullPointerException ex) {
      throw new FileAgentException("Empty filename to rm");
    }
  }

  // fixFilename
  //
  protected String fixFilename (String name) {
    if (name.startsWith("$INSTALL_DIR")) {
      name = installDir + name.substring("$INSTALL_DIR".length());
    } else if (name.startsWith("$BASE_DIR")) {
      name = baseDir + name.substring("$BASE_DIR".length());
    }
    
    return (name);
  }
}
