/*
** Job Arranger for ZABBIX
** Copyright (C) 2025 Daiwa Institute of Research Ltd. All Rights Reserved.
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
**/

package clientcommon

import (
	"bytes"
	"encoding/json"
	"flag"
	"fmt"
	"io"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"sync"
	"time"

	"jobarranger2/src/libs/golibs/common"
	jatcp "jobarranger2/src/libs/golibs/ja_tcp"
	"jobarranger2/src/libs/golibs/utils"
)

var (
	TransactionId        string
	ParentSocketFilePath string
	InFolderPath         string
	RunFolderPath        string
	UdsDirpath           string
	TmpDirPath           string
	ClientDataFolderPath string
	Timeout              uint
	DataFilePath         string
	SourceIp             string
	data                 common.EventData
	RunCountFolderPath   string
)

var BeforeVariableMap = make(map[string]string)
var BeforeVariableMu sync.Mutex

const (
	CLIENT_DATA_PATH    = "/var/lib/jobarranger/server/iconexecutionmanager/client_data"
	JobRun              = "jobrun" // kind for jobrun
	CheckJob            = "chkjob" // kind for checkjob
	Version             = 1.0      // protocol version
	PrefixRemoveFlagOn  = 1
	PrefixRemoveFlagOff = 0
)

// IconClient represeents job icon types in String
type IconClient string

const (
	IconClientStart  IconClient = "start_icon_client"
	IconClientEnd    IconClient = "end_icon_client"
	IconClientIf     IconClient = "if_icon_client"
	IconClientValue  IconClient = "value_icon_client"
	IconClientJob    IconClient = "job_icon_client"
	IconClientJobnet IconClient = "jobnet_icon_client"
	IconClientM      IconClient = "M_icon_client"
	IconClientW      IconClient = "W_icon_client"
	IconClientL      IconClient = "loop_icon_client"
	IconClientExtJob IconClient = "extjob_icon_client"
	IconClientCalc   IconClient = "calc_icon_client"
	IconClientTask   IconClient = "task_icon_client"
	IconClientInfo   IconClient = "info_icon_client"
	IconClientIfEnd  IconClient = "endif_icon_client"
	IconClientFCopy  IconClient = "fcopy_icon_client"
	IconClientFWait  IconClient = "fwait_icon_client"
	IconClientReboot IconClient = "reboot_icon_client"
	IconClientRel    IconClient = "rel_icon_client"
	IconClientLess   IconClient = "less_icon_client"
	IconClientLink   IconClient = "link_icon_client"
)

type SshExecRequest struct {
	Command      string `json:"command"`
	RunMode      int    `json:"run_mode"`
	SessionFlag  int    `json:"session_flag"`
	PromptString string `json:"prompt_string"`
	LineFeedCode int    `json:"line_feed_code"`
}

type SshExecResponse struct {
	Stdout   string `json:"stdout"`
	Stderr   string `json:"stderr"`
	ExitCode int    `json:"exit_code"`
}

// Parse run arguments
func ParseArgs() error {
	var timeout string

	funcName := "ParseArgs"
	flag.StringVar(&TransactionId, "id", "", "Transaction ID")
	flag.StringVar(&ParentSocketFilePath, "uds", "", "Icon Exec Manager Unix domain socket file path")
	flag.StringVar(&InFolderPath, "in", "", "Input folder path")
	flag.StringVar(&RunFolderPath, "run", "", "Run folder path")
	flag.StringVar(&UdsDirpath, "udsdir", "", "uds parent folderpath")
	flag.StringVar(&TmpDirPath, "tmpdir", "", "tmp folderpath")
	flag.StringVar(&timeout, "timeout", "0", "timeout")
	flag.StringVar(&ClientDataFolderPath, "clientdata", "", "client_data folderpath")
	flag.StringVar(&SourceIp, "sourceIp", "", "sourceIp")
	flag.Parse()

	if TransactionId == "" || ParentSocketFilePath == "" || InFolderPath == "" || RunFolderPath == "" || UdsDirpath == "" || TmpDirPath == "" || timeout == "0" || ClientDataFolderPath == "" {
		return fmt.Errorf("in %s(), %s", funcName, "Args missing, Usage: client -id <transaction-id> -uds <socket-file-path> -in <in-folder> -run <run-folder> -udsdir <usd-parent-path> -tmpdir <tmp-folder-path> -timeout <timeout> -clientdata <client-data-folder-path>")
	}
	DataFilePath = filepath.Join(InFolderPath, TransactionId+".json")

	// Convert string to uint64 first
	tout, _ := strconv.ParseUint(timeout, 10, 0)
	RunCountFolderPath = filepath.Join(TmpDirPath, string(common.IconExecManagerProcess), string(common.RunCountFolder))
	// Cast to uint
	Timeout = uint(tout)

	return nil
}

// Get data field from next process data
func GetIconExecData() (common.IconExecutionProcessData, error) {
	var (
		iconExecData common.IconExecutionProcessData
		eventData    common.EventData
	)

	funcName := "GetIconExecData"

	fd, err := os.Open(DataFilePath)
	if err != nil {
		return iconExecData, fmt.Errorf("fail to open %s in %s() : %v", DataFilePath, funcName, err)
	}

	content, err := io.ReadAll(fd)
	if err != nil {
		return iconExecData, fmt.Errorf("fail to read %s in %s() : %v", DataFilePath, funcName, err)
	}

	if err := utils.UnmarshalEventData(content, &eventData); err != nil {
		return iconExecData, fmt.Errorf("failed to unmarshal Data in %s() : %w", funcName, err)
	}

	iconExecData = eventData.NextProcess.Data.(common.IconExecutionProcessData)
	return iconExecData, nil
}

// EventDataPrep prepares and returns a common.EventData struct.
//
// This function is used when sending runEvnet to iconexecmanager
// Parameters:
// - iconClient: A string that identifies the client name for unique key
// - iconType: An integer representing the type icon
//
// Returns:
// - A common.EventData struct containing the prepared eventData information for CreateNextEvent().
func IconRunDataPrep(iconClient string, execData common.IconExecutionProcessData) common.EventData {
	//collect data
	var dataPrepare common.IconRunData
	data.Event.Name = common.EventIconExecRun
	data.Event.UniqueKey = fmt.Sprintf("%s_%d", iconClient, time.Now().UnixNano())
	data.NextProcess.Name = common.IconExecManagerProcess

	dataPrepare.TransactionFileId = TransactionId
	dataPrepare.ExecProcessData = execData

	data.NextProcess.Data = dataPrepare

	// Clean up unnecessary data
	data.TCPMessage = nil
	data.Transfer.Files = nil

	return data
}

/* TCP */

// connect tcp
func TcpConnect(hostip string, port int, timeout uint) (*common.NetConnection, error) {

	var (
		tcp_client *jatcp.TcpClient
		conn       *common.NetConnection
		err        error
	)

	funcName := "TcpConnect"
	tcp_client = jatcp.CreateTcpClient(hostip, port, timeout, SourceIp)

	conn, err = tcp_client.Connect()
	if err != nil {
		return nil, fmt.Errorf("fail to connect TCP in %s() : %w", funcName, err)
	}

	// defer conn.Close()
	return conn, nil
}

func Jaz1SendData(conn *common.NetConnection, data common.TCPMessage, timeout uint) error {
	funcName := "Jaz1SendData"
	conn.SetSendTimeout(int64(timeout))
	if err := conn.Send(data); err != nil {
		return fmt.Errorf("failed to send Data with TCP in %s() : %w", funcName, err)
	}
	return nil
}

func Jaz2SendData(conn *common.NetConnection, data common.EventData, timeout uint) error {
	funcName := "Jaz2SendData"
	conn.SetSendTimeout(int64(timeout))
	if err := conn.Send(data); err != nil {
		return fmt.Errorf("failed to send Data with TCP in %s() : %w", funcName, err)
	}
	return nil
}

func Jaz1ReceiveData(conn *common.NetConnection, timeout uint) (common.TCPMessage, error) {
	var tcpMessageData common.TCPMessage

	funcName := "Jaz1ReceiveData"
	conn.SetReceiveTimeout(int64(timeout))
	mapData, err := conn.Receive()
	if err != nil {
		return tcpMessageData, fmt.Errorf("failed to receive ACK Data in %s() : %w", funcName, err)
	}

	if err = utils.Convert(mapData, &tcpMessageData); err != nil {
		return tcpMessageData, fmt.Errorf("failed to convert Data in %s() : %w", funcName, err)
	}

	return tcpMessageData, nil
}

func Jaz2ReceiveData(conn *common.NetConnection, timeout uint) (common.EventData, error) {
	var tcpEventData common.EventData
	funcName := "Jaz2ReceiveData"
	conn.SetReceiveTimeout(int64(timeout))
	mapData, err := conn.Receive()
	if err != nil {
		return tcpEventData, fmt.Errorf("failed to receive ACK Data in %s() : %w", funcName, err)
	}

	if err = utils.Convert(mapData, &tcpEventData); err != nil {
		return tcpEventData, fmt.Errorf("failed to convert Data in %s() : %w", funcName, err)
	}

	return tcpEventData, nil
}

func CheckJazVersion(hostIp string, port int, hostName string, serverId string) (int, float64, error) {
	var (
		tcpMessageData common.TCPMessage
		tcpJobRunData  common.JobRunRequestData
		responseData   common.ResponseData
	)

	funcName := "CheckJazVersion"
	//connect host
	checkHostConn, err := TcpConnect(hostIp, port, Timeout)
	if err != nil {
		return 0, 0, err
	}
	defer checkHostConn.Close()

	tcpJobRunData.JobID = "1"
	tcpJobRunData.Type = common.AgentJobTypeCheckVersion

	tcpMessageData.Kind = common.KindFileCopy
	tcpMessageData.Version = 1.0
	tcpMessageData.ServerID = serverId
	tcpMessageData.Hostname = hostName
	tcpMessageData.Data = tcpJobRunData

	//send check request
	err = Jaz1SendData(checkHostConn, tcpMessageData, Timeout)
	if err != nil {
		return 0, 0, fmt.Errorf("check verion request send failed in %s() : %w", funcName, err)
	}

	//receive check response
	if tcpMessageData, err = Jaz1ReceiveData(checkHostConn, Timeout); err != nil {
		return 0, 0, fmt.Errorf("check version response receive failed in %s() : %w", funcName, err)
	}

	if err = utils.Convert(tcpMessageData.Data, &responseData); err != nil {
		return 0, 0, fmt.Errorf("fail to convert data in %s() : %w", funcName, err)
	}

	if responseData.Result == 2 {
		return 1, 0, nil
	}
	return 2, tcpMessageData.EncryptVersion, nil
}

// common for JOB, FWAIT, REBOOT

func JAZ1IconClient(conn *common.NetConnection, data common.EventData) (int, error) {

	var (
		tcpMessage common.TCPMessage
		jaz1Resp   common.ResponseData
		err        error
	)

	funcName := "JAZ1IconClient"
	// data sending with tcp
	err = Jaz1SendData(conn, *data.TCPMessage, Timeout)
	if err != nil {
		return common.JA_JOBEXEC_FAIL, err
	}
	// response data
	tcpMessage, err = Jaz1ReceiveData(conn, Timeout)
	if err != nil {
		return common.JA_JOBEXEC_FAIL, err
	}

	if (tcpMessage == common.TCPMessage{}) {
		return common.JA_JOBEXEC_FAIL, fmt.Errorf("%s(): Response TCPMessage is empty [Data: %v]", funcName, tcpMessage)
	}
	if tcpMessage.Data == nil {
		return common.JA_JOBEXEC_FAIL, fmt.Errorf("%s(): Response TCPMessage.Data is empty [Data: %v]", funcName, tcpMessage)
	}

	if err := utils.Convert(tcpMessage.Data, &jaz1Resp); err != nil {
		return common.JA_JOBEXEC_FAIL, fmt.Errorf("failed to convert Data in %s() : %w", funcName, err)
	}

	if jaz1Resp.Result != 0 {
		return common.JA_JOBRESULT_PRE_EXEC_FAIL, fmt.Errorf("TCP Response with error in %s(), result = %d ", funcName, jaz1Resp.Result)
	}
	return common.JA_JOBRESULT_SUCCEED, nil
}

func JAZ2IconClient(conn *common.NetConnection, data common.EventData) (int, error) {

	funcName := "JAZ2IconClient"
	var (
		err      error
		jaz2Resp common.ResponseData
	)
	// data sending with tcp
	err = Jaz2SendData(conn, data, Timeout)
	if err != nil {
		return common.JA_JOBEXEC_FAIL, err
	}

	// response data
	data, err = Jaz2ReceiveData(conn, Timeout)
	if err != nil {
		return common.JA_JOBEXEC_FAIL, err
	}

	if data.TCPMessage == nil {
		return common.JA_JOBEXEC_FAIL, fmt.Errorf("%s(): Response TCPMessage is empty [ Data: %v ]", funcName, data)
	}

	if data.TCPMessage.Data == nil {
		return common.JA_JOBEXEC_FAIL, fmt.Errorf("%s(): Response TCPMessage.Data is empty [Data: %v ]", funcName, data)
	}

	if err := utils.Convert(data.TCPMessage.Data, &jaz2Resp); err != nil {
		return common.JA_JOBEXEC_FAIL, fmt.Errorf("failed to convert Data in %s() : %w", funcName, err)
	}

	if jaz2Resp.Result != 0 {
		var msg string
		if jaz2Resp.Message != nil {
			msg = *jaz2Resp.Message
		}
		return common.JA_JOBRESULT_PRE_EXEC_FAIL, fmt.Errorf("TCP Response with error in %s(), result = %d, message= %s ", funcName, jaz2Resp.Result, msg)
	}
	return common.JA_JOBRESULT_SUCCEED, nil
}

func SendAndReceive(conn *common.NetConnection, data common.EventData, agentVersion, jaz1SupportFlag int) (int, error) {
	var err error
	var exitCode int

	// version 1
	if agentVersion == 1 {

		if jaz1SupportFlag == 1 {

			data.TCPMessage.JazVersion = &agentVersion

			exitCode, err = JAZ1IconClient(conn, data)
			if err != nil {
				return exitCode, err
			}
		} else {
			return common.JA_JOBRESULT_PRE_EXEC_FAIL, fmt.Errorf("if you want connect the JAZ1 Agent, please set Jaz1Support=1 in jobarg_server.conf")
		}

	} else { //version 2

		data.TCPMessage.JazVersion = &agentVersion

		exitCode, err = JAZ2IconClient(conn, data)
		if err != nil {
			return exitCode, err
		}

	}

	return common.JA_JOBRESULT_SUCCEED, nil
}

func WriteStructToFD3(data any) error {
	fd := 3
	file := os.NewFile(uintptr(fd), "fd3")
	if file == nil {
		return fmt.Errorf("failed to open fd3")
	}

	// Reset file offset to beginning
	if _, err := file.Seek(0, 0); err != nil {
		return fmt.Errorf("failed to seek fd3: %w", err)
	}

	// On overwrite, truncate file to remove old content
	if err := file.Truncate(0); err != nil {
		return fmt.Errorf("failed to truncate fd3: %w", err)
	}

	// Marshal with indentation
	pretty, err := json.MarshalIndent(data, "", "  ")
	if err != nil {
		return fmt.Errorf("failed to marshal data: %w", err)
	}

	// Write with a trailing newline
	if _, err := file.Write(append(pretty, '\n')); err != nil {
		return fmt.Errorf("failed to write to fd3: %w", err)
	}

	return nil
}

func SetBeforeVariable(executionData common.IconExecutionProcessData) error {
	variableMap := map[string]any{}
	dec := json.NewDecoder(bytes.NewReader(executionData.RunJobVariableData.BeforeVariable))
	dec.UseNumber() // prevent float64 conversion

	if err := dec.Decode(&variableMap); err != nil {
		return fmt.Errorf("failed to unmarshal Data: %w", err)
	}

	for k, v := range variableMap {
		switch num := v.(type) {
		case json.Number:
			BeforeVariableMap[k] = num.String() // keep as string
		default:
			BeforeVariableMap[k] = fmt.Sprintf("%v", v)
		}
	}

	return nil
}

func resolveVariable(value string, PrefixRemoveFlag int) string {
	if PrefixRemoveFlag == PrefixRemoveFlagOff {
		if val, ok := BeforeVariableMap[value]; ok {
			return val
		}
	} else {
		if strings.HasPrefix(value, "$") {
			varName := value[1:] // remove leading $
			if val, ok := BeforeVariableMap[varName]; ok {
				return val
			}
		} else {
			return value
		}
	}

	return ""
}

func setResolvedEnv(envVars map[string]string, key, value string, prefixFlag int) {
	resolved := resolveVariable(value, prefixFlag)

	if resolved == "" {
		envVars[key] = value
	} else {
		envVars[key] = resolved
	}
}

func ResolveEnvVars(executionData common.IconExecutionProcessData) (map[string]string, error) {
	envVars := map[string]string{}
	switch executionData.RunJobData.IconType {
	case common.IconTypeJob:
		// check job con data
		for _, jobConData := range executionData.RunValueJobConData {
			envVars[jobConData.ValueName] = resolveVariable(jobConData.ValueName, PrefixRemoveFlagOff)
		}

		// check run value job data
		for _, valueJobData := range executionData.RunValueJobData {
			envVars[valueJobData.ValueName] = resolveVariable(valueJobData.Value, PrefixRemoveFlagOn)
		}
	case common.IconTypeFWait:
		var iconData common.IconFWaitData
		err := utils.Convert(executionData.RunJobData.Data, &iconData)
		if err != nil {
			return nil, fmt.Errorf("failed to convert Data : %w", err)
		}
		setResolvedEnv(envVars, iconData.FileName, iconData.FileName, PrefixRemoveFlagOn)

	case common.IconTypeValue:
		var valueData common.IconValueData
		err := utils.Convert(executionData.RunJobData.Data, &valueData)
		if err != nil {
			return nil, fmt.Errorf("failed to convert Data : %w", err)
		}

		for varKey, varValue := range valueData.Variables {
			setResolvedEnv(envVars, varKey, varValue, PrefixRemoveFlagOn)
		}
	case common.IconTypeIf:
		var iconData common.IconIfData
		err := utils.Convert(executionData.RunJobData.Data, &iconData)
		if err != nil {
			return nil, fmt.Errorf("failed to convert Data : %w", err)
		}

		if val, ok := BeforeVariableMap[iconData.ValueName]; ok {
			envVars[iconData.ValueName] = val
		} else {
			// Explicitly fail when ValueName is missing
			return nil, fmt.Errorf("cannot find value_name '%s'", iconData.ValueName)
		}
	case common.IconTypeFCopy:
		var iconData common.IconFCopyData
		err := utils.Convert(executionData.RunJobData.Data, &iconData)
		if err != nil {
			return nil, fmt.Errorf("failed to convert Data : %w", err)
		}

		setResolvedEnv(envVars, iconData.FromDirectory, iconData.FromDirectory, PrefixRemoveFlagOn)
		setResolvedEnv(envVars, iconData.ToDirectory, iconData.ToDirectory, PrefixRemoveFlagOn)
		setResolvedEnv(envVars, iconData.FromFileName, iconData.FromFileName, PrefixRemoveFlagOn)

	case common.IconTypeLess:
		var decryptedPW string
		var iconData common.IconLessData
		err := utils.Convert(executionData.RunJobData.Data, &iconData)
		if err != nil {
			return nil, fmt.Errorf("failed to convert Data : %w", err)
		}

		setResolvedEnv(envVars, iconData.LoginUser, iconData.LoginUser, PrefixRemoveFlagOn)

		if iconData.LoginPassword != "" {
			if !strings.HasPrefix(iconData.LoginPassword, "2:") {
				// Custom decryption
				decryptedPW = utils.DecryptLegacyLessString(iconData.LoginPassword)
			} else {
				// AES decryption
				decryptedPW, err = utils.DecryptAESLessString(iconData.LoginPassword)
				if err != nil {
					return nil, err
				}
			}
		}

		setResolvedEnv(envVars, iconData.LoginPassword, decryptedPW, PrefixRemoveFlagOn)
		setResolvedEnv(envVars, iconData.PublicKey, iconData.PublicKey, PrefixRemoveFlagOn)
		setResolvedEnv(envVars, iconData.PrivateKey, iconData.PrivateKey, PrefixRemoveFlagOn)
		setResolvedEnv(envVars, iconData.Passphrase, iconData.Passphrase, PrefixRemoveFlagOn)
	}

	return envVars, nil
}

// This function prepares the tcp data for the agent job run from execution data
func PrepareJobRunRequest(executionData common.IconExecutionProcessData, jobRunRequest *common.JobRunRequestData) error {
	var err error

	// set before variables
	if err = SetBeforeVariable(executionData); err != nil {
		return fmt.Errorf("failed to set before variable : %w", err)
	}

	// search and replace env variables
	envVars, err := ResolveEnvVars(executionData)
	if err != nil {
		return fmt.Errorf("failed to set env variables: %w", err)
	}

	jobRunRequest.JobID = strconv.FormatUint(executionData.RunJobData.InnerJobID, 10)
	jobRunRequest.RunUser = &executionData.RunJobData.RunUser
	jobRunRequest.RunUserPassword = &executionData.RunJobData.RunUserPassword

	if executionData.RunJobData.MethodFlag != common.MethodAbort {
		if executionData.RunJobData.TestFlag == 0 {
			jobRunRequest.Method = common.AgentMethodNormal
		} else {
			jobRunRequest.Method = common.AgentMethodTest
		}

	} else {
		jobRunRequest.Method = common.AgentMethodKill
	}

	switch jobRunRequest.Type {
	case common.AgentJobTypeCommand:
		jobRunRequest.Env = envVars

		var iconData common.IconJobData
		err = utils.Convert(executionData.RunJobData.Data, &iconData)
		if err != nil {
			return fmt.Errorf("failed to convert Data : %w", err)
		}

		if executionData.RunJobData.MethodFlag != common.MethodAbort {
			jobRunRequest.Script = iconData.Command
		} else {
			if iconData.StopFlag == 1 {
				jobRunRequest.Method = common.AgentMethodAbort
				jobRunRequest.JobID = strconv.FormatUint(executionData.RunJobData.InnerJobIdFsLink, 10)
				jobRunRequest.Script = iconData.StopCommand
			}
		}
	case common.AgentJobTypeExt:
		var iconData common.IconFWaitData
		err = utils.Convert(executionData.RunJobData.Data, &iconData)
		if err != nil {
			return fmt.Errorf("failed to convert Data : %w", err)
		}

		// Check if any env var still contains "$"
		for key, val := range envVars {
			if strings.HasPrefix(val, "$") {
				return fmt.Errorf("can not find the value [%s]. inner_job_id: %d", key, executionData.RunJobData.InnerJobID)
			}
		}
		fileName := envVars[iconData.FileName]
		deleteFlag := strconv.Itoa(iconData.FileDeleteFlag)
		waitTime := strconv.Itoa(iconData.FileWaitTime)

		jobRunRequest.Argument = []string{
			fileName,
			deleteFlag,
			waitTime,
		}

		switch iconData.FwaitModeFlag {
		case 0:
			jobRunRequest.Script = "jafwait"
		case 1:
			jobRunRequest.Script = "jafcheck"
		default:
			return fmt.Errorf("invalid FwaitModeFlag: %d", iconData.FwaitModeFlag)
		}
	case common.AgentJobTypeReboot:
		var iconData common.IconRebootData
		err = utils.Convert(executionData.RunJobData.Data, &iconData)
		if err != nil {
			return fmt.Errorf("failed to convert Data : %w", err)
		}

		jobRunRequest.Argument = common.RebootArgument{
			RebootModeFlag: iconData.RebootModeFlag,
			RebootWaitTime: iconData.RebootWaitTime,
		}

	case common.AgentJobTypeGetFile:
	case common.AgentJobTypePutFile:
		var fcopyData common.IconFCopyData
		if err = utils.Convert(executionData.RunJobData.Data, &fcopyData); err != nil {
			return fmt.Errorf("failed to convert Data : %w", err)
		}

		var fcopyArguments common.FcopyArgumentData
		fcopyArguments.Filename = envVars[fcopyData.FromFileName]
		fcopyArguments.FromDir = envVars[fcopyData.FromDirectory]
		fcopyArguments.ToDir = envVars[fcopyData.ToDirectory]
		fcopyArguments.Overwrite = fcopyData.OverwriteFlag

		jobRunRequest.Argument = fcopyArguments
	}

	return nil
}
