// Copyright 2016 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 (
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"os"
	"path/filepath"
	"sort"
	"strings"
	"syscall"
	"time"
)

type repoTree struct {
	// repositories under this repository
	children map[string]*repoTree

	// files in this repository.
	entries []string
}

func newRepoTree(localRoot string) *repoTree {
	return &repoTree{
		children: make(map[string]*repoTree),
	}
}

// allChildren returns all the repositories (including the receiver)
// as a map keyed by relative path.
func (t *repoTree) allChildren() map[string]*repoTree {
	r := map[string]*repoTree{"": t}
	for nm, ch := range t.children {
		for sub, subCh := range ch.allChildren() {
			r[filepath.Join(nm, sub)] = subCh
		}
	}
	return r
}

// construct fills `parent` looking through `dir` subdir of `repoRoot`.
func construct(repoRoot, dir string, parent *repoTree) error {
	isRepo := false
	localRoot := filepath.Join(repoRoot, dir)
	if stat, err := os.Stat(filepath.Join(localRoot, ".git")); err == nil && stat.IsDir() {
		isRepo = true
	} else if stat, err := os.Stat(filepath.Join(localRoot, ".gitid")); err == nil && !stat.IsDir() {
		isRepo = true
	}

	if isRepo {
		sub := newRepoTree(localRoot)
		parent.children[dir] = sub
		parent = sub

		repoRoot = localRoot
		dir = ""
	}

	entries, err := ioutil.ReadDir(localRoot)
	if err != nil {
		return err
	}
	for _, e := range entries {
		if (e.IsDir() && e.Name() == ".git") || (!e.IsDir() && e.Name() == ".gitid") {
			continue
		}

		subName := filepath.Join(dir, e.Name())
		if e.IsDir() {
			construct(repoRoot, subName, parent)
		} else {
			parent.entries = append(parent.entries, subName)
		}
	}
	return nil
}

// symlinkRepo creates symlinks for all the files in `child`.
func symlinkRepo(name string, child *repoTree, roRoot, rwRoot string) error {
	fi, err := os.Stat(filepath.Join(rwRoot, name))
	if err == nil && fi.IsDir() {
		return nil
	}

	for _, e := range child.entries {
		dest := filepath.Join(rwRoot, name, e)

		if err := os.MkdirAll(filepath.Dir(dest), 0755); err != nil {
			return err
		}
		if err := os.Symlink(filepath.Join(roRoot, name, e), dest); err != nil {
			return err
		}
	}
	return nil
}

// createTreeLinks tries to short-cut symlinks for whole trees by
// symlinking to the root of a repository in the RO tree.
func createTreeLinks(ro, rw *repoTree, roRoot, rwRoot string) error {
	allRW := rw.allChildren()

outer:
	for nm, ch := range ro.children {
		foundCheckout := false
		foundRecurse := false
		for k := range allRW {
			if k == "" {
				continue
			}
			if nm == k {
				foundRecurse = true
				break
			}
			rel, err := filepath.Rel(nm, k)
			if err != nil {
				return err
			}

			if strings.HasPrefix(rel, "..") {
				continue
			}

			// we have a checkout below "nm".
			foundCheckout = true
			break
		}

		switch {
		case foundRecurse:
			if err := createTreeLinks(ch, rw.children[nm], filepath.Join(roRoot, nm), filepath.Join(rwRoot, nm)); err != nil {
				return err
			}
			continue outer
		case !foundCheckout:
			dest := filepath.Join(rwRoot, nm)
			if err := os.MkdirAll(filepath.Dir(dest), 0755); err != nil {
				return err
			}
			if err := os.Symlink(filepath.Join(roRoot, nm), dest); err != nil {
				return err
			}
		}
	}
	return nil
}

// createLinks will populate a RW tree with symlinks to the RO tree.
func createLinks(ro, rw *repoTree, roRoot, rwRoot string) error {
	if err := createTreeLinks(ro, rw, roRoot, rwRoot); err != nil {
		return err
	}

	rwc := rw.allChildren()
	for nm, ch := range ro.allChildren() {
		if _, ok := rwc[nm]; !ok {
			if err := symlinkRepo(nm, ch, roRoot, rwRoot); err != nil {
				return err
			}
		}
	}
	return nil
}

// clearLinks removes all symlinks to the RO tree. It returns the workspace name that was linked before.
func clearLinks(mount, dir string) (string, error) {
	mount = filepath.Clean(mount)

	var prefix string
	var dirs []string
	if err := filepath.Walk(dir, func(n string, fi os.FileInfo, err error) error {
		if fi.Mode()&os.ModeSymlink != 0 {
			target, err := os.Readlink(n)
			if err != nil {
				return err
			}
			if strings.HasPrefix(target, mount) {
				prefix = target
				if err := os.Remove(n); err != nil {
					return err
				}
			}
		}
		if fi.IsDir() {
			dirs = append(dirs, n)
		}
		return nil
	}); err != nil {
		return "", err
	}

	// Reverse the ordering, so we get the deepest subdirs first.
	sort.Strings(dirs)
	for i := range dirs {
		d := dirs[len(dirs)-1-i]
		// Ignore error: dir may still contain entries.
		os.Remove(d)
	}

	prefix = strings.TrimPrefix(prefix, mount+"/")
	if i := strings.Index(prefix, "/"); i != -1 {
		prefix = prefix[:i]
	}
	return prefix, nil
}

func getSHA1s(dir string) (map[string]string, error) {
	attr := "user.gitsha1"

	shamap := map[string]string{}

	data := make([]byte, 1024)

	if err := filepath.Walk(dir, func(n string, fi os.FileInfo, err error) error {
		if n == filepath.Join(dir, "manifest.xml") {
			return nil
		}
		if fi.Mode()&os.ModeType != 0 {
			return nil
		}
		if filepath.Base(n) == ".gitid" {
			return nil
		}

		sz, err := syscall.Getxattr(n, attr, data)
		if err != nil {
			return fmt.Errorf("Getxattr(%s, %s): %v", n, attr, err)
		}
		rel, err := filepath.Rel(dir, n)
		if err != nil {
			return err
		}
		shamap[rel] = string(data[:sz])
		return nil
	}); err != nil {
		return nil, err
	}

	return shamap, nil
}

// Returns the filenames (as relative paths) in newDir that have
// changed relative to the files in oldDir.
func changedFiles(oldDir, newDir string) ([]string, error) {
	// TODO(hanwen): could be parallel.
	oldSHA1s, err := getSHA1s(oldDir)
	if err != nil {
		return nil, err
	}
	newSHA1s, err := getSHA1s(newDir)
	if err != nil {
		return nil, err
	}

	var changed []string
	for k, v := range newSHA1s {
		old, ok := oldSHA1s[k]
		if !ok || old != v {
			changed = append(changed, k)
		}
	}
	sort.Strings(changed)
	return changed, nil
}

// populateCheckout updates a RW dir with new symlinks to the given RO dir.
func populateCheckout(ro, rw string) error {
	wsName, err := clearLinks(filepath.Dir(ro), rw)
	if err != nil {
		log.Fatal(err)
	}

	rwTree := newRepoTree(rw)
	if err := construct(rw, "", rwTree); err != nil {
		return err
	}

	roTree := newRepoTree(ro)
	if err := construct(ro, "", roTree); err != nil {
		return err
	}

	if err := createLinks(roTree, rwTree, ro, rw); err != nil {
		return err
	}

	// TODO(hanwen): can be done in parallel to the other processes.
	oldRoot := filepath.Join(filepath.Dir(ro), wsName)
	changed, err := changedFiles(oldRoot, ro)
	if err != nil {
		return fmt.Errorf("changedFiles: %v", err)
	}

	// TODO(hanwen): parallel?
	now := time.Now()
	for _, n := range changed {
		if err := os.Chtimes(filepath.Join(ro, n), now, now); err != nil {
			return err
		}
	}

	return nil
}

func main() {
	mount := flag.String("ro", "", "path to slothfs-multifs mount.")
	flag.Parse()

	dir := "."
	if len(flag.Args()) == 1 {
		dir = flag.Arg(0)
	} else if len(flag.Args()) > 1 {
		log.Fatal("too many arguments.")
	}

	if err := populateCheckout(*mount, dir); err != nil {
		log.Fatalf("populateCheckout: %v", err)
	}
}
