package scala.tools.nsc
package transform

import symtab._
import Flags._

import collection.mutable.Buffer

abstract class Statics extends Transform with ast.TreeDSL {
  import global._

  class StaticsTransformer extends Transformer {

    /** finds the static ctor DefDef tree within the template if it exists. */
    def findStaticCtor(template: Template): Option[Tree] =
      template.body find {
        case defdef @ DefDef(_, nme.CONSTRUCTOR, _, _, _, _) => defdef.symbol.hasStaticFlag
        case _ => false
      }

    /** changes the template for the class so that it contains a static constructor with symbol fields inits,
      * augments an existing static ctor if one already existed.
      */
    def addStaticInits(template: Template, newStaticInits: Buffer[Tree], localTyper: analyzer.Typer): Template = {
      if (newStaticInits.isEmpty)
        template
      else {
        val newCtor = findStaticCtor(template) match {
          // in case there already were static ctors - augment existing ones
          // currently, however, static ctors aren't being generated anywhere else
          case Some(ctor @ DefDef(_,_,_,_,_,_)) =>
            // modify existing static ctor
            deriveDefDef(ctor) {
              case block @ Block(stats, expr) =>
                // need to add inits to existing block
                treeCopy.Block(block, newStaticInits.toList ::: stats, expr)
              case term: TermTree =>
                // need to create a new block with inits and the old term
                treeCopy.Block(term, newStaticInits.toList, term)
            }
          case _ =>
            // create new static ctor
            val staticCtorSym  = currentClass.newStaticConstructor(template.pos)
            val rhs            = Block(newStaticInits.toList, Literal(Constant(())))

            localTyper.typedPos(template.pos)(DefDef(staticCtorSym, rhs))
        }
        deriveTemplate(template)(newCtor :: _)
      }
    }
  }
}
