package main

import (
	"fmt"
	//"math"
	"path/filepath"
	"log"
	"github.com/jlaffaye/ftp"
	"time"
	"bytes"
	"os"
	"io/ioutil"
	"strconv"
	"encoding/json"
)

type FtpTransferInfo struct
{
	ServerAddr string 
	Port int64 
	Id string
	Pw string
	Remote string
	SourceDir string
	FileFilter string
	RenameDir string
	LogFileNameWithoutExtension string
	IntervalInSec int64
}

func main() {
	fti, err := GetConfigInfo("./ftpConfig.json")
	IsThereError(nil, err)

	//transferTicker := time.NewTicker(30 * time.Second)
	transferTicker := time.NewTicker(time.Duration(fti.IntervalInSec) * time.Second)
	for{
		select{
			case <-transferTicker.C:
				TransferFiles(fti)
		}
	}
}

func IsThereError(fo *os.File, err error)(bool){
	if err != nil {
		log.Fatal(err)
		if fo != nil {
			fmt.Fprint(fo, time.Now().String() + ">>> ")
			fmt.Fprintln(fo, err)
		}

		return true
	}

	return false
}

func GetLogNameEveryDay()(string){
	//dayInfo := strconv.FormatInt((int64)time.Now().Year(), 10) + strconv.FormatInt(time.Now().Month(), 10) + strconv.FormatInt(time.Now().Day(), 10)
	t := time.Now()
	dayInfo := fmt.Sprintf("%d%02d%02d", t.Year(), t.Month(), t.Day())

	return dayInfo
}

func GetConfigInfo(configFile string) (FtpTransferInfo, error){
	// Open our jsonFile
    jsonFile, err := os.Open(configFile)
    IsThereError(nil, err)

    // defer the closing of our jsonFile so that we can parse it later on
    defer jsonFile.Close()

    byteValue, _ := ioutil.ReadAll(jsonFile)

    var ftpInfo FtpTransferInfo

    json.Unmarshal(byteValue, &ftpInfo)

    fo, err := os.OpenFile(ftpInfo.LogFileNameWithoutExtension + GetLogNameEveryDay() + ".txt", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0777)
	IsThereError(fo, err)

	fmt.Println("Successfully Opened " + configFile)
    fmt.Fprintln(fo, time.Now().String() + ">>> Successfully Opened " + configFile)
    
    fmt.Println(ftpInfo)
    fmt.Fprint(fo, time.Now().String() + ">>> ")
    fmt.Fprintln(fo, ftpInfo)

	return ftpInfo, nil
}

func PrintLog(logMessage string, fo *os.File, err error){
	fmt.Println(time.Now().String() + ">>> " + logMessage)
    fmt.Fprint(fo, time.Now().String() + ">>> " + logMessage, err)
}

func TransferFiles(ftpTransferInfo FtpTransferInfo)(){
	fo, err := os.OpenFile(ftpTransferInfo.LogFileNameWithoutExtension + GetLogNameEveryDay() + ".txt", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0777)
	if IsThereError(fo, err) == true {
		return
	}

	// files, err := filepath.Glob(ftpTransferInfo.FileFilter)
	// if IsThereError(fo, err) == true {
	// 	return
	// }

	var files []string

	err = filepath.Walk(ftpTransferInfo.SourceDir, func(path string, info os.FileInfo, err error) error {
		if info.IsDir() {
			return nil
		}

		if filepath.Ext(path) == ftpTransferInfo.FileFilter {
			return nil
		}

		files = append(files, path)
		return nil
	})

	for _, file := range files {
        fmt.Println(file)
    }

	if IsThereError(fo, err) == true {
		return
	}

	if len(files) == 0 {
		logMessage := "There is no file to transter."
		PrintLog(logMessage, fo, nil)
		return
	}

	c, err := ftp.Dial(ftpTransferInfo.ServerAddr + ":" + strconv.FormatInt(ftpTransferInfo.Port, 10), ftp.DialWithTimeout(5*time.Second))
	if IsThereError(fo, err) == true {
		return
	}

	err = c.Login(ftpTransferInfo.Id, ftpTransferInfo.Pw)
	if IsThereError(fo, err) == true {
		return
	}

	path, err := c.CurrentDir()
	if IsThereError(fo, err) == true {
		return
	}

	PrintLog(path, fo, nil)

	err = c.ChangeDir(ftpTransferInfo.Remote)
	if IsThereError(fo, err) == true {
		return
	}

	path, err = c.CurrentDir()
	if IsThereError(fo, err) == true {
		return
	}

	PrintLog(path, fo, nil)

	logMessage := "FTP Uploading is started."
	PrintLog(logMessage, fo, nil)

	for _, file := range files{
		data := bytes.NewBufferString(file)
		err = c.Stor(file, data)

		// if err != nil {
		// 	log.Fatal(err)
		// } else {
		if IsThereError(fo, err) == false {
			logMsg := time.Now().String() + ">>> Succeeded to upload file: " + file
			PrintLog(logMsg, fo, err)

			target := ftpTransferInfo.RenameDir + file
			err = os.Rename(file, target)
			if IsThereError(fo, err) == true {
				return
			}

			logMsg = time.Now().String() + ">>> Succeeded to move file: <source: " + file + ">, <target: " + target + ">"
			PrintLog(logMsg, fo, err)
		}
	}

	err = c.Quit()
	if IsThereError(fo, err) == true {
		return
	}

	logMessage = "FTP Uploading is terminated."
	PrintLog(logMessage, fo, nil)
	fmt.Fprintln(fo, "")

	defer func() {
        if err := recover(); err != nil {
            fmt.Println(err)
            fmt.Fprint(fo, time.Now().String() + ">>> ")
			fmt.Fprintln(fo, err)
        }
    }()
}