// Copyright 2015 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 main

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

const BootstrapMakefile = "*bootstrap*"

type AST interface {
	eval(*Evaluator)
	show()
}

type ASTBase struct {
	filename string
	lineno   int
}

type AssignAST struct {
	ASTBase
	lhs Value
	rhs Value
	op  string
	opt string // "override", "export"
}

func (ast *AssignAST) eval(ev *Evaluator) {
	ev.evalAssign(ast)
}

func (ast *AssignAST) evalRHS(ev *Evaluator, lhs string) Var {
	origin := "file"
	if ast.filename == BootstrapMakefile {
		origin = "default"
	}
	if ast.opt == "override" {
		origin = "override"
	}
	// TODO(ukai): handle ast.opt == "export"
	switch ast.op {
	case ":=":
		var buf bytes.Buffer
		ast.rhs.Eval(&buf, ev)
		return SimpleVar{value: buf.Bytes(), origin: origin}
	case "=":
		return RecursiveVar{expr: ast.rhs, origin: origin}
	case "+=":
		prev := ev.LookupVarInCurrentScope(lhs)
		if !prev.IsDefined() {
			return RecursiveVar{expr: ast.rhs, origin: origin}
		}
		return prev.AppendVar(ev, ast.rhs)
	case "?=":
		prev := ev.LookupVarInCurrentScope(lhs)
		if prev.IsDefined() {
			return prev
		}
		return RecursiveVar{expr: ast.rhs, origin: origin}
	default:
		panic(fmt.Sprintf("unknown assign op: %q", ast.op))
	}
}

func (ast *AssignAST) show() {
	Logf("%s %s %s %q", ast.opt, ast.lhs, ast.op, ast.rhs)
}

// MaybeRuleAST is an ast for rule line.
// Note we cannot be sure what this is, until all variables in |expr|
// are expanded.
type MaybeRuleAST struct {
	ASTBase
	expr      Value
	term      byte // Either ':', '=', or 0
	afterTerm []byte
}

func (ast *MaybeRuleAST) eval(ev *Evaluator) {
	ev.evalMaybeRule(ast)
}

func (ast *MaybeRuleAST) show() {
	Logf("%s", ast.expr)
}

type CommandAST struct {
	ASTBase
	cmd string
}

func (ast *CommandAST) eval(ev *Evaluator) {
	ev.evalCommand(ast)
}

func (ast *CommandAST) show() {
	Logf("\t%s", strings.Replace(ast.cmd, "\n", `\n`, -1))
}

type IncludeAST struct {
	ASTBase
	expr string
	op   string
}

func (ast *IncludeAST) eval(ev *Evaluator) {
	ev.evalInclude(ast)
}

func (ast *IncludeAST) show() {
	Logf("include %s", ast.expr)
}

type IfAST struct {
	ASTBase
	op         string
	lhs        Value
	rhs        Value // Empty if |op| is ifdef or ifndef.
	trueStmts  []AST
	falseStmts []AST
}

func (ast *IfAST) eval(ev *Evaluator) {
	ev.evalIf(ast)
}

func (ast *IfAST) show() {
	// TODO
	Logf("if")
}

type ExportAST struct {
	ASTBase
	expr   []byte
	export bool
}

func (ast *ExportAST) eval(ev *Evaluator) {
	ev.evalExport(ast)
}

func (ast *ExportAST) show() {
	// TODO
	Logf("export")
}
