package todotxt import ( "errors" "sort" "time" ) // Flags for defining sort element and order. const ( SortPriorityAsc = iota SortPriorityDesc SortCreatedDateAsc SortCreatedDateDesc SortCompletedDateAsc SortCompletedDateDesc SortDueDateAsc SortDueDateDesc ) // Sort allows a TodoList to be sorted by certain predefined fields. // See constants SORT_* for fields and sort order. func (todolist *TodoList) Sort(sortFlag int) error { switch sortFlag { case SortPriorityAsc, SortPriorityDesc: todolist.sortByPriority(sortFlag) case SortCreatedDateAsc, SortCreatedDateDesc: todolist.sortByCreatedDate(sortFlag) case SortCompletedDateAsc, SortCompletedDateDesc: todolist.sortByCompletedDate(sortFlag) case SortDueDateAsc, SortDueDateDesc: todolist.sortByDueDate(sortFlag) default: return errors.New("unrecognized sort option") } return nil } func (todolist *TodoList) refresh() { todolist.Sort(todolist.SortFlag) for i, t := range todolist.Todos { t.Id = i } } type todolistSort struct { todolists TodoList by func(t1, t2 *Todo) bool } func (ts *todolistSort) Len() int { return len(ts.todolists.Todos) } func (ts *todolistSort) Swap(l, r int) { ts.todolists.Todos[l], ts.todolists.Todos[r] = ts.todolists.Todos[r], ts.todolists.Todos[l] } func (ts *todolistSort) Less(l, r int) bool { return ts.by(ts.todolists.Todos[l], ts.todolists.Todos[r]) } func (todolist *TodoList) sortBy(by func(t1, t2 *Todo) bool) *TodoList { ts := &todolistSort{ todolists: *todolist, by: by, } sort.Sort(ts) return todolist } func (todolist *TodoList) sortByPriority(order int) *TodoList { todolist.sortBy(func(t1, t2 *Todo) bool { if order == SortPriorityAsc { // ASC if t1.HasPriority() && t2.HasPriority() { return t1.Priority < t2.Priority } return t1.HasPriority() } // DESC if t1.HasPriority() && t2.HasPriority() { return t1.Priority > t2.Priority } return !t1.HasPriority() }) return todolist } func sortByDate(asc bool, hasDate1, hasDate2 bool, date1, date2 time.Time) bool { if asc { // ASC if hasDate1 && hasDate2 { return date1.Before(date2) } return hasDate2 } // DESC if hasDate1 && hasDate2 { return date1.After(date2) } return !hasDate2 } func (todolist *TodoList) sortByCreatedDate(order int) *TodoList { todolist.sortBy(func(t1, t2 *Todo) bool { return sortByDate(order == SortCreatedDateAsc, t1.HasCreatedDate(), t2.HasCreatedDate(), t1.CreatedDate, t2.CreatedDate) }) return todolist } func (todolist *TodoList) sortByCompletedDate(order int) *TodoList { todolist.sortBy(func(t1, t2 *Todo) bool { return sortByDate(order == SortCompletedDateAsc, t1.HasCompletedDate(), t2.HasCompletedDate(), t1.CompletedDate, t2.CompletedDate) }) return todolist } func (todolist *TodoList) sortByDueDate(order int) *TodoList { todolist.sortBy(func(t1, t2 *Todo) bool { return sortByDate(order == SortDueDateAsc, t1.HasDueDate(), t2.HasDueDate(), t1.DueDate, t2.DueDate) }) return todolist }