// Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// licence that can be found in the LICENSE file.

// This file contains the implementation of the 'gomvpkg' command
// whose main function is in golang.org/x/tools/cmd/gomvpkg.

package rename

// TODO(matloob):
// - think about what happens if the package is moving across version control systems.
// - dot imports are not supported. Make sure it's clearly documented.

import (
	"bytes"
	"fmt"
	"go/ast"
	"go/build"
	"go/format"
	"go/token"
	"log"
	"os"
	"os/exec"
	"path"
	"path/filepath"
	"regexp"
	"runtime"
	"strconv"
	"strings"
	"text/template"

	"golang.org/x/tools/go/buildutil"
	"golang.org/x/tools/go/loader"
	"golang.org/x/tools/refactor/importgraph"
)

// Move, given a package path and a destination package path, will try
// to move the given package to the new path. The Move function will
// first check for any conflicts preventing the move, such as a
// package already existing at the destination package path. If the
// move can proceed, it builds an import graph to find all imports of
// the packages whose paths need to be renamed. This includes uses of
// the subpackages of the package to be moved as those packages will
// also need to be moved. It then renames all imports to point to the
// new paths, and then moves the packages to their new paths.
func Move(ctxt *build.Context, from, to, moveTmpl string) error {
	srcDir, err := srcDir(ctxt, from)
	if err != nil {
		return err
	}

	// This should be the only place in the program that constructs
	// file paths.
	fromDir := buildutil.JoinPath(ctxt, srcDir, filepath.FromSlash(from))
	toDir := buildutil.JoinPath(ctxt, srcDir, filepath.FromSlash(to))
	toParent := filepath.Dir(toDir)
	if !buildutil.IsDir(ctxt, toParent) {
		return fmt.Errorf("parent directory does not exist for path %s", toDir)
	}

	// Build the import graph and figure out which packages to update.
	_, rev, errors := importgraph.Build(ctxt)
	if len(errors) > 0 {
		// With a large GOPATH tree, errors are inevitable.
		// Report them but proceed.
		fmt.Fprintf(os.Stderr, "While scanning Go workspace:\n")
		for path, err := range errors {
			fmt.Fprintf(os.Stderr, "Package %q: %s.\n", path, err)
		}
	}

	// Determine the affected packages---the set of packages whose import
	// statements need updating.
	affectedPackages := map[string]bool{from: true}
	destinations := make(map[string]string) // maps old import path to new import path
	for pkg := range subpackages(ctxt, srcDir, from) {
		for r := range rev[pkg] {
			affectedPackages[r] = true
		}
		destinations[pkg] = strings.Replace(pkg, from, to, 1)
	}

	// Load all the affected packages.
	iprog, err := loadProgram(ctxt, affectedPackages)
	if err != nil {
		return err
	}

	// Prepare the move command, if one was supplied.
	var cmd string
	if moveTmpl != "" {
		if cmd, err = moveCmd(moveTmpl, fromDir, toDir); err != nil {
			return err
		}
	}

	m := mover{
		ctxt:             ctxt,
		rev:              rev,
		iprog:            iprog,
		from:             from,
		to:               to,
		fromDir:          fromDir,
		toDir:            toDir,
		affectedPackages: affectedPackages,
		destinations:     destinations,
		cmd:              cmd,
	}

	if err := m.checkValid(); err != nil {
		return err
	}

	m.move()

	return nil
}

// srcDir returns the absolute path of the srcdir containing pkg.
func srcDir(ctxt *build.Context, pkg string) (string, error) {
	for _, srcDir := range ctxt.SrcDirs() {
		path := buildutil.JoinPath(ctxt, srcDir, pkg)
		if buildutil.IsDir(ctxt, path) {
			return srcDir, nil
		}
	}
	return "", fmt.Errorf("src dir not found for package: %s", pkg)
}

// subpackages returns the set of packages in the given srcDir whose
// import path equals to root, or has "root/" as the prefix.
func subpackages(ctxt *build.Context, srcDir string, root string) map[string]bool {
	var subs = make(map[string]bool)
	buildutil.ForEachPackage(ctxt, func(pkg string, err error) {
		if err != nil {
			log.Fatalf("unexpected error in ForEachPackage: %v", err)
		}

		// Only process the package root, or a sub-package of it.
		if !(strings.HasPrefix(pkg, root) &&
			(len(pkg) == len(root) || pkg[len(root)] == '/')) {
			return
		}

		p, err := ctxt.Import(pkg, "", build.FindOnly)
		if err != nil {
			log.Fatalf("unexpected: package %s can not be located by build context: %s", pkg, err)
		}
		if p.SrcRoot == "" {
			log.Fatalf("unexpected: could not determine srcDir for package %s: %s", pkg, err)
		}
		if p.SrcRoot != srcDir {
			return
		}

		subs[pkg] = true
	})
	return subs
}

type mover struct {
	// iprog contains all packages whose contents need to be updated
	// with new package names or import paths.
	iprog *loader.Program
	ctxt  *build.Context
	// rev is the reverse import graph.
	rev importgraph.Graph
	// from and to are the source and destination import
	// paths. fromDir and toDir are the source and destination
	// absolute paths that package source files will be moved between.
	from, to, fromDir, toDir string
	// affectedPackages is the set of all packages whose contents need
	// to be updated to reflect new package names or import paths.
	affectedPackages map[string]bool
	// destinations maps each subpackage to be moved to its
	// destination path.
	destinations map[string]string
	// cmd, if not empty, will be executed to move fromDir to toDir.
	cmd string
}

func (m *mover) checkValid() error {
	const prefix = "invalid move destination"

	match, err := regexp.MatchString("^[_\\pL][_\\pL\\p{Nd}]*$", path.Base(m.to))
	if err != nil {
		panic("regexp.MatchString failed")
	}
	if !match {
		return fmt.Errorf("%s: %s; gomvpkg does not support move destinations "+
			"whose base names are not valid go identifiers", prefix, m.to)
	}

	if buildutil.FileExists(m.ctxt, m.toDir) {
		return fmt.Errorf("%s: %s conflicts with file %s", prefix, m.to, m.toDir)
	}
	if buildutil.IsDir(m.ctxt, m.toDir) {
		return fmt.Errorf("%s: %s conflicts with directory %s", prefix, m.to, m.toDir)
	}

	for _, toSubPkg := range m.destinations {
		if _, err := m.ctxt.Import(toSubPkg, "", build.FindOnly); err == nil {
			return fmt.Errorf("%s: %s; package or subpackage %s already exists",
				prefix, m.to, toSubPkg)
		}
	}

	return nil
}

// moveCmd produces the version control move command used to move fromDir to toDir by
// executing the given template.
func moveCmd(moveTmpl, fromDir, toDir string) (string, error) {
	tmpl, err := template.New("movecmd").Parse(moveTmpl)
	if err != nil {
		return "", err
	}

	var buf bytes.Buffer
	err = tmpl.Execute(&buf, struct {
		Src string
		Dst string
	}{fromDir, toDir})
	return buf.String(), err
}

func (m *mover) move() error {
	filesToUpdate := make(map[*ast.File]bool)

	// Change the moved package's "package" declaration to its new base name.
	pkg, ok := m.iprog.Imported[m.from]
	if !ok {
		log.Fatalf("unexpected: package %s is not in import map", m.from)
	}
	newName := filepath.Base(m.to)
	for _, f := range pkg.Files {
		// Update all import comments.
		for _, cg := range f.Comments {
			c := cg.List[0]
			if c.Slash >= f.Name.End() &&
				sameLine(m.iprog.Fset, c.Slash, f.Name.End()) &&
				(f.Decls == nil || c.Slash < f.Decls[0].Pos()) {
				if strings.HasPrefix(c.Text, `// import "`) {
					c.Text = `// import "` + m.to + `"`
					break
				}
				if strings.HasPrefix(c.Text, `/* import "`) {
					c.Text = `/* import "` + m.to + `" */`
					break
				}
			}
		}
		f.Name.Name = newName // change package decl
		filesToUpdate[f] = true
	}

	// Look through the external test packages (m.iprog.Created contains the external test packages).
	for _, info := range m.iprog.Created {
		// Change the "package" declaration of the external test package.
		if info.Pkg.Path() == m.from+"_test" {
			for _, f := range info.Files {
				f.Name.Name = newName + "_test" // change package decl
				filesToUpdate[f] = true
			}
		}

		// Mark all the loaded external test packages, which import the "from" package,
		// as affected packages and update the imports.
		for _, imp := range info.Pkg.Imports() {
			if imp.Path() == m.from {
				m.affectedPackages[info.Pkg.Path()] = true
				m.iprog.Imported[info.Pkg.Path()] = info
				if err := importName(m.iprog, info, m.from, path.Base(m.from), newName); err != nil {
					return err
				}
			}
		}
	}

	// Update imports of that package to use the new import name.
	// None of the subpackages will change their name---only the from package
	// itself will.
	for p := range m.rev[m.from] {
		if err := importName(m.iprog, m.iprog.Imported[p], m.from, path.Base(m.from), newName); err != nil {
			return err
		}
	}

	// Update import paths for all imports by affected packages.
	for ap := range m.affectedPackages {
		info, ok := m.iprog.Imported[ap]
		if !ok {
			log.Fatalf("unexpected: package %s is not in import map", ap)
		}
		for _, f := range info.Files {
			for _, imp := range f.Imports {
				importPath, _ := strconv.Unquote(imp.Path.Value)
				if newPath, ok := m.destinations[importPath]; ok {
					imp.Path.Value = strconv.Quote(newPath)

					oldName := path.Base(importPath)
					if imp.Name != nil {
						oldName = imp.Name.Name
					}

					newName := path.Base(newPath)
					if imp.Name == nil && oldName != newName {
						imp.Name = ast.NewIdent(oldName)
					} else if imp.Name == nil || imp.Name.Name == newName {
						imp.Name = nil
					}
					filesToUpdate[f] = true
				}
			}
		}
	}

	for f := range filesToUpdate {
		var buf bytes.Buffer
		if err := format.Node(&buf, m.iprog.Fset, f); err != nil {
			log.Printf("failed to pretty-print syntax tree: %v", err)
			continue
		}
		tokenFile := m.iprog.Fset.File(f.Pos())
		writeFile(tokenFile.Name(), buf.Bytes())
	}

	// Move the directories.
	// If either the fromDir or toDir are contained under version control it is
	// the user's responsibility to provide a custom move command that updates
	// version control to reflect the move.
	// TODO(matloob): If the parent directory of toDir does not exist, create it.
	//      For now, it's required that it does exist.

	if m.cmd != "" {
		// TODO(matloob): Verify that the windows and plan9 cases are correct.
		var cmd *exec.Cmd
		switch runtime.GOOS {
		case "windows":
			cmd = exec.Command("cmd", "/c", m.cmd)
		case "plan9":
			cmd = exec.Command("rc", "-c", m.cmd)
		default:
			cmd = exec.Command("sh", "-c", m.cmd)
		}
		cmd.Stderr = os.Stderr
		cmd.Stdout = os.Stdout
		if err := cmd.Run(); err != nil {
			return fmt.Errorf("version control system's move command failed: %v", err)
		}

		return nil
	}

	return moveDirectory(m.fromDir, m.toDir)
}

// sameLine reports whether two positions in the same file are on the same line.
func sameLine(fset *token.FileSet, x, y token.Pos) bool {
	return fset.Position(x).Line == fset.Position(y).Line
}

var moveDirectory = func(from, to string) error {
	return os.Rename(from, to)
}
