/* NSC -- new Scala compiler
 * Copyright 2005-2009 LAMP/EPFL
 * @author  Sean McDirmid
 */
// $Id: DocUtil.scala 18595 2009-08-28 12:39:50Z extempore $

package scala.tools.nsc
package doc

import java.io.StringReader
import org.xml.sax.InputSource

import scala.collection.immutable.{ListMap, TreeSet}
import scala.xml._

object DocUtil
{
  def load(str: String): NodeSeq =
    if ((str == null) || (str.length == 0))
      NodeSeq.Empty
    else {
      val xmlSrc =
        if (str.matches("^(<!--.*-->)*<[^>]+>.*<[^>]+>(<!--.*-->)*$")) str
        else "<div>" + str + "</div>"
      XML.load(new StringReader(xmlSrc))
    }

  def br(nodes: NodeSeq): NodeSeq = nodes ++ (<br/>)
  def hr(nodes: NodeSeq): NodeSeq = nodes ++ (<hr/>)

  trait UrlContext {
    def relative: String

    def aref(href0: String, target: String, text: String): NodeSeq = {
      if (href0 == null) return Text(text);
      
      val href = {
        if (href0.startsWith("http:") || href0.startsWith("file:")) "";
        else relative
      } + Utility.escape(href0)
      if ((target ne null) && target.indexOf('<') != -1) throw new Error(target)

      val t0 = Text(text)
      if (target ne null)
        (<a href={href} target={target}>{t0}</a>);
      else
        (<a href={href}>{t0}</a>);
    }

    // can't use platform default here or the generated XML may end up all MacRoman
    val encoding = Properties.sourceEncoding
    val generator = System.getProperty("doc.generator", "scaladoc (" + Properties.versionString + ")")
    val header =
      (<meta http-equiv="content-type" content={"text/html; charset=" + encoding}/>
      <meta name="generator" content={generator}/>
      <link rel="stylesheet" type="text/css" href={ relative + "style.css"}/>
      <script type="text/javascript" src={relative + "script.js"}></script>);

    def body0(hasBody: Boolean, nodes: NodeSeq): NodeSeq =
      if (!hasBody) nodes else (<body onload="init()">{nodes}</body>);

    val dtype = "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">"

    def page(title: String, body: NodeSeq, hasBody: Boolean): NodeSeq =
      (<html>
        <head><title>{Text(if (title eq null) "null title" else title)}</title>
        {header}
        </head>
        {body0(hasBody, body)}
      </html>)
  } // UrlContext

  def div0(title: String): NodeSeq =
    (<div class="doctitle-larger">{Text(title)}</div>);

  def merge[T](ts0: TreeSet[T], ts1: TreeSet[T]): TreeSet[T] = ts0 ++ ts1
  
  def merge[T,S](ts0: ListMap[T,TreeSet[S]], ts1: ListMap[T,TreeSet[S]]): ListMap[T,TreeSet[S]] = {
    (ts1 foldLeft ts0) { case (xs, (k, v)) =>
      if (xs contains k) xs.updated(k, xs(k) ++ v)
      else xs.updated(k, v)
    }
  }

  implicit def coerceIterable[T](list : Iterable[T]) = NodeWrapper(list.iterator)
  implicit def coerceIterator[T](list : Iterator[T]) = NodeWrapper(list)

  case class NodeWrapper[T](list: Iterator[T]) {
    def interleave(xs: Seq[NodeSeq], sep: NodeSeq): NodeSeq =
      if (xs.isEmpty) NodeSeq.Empty
      else if (xs.size == 1) xs.head
      else xs.head ++ sep ++ interleave(xs.tail, sep)

    def mkXML(begin: NodeSeq, separator: NodeSeq, end: NodeSeq)(f: T => NodeSeq): NodeSeq =
      begin ++ interleave(list.toSequence map f, separator) ++ end

    def mkXML(begin: String, separator: String, end: String)(f: T => NodeSeq): NodeSeq =
      this.mkXML(Text(begin), Text(separator), Text(end))(f)

    def surround(open: String, close: String)(f: T => NodeSeq) =
      if (list.hasNext) mkXML(open, ", ", close)(f)
      else NodeSeq.Empty
  }
}