///////////////////////////////////////////////////////////////////////////////
//
// JTOpen (IBM Toolbox for Java - OSS version)
//
// Filename:  CallStackEntry.java
//
// The source code contained herein is licensed under the IBM Public License
// Version 1.0, which has been approved by the Open Source Initiative.
// Copyright (C) 1997-2004 International Business Machines Corporation and
// others.  All rights reserved.
//
///////////////////////////////////////////////////////////////////////////////

package com.ibm.as400.access;

/**
 * Represents an entry in the call stack of a specific thread of a server job.
 * Objects of this type are generated by calling {@link com.ibm.as400.access.Job#getCallStack Job.getCallStack()}.
 * @see com.ibm.as400.access.Job
**/
public class CallStackEntry implements java.io.Serializable
{
  private static final String copyright = "Copyright (C) 1997-2004 International Business Machines Corporation and others.";

  static final long serialVersionUID = 7L;

  private int requestLevel_;
  private String programName_;
  private String programLibrary_;
  private int miInstructionNumber_;
  private String moduleName_;
  private String moduleLibrary_;
  private byte controlBoundary_;
  private long activationGroupNumber_;
  private String activationGroupName_;
  private String programASP_;
  private String programLibraryASP_;
  private int programASPNumber_;
  private int programLibraryASPNumber_;
  private long activationGroupNumberLong_;
  private String[] statementIdentifiers_;
  private String procedureName_;

  private Job job_;
  private long threadID_;

  // Note: This class does not need to be synchronized because it is immutable.

  CallStackEntry(Job job, long threadID, int reqLevel, String progName, String progLib, int mi, String modName, String modLib,
                 byte controlBound, long actGroupNum, String actGroupName, String progASP, String progLibASP,
                 int progASPNum, int progLibASPNum, long actGroupNumLong, String[] stID, String procName)
  {
    job_ = job;
    threadID_ = threadID;
    requestLevel_ = reqLevel;
    programName_ = progName;
    programLibrary_ = progLib;
    miInstructionNumber_ = mi;
    moduleName_ = modName;
    moduleLibrary_ = modLib;
    controlBoundary_ = controlBound;
    activationGroupNumber_ = actGroupNum;
    activationGroupName_ = actGroupName;
    programASP_ = progASP;
    programLibraryASP_ = progLibASP;
    programASPNumber_ = progASPNum;
    programLibraryASPNumber_ = progLibASPNum;
    activationGroupNumberLong_ = actGroupNumLong;
    statementIdentifiers_ = stID;
    procedureName_ = procName;
  }

  /**
   * Returns the name of the activation group within which the program or procedure is running.
   * @return The activation group name. Special values include:
   * <ul>
   * <li>"*DFTACTGRP" - The activation group is one of the default activation groups for the system.
   * <li>"*NEW" - The activation group was created when the program was called.
   * </ul>
   * @see #getActivationGroupNumber
  **/
  public String getActivationGroupName()
  {
    return activationGroupName_;
  }

  /**
   * Returns the number of the activation group within which the program or procedure is running. This
   * is an internal number that uniquely identifies the activation group within the job.
   * @return The activation group number.
   * @see #getActivationGroupName
  **/
  public long getActivationGroupNumber()
  {
    // In V5R3 and higher, a better number is returned for the activation group.
    // We use that if it has been passed into us.
    if (activationGroupNumberLong_ != 0) return activationGroupNumberLong_;
    return activationGroupNumber_;
  }

  /**
   * Returns the Job object that generated this call stack entry.
   * @return The job.
  **/
  public Job getJob()
  {
    return job_;
  }

  /**
   * Returns the current machine instruction number in the program.
   * @return The MI instruction number, or 0 for integrated language environment (ILE) procedures.
  */
  public int getMIInstructionNumber()
  {
    return miInstructionNumber_;
  }

  /**
   * Returns the library in which the module is located.
   * @return The name of the module library. Special values include:
   * <ul>
   * <li>"*N" - The module library name is unavailable because the program has been destroyed
   * or the library containing the program is locked.
   * <li>"" (empty String) - The program at this call stack entry is not an ILE program.
   * </ul>
   * @see #getModuleName
  **/
  public String getModuleLibrary()
  {
    return moduleLibrary_;
  }

  /**
   * Returns the module containing the integrated language environment (ILE) procedure.
   * @return The name of the module. Special values include:
   * <ul>
   * <li>"*N" - The module name is unavailable because the program has been destroyed or
   * the library containing the program is locked.
   * <li>"" (empty String) - The program at this call stack entry is not an ILE program.
   * </ul>
   * @see #getModuleLibrary
  **/
  public String getModuleName()
  {
    return moduleName_;
  }

  /**
   * Returns the name of the procedure at this level of the call stack.
   * @return The procedure name, or null if unknown.
  **/
  public String getProcedureName()
  {
    return procedureName_;
  }

  /**
   * Returns the name of the auxiliary storage pool (ASP) device in which the program is located.
   * @return The ASP name. Special values include:
   * <ul>
   * <li>"*SYSBAS" - The program is located in the system ASP or a basic user ASP.
   * <li>"*N" - The name of the ASP cannot be determined.
   * </ul>
   * @see #getProgramASPNumber
   * @see #getProgramLibraryASPName
   * @see #getProgramLibraryASPNumber
  **/
  public String getProgramASPName()
  {
    return programASP_;
  }

  /**
   * Returns the numeric identifier of the auxiliary storage pool (ASP) device containing the program.
   * @return The ASP number. Valid values are:
   * <ul>
   * <li>1: The library is located in the system ASP.
   * <li>2-32: The library is located in a basic user ASP.
   * <li>33-255: The library is located in an independent ASP.
   * <li>-1: The ASP device cannot be determined.
   * </ul>
   * @see #getProgramASPName
   * @see #getProgramLibraryASPName
   * @see #getProgramLibraryASPNumber
  **/ 
  public int getProgramASPNumber()
  {
    return programASPNumber_;
  }


  /**
   * Returns the library in which the program is located.
   * @return The name of the program library. Special values include:
   * <li>"*N" - The program library name is unavailable because the library has been destroyed
   * or is locked.
   * <li>"" (empty String) - The program is not located in a library.
   * </ul>
   * @see #getProgramName
  **/
  public String getProgramLibrary()
  {
    return programLibrary_;
  }

  /**
   * Returns the name of the auxiliary storage pool (ASP) device in which the program library is located.
   * @return The ASP name. Special values include:
   * <ul>
   * <li>"*SYSBAS" - The program library is located in the system ASP or a basic user ASP.
   * <li>"*N" - The name of the ASP cannot be determined.
   * </ul>
   * @see #getProgramLibraryASPNumber
   * @see #getProgramASPName
   * @see #getProgramASPNumber
  **/   
  public String getProgramLibraryASPName()
  {
    return programLibraryASP_;
  }

  /**
   * Returns the numeric identifier of the auxiliary storage pool (ASP) device containing the program library.
   * @return The ASP number. Valid values are:
   * <ul>
   * <li>1: The library is located in the system ASP.
   * <li>2-32: The library is located in a basic user ASP.
   * <li>33-255: The library is located in an independent ASP.
   * <li>-1: The ASP device cannot be determined.
   * </ul>
   * @see #getProgramLibraryASPName
   * @see #getProgramASPName
   * @see #getProgramASPNumber
  **/ 
  public int getProgramLibraryASPNumber()
  {
    return programLibraryASPNumber_;
  }

  /** 
   * Returns the name of the procedure at this level of the call stack.
   * @return The program name.
   * @see #getProgramLibrary
  **/
  public String getProgramName()
  {
    return programName_;
  }

  /**
   * Returns the level of the request-processing program or procedure.
   * @return The request level, or 0 if the program or procedure has not received a request message.
  **/
  public int getRequestLevel()
  {
    return requestLevel_;
  }

  /**
   * Returns the high-level language statement identifier. If this field contains the character
   * representation of a number, the number is right-adjusted in the field and padded on the left
   * with zeros (for example, '0000000246'). If the call stack entry is for an integrated language
   * environment (ILE) procedure, more than one statement identifier may exist because of the 
   * compilers used for ILE languages.
   * @return The statement identifier(s), or an empty array if none exist.
  **/
  public String[] getStatementIdentifier()
  {
    if (statementIdentifiers_.length > 0)
    {
      String[] copy = new String[statementIdentifiers_.length];
      System.arraycopy(statementIdentifiers_, 0, copy, 0, statementIdentifiers_.length);
      return copy;
    }
    return statementIdentifiers_;
  }

  /**
   * Returns the identifier of the thread in whose call stack this entry belongs.
   * @return The thread identifier.
  **/
  public long getThreadID()
  {
    return threadID_;
  }

  /**
   * Indicates whether a control boundary is active for a particular program or procedure.
   * @return true if a control boundary is active, false otherwise.
  **/
  public boolean isControlBoundaryActive()
  {
    return controlBoundary_ == (byte)0xF1; // '1' means active, '0' means not.
  }

  /**
   * Returns a String representation of this call stack entry.
   * @return The String, which includes the system name, the job name, the job user, the job number,
   * the thread identifier, the request level, the procedure or program name and library, and the
   * MI instruction number.
  **/
  public String toString()
  {
    return super.toString()+"["+job_.getSystem().getSystemName()+"/"+job_.getName()+"/"+job_.getUser()+"/"+job_.getNumber()+"/0x"+Long.toHexString(threadID_).toUpperCase()+"/"+requestLevel_+"/"+(procedureName_ == null ? programName_+"/"+programLibrary_ : procedureName_)+"/"+Integer.toHexString(miInstructionNumber_).toUpperCase()+"]";
  }

}