func PrintJSON(r *review.Review) error {
	json, err := r.GetJSON()
	if err != nil {
		return err
	}
	fmt.Println(json)
	return nil
}
PrintJSON pretty prints the given review in JSON format.
package output
import (
	"fmt"
	"strconv"
	"strings"
	"time"
	"github.com/google/git-appraise/repository"
	"github.com/google/git-appraise/review"
)
const (
	reviewListTemplate = `Loaded %d reviews:
`
	openReviewListTemplate = `Loaded %d open reviews:
`
	commentListTemplate = `Loaded %d comment threads:
`
	reviewSummaryTemplate = `[%s] %.12s
  %s
`
	reviewDetailsTemplate = `  %q -> %q
  reviewers: %q
  requester: %q
  build status: %s
`
	commentLocationTemplate = `%s%q@%.12s
`
	commentTemplate = `comment: %s
author: %s
time:   %s
status: %s
%s`
	commentSummaryTemplate = `  comments (%d threads):
`
	contextLineCount = 5
)
func getStatusString(r *review.Summary) string {
	if r.Resolved == nil && r.Submitted {
		return "tbr"
	}
	if r.Resolved == nil {
		return "pending"
	}
	if *r.Resolved && r.Submitted {
		return "submitted"
	}
	if *r.Resolved {
		return "accepted"
	}
	if r.Submitted {
		return "danger"
	}
	if r.Request.TargetRef == "" {
		return "abandon"
	}
	return "rejected"
}
func PrintSummaries(reviews []review.Summary, listAll bool) {
	if listAll {
		fmt.Printf(reviewListTemplate, len(reviews))
	} else {
		fmt.Printf(openReviewListTemplate, len(reviews))
	}
	for _, r := range reviews {
		PrintSummary(&r)
	}
}
func PrintSummary(r *review.Summary) {
	statusString := getStatusString(r)
	indentedDescription := strings.Replace(r.Request.Description, "\n", "\n  ", -1)
	fmt.Printf(reviewSummaryTemplate, statusString, r.Revision, indentedDescription)
}
func reformatTimestamp(timestamp string) string {
	parsedTimestamp, err := strconv.ParseInt(timestamp, 10, 64)
	if err != nil {
		return timestamp
	}
	t := time.Unix(parsedTimestamp, 0)
	return t.Format(time.UnixDate)
}
func showThread(repo repository.Repo, thread review.CommentThread, indent string) error {
	comment := thread.Comment
	if comment.Location != nil && comment.Location.Path != "" && comment.Location.Range != nil && comment.Location.Range.StartLine > 0 {
		contents, err := repo.Show(comment.Location.Commit, comment.Location.Path)
		if err != nil {
			return err
		}
		lines := strings.Split(contents, "\n")
		err = comment.Location.Check(repo)
		if err != nil {
			return err
		}
		if comment.Location.Range.StartLine <= uint32(len(lines)) {
			firstLine := comment.Location.Range.StartLine
			lastLine := comment.Location.Range.EndLine
			if firstLine == 0 {
				firstLine = 1
			}
			if lastLine == 0 {
				lastLine = firstLine
			}
			if lastLine == firstLine {
				minLine := int(lastLine) - int(contextLineCount)
				if minLine <= 0 {
					minLine = 1
				}
				firstLine = uint32(minLine)
			}
			fmt.Printf(commentLocationTemplate, indent, comment.Location.Path, comment.Location.Commit)
			fmt.Println(indent + "|" + strings.Join(lines[firstLine-1:lastLine], "\n"+indent+"|"))
		}
	}
	return showSubThread(repo, thread, indent)
}
func showSubThread(repo repository.Repo, thread review.CommentThread, indent string) error {
	statusString := "fyi"
	if thread.Resolved != nil {
		if *thread.Resolved {
			statusString = "lgtm"
		} else {
			statusString = "needs work"
		}
	}
	comment := thread.Comment
	threadHash := thread.Hash
	timestamp := reformatTimestamp(comment.Timestamp)
	commentSummary := fmt.Sprintf(indent+commentTemplate, threadHash, comment.Author, timestamp, statusString, comment.Description)
	indent = indent + "  "
	indentedSummary := strings.Replace(commentSummary, "\n", "\n"+indent, -1)
	fmt.Println(indentedSummary)
	for _, child := range thread.Children {
		err := showSubThread(repo, child, indent)
		if err != nil {
			return err
		}
	}
	return nil
}
func printAnalyses(r *review.Review) {
	fmt.Println("  analyses: ", r.GetAnalysesMessage())
}
func printCommentsWithIndent(repo repository.Repo, c []review.CommentThread, indent string) error {
	for _, thread := range c {
		err := showThread(repo, thread, indent)
		if err != nil {
			return err
		}
	}
	return nil
}
func PrintComments(repo repository.Repo, c []review.CommentThread) error {
	fmt.Printf(commentListTemplate, len(c))
	return printCommentsWithIndent(repo, c, "  ")
}
func printComments(r *review.Review) error {
	fmt.Printf(commentSummaryTemplate, len(r.Comments))
	return printCommentsWithIndent(r.Repo, r.Comments, "    ")
}
func PrintDetails(r *review.Review) error {
	PrintSummary(r.Summary)
	fmt.Printf(reviewDetailsTemplate, r.Request.ReviewRef, r.Request.TargetRef,
		strings.Join(r.Request.Reviewers, ", "),
		r.Request.Requester, r.GetBuildStatusMessage())
	printAnalyses(r)
	if err := printComments(r); err != nil {
		return err
	}
	return nil
}
func PrintCommentsJSON(c []review.CommentThread) error {
	json, err := review.GetCommentsJSON(c)
	if err != nil {
		return err
	}
	fmt.Println(json)
	return nil
}