package require html
package require clay
package require Tcl 8.6
package provide html_slidemaker 0.1

namespace eval ::html_slidemaker {}

set ::html_slidemaker::home [file dirname [file join [pwd] [info script]]]

###
# Concatenate a file
###
proc ::html_slidemaker::cat fname {
  if {![file exists $fname]} {
     return
  }
  set fin [open $fname r]
  set data [read $fin]
  close $fin
  return $data
}

proc ::html_slidemaker::svg fname {
  if {![file exists $fname]} {
     return
  }
  set fin [open $fname r]
  # Throw out the first line
  gets $fin
  set data [read $fin]
  close $fin
  return $data
}

###
# Append a line of text to a variable. Optionally apply a string mapping.
# arglist:
#   map {mandatory 0 positional 1}
#   text {mandatory 1 positional 1}
###
proc ::html_slidemaker::putb {buffername args} {
  upvar 1 $buffername buffer
  switch [llength $args] {
    1 {
      append buffer [lindex $args 0] \n
    }
    2 {
      append buffer [string map {*}$args] \n
    }
    default {
      error "usage: putb buffername ?map? string"
    }
  }
}

::clay::define ::html_slidemaker::object {

  clay set mixin map-script {
    namespace path [list {*}[namespace path] ::html_slidemaker]
  }

  constructor {} {
    namespace path [list {*}[namespace path] ::html_slidemaker]
  }

  method html_header {{title {}} args} {
    set result "<!DOCTYPE html>\n<HTML><HEAD>"
    if {$title ne {}} {
      putb result "<TITLE>$title</TITLE>"
    }
    putb result "<style>"
    if {[dict exists $args stylesheet]} {
      putb result [cat [dict get $args stylesheet]]
    } else {
      putb result [cat [file join $::html_slidemaker::home slides.css]]
    }
    putb result "</style>"
    putb result "</HEAD><BODY>"
    return $result
  }
  method html_footer args {
    return "</BODY></HTML>"
  }
  method slide {text args} {
    my variable slides slidecount
    incr slidecount
    dict set slides $slidecount main type main
    dict set slides $slidecount main content $text
    set stepcount 0
    foreach {type step} $args {
      incr stepcount
      set text {}
      switch $type {
        code {
          putb text "<div>"
          putb text "<pre><typewriter>"
          putb text [::html::html_entities $step]
          putb text "</pre></typewriter>"
          putb text "</div>"
        }
        ol  {putb text "<ol>"}
        /ol {putb text "</ol>"}
        ul  {putb text "<ul>"}
        /ul {putb text "</ul>"}
        li {
          putb text "<li class=\"step\" id=\"%name%\">"
          putb text $step
          putb text </li>
        }
        default {
          putb text "<div class=\"step\" id=\"%name%\">"
          putb text $step
          putb text </div>
        }
      }
      dict set slides $slidecount $stepcount  content $text
      dict set slides $slidecount $stepcount   type $type
    }
  }
  method assemble {} {
    my variable slides
    set data [cat [file join $::html_slidemaker::home slides.js]]
    set slidedata {}
    putb result {<div id="slides">}
    putb result {<div class="centre_outer"><div class="centre_middle"><div class="centre_inner">}
    dict for {slideid info} $slides {
      putb result "<div class=\"slide\" id=slide$slideid>"
      putb slidedata "slides.push(\{"
      set steplist {}
      set stepcount 0
      dict for {step sinfo} $info {
        putb result "<!-- Step $step type [dict get $sinfo type] -->"
        if {[dict get $sinfo type] ni {div li}} {
          putb result [dict get $sinfo content]
          putb result "<!-- /Step $step -->"
          continue
        }
        set name "step$slideid.[incr stepcount]"
        putb result [list %name% $name %count% $stepcount] [dict get $sinfo content]
        lappend steplist \'$name\'
        putb result "<!-- STEP /Step $step -->"
      }
      if {[llength $steplist]} {
        putb slidedata "    id: \'slide$slideid\',"
        putb slidedata "    steps: \[\n      [join $steplist ",\n      "]"
        putb slidedata "    \]"
      } else {
        putb slidedata "    id: \'slide$slideid\'"
      }
      putb slidedata "  \})\;"
      putb result "</div>"
    }
    putb result </div></div></div>
    putb result {</div><div id="debug"></div>}
    putb result </div>
    dict set map %SLIDE_DATA% $slidedata
    putb result $map $data
    return $result
  }
}

###
# Example:
if 0 {
set A [::html_slidemaker::object new]
$A slide {
  <h1>My awesome talk</h1>
}
$A slide {
<h1>I love bulleted lists</h1>
} ul {
} li {And here I reveal
} li {One idea
} ol {} li at li a li time /ol {} /ul {}

$A slide {<h1>And have div pop up</h1>
} div {This will show up on mouse click}

$A slide {<h1>We can even drop in code</h1> } code {
proc makehtml {} {
  return "<html><body><h1>Ouch this embeds html tags</h1></body></html>"
}
}

# And when we are done
set fout [open example.html w]
puts $fout [$A html_header {Hi World!}]
puts $fout [$A assemble]
puts $fout [$A html_footer]
close $fout
}
