@@ 10,6 10,9 @@ import (
"github.com/ajstarks/svgo"
)
+/**************************************************************************
+ * Constants & global variables *
+ **************************************************************************/
const (
boxW = 170
gapW = 30
@@ 25,10 28,40 @@ const (
var pageWidth int
+/**************************************************************************
+ * Main *
+ **************************************************************************/
+func main() {
+ c := flag.String("c", "", "CSV input file")
+ flag.Parse()
+ if *c == "" {
+ fmt.Println("CSV is required")
+ flag.Usage()
+ os.Exit(1)
+ }
+ f, e := os.Open(*c)
+ defer f.Close()
+ if e != nil {
+ fmt.Println(e.Error())
+ os.Exit(1)
+ }
+ ps, e := makePeople(f)
+ if e != nil {
+ fmt.Println(e.Error())
+ os.Exit(1)
+ }
+ rs := rank(ps)
+ renderSVG(os.Stdout, rs)
+}
+
+/**************************************************************************
+ * Person & methods *
+ **************************************************************************/
type Person struct {
- Name string
- Manager *Person
- Reports []*Person
+ Name string
+ Manager *Person
+ Reports []*Person
+ Contractor bool
}
// The index of this person in the person's manager's reports
@@ 87,6 120,9 @@ func New(n string) *Person {
return &Person{Name: n, Reports: make([]*Person, 0)}
}
+/**************************************************************************
+ * Box & methods *
+ **************************************************************************/
type Box struct {
X, Y int
Leaf bool
@@ 103,29 139,12 @@ func (b Box) in() (int, int) {
return b.X + boxW/2, b.Y
}
-func main() {
- c := flag.String("c", "", "CSV input file")
- flag.Parse()
- if *c == "" {
- fmt.Println("CSV is required")
- flag.Usage()
- os.Exit(1)
- }
- f, e := os.Open(*c)
- defer f.Close()
- if e != nil {
- fmt.Println(e.Error())
- os.Exit(1)
- }
- ps, e := makePeople(f)
- if e != nil {
- fmt.Println(e.Error())
- os.Exit(1)
- }
- rs := rank(ps)
- renderSVG(os.Stdout, rs)
-}
+/**************************************************************************
+ * Utility functions *
+ **************************************************************************/
+// Parses a CSV data stream, producing a map of people indexed by the person
+// name. Returns an error if a non-EOF read error is encountered
func makePeople(f io.Reader) (map[string]*Person, error) {
r := csv.NewReader(f)
r.LazyQuotes = true
@@ 159,6 178,8 @@ func makePeople(f io.Reader) (map[string
return ps, e
}
+// Given a map of people, produces a ranking where rank[0] are people with no
+// managers, rank[1] are people who's managers are in rank[1], and so on.
func rank(ps map[string]*Person) Ranks {
rs := make(Ranks, 0)
for _, p := range ps {
@@ 173,6 194,8 @@ func rank(ps map[string]*Person) Ranks {
return rs
}
+// Adds a person and their reports to the supplied ranks structure and recurses
+// into the reports, creating new ranks as needed
func addRecursively(p *Person, rs Ranks, i int) Ranks {
if len(rs) <= i {
rs = append(rs, make(Rank, 0))
@@ 184,6 207,9 @@ func addRecursively(p *Person, rs Ranks,
return rs
}
+/**************************************************************************
+ * SVG generating code *
+ **************************************************************************/
func renderSVG(out io.Writer, rs Ranks) {
c := svg.New(out)
pageWidth := rs.width()