package drivers

import (
	"errors"
	"io"
	"io/ioutil"
	"os"
	"path"
)

type FSDriver struct {
	Path string // Where the objects are stored
}

// Create creates a new object in the storage with given body.
// This just copying the given file into the right location.
func (f FSDriver) Create(key string, filePath string) error {
	err := os.MkdirAll(path.Dir(path.Join(f.Path, key)), 0755)
	if err != nil {
		return err
	}

	source, err := os.Open(filePath)
	if err != nil {
		return err
	}
	defer source.Close()

	destination, err := os.Create(path.Join(f.Path, key))
	if err != nil {
		return err
	}
	defer destination.Close()

	_, err = io.Copy(destination, source)
	return err
}

// Get copies file from the storage into a local file
func (f FSDriver) Get(key string, filePath string) error {
	source, err := os.Open(path.Join(f.Path, key))
	if err != nil {
		return err
	}
	defer source.Close()

	destination, err := os.Create(filePath)
	if err != nil {
		return err
	}
	defer destination.Close()

	_, err = io.Copy(destination, source)
	return err
}

// Read returns content of given key
func (f *FSDriver) Read(key string) ([]byte, error) {
	body, err := ioutil.ReadFile(path.Join(f.Path, key))
	return body, err
}

// Write writes content of body into key
func (f FSDriver) Write(key string, body []byte) error {
	return ioutil.WriteFile(path.Join(f.Path, key), body, 0644)
}

// List returns list of objects in fiven prefix
func (f FSDriver) List(prefix string) ([]string, error) {
	keys := []string{}

	files, err := ioutil.ReadDir(path.Join(f.Path, prefix))
	if err != nil {
		return keys, err
	}
	for _, file := range files {
		keys = append(keys, file.Name())
	}

	return keys, nil
}

// Delete deletes one object
func (f FSDriver) Delete(key string) error {
	return os.Remove(path.Join(f.Path, key))
}

// GetDownloadLink is not implemented in this driver
func (f FSDriver) GetDownloadLink(key string) (string, error) {
	return "", errors.New("not implemented")
}