hlfw.ca

todo2

ref: 0ef8293bced988566398b44feecf60d1bd1ffa67
dir: /layout.go/

View raw version
package main

import (
	"bufio"
	"errors"
	"fmt"
	"log"
	"os"
)

/* This is what we want after parsing
type Layout struct {
	TaskList []*Tasks
}

type Tasks struct {
	Tag string
	Requires []string
	Tasks []*Task
}

type Task struct {
	Title string
	Entries []*Entry
}

type Entry struct {
	Desc string
	Done bool
}
*/

// Layout - Structure representing a given .todo file
type Layout struct {
	TaskList []*Entries
}

// Entries - set of todo items for a give task
type Entries struct {
	Title string
	List  []*Entry
}

// Entry - individual item of a set of tasks
type Entry struct {
	Desc string
	Done bool
}

func layoutFromTodoFile() (*Layout, error) {
	l := &Layout{
		TaskList: []*Entries{},
	}
	fl, err := os.Open(".todo")
	if err != nil {
		return nil, err
	}
	sc := bufio.NewScanner(fl)
	for sc.Scan() {
		if sc.Text() == "" {
			continue
		}

		tl := &Entries{
			Title: sc.Text(),
			List:  parseEntries(sc),
		}
		l.TaskList = append(l.TaskList, tl)
	}
	if err := sc.Err(); err != nil {
		return nil, err
	}

	return l, nil
}

func parseEntries(sc *bufio.Scanner) []*Entry {
	sc.Scan()
	en := []*Entry{}
	for {
		d := sc.Text()
		if len(d) < 4 {
			return en
		}
		if err := sc.Err(); err != nil {
			log.Fatal(err)
		}
		switch d[:3] {
		case "[ ]":
			en = append(en, &Entry{
				Desc: d[4:],
				Done: false,
			})
		case "[x]":
			en = append(en, &Entry{
				Desc: d[4:],
				Done: true,
			})
		default:
			return en
		}
		sc.Scan()
	}
}

func (l *Layout) destroy(title string) error {
	if _, err := os.Stat(".todo"); err != nil {
		return errors.New("Unable to locate .todo file")
	}
	for i, e := range l.TaskList {
		if e.Title != title {
			continue
		}
		if i < len(l.TaskList)-1 {
			copy(l.TaskList[i:], l.TaskList[i+1:])
		}
		l.TaskList = l.TaskList[:len(l.TaskList)-1]
		return nil
	}
	return errors.New("No such Entry")
}

func (l *Layout) create(title string) error {
	if len(title) < 1 {
		return errors.New("Unable to add nil Entry")
	}
	l.TaskList = append(l.TaskList, &Entries{
		Title: title,
		List:  []*Entry{},
	})
	return nil
}

func (l *Layout) taskExists(Title, item string) bool {
	for _, e := range l.TaskList {
		if e.Title != Title {
			continue
		}
		for _, t := range e.List {
			if t.Desc == item {
				return true
			}
		}
	}
	return false
}

func (l *Layout) addTask(Title, item string) error {
	for _, e := range l.TaskList {
		// Found existing task, append to List
		if e.Title != Title {
			continue
		}
		e.List = append(e.List, &Entry{
			Desc: item,
			Done: false,
		})
		return nil
	}
	line := &Entry{
		Desc: item,
		Done: false,
	}
	l.TaskList = append(l.TaskList, &Entries{
		Title: Title,
		List:  []*Entry{line},
	})
	return nil
}

func (l *Layout) rmTask(Title, item string) error {
	for _, e := range l.TaskList {
		if e.Title != Title {
			continue
		}
		for i, t := range e.List {
			if t.Desc != item {
				continue
			}
			if i < len(e.List)-1 {
				copy(e.List[i:], e.List[i+1:])
			}
			e.List = e.List[:len(e.List)-1]
			return nil
		}
	}
	return fmt.Errorf("No such task/Entry")
}

func (l *Layout) toggleTask(Title, item string) error {
	for _, e := range l.TaskList {
		if e.Title != Title {
			continue
		}
		for _, t := range e.List {
			if t.Desc != item {
				continue
			}
			t.Done = !t.Done
			return nil
		}
	}
	return fmt.Errorf("No such task/Entry")
}