// Package email helps manage emails stored in Maildir format.  A good
// write-up on the format is available at http://cr.yp.to/proto/maildir.html
package email

import (
	"bytes"
	"fmt"
	"strings"
)

// Info represents the info bits encoded as the suffix of a Maildir file.  info
// starting with "2,": Each character after the comma is an independent flag.
//   Flag "P" (passed): the user has resent/forwarded/bounced this message to someone else.
//   Flag "R" (replied): the user has replied to this message.
//   Flag "S" (seen): the user has viewed this message, though perhaps he didn't read all the way through it.
//   Flag "T" (trashed): the user has moved this message to the trash; the trash will be emptied by a later user action.
//   Flag "D" (draft): the user considers this message a draft; toggled at user discretion.
//   Flag "F" (flagged): user-defined flag; toggled at user discretion.
// New flags may be defined later. Flags must be stored in ASCII order: e.g., "2,FRS".
type Info struct {
	Base    string // The portion of the filename before the ':'.
	Passed  bool
	Replied bool
	Seen    bool
	Trashed bool
	Draft   bool
	Flagged bool
}

// NewInfo returns an Info containing the version 2 Maildir flags parsed from
// fn's suffix.
func NewInfo(fn string) (info Info) {
	info.Base = fn
	i := strings.LastIndex(fn, ":")
	if i != -1 {
		info.Base = fn[:i]
		infoStr := fn[i:]
		i = strings.Index(infoStr, ",")
		if i == -1 {
			return
		}

		flags := infoStr[i:]
		info.Passed = strings.Contains(flags, "P")
		info.Replied = strings.Contains(flags, "R")
		info.Seen = strings.Contains(flags, "S")
		info.Trashed = strings.Contains(flags, "T")
		info.Draft = strings.Contains(flags, "D")
		info.Flagged = strings.Contains(flags, "F")
	}
	return
}

func (i Info) String() string {
	if i.Passed || i.Replied || i.Seen || i.Trashed || i.Draft || i.Flagged {
		b := new(bytes.Buffer)
		fmt.Fprintf(b, "%s:2,", i.Base)
		if i.Passed {
			fmt.Fprint(b, "P")
		}
		if i.Replied {
			fmt.Fprint(b, "R")
		}
		if i.Seen {
			fmt.Fprint(b, "S")
		}
		if i.Trashed {
			fmt.Fprint(b, "T")
		}
		if i.Draft {
			fmt.Fprint(b, "D")
		}
		if i.Flagged {
			fmt.Fprint(b, "F")
		}
		return b.String()
	}

	return i.Base
}
