// Copyright (C) 2016 The Android Open Source Project
//
// 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 apk

import (
	"archive/zip"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"os/user"
	"path/filepath"
	"regexp"
	"strings"

	"android.googlesource.com/platform/tools/gpu/client/android/binaryxml"
	"android.googlesource.com/platform/tools/gpu/framework/log"
)

// ApkDebugifier makes an APK debuggable. The fields in the struct
// are used to configure the various paths and passwords required,
// as well as providing a log context.
// Intended use is ApkDebugifier{Ctx: ..., JarSignCmd: "jarsigner", ..., KeyStorePath: "..."}.Run(...).
type ApkDebugifier struct {
	Ctx          log.Context // log context
	JarSignCmd   string      // path to the jarsigner binary
	ZipAlignCmd  string      // path to the zipalign binary
	KeyPass      string      // key passphrase
	KeyAlias     string      // key alias for signing
	StorePass    string      // keystore passphrase
	KeyStorePath string      // path to keystore (e.g. /path/to/debug.keystore)
}

// Run takes the path (src) to an APK, sets the debuggable flag in its manifest,
// re-signs and aligns it, and saves it to a different path (dst).
func (a ApkDebugifier) Run(src string, dst string) error {
	tempFile, err := ioutil.TempFile("", "debuggable.apk")
	if err != nil {
		return err
	}
	defer os.Remove(tempFile.Name())

	a.Ctx.Printf("Making apk %s debuggable and saving to %s", src, tempFile.Name())
	err = a.makeApkDebuggableAndRemoveSignatureFiles(src, tempFile)
	if err != nil {
		return err
	}

	a.Ctx.Printf("Signing apk %s", tempFile.Name())
	err = a.jarSign(tempFile.Name())
	if err != nil {
		return err
	}

	a.Ctx.Printf("Zipaligning %s to %s", tempFile.Name(), dst)
	err = a.zipAlign(tempFile.Name(), dst)
	if err != nil {
		return err
	}

	return nil
}

func expandHomeDir(p string) string {
	if !strings.HasPrefix(p, "~") {
		return p
	}
	user, err := user.Current()
	if err != nil {
		return p // shrug
	}
	return filepath.Join(user.HomeDir, strings.TrimLeft(p, "~"))
}

func (a ApkDebugifier) execCommand(name string, args ...string) error {
	cmd := exec.Command(name, args...)
	a.Ctx.Printf("Executing %v", cmd.Args)
	out, err := cmd.CombinedOutput()
	logger := a.Ctx.Debug()
	if err != nil {
		logger = a.Ctx.Error()
	}
	logger.Writer().Write(out)
	return err
}

func (a ApkDebugifier) jarSign(apk string) error {
	return a.execCommand(
		expandHomeDir(a.JarSignCmd),
		"-sigalg", "SHA1withRSA",
		"-digestalg", "SHA1",
		"-keystore", expandHomeDir(a.KeyStorePath),
		"-storepass", a.StorePass,
		"-keypass", a.KeyPass,
		apk,
		a.KeyAlias,
	)
}

func (a ApkDebugifier) zipAlign(src string, dst string) error {
	return a.execCommand(expandHomeDir(a.ZipAlignCmd), "-v", "-f", "4", src, dst)
}

func (a ApkDebugifier) makeApkDebuggableAndRemoveSignatureFiles(src string, outFile *os.File) error {
	inZip, err := zip.OpenReader(src)
	if err != nil {
		return err
	}
	defer inZip.Close()

	defer outFile.Close()
	w := zip.NewWriter(outFile)
	defer w.Close()

	jarSignatureFilePattern := regexp.MustCompile(`META-INF/[^/]*(DSA|RSA|SF)`)

	for _, zf := range inZip.File {
		if jarSignatureFilePattern.MatchString(zf.Name) {
			a.Ctx.Debug().Logf("Skipping file %s", zf.Name)
			continue
		}

		fr, err := zf.Open()
		if err != nil {
			return err
		}
		defer fr.Close()

		fw, err := w.CreateHeader(&zip.FileHeader{
			Name:         zf.Name,
			Method:       zf.Method,
			ModifiedDate: zf.ModifiedDate,
			ModifiedTime: zf.ModifiedTime,
		})
		if err != nil {
			return err
		}

		if zf.Name == "AndroidManifest.xml" {
			a.Ctx.Debug().Logf("Modifying manifest file")
			err := binaryxml.SetDebuggableFlag(fr, fw)
			if err != nil {
				return err
			}
		} else {
			_, err = io.Copy(fw, fr)
		}

		if err != nil {
			return err
		}
	}

	return nil
}

func IsApkDebuggable(ctx log.Context, apk string) (bool, error) {
	inZip, err := zip.OpenReader(apk)
	if err != nil {
		return false, err
	}
	defer inZip.Close()
	m, err := GetManifest(ctx, inZip.File)
	if err != nil {
		return false, err
	}

	return m.Application.Debuggable, nil
}
