// this file has been modified from its original found in:
// https://github.com/kubernetes-sigs/aws-ebs-csi-driver

/*
Copyright 2019 The Kubernetes Authors.

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 util

import (
	"crypto/sha256"
	"encoding/binary"
	"fmt"
	"net/url"
	"os"
	"path/filepath"
	"strings"
)

func ParseEndpoint(endpoint string) (string, string, error) {
	scheme, addr, err := ParseEndpointNoRemove(endpoint)
	if err != nil {
		return "", "", err
	}

	if scheme == "unix" {
		if err := os.Remove(addr); err != nil && !os.IsNotExist(err) {
			return "", "", fmt.Errorf("could not remove unix domain socket %q: %w", addr, err)
		}
	}

	return scheme, addr, nil
}

// Parses the endpoint but doesn't remove the unix socket file if
// the endoint is a unix socket.
func ParseEndpointNoRemove(endpoint string) (string, string, error) {
	u, err := url.Parse(endpoint)
	if err != nil {
		return "", "", fmt.Errorf("could not parse endpoint: %w", err)
	}

	addr := filepath.Join(u.Host, filepath.FromSlash(u.Path))
	scheme := strings.ToLower(u.Scheme)
	switch scheme {
	case "tcp":
	case "unix":
		addr = filepath.Join("/", addr)
	default:
		return "", "", fmt.Errorf("unsupported protocol: %s", scheme)
	}

	return scheme, addr, nil
}

const (
	// GID range for mount point permissions to minimize probability of collisions
	minGID = 900000
	maxGID = 999999
)

// GenerateGIDFromPath generates a GID in range [900000, 999999] from a string
func GenerateGIDFromPath(path string) int {
	// Generate SHA256 hash of the path
	h := sha256.New()
	h.Write([]byte(path))
	hash := h.Sum(nil)

	// Use last 4 bytes of hash to generate number in our range
	num := binary.BigEndian.Uint32(hash[len(hash)-4:])

	// Map to our range
	diff := maxGID - minGID + 1
	gid := minGID + (int(num) % diff)

	return gid
}
