// Copyright 2016 Google Inc. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.

package main

import (
	"go/ast"
	"path"
	"strconv"
	"strings"
)

const (
	ctxPackage = "context"

	newPackageBase = "google.golang.org/"
	stutterPackage = false
)

func init() {
	register(fix{
		"ae",
		"2016-04-15",
		aeFn,
		`Update old App Engine APIs to new App Engine APIs`,
	})
}

// logMethod is the set of methods on appengine.Context used for logging.
var logMethod = map[string]bool{
	"Debugf":    true,
	"Infof":     true,
	"Warningf":  true,
	"Errorf":    true,
	"Criticalf": true,
}

// mapPackage turns "appengine" into "google.golang.org/appengine", etc.
func mapPackage(s string) string {
	if stutterPackage {
		s += "/" + path.Base(s)
	}
	return newPackageBase + s
}

func aeFn(f *ast.File) bool {
	// During the walk, we track the last thing seen that looks like
	// an appengine.Context, and reset it once the walk leaves a func.
	var lastContext *ast.Ident

	fixed := false

	// Update imports.
	mainImp := "appengine"
	for _, imp := range f.Imports {
		pth, _ := strconv.Unquote(imp.Path.Value)
		if pth == "appengine" || strings.HasPrefix(pth, "appengine/") {
			newPth := mapPackage(pth)
			imp.Path.Value = strconv.Quote(newPth)
			fixed = true

			if pth == "appengine" {
				mainImp = newPth
			}
		}
	}

	// Update any API changes.
	walk(f, func(n interface{}) {
		if ft, ok := n.(*ast.FuncType); ok && ft.Params != nil {
			// See if this func has an `appengine.Context arg`.
			// If so, remember its identifier.
			for _, param := range ft.Params.List {
				if !isPkgDot(param.Type, "appengine", "Context") {
					continue
				}
				if len(param.Names) == 1 {
					lastContext = param.Names[0]
					break
				}
			}
			return
		}

		if as, ok := n.(*ast.AssignStmt); ok {
			if len(as.Lhs) == 1 && len(as.Rhs) == 1 {
				// If this node is an assignment from an appengine.NewContext invocation,
				// remember the identifier on the LHS.
				if isCall(as.Rhs[0], "appengine", "NewContext") {
					if ident, ok := as.Lhs[0].(*ast.Ident); ok {
						lastContext = ident
						return
					}
				}
				// x (=|:=) appengine.Timeout(y, z)
				//   should become
				// x, _ (=|:=) context.WithTimeout(y, z)
				if isCall(as.Rhs[0], "appengine", "Timeout") {
					addImport(f, ctxPackage)
					as.Lhs = append(as.Lhs, ast.NewIdent("_"))
					// isCall already did the type checking.
					sel := as.Rhs[0].(*ast.CallExpr).Fun.(*ast.SelectorExpr)
					sel.X = ast.NewIdent("context")
					sel.Sel = ast.NewIdent("WithTimeout")
					fixed = true
					return
				}
			}
			return
		}

		// If this node is a FuncDecl, we've finished the function, so reset lastContext.
		if _, ok := n.(*ast.FuncDecl); ok {
			lastContext = nil
			return
		}

		if call, ok := n.(*ast.CallExpr); ok {
			if isPkgDot(call.Fun, "appengine", "Datacenter") && len(call.Args) == 0 {
				insertContext(f, call, lastContext)
				fixed = true
				return
			}
			if isPkgDot(call.Fun, "taskqueue", "QueueStats") && len(call.Args) == 3 {
				call.Args = call.Args[:2] // drop last arg
				fixed = true
				return
			}

			sel, ok := call.Fun.(*ast.SelectorExpr)
			if !ok {
				return
			}
			if lastContext != nil && refersTo(sel.X, lastContext) && logMethod[sel.Sel.Name] {
				// c.Errorf(...)
				//   should become
				// log.Errorf(c, ...)
				addImport(f, mapPackage("appengine/log"))
				sel.X = &ast.Ident{ // ast.NewIdent doesn't preserve the position.
					NamePos: sel.X.Pos(),
					Name:    "log",
				}
				insertContext(f, call, lastContext)
				fixed = true
				return
			}
		}
	})

	// Change any `appengine.Context` to `context.Context`.
	// Do this in a separate walk because the previous walk
	// wants to identify "appengine.Context".
	walk(f, func(n interface{}) {
		expr, ok := n.(ast.Expr)
		if ok && isPkgDot(expr, "appengine", "Context") {
			addImport(f, ctxPackage)
			// isPkgDot did the type checking.
			n.(*ast.SelectorExpr).X.(*ast.Ident).Name = "context"
			fixed = true
			return
		}
	})

	// The changes above might remove the need to import "appengine".
	// Check if it's used, and drop it if it isn't.
	if fixed && !usesImport(f, mainImp) {
		deleteImport(f, mainImp)
	}

	return fixed
}

// ctx may be nil.
func insertContext(f *ast.File, call *ast.CallExpr, ctx *ast.Ident) {
	if ctx == nil {
		// context is unknown, so use a plain "ctx".
		ctx = ast.NewIdent("ctx")
	} else {
		// Create a fresh *ast.Ident so we drop the position information.
		ctx = ast.NewIdent(ctx.Name)
	}

	call.Args = append([]ast.Expr{ctx}, call.Args...)
}
