package engine

import (
	"bytes"
	"compress/gzip"
	"encoding/binary"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"

	"github.com/deranjer/gvc/common/database"
)

// CompressIntArray compresses an array of integers into a buffer
func CompressIntArray(arry []int64, compressionBuffer *bytes.Buffer) (float64, error) {
	buf := new(bytes.Buffer)
	err := binary.Write(buf, binary.LittleEndian, arry)
	if err != nil {
		return 0, err
	}
	//now compress it
	compressor := gzip.NewWriter(compressionBuffer)
	// if err != nil {
	// 	fmt.Println("writer level failed to set compression level")
	// }
	if _, err := compressor.Write(buf.Bytes()); err != nil {
		return 0, err
	}
	if err := compressor.Close(); err != nil {
		return 0, err
	}
	ratio := float64(len(compressionBuffer.Bytes())) / float64(len(buf.Bytes()))
	return ratio, nil
}

// ExpandToIntArray firstly unzips the byte array, then it
// converts the byte array back into an int array for use
func ExpandToIntArray(length int64, arry []byte, intArray *[]int64) error {
	buf := bytes.NewBuffer(arry)
	if reader, err := gzip.NewReader(buf); err != nil {
		fmt.Println("gzip failed ", err)
		return err
	} else {
		*intArray = make([]int64, length) //you must know the length of the original data if you are to do it this way.
		err := binary.Read(reader, binary.LittleEndian, intArray)
		if err != nil {
			fmt.Println("read failed ", err)
		}
		return nil
	}
}

// VerifySrcFile checks to see that the file is a regular file
// that the OS has meta information about and that can be read by
// the os.  Currently done in client or server before handing off to engine since some checks don't involve database/manager
// func VerifySrcFile(src string) (string, error) {
// 	_, fileName := filepath.Split(src) //dirPath
// 	sourceFileStat, err := os.Stat(src)
// 	if err != nil {
// 		return fileName, errors.New("error on os.Stat " + err.Error())
// 	}

// 	if !sourceFileStat.Mode().IsRegular() {
// 		return fileName, errors.New("%s is not a regular file" + src)
// 	}
// 	return fileName, nil
// }

//InitiateDirectory checks all of the directories to make sure they exist
func InitiateDirectory(directory string) {
	// For the keys-folder we need to check if the folder exists...
	checkDir, err := IsDirectory(directory)
	if err != nil {
		fmt.Println("Error checking for "+directory+" directory: %s\r\n", err)
		panic(err)
	}

	if checkDir == true {
		fmt.Println(directory + " already exists")
	} else {
		// Create the directory.
		fmt.Println("Creating " + directory)
		err = CreateDirectory(directory)
		if err != nil {
			fmt.Println("Error creating the folder %s\r\n", err)
			panic(err)
		}
	}
}

func ConvertFileForStorage(file *database.File, folder string) error {
	fileBytes, err := ioutil.ReadFile(file.Path)
	if err != nil {
		return err
	}
	fmt.Println("REMOVE: ", fileBytes)
	filename := folder + string(filepath.Separator) + file.Name
	err = ioutil.WriteFile(filename, fileBytes, 0666)
	if err != nil {
		return err
	}
	return nil

}

func IsDirectory(path string) (bool, error) {

	s, err := os.Stat(path) // returns an error if the path does not exist.
	if err != nil {
		if os.IsNotExist(err) {
			return false, nil
		}
		return false, err // Different error...?
	}

	if s.IsDir() {
		return true, nil
	}

	return false, nil // Redundancy

}

func CreateDirectory(path string) error {
	// Assumes checks have been done on if the directory exists...
	err := os.MkdirAll(path, os.ModePerm)
	if err != nil {
		return err
	}
	return nil // Redundancy

}

func DeleteDirectory(path string) error {
	err := os.RemoveAll(path)
	return err

}

//TODO: Most likely can be done with the filepath command so replace this everywhere
func StripFilePathBase(pathToFile, base string) string {
	return strings.Replace(pathToFile, base, "", -1)
}
