package jp.sf.amateras.mirage.scala

import jp.sf.amateras.mirage.bean.DefaultPropertyExtractor
import jp.sf.amateras.mirage.bean.PropertyExtractor.PropertyInfo
import java.lang.reflect.Modifier
import jp.sf.amateras.mirage.scala.Utilities._

/**
 * PropertyExtractor implementation for Scala.
 *
 * This implementation recognizes public fields of Scala classes as a property.
 */
class ScalaPropertyExtractor extends DefaultPropertyExtractor {

  override def extractProperties(clazz: java.lang.Class[_]): java.util.Map[String, PropertyInfo] = {
    val map = super.extractProperties(clazz)
    extract(clazz, map)
    return map
  }

  private def extract(clazz: Class[_], map: java.util.Map[String, PropertyInfo]): Unit = {
    if(clazz == null){
      return
    }
    for(field <- clazz.getDeclaredFields){
      if(!Modifier.isPublic(field.getModifiers)){
        val propertyName = field.getName
        withoutException {
          val method = clazz.getMethod(propertyName)
          if(map.containsKey(propertyName)){
            val info = map.get(propertyName)
            info.getterMethod = method
          } else {
            val info = new PropertyInfo
            info.name = propertyName
            info.getterMethod = method
            info.`type` = method.getReturnType
            map.put(propertyName, info)
          }
        }
        withoutException {
          val method = clazz.getMethod(propertyName + "_$eq", field.getType)
          if(map.containsKey(propertyName)){
            val info = map.get(propertyName)
            info.setterMethod = method
          } else {
            val info = new PropertyInfo
            info.name = propertyName
            info.setterMethod = method
            info.`type` = method.getReturnType
            map.put(propertyName, info)
          }
        }
      }
    }
    extract(clazz.getSuperclass, map)
  }

}