package main
import (
"encoding/csv"
"html/template"
"io"
"log"
"net/http"
"os"
"strconv"
)
var COLUMNS []string
type FinancialData struct {
Date string
Open, High, Low, Close, Adj_Close, Volume float64
}
type TplData struct {
Columns []string
Rows []FinancialData
}
func printHTML(tpl *template.Template, data []FinancialData, out io.Writer) {
tplData := TplData{
COLUMNS,
data,
}
err := tpl.ExecuteTemplate(out, "tpl.html", tplData)
if err != nil {
panic(err)
}
}
func readCsvLine(line []string) *FinancialData {
data := new(FinancialData)
for i, col := range line {
switch COLUMNS[i] {
case "Date":
data.Date = col
case "Open":
data.Open = toFloat(col)
case "High":
data.High = toFloat(col)
case "Low":
data.Low = toFloat(col)
case "Close":
data.Close = toFloat(col)
case "Adj Close":
data.Adj_Close = toFloat(col)
case "Volume":
data.Volume = toFloat(col)
}
}
return data
}
func toFloat(v string) float64 {
f, err := strconv.ParseFloat(v, 64)
if err != nil {
log.Fatalln(err)
}
return f
}
func readCsvHeader(line []string) {
for _, col := range line {
COLUMNS = append(COLUMNS, col)
}
}
func readCsv(in io.Reader) []FinancialData {
data := []FinancialData{}
csvReader := csv.NewReader(in)
for {
line, err := csvReader.Read()
if err == io.EOF {
break
} else if err != nil {
log.Fatal(err)
}
if len(COLUMNS) == 0 {
readCsvHeader(line)
} else {
data = append(data, *readCsvLine(line))
}
}
return data
}
func main() {
if len(os.Args) < 2 {
log.Fatalln("Usage go-financial ")
}
// read input
csv, err := os.Open(os.Args[1])
if err != nil {
log.Fatalln("Error reading file", err)
}
defer csv.Close()
// parse data
data := readCsv(csv)
tpl, err := template.New("").Funcs(template.FuncMap{
"class": func(index int) string {
if index%2 == 0 {
return "even"
}
return "odd"
},
}).ParseFiles("tpl.html", "script.js")
if err != nil {
panic(err)
}
http.HandleFunc("/", func(res http.ResponseWriter, req *http.Request) {
printHTML(tpl, data, res)
})
http.ListenAndServe(":9000", nil)
}