<commit_before>package webapp

import (
	"html/template"
	"io"

	"bytes"
	"strings"

	"github.com/monopole/mdrip/base"
	"github.com/monopole/mdrip/model"
	"github.com/monopole/mdrip/program"
)

type TypeSessId string

// WebApp presents a tutorial to a web browser.
// Not a complex app, so eschewing react, angular2, polymer, etc.
type WebApp struct {
	sessId      TypeSessId
	host        string
	tut         model.Tutorial
	ds          *base.DataSource
	tmpl        *template.Template
	lessonPath  []int
	coursePaths [][]int
}

func NewWebApp(
	sessId TypeSessId, host string,
	tut model.Tutorial, ds *base.DataSource, lp []int, cp [][]int) *WebApp {
	return &WebApp{sessId, host, tut, ds, makeParsedTemplate(tut), lp, cp}
}

func (wa *WebApp) SessId() TypeSessId { return wa.sessId }

func (wa *WebApp) Host() string { return wa.host }

func (wa *WebApp) Lessons() []*program.LessonPgm {
	v := program.NewLessonPgmExtractor(base.WildCardLabel)
	wa.tut.Accept(v)
	return v.Lessons()
}

func (wa *WebApp) AppName() string {
	return wa.ds.Display()
}

func (wa *WebApp) AppLink() template.URL {
	return template.URL(wa.ds.Href())
}

func (wa *WebApp) TrimName() string {
	result := strings.TrimSpace(wa.AppName())
	if len(result) > maxAppNameLen {
		return result[maxAppNameLen-3:] + "..."
	}
	return result
}

const (
	// arbitrary
	maxAppNameLen = len("gh:kubernetes/website/reference") + 10
)

// Return the last element or zero.
func (wa *WebApp) InitialLesson() int {
	if len(wa.lessonPath) == 0 {
		return 0
	}
	return wa.lessonPath[len(wa.lessonPath)-1]
}

// Return everything BUT the last element
// i.e. omit the file, just return the directory path.
func (wa *WebApp) xCoursePath() []int {
	if len(wa.lessonPath) == 0 {
		return []int{}
	}
	return wa.lessonPath[:len(wa.lessonPath)-1]
}

// Emit a javascript 2D array
// with length equal to the number of lessons.
// each entry should contain an array of course indices
// that should be active when the lesson is actice.
func (wa *WebApp) CoursePaths() [][]int {
	return wa.coursePaths
}

const (
	blue700         = "#1976D2" // header
	blue500         = "#2196F3" // hav
	blue200         = "#90CAF9" // help
	deepOrange500   = "#FF5722" // controls
	deepOrange200   = "#FF8A65"
	deepOrange700   = "#E64A19"
	teal            = "#00838f"
	hackerNewsBeige = "#f6f6ef"
	k8sBlue         = "#326DE6"
	grayIsh         = "#c9c9c9"
	whiteIsh        = "#e3e3e3"
	seaBlue         = "#9ad3de"
	darkerBlue      = "#89bdd3"
	hoverBlue       = "#06e"
	terminalGreen   = "#33ff66"
	greenA200       = "#B2FF59"
	greenA400       = "#76FF03"
	greenA700       = "#64DD17"
)

func (wa *WebApp) TransitionSpeedMs() int        { return 250 }
func (wa *WebApp) LayBodyWideWidth() int         { return 1200 }
func (wa *WebApp) LayBodyMediumWidth() int       { return 800 }
func (wa *WebApp) LayMinHeaderWidth() int        { return 400 }
func (wa *WebApp) LayNavBoxWidth() int           { return 210 }
func (wa *WebApp) LayHeaderHeight() int          { return 120 }
func (wa *WebApp) LayFooterHeight() int          { return 50 }
func (wa *WebApp) LayMinimizedHeaderHeight() int { return wa.LayFooterHeight() }
func (wa *WebApp) LayNavTopBotPad() int          { return 7 }
func (wa *WebApp) LayNavLeftPad() int            { return 20 }

func (wa *WebApp) ColorBackground() string          { return "white" }
func (wa *WebApp) ColorHelpBackground() string      { return whiteIsh }
func (wa *WebApp) ColorHeader() string              { return blue700 }
func (wa *WebApp) ColorCodeBlockText() string       { return greenA400 }
func (wa *WebApp) ColorCodeBlockBackground() string { return "black" }
func (wa *WebApp) ColorNavBackground() string       { return blue200 }
func (wa *WebApp) ColorNavText() string             { return "black" }
func (wa *WebApp) ColorNavSelected() string         { return wa.ColorBackground() }
func (wa *WebApp) ColorHover() string               { return deepOrange500 }
func (wa *WebApp) ColorCodeHover() string           { return deepOrange700 }
func (wa *WebApp) ColorControls() string            { return greenA200 }
func (wa *WebApp) ColorTitle() string               { return wa.ColorControls() }

//func (wa *WebApp) ColorHeader() string

func (wa *WebApp) LessonCount() int {
	c := model.NewTutorialLessonCounter()
	wa.tut.Accept(c)
	return c.Count()
}

func (wa *WebApp) Render(w io.Writer) error {
	return wa.tmpl.ExecuteTemplate(w, tmplNameWebApp, wa)
}

func makeParsedTemplate(tut model.Tutorial) *template.Template {
	return template.Must(
		template.New("main").Parse(
			tmplBodyLesson +
				tmplBodyBlockPgm +
				tmplBodyLessonList +
				tmplBodyLessonHead +
				makeAppTemplate(makeLeftNavBody(tut))))
}

// The logic involved in building the leftnav is much less awkward
// in plain Go than in the Go template language, so creating it
// this way rather than writing it out with a bunch of {{if}}s, etc.
func makeLeftNavBody(tut model.Tutorial) string {
	var b bytes.Buffer
	v := NewTutorialNavPrinter(&b)
	tut.Accept(v)
	return b.String()
}

func makeAppTemplate(htmlNavActual string) string {
	return `
{{define "` + tmplNameWebApp + `"}}
<html>
<head>
<style type="text/css">` + cssInHeader + `
</style>
<script type="text/javascript">` + jsInHeader + `
</script>
</head>
<body onload='onLoad()'>

  <header id='header'>
    <div class='navButtonBox' onclick='navController.toggle()'>
      <div class='navBurger'>
        <div class='burgBar1'></div>
        <div class='burgBar2'></div>
        <div class='burgBar3'></div>
      </div>
    </div>
    <div class='headerColumn'>
      <a target='_blank' href='{{.AppLink}}'>
        <title id='title'> YIKES {{.TrimName}} </title>
      </a>
      <div class='activeLessonName'> Droplet Formation Rates </div>
      ` + htmlLessonNavRow + `<commit_msg>remove yikes<commit_after>package webapp

import (
	"html/template"
	"io"

	"bytes"
	"strings"

	"github.com/monopole/mdrip/base"
	"github.com/monopole/mdrip/model"
	"github.com/monopole/mdrip/program"
)

type TypeSessId string

// WebApp presents a tutorial to a web browser.
// Not a complex app, so eschewing react, angular2, polymer, etc.
type WebApp struct {
	sessId      TypeSessId
	host        string
	tut         model.Tutorial
	ds          *base.DataSource
	tmpl        *template.Template
	lessonPath  []int
	coursePaths [][]int
}

func NewWebApp(
	sessId TypeSessId, host string,
	tut model.Tutorial, ds *base.DataSource, lp []int, cp [][]int) *WebApp {
	return &WebApp{sessId, host, tut, ds, makeParsedTemplate(tut), lp, cp}
}

func (wa *WebApp) SessId() TypeSessId { return wa.sessId }

func (wa *WebApp) Host() string { return wa.host }

func (wa *WebApp) Lessons() []*program.LessonPgm {
	v := program.NewLessonPgmExtractor(base.WildCardLabel)
	wa.tut.Accept(v)
	return v.Lessons()
}

func (wa *WebApp) AppName() string {
	return wa.ds.Display()
}

func (wa *WebApp) AppLink() template.URL {
	return template.URL(wa.ds.Href())
}

func (wa *WebApp) TrimName() string {
	result := strings.TrimSpace(wa.AppName())
	if len(result) > maxAppNameLen {
		return result[maxAppNameLen-3:] + "..."
	}
	return result
}

const (
	// arbitrary
	maxAppNameLen = len("gh:kubernetes/website/reference") + 10
)

// Return the last element or zero.
func (wa *WebApp) InitialLesson() int {
	if len(wa.lessonPath) == 0 {
		return 0
	}
	return wa.lessonPath[len(wa.lessonPath)-1]
}

// Return everything BUT the last element
// i.e. omit the file, just return the directory path.
func (wa *WebApp) xCoursePath() []int {
	if len(wa.lessonPath) == 0 {
		return []int{}
	}
	return wa.lessonPath[:len(wa.lessonPath)-1]
}

// Emit a javascript 2D array
// with length equal to the number of lessons.
// each entry should contain an array of course indices
// that should be active when the lesson is actice.
func (wa *WebApp) CoursePaths() [][]int {
	return wa.coursePaths
}

const (
	blue700         = "#1976D2" // header
	blue500         = "#2196F3" // hav
	blue200         = "#90CAF9" // help
	deepOrange500   = "#FF5722" // controls
	deepOrange200   = "#FF8A65"
	deepOrange700   = "#E64A19"
	teal            = "#00838f"
	hackerNewsBeige = "#f6f6ef"
	k8sBlue         = "#326DE6"
	grayIsh         = "#c9c9c9"
	whiteIsh        = "#e3e3e3"
	seaBlue         = "#9ad3de"
	darkerBlue      = "#89bdd3"
	hoverBlue       = "#06e"
	terminalGreen   = "#33ff66"
	greenA200       = "#B2FF59"
	greenA400       = "#76FF03"
	greenA700       = "#64DD17"
)

func (wa *WebApp) TransitionSpeedMs() int        { return 250 }
func (wa *WebApp) LayBodyWideWidth() int         { return 1200 }
func (wa *WebApp) LayBodyMediumWidth() int       { return 800 }
func (wa *WebApp) LayMinHeaderWidth() int        { return 400 }
func (wa *WebApp) LayNavBoxWidth() int           { return 210 }
func (wa *WebApp) LayHeaderHeight() int          { return 120 }
func (wa *WebApp) LayFooterHeight() int          { return 50 }
func (wa *WebApp) LayMinimizedHeaderHeight() int { return wa.LayFooterHeight() }
func (wa *WebApp) LayNavTopBotPad() int          { return 7 }
func (wa *WebApp) LayNavLeftPad() int            { return 20 }

func (wa *WebApp) ColorBackground() string          { return "white" }
func (wa *WebApp) ColorHelpBackground() string      { return whiteIsh }
func (wa *WebApp) ColorHeader() string              { return blue700 }
func (wa *WebApp) ColorCodeBlockText() string       { return greenA400 }
func (wa *WebApp) ColorCodeBlockBackground() string { return "black" }
func (wa *WebApp) ColorNavBackground() string       { return blue200 }
func (wa *WebApp) ColorNavText() string             { return "black" }
func (wa *WebApp) ColorNavSelected() string         { return wa.ColorBackground() }
func (wa *WebApp) ColorHover() string               { return deepOrange500 }
func (wa *WebApp) ColorCodeHover() string           { return deepOrange700 }
func (wa *WebApp) ColorControls() string            { return greenA200 }
func (wa *WebApp) ColorTitle() string               { return wa.ColorControls() }

//func (wa *WebApp) ColorHeader() string

func (wa *WebApp) LessonCount() int {
	c := model.NewTutorialLessonCounter()
	wa.tut.Accept(c)
	return c.Count()
}

func (wa *WebApp) Render(w io.Writer) error {
	return wa.tmpl.ExecuteTemplate(w, tmplNameWebApp, wa)
}

func makeParsedTemplate(tut model.Tutorial) *template.Template {
	return template.Must(
		template.New("main").Parse(
			tmplBodyLesson +
				tmplBodyBlockPgm +
				tmplBodyLessonList +
				tmplBodyLessonHead +
				makeAppTemplate(makeLeftNavBody(tut))))
}

// The logic involved in building the leftnav is much less awkward
// in plain Go than in the Go template language, so creating it
// this way rather than writing it out with a bunch of {{if}}s, etc.
func makeLeftNavBody(tut model.Tutorial) string {
	var b bytes.Buffer
	v := NewTutorialNavPrinter(&b)
	tut.Accept(v)
	return b.String()
}

func makeAppTemplate(htmlNavActual string) string {
	return `
{{define "` + tmplNameWebApp + `"}}
<html>
<head>
<style type="text/css">` + cssInHeader + `
</style>
<script type="text/javascript">` + jsInHeader + `
</script>
</head>
<body onload='onLoad()'>

  <header id='header'>
    <div class='navButtonBox' onclick='navController.toggle()'>
      <div class='navBurger'>
        <div class='burgBar1'></div>
        <div class='burgBar2'></div>
        <div class='burgBar3'></div>
      </div>
    </div>
    <div class='headerColumn'>
      <a target='_blank' href='{{.AppLink}}'>
        <title id='title'> {{.TrimName}} </title>
      </a>
      <div class='activeLessonName'> Droplet Formation Rates </div>
      ` + htmlLessonNavRow + `
{'fraction_non_alphanumeric': 0.1337365010799136, 'fraction_numerical': 0.025226781857451405, 'mean_word_length': 3.298551800965466, 'pattern_counts': {'":': 0, '<': 55, '<?xml version=': 0, '>': 57, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1728203', 'n_tokens_mistral': 4239, 'n_tokens_neox': 3971, 'n_words': 1088}