// Copyright (c) Acrosync LLC. All rights reserved.
// Free for personal use and commercial trial
// Commercial use requires per-user licenses available from https://duplicacy.com

package duplicacy

import (
	"encoding/json"
	"io/ioutil"
	"os"
	"path"
	"reflect"
	"strings"
)

// Preference stores options for each storage.
type Preference struct {
	Name              string            `json:"name"`
	SnapshotID        string            `json:"id"`
	RepositoryPath    string            `json:"repository"`
	StorageURL        string            `json:"storage"`
	Encrypted         bool              `json:"encrypted"`
	BackupProhibited  bool              `json:"no_backup"`
	RestoreProhibited bool              `json:"no_restore"`
	DoNotSavePassword bool              `json:"no_save_password"`
	NobackupFile      string            `json:"nobackup_file"`
	Keys              map[string]string `json:"keys"`
	FiltersFile       string            `json:"filters"`
	ExcludeByAttribute bool             `json:"exclude_by_attribute"`
}

var preferencePath string
var Preferences []Preference

func LoadPreferences(repository string) bool {

	preferencePath = path.Join(repository, DUPLICACY_DIRECTORY)

	stat, err := os.Stat(preferencePath)
	if err != nil {
		LOG_ERROR("PREFERENCE_PATH", "Failed to retrieve the information about the directory %s: %v", repository, err)
		return false
	}

	if !stat.IsDir() {
		content, err := ioutil.ReadFile(preferencePath)
		if err != nil {
			LOG_ERROR("DOT_DUPLICACY_PATH", "Failed to locate the preference path: %v", err)
			return false
		}
		realPreferencePath := strings.TrimSpace(string(content))
		stat, err := os.Stat(realPreferencePath)
		if err != nil {
			LOG_ERROR("PREFERENCE_PATH", "Failed to retrieve the information about the directory %s: %v", content, err)
			return false
		}
		if !stat.IsDir() {
			LOG_ERROR("PREFERENCE_PATH", "The preference path %s is not a directory", realPreferencePath)
		}

		preferencePath = realPreferencePath
	}

	description, err := ioutil.ReadFile(path.Join(preferencePath, "preferences"))
	if err != nil {
		LOG_ERROR("PREFERENCE_OPEN", "Failed to read the preference file from repository %s: %v", repository, err)
		return false
	}

	err = json.Unmarshal(description, &Preferences)
	if err != nil {
		LOG_ERROR("PREFERENCE_PARSE", "Failed to parse the preference file for repository %s: %v", repository, err)
		return false
	}

	if len(Preferences) == 0 {
		LOG_ERROR("PREFERENCE_NONE", "No preference found in the preference file")
		return false
	}

	for _, preference := range Preferences {
		if strings.ToLower(preference.Name) == "ssh" {
			LOG_ERROR("PREFERENCE_INVALID", "'%s' is an invalid storage name", preference.Name)
			return false
		}
	}

	return true
}

func GetDuplicacyPreferencePath() string {
	if preferencePath == "" {
		LOG_ERROR("PREFERENCE_PATH", "The preference path has not been set")
		return ""
	}
	return preferencePath
}

// Normally 'preferencePath' is set in LoadPreferences; however, if LoadPreferences is not called, this function
// provide another change to set 'preferencePath'
func SetDuplicacyPreferencePath(p string) {
	preferencePath = p
}

func SavePreferences() bool {
	description, err := json.MarshalIndent(Preferences, "", "    ")
	if err != nil {
		LOG_ERROR("PREFERENCE_MARSHAL", "Failed to marshal the repository preferences: %v", err)
		return false
	}
	preferenceFile := path.Join(GetDuplicacyPreferencePath(), "preferences")

	err = ioutil.WriteFile(preferenceFile, description, 0600)
	if err != nil {
		LOG_ERROR("PREFERENCE_WRITE", "Failed to save the preference file %s: %v", preferenceFile, err)
		return false
	}

	return true
}

func FindPreference(name string) *Preference {
	for i, preference := range Preferences {
		if preference.Name == name || preference.StorageURL == name {
			return &Preferences[i]
		}
	}

	return nil
}

func (preference *Preference) Equal(other *Preference) bool {
	return reflect.DeepEqual(preference, other)
}
