/*
Copyright 2013 Google Inc. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

// Package lint provides helper methods for quickly running lint checks
// against a proposed change on Gerrit.
package lint

import (
	"errors"
	"fmt"
	"log"
	"regexp"
	"strings"

	"gwt.googlesource.com/buildglue.git/checkstyle"
	"gwt.googlesource.com/buildglue.git/gerrit"
	"gwt.googlesource.com/buildglue.git/git"
)

// Errors that can be returned by Lint.
var (
	LintFailed = errors.New("commit failed lint checking")
)

// Should be kept in sync with GWT's build.xml files.
var checks = []struct {
	config   string
	includes []string
	excludes []string
}{
	{
		config: "eclipse/settings/code-style/gwt-checkstyle.xml",
		includes: []string{
			"dev/core/src/",
			"dev/core/super/",
			"user/src/",
			"user/super/com/google/gwt/emul/",
			"user/super/com/google/gwt/junit/translatable/",
			"codeserver/java/",
			"samples/",
		},
		excludes: []string{
			"dev/core/src/com/google/gwt/dev/shell/remoteui/RemoteMessageProto.java",
			"dev/core/src/com/google/gwt/dev/asm/",
			"dev/core/src/com/google/gwt/dev/js/rhino/",
			"dev/core/src/org/eclipse/",
			"dev/core/src/org/apache/",
			"user/src/javax/validation/",
			"user/src/org/hibernate/validator/",
		},
	},
	{
		config: "eclipse/settings/code-style/gwt-checkstyle-tests.xml",
		includes: []string{
			"user/test/com/google/",
			"user/test-super/com/google/",
			"user/test/test/",
			"dev/core/test/",
		},
	},
}

// Match returns true if file is a ".java" file that starts with a string
// from includes but does not start with any strings from excludes.
func match(file string, includes, excludes []string) bool {
	if !strings.HasSuffix(file, ".java") {
		return false
	}
	for _, exclude := range excludes {
		if strings.HasPrefix(file, exclude) {
			return false
		}
	}
	for _, include := range includes {
		if strings.HasPrefix(file, include) {
			return true
		}
	}
	return false
}

// Matches returns the sublist of files that match the provided includes
// and excludes rules.
func matches(files, includes, excludes []string) []string {
	res := []string{}
	for _, file := range files {
		if match(file, includes, excludes) {
			res = append(res, file)
		}
	}
	return res
}

type linter struct {
	rev      string
	comments map[string][]gerrit.Comment
	failed   bool
}

func newLinter(rev string) *linter {
	return &linter{
		rev:      rev,
		comments: make(map[string][]gerrit.Comment),
	}
}

func (l *linter) comment(file string, line int, severity, message string) {
	comment := gerrit.Comment{Line: line, Message: fmt.Sprintf("[%s] %s", severity, message)}
	l.comments[file] = append(l.comments[file], comment)
	if severity == "error" {
		l.failed = true
	}
}

func (l *linter) checkStyle(config string, files []string) error {
	out, err := checkstyle.Run(config, files)
	if err != nil {
		log.Println("running checkstyle failed:", err)
		return err
	}
	for _, file := range out {
		if len(file.Errors) == 0 {
			continue
		}
		blameable, err := git.Blame(l.rev, file.Name)
		if err != nil {
			return err
		}
		l.addCheckStyleComments(file, blameable)
	}
	return nil
}

func (l *linter) addCheckStyleComments(file checkstyle.File, blameable map[int]bool) {
	for _, err := range file.Errors {
		for i := 0; i < 3; i++ {
			if blameable[err.Line-i] || blameable[err.Line+i] {
				l.comment(file.Name, err.Line, err.Severity, err.Message)
				break
			}
		}
	}
}

var fixesIssueRegexp = regexp.MustCompile("(?i)^fixes issue [0-9]{3,}[.]?$")
var issueRegexp = regexp.MustCompile("(?i)issue [0-9]{3,}")
var footerRegexp = regexp.MustCompile("^[A-Za-z0-9-]+:")

func (l *linter) checkMessage(commitmsg []string, offset int) {
	warn := func(line int, message string) {
		l.comment("/COMMIT_MSG", line+offset, "warning", message)
	}

	lengthWarning := false
	bugWarning := false

	if len(commitmsg) >= 3 && len(commitmsg[1]) > 0 {
		warn(2, "Subject line and body should be separated by a blank line.")
	}
	for i, line := range commitmsg {
		if !lengthWarning && i != 1 && len(line) > 72 {
			warn(i+1, "Commit message lines should be 72 characters or fewer.")
			lengthWarning = true
		}
		if !bugWarning && ((i == 0 && issueRegexp.MatchString(line)) || fixesIssueRegexp.MatchString(line)) {
			warn(i+1, "Please use 'Bug: issue NNNN' and place it just above the Change-Id line.")
			bugWarning = true
		}
	}

	// Note: don't check subject line
	for i, inFooter := len(commitmsg)-1, true; i >= 1; i-- {
		if len(commitmsg[i]) == 0 {
			inFooter = false
			continue
		}
		if !footerRegexp.MatchString(commitmsg[i]) {
			if inFooter {
				warn(i+1, "Footer lines should be separated from message body by a blank line.")
			}
			break
		}
		if !inFooter {
			warn(i+1, "Footer lines should form a single paragraph (i.e. must not be separated by blank lines.)")
		}
		field := strings.SplitN(commitmsg[i], ":", 2)[0]
		if field != strings.Title(field) {
			warn(i+1, "Footer fields should be in Title-Case.")
			break
		}
	}
}

func (l *linter) review() gerrit.Review {
	res := gerrit.Review{}
	if l.failed {
		res.Message = ("Oops, this change failed the fast style check! " +
			"Please fix all errors and try again.")
		res.Labels = &gerrit.Labels{Verified: -1}
	} else if len(l.comments) != 0 {
		res.Message = ("This change passed the fast style check, " +
			"but still triggered some non-error warnings. " +
			"Please review and fix if appropriate.")
	} else {
		res.Message = ("Woo hoo, this change passed the fast style check " +
			"with ZERO new warnings! You rock!")
	}
	if len(l.comments) != 0 {
		res.Comments = l.comments
	}
	return res
}

// Lint fetches ref from Gerrit, inspects the commit message and runs checkstyle against
// any added or modified files, and posts a review to Gerrit with the results.
// Returns a LintFailed error if any lint errors were found.
func Lint(ref string) error {
	if err := git.Run("fetch", "https://gwt.googlesource.com/gwt", ref); err != nil {
		log.Println("fetch failed:", err)
		return err
	}
	rev, err := git.Line("rev-parse", "FETCH_HEAD")
	if err != nil {
		return err
	}
	if err = git.Run("checkout", rev); err != nil {
		return err
	}
	files, err := git.Lines("diff-tree", "-r", "--name-only", "--diff-filter=AM", rev+"^", rev)
	if err != nil {
		return err
	}

	log.Println("running lint checks")

	linter := newLinter(rev)
	for _, check := range checks {
		if err := linter.checkStyle(check.config, matches(files, check.includes, check.excludes)); err != nil {
			log.Println("checkstyle error:", err)
			return err
		}
	}

	commitmsg, err := git.Lines("show", "-s", "--pretty=format:%B", rev)
	if err != nil {
		return err
	}
	// Gerrit always adds 1 line per parent and 4 lines for authorship as header,
	// and 1 blank line as separator; let's compute the offset.
	// See https://gerrit.googlesource.com/gerrit/+/master/gerrit-server/src/main/java/com/google/gerrit/server/patch/Text.java
	parents, err := git.Line("show", "-s", "--pretty=tformat:%P", rev)
	if err != nil {
		return err
	}
	parentCount := len(strings.Split(parents, " "))
	linter.checkMessage(commitmsg, parentCount+5)

	if err = gerrit.Post(ref, linter.review()); err != nil {
		return err
	}

	if linter.failed {
		return LintFailed
	}
	return nil
}
