/*
 *  This file is part of the Jikes RVM project (http://jikesrvm.org).
 *
 *  This file is licensed to You under the Common Public License (CPL);
 *  You may not use this file except in compliance with the License. You
 *  may obtain a copy of the License at
 *
 *      http://www.opensource.org/licenses/cpl1.0.php
 *
 *  See the COPYRIGHT.txt file distributed with this work for information
 *  regarding copyright ownership.
 */
package org.jikesrvm;

import org.jikesrvm.classloader.Atom;
import org.jikesrvm.classloader.RVMClass;
import org.jikesrvm.classloader.RVMMember;

/**
 * This interface is implemented by org.jikesrvm.PrintContainer.  The
 * interfaces is used by our java.lang.Throwable to print stack traces.
 */
@SuppressWarnings("unused")
// Suppress the unused import warning as per comment above
public abstract class PrintLN {
  //  PrintLN(PrintWriter out);
  //  PrintLN(PrintStream out);
  public boolean isSysWrite() { return false; }

  public boolean isSystemErr() { return false; }

  public abstract void flush();

  public abstract void println();

  public void println(String s) {
    print(s);
    println();
  }

  public abstract void print(String s);

  /* Here, we are writing code to make sure that we do not rely upon any
   * external memory accesses. */
  // largest power of 10 representable as a Java integer.
  // (max int is            2147483647)
  static final int max_int_pow10 = 1000000000;

  public void print(int n) {
    boolean suppress_leading_zero = true;
    if (n == 0x80000000) {
      print("-2147483648");
      return;
    } else if (n == 0) {
      print('0');
      return;
    } else if (n < 0) {
      print('-');
      n = -n;
    }
    /* We now have a positive # of the proper range.  Will need to exit from
the bottom of the loop. */
    for (int p = max_int_pow10; p >= 1; p /= 10) {
      int digit = n / p;
      n -= digit * p;
      if (digit == 0 && suppress_leading_zero) {
        continue;
      }
      suppress_leading_zero = false;
      char c = (char) ('0' + digit);
      print(c);
    }
  }

  public void printHex(int n) {
    print("0x");
    // print exactly 8 hexadec. digits.
    for (int i = 32 - 4; i >= 0; i -= 4) {
      int digit = (n >>> i) & 0x0000000F;               // fill with 0 bits.
      char c;

      if (digit <= 9) {
        c = (char) ('0' + digit);
      } else {
        c = (char) ('A' + (digit - 10));
      }
      print(c);
    }
  }

  public abstract void print(char c);

//   /** Print the name of the class to which the argument belongs.
//    *
//    * @param o Print the name of the class to which o belongs. */
//   public void printClassName(Object o) {

//   }

  /** Print the name of the class represented by the class descriptor.
   *
   * @param descriptor The class descriptor whose name we'll print. */
  public void printClassName(Atom descriptor) {
    // toByteArray does not allocate; just returns an existing descriptor.
    byte[] val = descriptor.toByteArray();

    if (VM.VerifyAssertions) {
      VM._assert(val[0] == 'L' && val[val.length - 1] == ';');
    }
    for (int i = 1; i < val.length - 1; ++i) {
      char c = (char) val[i];
      if (c == '/') {
        print('.');
      } else {
        print(c);
      }
    }
    // We could do this in an emergency.  But we don't need to.
    // print(descriptor);
  }

  /* Code related to Atom.classNameFromDescriptor() */
  public void print(RVMClass class_) {
    // getDescriptor() does no allocation.
    Atom descriptor = class_.getDescriptor();
    printClassName(descriptor);
  }

  // A kludgy alternative:
//     public void print(RVMClass c) {
//       Atom descriptor = c.getDescriptor();
//       try {
//      print(descriptor.classNameFromDescriptor());
//       } catch(OutOfMemoryError e) {
//      print(descriptor);
//       }
//     }

  // No such method:
  //public void print(RVMClass c) {
  //      VM.sysWrite(c);
  //    }

  /* Here we need to imitate the work that would normally be done by
* RVMMember.toString() (which RVMMethod.toString() inherits) */

  public void print(RVMMember m) {
    print(m.getDeclaringClass()); // RVMClass
    print('.');
    print(m.getName());
    print(' ');
    print(m.getDescriptor());
  }

  public void print(Atom a) {
    byte[] val;
    if (a != null) {
      val = a.toByteArray();
      for (byte aVal : val) {
        print((char) aVal);
      }
    } else {
      print("(null)");
    }
  }
}

