package sync

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

// LocalImporter implements an Importer, where files to imports are located
// inside a local directory from your filesystem.
type LocalImporter struct {
	// Base is the root directory used by the LocalImporter. It should contains all themes.
	Base string
	// Symlink changes the normal file copy/concatenate behaviour to symlink/concatenate.
	// If enable, your base directory must be accessible by the frontend processus as it will follow the symlink.
	Symlink bool
}

func (i LocalImporter) Kind() string {
	if i.Symlink {
		return "local file importer (through symlink): " + i.Base
	} else {
		return "local file importer: " + i.Base
	}
}

func (i LocalImporter) Id() *string {
	return nil
}

func (i LocalImporter) Init() error {
	if f, err := os.Stat(i.Base); os.IsNotExist(err) {
		if err = os.Mkdir(i.Base, 0751); err != nil {
			return err
		}
	} else if err != nil {
		return err
	} else if !f.IsDir() {
		return fmt.Errorf("%q exists and is not a directory", i.Base)
	}
	return nil
}

func (i LocalImporter) Sync() error {
	return nil
}

func (i LocalImporter) Exists(filename string) bool {
	_, err := os.Stat(i.toURL(filename))
	return !os.IsNotExist(err)
}

func (i LocalImporter) toURL(filename string) string {
	return path.Join(i.Base, filename)
}

func (i LocalImporter) GetLocalPath(p ...string) string {
	return i.toURL(path.Join(p...))
}

func (i LocalImporter) importFile(URI string, next func(string, string) (interface{}, error)) (interface{}, error) {
	if i.Symlink {
		dest := GetDestinationFilePath(URI, nil)

		if err := os.MkdirAll(path.Dir(dest), 0751); err != nil {
			return nil, err
		}

		if i.Exists(URI) {
			os.Symlink(i.toURL(URI), dest)
			return next(dest, URI)
		} else {
			os.Symlink(i.toURL(URI)+"_MERGED", dest)
			return ImportFile(i, URI, next)
		}
	} else {
		return ImportFile(i, URI, next)
	}
}

func (i LocalImporter) GetFile(filename string) (io.Reader, error) {
	if fd, err := os.Open(path.Join(i.Base, filename)); err != nil {
		return nil, err
	} else {
		return fd, nil
	}
}

func (i LocalImporter) writeFile(filename string, reader io.Reader) error {
	if fd, err := os.Create(path.Join(i.Base, filename)); err != nil {
		return err
	} else {
		defer fd.Close()
		io.Copy(fd, reader)
		return nil
	}
}

func (i LocalImporter) ListDir(filename string) ([]string, error) {
	if files, err := ioutil.ReadDir(path.Join(i.Base, filename)); err != nil {
		return nil, err
	} else {
		res := make([]string, 0)
		for _, file := range files {
			res = append(res, file.Name())
		}
		return res, nil
	}
}

func (i LocalImporter) Stat(filename string) (os.FileInfo, error) {
	return os.Stat(path.Join(i.Base, filename))
}
