rgoplot/data.go

202 lines
3.3 KiB
Go

package main
import (
"bufio"
"bytes"
"encoding/json"
"errors"
"io"
"log"
"os"
"path/filepath"
"strconv"
"strings"
)
const (
START = iota
PROP
DATA
)
var (
prop_header_str = []byte("===")
data_header_str = []byte("---")
)
type ChartPropType struct {
Name string
Width int
Height int
}
type ChartItemType struct {
key string
values []int
}
func newChartItem(d string) *ChartItemType {
item := &ChartItemType{}
item.values = make([]int, 0, 2)
fields := strings.Split(d, " ")
toValue := false
for _, f := range fields {
if len(f) == 0 {
continue
}
if toValue {
if i, err := strconv.Atoi(f); err != nil {
log.Println(err)
} else {
item.values = append(item.values, i)
}
} else {
item.key = f
toValue = true
}
}
return item
}
type ChartDataType struct {
prop *bytes.Buffer
items []*ChartItemType
}
func newChartData() *ChartDataType {
c := new(ChartDataType)
c.prop = bytes.NewBuffer(make([]byte, 0, 128))
c.items = make([]*ChartItemType, 0, 10)
return c
}
func (c *ChartDataType) appendProp(p []byte) {
c.prop.Write(p)
}
func (c *ChartDataType) appendValue(item *ChartItemType) {
c.items = append(c.items, item)
}
func (c *ChartDataType) Prop() (p ChartPropType, err error) {
b := c.prop.Bytes()
b = bytes.Trim(b, " ")
err = json.Unmarshal(b, &p)
return
}
func (c *ChartDataType) ItemNum() int {
return len(c.items)
}
func (c *ChartDataType) ItemName() []string {
names := make([]string, 0, 5)
for _, it := range c.items {
names = append(names, it.key)
}
return names
}
func (c *ChartDataType) ValueNum() int {
if len(c.items) == 0 {
return 0
}
return len(c.items[0].values)
}
func (c *ChartDataType) ItemValue(i int) []int {
values := make([]int, 0, 5)
for _, it := range c.items {
if i >= len(it.values) {
return nil
}
values = append(values, it.values[i])
}
return values
}
func ParseDataFile(file string) ([]*ChartDataType, error) {
f, err := os.Open(file)
if err != nil {
return nil, err
}
defer f.Close()
var c *ChartDataType
charts := make([]*ChartDataType, 0, 2)
reader := bufio.NewReader(f)
status := START
for {
line, _, err := reader.ReadLine()
if err != nil {
if err == io.EOF {
break
}
return nil, err
}
if line = bytes.Trim(line, " "); len(line) == 0 {
continue
}
switch status {
case START:
if bytes.Compare(line, prop_header_str) == 0 {
status = PROP
c = newChartData()
} else {
return nil, errors.New("invalid chart file")
}
case PROP:
if bytes.Compare(line, data_header_str) == 0 {
status = DATA
} else {
c.appendProp(line)
}
case DATA:
if bytes.Compare(line, prop_header_str) == 0 {
status = PROP
charts = append(charts, c)
c = newChartData()
} else {
item := newChartItem(string(line))
c.appendValue(item)
}
}
}
charts = append(charts, c)
return charts, nil
}
func LookupCurrentDir(dir string) ([]*ChartDataType, error) {
var data []*ChartDataType
err := filepath.Walk(dir, func(path string, f os.FileInfo, err error) error {
if f == nil {
return err
}
if f.IsDir() {
return nil
}
if ok, err := filepath.Match("*.chart", f.Name()); err != nil {
return err
} else if ok {
if path == f.Name() {
data, err = ParseDataFile(path)
return err
}
}
return nil
})
return data, err
}