// Copyright (C) 2023  Nexedi SA and Contributors
//
// This program is free software: you can Use, Study, Modify and Redistribute
// it under the terms of the GNU General Public License version 3, or (at your
// option) any later version, as published by the Free Software Foundation.
//
// You can also Link and Combine this program with other software covered by
// the terms of any of the Free Software licenses or any of the Open Source
// Initiative approved licenses and Convey the resulting work. Corresponding
// source of such a combination shall include the source code for all other
// software used.
//
// This program is distributed WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
//
// See COPYING file for full licensing terms.
// See https://www.nexedi.com/licensing for rationale and options.

// Package xfilepath provides addons to std package filepath.
package xfilepath

import (
	"os/user"
	path_ "path"
	"strings"
)

// ExpandUser does '~' and '~username' expansion.
//
// It resolves '~' into the $HOME directory of current user
// and '~user' into the $HOME directory of 'user'.
//
// If the provided path doesn't start with '~', ExpandUser returns the path
// without any changes.
//
// ExpandUser does NOT support bashs '~+' and '~-' prefix (for '$PWD' and '$OLDPWD')
// and it does NOT support bashs '~N', '~+N' and '~-N' prefix.
//
// Please see here for bash tilde expansion documentation:
//   https://www.gnu.org/software/bash/manual/html_node/Tilde-Expansion.html
func ExpandUser(path string) string {
	if strings.HasPrefix(path, "~") {
		s := strings.SplitN(path[1:], "/", 2)
		if home, err := homeOf(s[0]); err == nil {
			var remainder string
			if len(s) > 1 { remainder = s[1] }
			return path_.Join(home, remainder)
		}
		// We ignore any error returned by 'homeOf' and simply
		// return path as it is.
		// We do so to be compatible with the behaviour of bash and
		// of pythons 'os.path.expanduser' function.
	}
	return path
}

// homeOf returns $HOME of user with given username.
// If username is an empty string (e.g. ""), homeOf returns
// $HOME of the current user.
func homeOf(username string) (string, error) {
	usr, err := lookupUser(username)
	if err != nil {
		return "", err
	}
	return usr.HomeDir, nil
}

// lookupUser returns User with username.
//
// If username is an empty string (""), lookupUser
// returns the current user.
func lookupUser(username string) (*user.User, error) {
	if username == "" {
		return user.Current()
	} else {
		return user.Lookup(username)
	}
}
