// scalatags 
import ammonite.ops._

import $ivy.`com.lihaoyi::scalatags:0.8.2` 
import scalatags.Text.all._
import scalatags.Text._

// regular expressions including records
abstract class Rexp 
case object ZERO extends Rexp
case object ONE extends Rexp
case class CHAR(c: Char) extends Rexp
case class ALT(r1: Rexp, r2: Rexp) extends Rexp 
case class SEQ(r1: Rexp, r2: Rexp) extends Rexp 
case class STAR(r: Rexp) extends Rexp 
case class SPECIAL(s: String) extends Rexp

def nullable (r: Rexp) : Boolean = r match {
  case ZERO => false
  case ONE => true
  case CHAR(_) => false
  case ALT(r1, r2) => nullable(r1) || nullable(r2)
  case SEQ(r1, r2) => nullable(r1) && nullable(r2)
  case STAR(_) => true
}

def der(c: Char, r: Rexp) : Rexp = r match {
  case ZERO => ZERO
  case ONE => ZERO
  case CHAR(d) => if (c == d) ONE else ZERO
  case ALT(r1, r2) => ALT(der(c, r1), der(c, r2))
  case SEQ(r1, r2) => 
    if (nullable(r1)) ALT(SEQ(der(c, r1), r2), der(c, r2))
    else SEQ(der(c, r1), r2)
  case STAR(r1) => SEQ(der(c, r1), STAR(r1))
}

def ders(s: List[Char], r: Rexp) : Rexp = s match {
  case Nil => r
  case c::s => ders(s, der(c, r))
}

def simp(r: Rexp) : Rexp = r match {
  case ALT(r1, r2) => (simp(r1), simp(r2)) match {
    case (ZERO, r2s) => r2s
    case (r1s, ZERO) => r1s
    case (r1s, r2s) => if (r1s == r2s) r1s else ALT (r1s, r2s)
  }
  case SEQ(r1, r2) =>  (simp(r1), simp(r2)) match {
    case (ZERO, _) => ZERO
    case (_, ZERO) => ZERO
    case (ONE, r2s) => r2s
    case (r1s, ONE) => r1s
    case (r1s, r2s) => SEQ(r1s, r2s)
  }
  case r => r
}

def ders_simp(s: List[Char], r: Rexp) : Rexp = s match {
  case Nil => r
  case c::s => ders_simp(s, simp(der(c, r)))
}


def pp(r: Rexp) : TypedTag[String] = r match {
  case CHAR(c) => li(code(c.toString))
  case ALT(r1, r2) => li(code("+"), ul(pp(r1), pp(r2)))
  case SEQ(r1, r2) => li(code(raw("&middot")), ul(pp(r1), pp(r2)))
  case STAR(r1) => li(code("*"), ul(pp(r1)))
  case ZERO => li(code("0"))
  case ONE => li(code("1"))
  case SPECIAL(s) => li(code(raw(s)))
} 

def mktree(r: Rexp) = 
   ul(cls := "tree")(pp(r))


def index(rs: List[Rexp]) = 
  html(
    head(link(rel := "stylesheet", href := "./style.css")),
    body(rs.map(mktree))
  )



/*
println(index(List(simple, test, evil2)))

val simple = CHAR('a')
val test = ALT(CHAR('a'), CHAR('b'))


write.over(pwd/"t1.html", 
    index(List(evil2, 
               ders("a".toList, evil2),
               ders("aa".toList, evil2),
               ders("aaa".toList, evil2))))
*/

val evil2 = SEQ(STAR(STAR(CHAR('a'))), CHAR('b'))
val r1 = STAR(ALT(SPECIAL("<i>r<sub>1</sub></i>"), SPECIAL("<i>r<sub>2</sub></i>")))
val r2 = ALT(SPECIAL("<i>r<sub>1</sub></i>"), STAR(SPECIAL("<i>r<sub>2</sub></i>")))

@main
def main(fname: String) = {
  val content = index(List(r1))
  write.over(pwd / fname, content)
}  
