package main

import (
	"errors"
	"fmt"
	"path/filepath"
	"runtime"
	"strings"
)

// highestCommonParent finds the oldest ancestor of a set of paths.
// If there is no common ancestor, returns / on Linux or an error on Windows.
func highestCommonParent(paths []string) (string, error) {
	if len(paths) == 0 {
		return "", errors.New("no input")
	}

	parts := strings.Split(paths[0], string(filepath.Separator))

	caseSensitive := runtime.GOOS != "windows"

	for _, check := range paths {
		checkn := strings.Split(check, string(filepath.Separator))

		// If this check path is shorter, the common part must also shrink
		if len(checkn) < len(parts) {
			parts = parts[0:len(checkn)]
		}

		for i, checkpart := range checkn[0:len(parts)] { // len(parts) is now <= len(checkn) so this is safe
			if caseSensitive {
				if parts[i] == checkpart {
					continue
				}
			} else {
				// case insensitive comparison
				if strings.EqualFold(parts[i], checkpart) {
					continue
				}
			}

			// Divergence from i: onwards
			parts = parts[0:i]
			break
		}

		// Early failure case
		if len(parts) == 0 {
			break
		}

	}

	isEmpty := len(parts) == 0 || (len(parts) == 1 && parts[0] == "")

	if isEmpty {
		if runtime.GOOS == "windows" {
			return "", fmt.Errorf("Selected paths have no common ancestor: %v", paths)
		}
		return `/`, nil
	}

	return strings.Join(parts, string(filepath.Separator)), nil
}