package ht

import "bytes"
import "fmt"
import "html"
import "strings"

type Ht interface {
	Bytes() []byte
	String() string
}

type AttrList []string

type htImpl struct {
	guts string
}

func (p *htImpl) String() string {
	return p.guts
}

func (p *htImpl) Bytes() []byte {
	z := make([]byte, len(p.guts))
	copy(z, p.guts)
	return z
}

func newImplFromString(s string) Ht {
	return &htImpl{guts: html.EscapeString(s)}
}

func newImplRawHtml(s string) Ht {
	return &htImpl{guts: s}
}

func Cat(things ...interface{}) Ht {
	buf := bytes.NewBuffer(make([]byte, 0))
	for _, thing := range things {
		switch t := thing.(type) {
		case Ht:
			buf.WriteString(t.String())
		case string:
			buf.WriteString(html.EscapeString(t))
		case fmt.Stringer:
			buf.WriteString(html.EscapeString(t.String()))
		default:
			buf.WriteString(html.EscapeString(fmt.Sprintf("%v", t)))
		}
	}
	return newImplRawHtml(buf.String())
}

func strcat(strs ...string) string {
	return strings.Join(strs, "")
}

func formatAttrs(attrs AttrList) string {
	buf := bytes.NewBuffer(make([]byte, 0))
	k := ""
	for i, e := range attrs {
	  if i&1 == 0 {
	    k = e
	  } else {
		buf.WriteString(` `)
		buf.WriteString(html.EscapeString(k))
		buf.WriteString(`="`)
		buf.WriteString(html.EscapeString(e))
		buf.WriteString(`"`)
	  }
	}
	return buf.String()
}

func Tag(tag string, attrs AttrList, body Ht) Ht {
	front := newImplRawHtml(strcat(`<`, tag, formatAttrs(attrs), `>`))
	back := newImplRawHtml(strcat(`</`, tag, `>`))
	return Cat(front, body, back)
}

func Attrs(kvList ...string) AttrList {
  return kvList
}
