package nxm.sys.lib;

import nxm.sys.inc.Debug;
import nxm.sys.inc.IDable;
import nxm.sys.inc.InternalUseOnly;

/**
  Class to hold system logging capabilities.

  @author Jeff Schoen
*/
public class Logger {

  private Midas M;
  private DataFile lf;
  private Data lfd;
  private int size;
  private int textBPA = 80;
  private boolean firstCharacters = true;

  private static boolean autoSave=false;
  /** Toggles auto-saving on and off
      @param state on or off (true or false)
   */
  public static void setAutoSave (boolean state) { autoSave = state; }

  /** Logger Constructor
      @param midas Midas context
   */
  public Logger (Midas midas) {
    M = midas;
  }

  /** open new log file, if exists saveOff() old file first
      @param filename log file name
   */
  public void open (Object filename) {
    open(filename, "XA", true);
  }

  /** open new log file, if exists saveOff() old file first
   *
   *  @param filename log file name
   *  @param format   2 character format for text (default is XA)
   *  @param firstCharacters if the entire text doesnot fit, keep the first characters
   */
  @InternalUseOnly
  public void open (Object filename, String format, boolean firstCharacters) {
    textBPA = Data.getBPA(format);
    this.firstCharacters = firstCharacters;
    lf = new DataFile();
    lf.init(M,filename,"3000","NH",0);
    lf.setExt("mlog");
    lf.setSubRecords("TIME|3A,TYPE|1A,TEXT|"+format+",FROM|2A");
    lf.setTimeCode (Time.current());
    if (autoSave && lf.find(-1)) saveOff();
    lf.open(BaseFile.OUTPUT);
    lfd = lf.getDataBuffer(1);
    size=0;
  }

  /** flush log file */
  public void flush () {
    lf.flush();
  }

  /** close current log file */
  public void close () {
    lf.close();
  }

  /** save off named file with _timeTag */
  public void saveOff () {
    DataFile lfs = new DataFile();
    lfs.init(M,lf.getURL(),"3000","NH",0);
    lfs.open(BaseFile.INPUT);
    double time = lfs.getTimeCode();
    lfs.close();
    FileName fn = new FileName( lfs.getURL() );
    String tag = Time.format(time,Time.FILENAME,0);
    fn.setRoot( lfs.getFileName().getRoot()+"_"+tag );
    CoreIO.rename( lfs.getURL(), fn.getFullName() );
  }

  /** process log message
   *  @param msg log message */
  public void processMessage (Message msg) {
    String from = "UNKNOWN";
    if (msg.from instanceof IDable) from = ((IDable)msg.from).getID();
    String type = "UNKNOWN";
    if (msg.info==Midas.INFO) type = "INFO";
    else if (msg.info==Midas.WARNING) type = "WARNING";
    else if (msg.info==Midas.ERROR) type = "ERROR";
    processMessage(type, msg.data.toString(), from);
  }

  /** process log string to log file.
      @param type The type of message (only first 8 chars are used); if null, DEF="TEXT"
      @param text The message text (only first 80 chars are used by default); if null, DEF=""
                  This can be expanded by setting the format in the open
      @param from The from ID (only first 16 chars are used); if null, DEF=""
      @since NeXtMidas 2.7.1
   */
  public void processMessage (CharSequence type, CharSequence text, CharSequence from) {
    if (lf==null || lfd==null) return;
    String time = Time.tag();
    if (type==null) type="TEXT";
    if (text==null) text="";
    if (from==null) from="";
    lfd.packS(0,24,time);
    lfd.packS(24,8,type);
    if (!firstCharacters && (text.length() > textBPA)) {
      text = text.subSequence(text.length() - textBPA, text.length());
    }
    lfd.packS(32,textBPA,text);
    int locFrom = 32 + textBPA;
    lfd.packS(locFrom,16,from);
    if ((M.debug&Debug.IO)==0) lf.write(lfd);
    size++;
  }

  /** process log string to log file.
   *  @param midas Midas reference for logging that requires direct terminal access (can be null during bootstrap
   *               of the Shell.)
   *  @param type  The type of message (only first 8 chars are used); if null, DEF="TEXT"
   *  @param text  The message text (only first 80 chars are used); if null, DEF=""
   *  @param from  The from ID (only first 16 chars are used); if null, DEF=""
   *  @since NeXtMidas 3.7.1
   */
  public void processMessage (Midas midas, CharSequence type, CharSequence text, CharSequence from) {
    processMessage(type, text, from);
  }

  /** Get the number of log messages processed
   *  @return number of log messages processed */
  public int getSize () { return size; }
}
