/* sbt -- Simple Build Tool
 * Copyright 2009 Mark Harrah
 */
package sbt
package classfile

import Constants._
import java.io.File

private[sbt] trait ClassFile {
  val majorVersion: Int
  val minorVersion: Int
  val fileName: String
  val className: String
  val superClassName: String
  val interfaceNames: Array[String]
  val accessFlags: Int
  val constantPool: Array[Constant]
  val fields: Array[FieldOrMethodInfo]
  val methods: Array[FieldOrMethodInfo]
  val attributes: Array[AttributeInfo]
  val sourceFile: Option[String]
  def types: Set[String]
  def stringValue(a: AttributeInfo): String
}

private[sbt] final case class Constant(tag: Byte, nameIndex: Int, typeIndex: Int, value: Option[AnyRef]) extends NotNull {
  def this(tag: Byte, nameIndex: Int, typeIndex: Int) = this(tag, nameIndex, typeIndex, None)
  def this(tag: Byte, nameIndex: Int) = this(tag, nameIndex, -1)
  def this(tag: Byte, value: AnyRef) = this(tag, -1, -1, Some(value))
  def wide = tag == ConstantLong || tag == ConstantDouble
}
private[sbt] final case class FieldOrMethodInfo(accessFlags: Int, name: Option[String], descriptor: Option[String], attributes: IndexedSeq[AttributeInfo]) extends NotNull {
  def isStatic = (accessFlags & ACC_STATIC) == ACC_STATIC
  def isPublic = (accessFlags & ACC_PUBLIC) == ACC_PUBLIC
  def isMain = isPublic && isStatic && descriptor.filter(_ == "([Ljava/lang/String;)V").isDefined
}
private[sbt] final case class AttributeInfo(name: Option[String], value: Array[Byte]) extends NotNull {
  def isNamed(s: String) = name.filter(s == _).isDefined
  def isSignature = isNamed("Signature")
  def isSourceFile = isNamed("SourceFile")
}
private[sbt] object Constants {
  final val ACC_STATIC = 0x0008
  final val ACC_PUBLIC = 0x0001

  final val JavaMagic = 0xCAFEBABE
  final val ConstantUTF8 = 1
  final val ConstantUnicode = 2
  final val ConstantInteger = 3
  final val ConstantFloat = 4
  final val ConstantLong = 5
  final val ConstantDouble = 6
  final val ConstantClass = 7
  final val ConstantString = 8
  final val ConstantField = 9
  final val ConstantMethod = 10
  final val ConstantInterfaceMethod = 11
  final val ConstantNameAndType = 12
  final val ConstantMethodHandle = 15
  final val ConstantMethodType = 16
  final val ConstantInvokeDynamic = 18
  final val ClassDescriptor = 'L'
}