package nxm.sys.lib;

import java.io.InputStream;
import java.io.OutputStream;
import java.util.StringTokenizer;

import nxm.sys.inc.InternalUseOnly;

/**
  A class to interface to System functions.

  @author Jeff Schoen
*/
public class OS {

  /** This constructor was automatically provided by Java,
   *  but it is unneeded as all the methods are static methods.
   *  @deprecated now that Javadocs are required, it is temporarily
   *              being explicitely provided but deprecated
   */
  @Deprecated
  public OS () {}

  /** Get system file system stats.

      @param path The path to the file system to get statistics for.
      @return The statistics in a taburar format or <code>null</code> if the
              specified file system can not be found.
   */
  public static Table getStatFS (String path) {
    if (path==null) return null;
    if (path.startsWith("file:")) path = path.substring(5);
    if (path.indexOf(':')>0) return null;
    long[] data = new long[10];
    int stat = Native.statfs (path,data);
    if (stat<0) { data[0]=data[1]=data[2]=1024; data[3]=0; }
    int tmby = (int)(data[0]*data[1]/1000000);
    int fmby = (int)(data[0]*data[2]/1000000);
    int files = (int)data[3];
    int used = (int)(100-100*data[2]/Math.max(1,data[1]));
    String stats = "{PATH="+path+",FILES="+files+",TMBY="
                 + tmby+",FMBY="+fmby+",USED="+used+"}";
    return new Table(stats);
  }

  /** Gets OS statistics. Currently this is simply the results of running
      the unix command <code>top -n 1 -b</code>.

      @param buf   The buffer to write the statistics into.
      @param flags <i>This is currently ignored.</i>
      @return The number of bytes written to <code>buf</code>.

      @todo Make this portable to non-unix file systems.
   */
  public static int getStats (int flags, byte[] buf) {
    return runCommand ("top -n 1 -b",flags,buf);
  }

  /** Run an OS command and return its textual output.
      @param cmd   OS command to run
      @param buf   The buffer to write the output into.
      @param flags <i>This is currently ignored.</i>
      @return The number of bytes written to <code>buf</code>.
      @since NeXtMidas 3.7.0
   */
  @InternalUseOnly("Since added")
  public static int runCommand (String cmd, int flags, byte[] buf) {
    int state,boff=0,bytes,timeout=20;
    try {
      Runtime runtime = java.lang.Runtime.getRuntime();
      StringTokenizer st = new StringTokenizer(cmd);
      String[] cmdArray = new String[st.countTokens()];
      for (int i = 0; st.hasMoreTokens(); i++) {
        cmdArray[i] = st.nextToken();
      }
      Process osProcess = runtime.exec(cmdArray); // use non-deprecated API for JDK 18+ NXM-3867
      OutputStream osInput = osProcess.getOutputStream();
      InputStream osOutput = osProcess.getInputStream();
      for (state=0; state>=0 && timeout!=0 && boff<buf.length;) {
        if ((bytes=osOutput.available()) > 0) {
          bytes = Math.min(bytes,buf.length-boff);
          bytes = osOutput.read(buf,boff,bytes);
          if (bytes>0) boff+=bytes;
          state=1;
        }
        try {
          int status = osProcess.exitValue();
          // check for any output left in buffer after exit
          if (osOutput.available()>0) state=0; else state=-1;
        } catch (IllegalThreadStateException e) {
          if (state==0) { Time.sleep(0.1); timeout--; }
          else state=0;
        }
      }
      osInput.close();
      osOutput.close();
    } catch (Exception e) {
      Shell.printStackTrace("Error running OS cmd", e);
    }
    return boff;
  }
}

