
// See http://www.ibm.com/developerworks/jp/xml/library/x-scalaxml/?ca=drs-jp

package xml

import java.net.{URL}
import scala.xml._
import scala.collection.mutable._

trait Attrs {
    def attrs2Map(node:Node): HashMap[String, String] = {
        var attrs = new HashMap[String, String]
        node.attributes.elements.foreach( a => attrs += (a.key -> a.value.toString))
        attrs
    }
}

class Label(prefix:String, ns:String) extends Attrs {
    val info = new HashMap[String, String]
    def this(prefix:String, ns:String, node:Node) {
        this(prefix, ns)
        info ++= attrs2Map(node)
    }
    override def toString() = {
        val sb = new StringBuffer
        sb.append("label=" + "\n   " + info.mkString(",") + "\n")
        sb.toString
    }
}

class Element(prefix:String, ns:String) extends Attrs {
    val info = new HashMap[String, String]
    def this(prefix:String, ns:String, node:Node) {
        this(prefix, ns)
        info ++= attrs2Map(node)
    }
    override def toString() = {
        val sb = new StringBuffer
        sb.append("element=" + "\n   " + info.mkString(",") + "\n")
        sb.toString
    }
}

class Xsd {
    var labels = List[Label]()
    var elements = List[Element]()
}

class Link(ns:String, name:String) extends Attrs {
    val info = new HashMap[String, String]
    def this(ns:String, name:String, node:Node) {
        this(ns, name)
        info ++= HashMap("ns"->ns, "name"->name,
                         "href"-> (node.attribute("http://www.w3.org/1999/xlink", "href").get.toString))
        info ++= attrs2Map(node)
    }
    override def toString() = {
        val sb = new StringBuffer
        sb.append("link=" + name +
                  "\n   "  + info("href") +
                  "\n   " + info.mkString(",") + "\n")
        sb.toString
    }
}
class Context(prefix:String, ns:String) extends Attrs {
    val info = new HashMap[String, String]
    def this(prefix:String, ns:String, node:Node) {
        this(prefix, ns)
        info ++= attrs2Map(node)
    }
    override def toString() = {
        val sb = new StringBuffer
        sb.append("context=" + info("contextRef") +
                  "\n   " + info.mkString(",") + "\n")
        sb.toString
    }
}
class FootnoteLink(prefix:String, ns:String) extends Attrs {
    val info = new HashMap[String, String]
    def this(prefix:String, ns:String, node:Node) {
        this(prefix, ns)
        info ++= attrs2Map(node)
    }
    override def toString() = {
        val sb = new StringBuffer
        sb.append("footnoteLink=" + "\n   " + info.mkString(",") + "\n")
        sb.toString
    }
}

class XUnit(prefix:String, ns:String) extends Attrs {
    val info = new HashMap[String, String]
    def this(prefix:String, ns:String, node:Node) {
        this(prefix, ns)
        info ++= attrs2Map(node)
    }
    override def toString() = {
        val sb = new StringBuffer
        sb.append("unit=" + "\n   " + info.mkString(",") + "\n")
        sb.toString
    }
}

class Item(prefix:String, ns:String, name:String, text:String) extends Attrs {
    val info = new HashMap[String,String]()
    def this(prefix:String, ns:String, name:String, text:String, node:Node) {
        this(prefix, ns, name, text)
        info ++= attrs2Map(node)
    }
    override def toString() = {
        val sb = new StringBuffer
        sb.append("item=" + name +
                  "\n   " + info.mkString(",") + "\n")
        sb.append("    => [" + text + "]\n")
        sb.toString
    }
}

class Instance {
    var items = List[Item]()
    var contexts = List[Context]()
    var units = List[XUnit]()
    var links = List[Link]()
    var footnotes = List[FootnoteLink]()

    var xsds = List[XUnit]()
}

object Xbrl {
    def readXBRLFile(file:String):Elem = { XML.loadFile(file) }

    def readXBRL(urlStr:String):Elem = {
        val url = new URL(urlStr)
        val conn = url.openConnection
        XML.load(conn.getInputStream)
    }

    def parseXsd(node:Node): Xsd = {
        val xsd = new Xsd()
        return xsd
    }

    def parseInstance(node:Node): Instance = {
        val instance = new Instance()
        parseInstance_sub(node, instance)
        return instance
    }

    private def parseInstance_sub(node:Node, instance:Instance) :scala.Unit = {

        node foreach {ch =>
            ch match {
                case Elem(prefix, "context", attrs, scope, children @ _*) =>
                    instance.contexts :::= List(new Context(prefix, scope.getPrefix(prefix), ch))
                case Elem(prefix, "unit", attrs, scope, children @ _*) =>
                    instance.units :::= List(new XUnit(prefix, scope.getPrefix(prefix), ch))
                case Elem(prefix, "footnoteLink", attrs, scope, children @ _*) =>
                    instance.footnotes :::= List(new FootnoteLink(prefix, scope.getPrefix(prefix), ch))
                case Elem(prefix, label, attrs, scope, children @ _*) =>
                    val childNum = children.size
                    val ns = scope.getPrefix(prefix)
                    if (ns == "http://www.xbrl.org/2003/linkbase") {
                        instance.links :::= List(new Link(ns, label, ch))
                    } else {
                        children.foreach { ch2 =>
                            ch2 match {
                                case t @ Text(_) =>
                                    if (label != "xbrl") instance.items :::= List(new Item(ns, prefix, label, t.text.trim, ch))
                                case _ => parseInstance_sub(ch2, instance)
                            }
                        }
                    }
                case t @ Text(_) =>
                    //case _ => println("no match")
            }
        }
    }
}

object XbrlSample extends Application {

    // val url ="http://blogsearch.google.co.jp/blogsearch_feeds?hl=ja&q=scala&lr=&um=1&scoring=d&ie=utf-8&num=10&output=rss"
    // val url = "http://zip.cgis.biz/xml/zip.php?zn=0600000"

    // http://www.sec.gov/Archives/edgar/data/789019/000119312509212454/0001193125-09-212454-index.htm
    //val url = "http://www.sec.gov/Archives/edgar/data/789019/000119312509212454/msft-20090930.xml"
    //val docNode = Xbrl.readXBRL(url)

    val path = "/Users/youichikato/NetBeansProjects/ruby-xbrl/Edinet/tools/data/X99001-000/jpfr-asr-X99001-000-2008-03-31-01-2008-06-27.xbrl"
    val docNode = Xbrl.readXBRLFile(path)
    val inst = Xbrl.parseInstance(docNode)

    //println("================ items \n" + inst.items)
    println("================ links \n" + inst.links)
    //println("================ units \n" + inst.units)
    //println("================ contexts \n" + inst.contexts)
    //println("================ footnotes \n" + inst.footnotes)
}
