package main

import (
	"crypto/tls"
	"flag"
	"fmt"
	"log"
	"os"
	"time"

	"github.com/secsy/goftp"
)

var (
	host  string = ""
	port  string = ""
	user  string = ""
	pswd  string = ""
	rmt   string = ""
	loc   string = ""
	act   string = ""
	debug bool   = false
	retry int    = 0
)

func init() {
	flag.BoolVar(&debug, "d", false, "Show Debug Messages")
	flag.StringVar(&host, "h", "203.93.100.58", "FTPS Server Address")
	flag.StringVar(&port, "o", "3031", "FTPS Server Port")
	flag.StringVar(&user, "u", "idte", "Username")
	flag.StringVar(&pswd, "p", "wistronTE2022", "Password")
	flag.StringVar(&loc, "L", "", "Local Path")
	flag.StringVar(&rmt, "R", "", "Remote Path")
	flag.StringVar(&act, "A", "list", "Action: list,upld,dnld")
	flag.IntVar(&retry, "T", 5, "Retry Times")
	flag.Parse()
}

func main() {
	log.SetFlags(log.Ldate | log.Ltime)
	log.SetOutput(os.Stdout)

	if host == "" || port == "" || user == "" || pswd == "" {
		log.Println("[ERR]  Invalid Arguments.")
		os.Exit(1)
	}

	cfg := goftp.Config{
		User:     user,
		Password: pswd,
		Timeout:  time.Second * 30,
		TLSMode:  goftp.TLSExplicit,
		TLSConfig: &tls.Config{
			InsecureSkipVerify: true,
			MinVersion:         tls.VersionTLS10,
		},
	}

	client, err := goftp.DialConfig(cfg, host+":"+port)
	if err != nil {
		log.Printf("[ERR]  %s\r\n", err.Error())
		os.Exit(1)
	}
	defer client.Close()

	cwd, err := client.Getwd()
	if err != nil {
		log.Printf("[ERR]  %s\r\n", err.Error())
		os.Exit(1)
	}
	if debug {
		log.Printf("[MSG]  CWD: %s\r\n", cwd)
	}

	switch act {
	case "list":
		_List(client, rmt)
	case "dnld":
		_Download(client, loc, rmt)
	case "upld":
		_Upload(client, loc, rmt)
	default:
		_List(client, loc)
	}
}

func _List(client *goftp.Client, path string) {
	fis, err := client.ReadDir(path)
	if err != nil {
		log.Printf("[ERR]  %s\r\n", err.Error())
		os.Exit(1)
	}

	fmt.Println("### Name;Size;ModTime;IsDir")
	for _, f := range fis {
		fmt.Printf("%v;%v;%v;%v\r\n", f.Name(), f.Size(), f.ModTime().Format("2006-01-02 15:04:05"), f.IsDir())
	}
}

func _Download(client *goftp.Client, local, remote string) {
	if local == "" || remote == "" {
		log.Println("[ERR]  Invalid Local/Remote Path")
		return
	}
	log.Printf("[MSG]  Downloading %s\r\n", remote)
	var err error
	var wtr *os.File
	defer wtr.Close()
	for r := 0; r <= retry; r++ {
		if r > 0 {
			time.Sleep(time.Second * 1)
			log.Printf("[MSG]  Retrying %d: %s\r\n", r, remote)
		}
		wtr, err = os.Create(local)
		if err != nil {
			continue
		}
		err = client.Retrieve(remote, wtr)
		if err != nil {
			continue
		}
	}
	if err != nil {
		log.Printf("[ERR]  Download NG: %s\r\n", remote)
		log.Printf("[###]  %s\r\n", err.Error())
	} else {
		log.Printf("[MSG]  Download OK: %s\r\n", remote)
	}
}

func _Upload(client *goftp.Client, local, remote string) {
	if local == "" || remote == "" {
		log.Println("[ERR]  Invalid Local/Remote Path")
		return
	}
	log.Printf("[MSG]  Uploading %s\r\n", local)
	var err error
	var rdr *os.File
	defer rdr.Close()
	for r := 0; r <= retry; r++ {
		if r > 0 {
			time.Sleep(time.Second * 1)
			log.Printf("[MSG]  Retrying %d: %s\r\n", r, local)
		}
		rdr, err = os.Open(local)
		if err != nil {
			continue
		}
		err = client.Store(remote, rdr)
		if err != nil {
			continue
		}
	}
	if err != nil {
		log.Printf("[ERR]  Upload NG: %s\r\n", local)
		log.Printf("[###]  %s\r\n", err.Error())
	} else {
		log.Printf("[MSG]  Upload OK: %s\r\n", local)
	}
}
