/*
** 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 main

import (
	"encoding/json"
	"fmt"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"time"

	"jobarranger2/src/libs/golibs/common"
	"jobarranger2/src/libs/golibs/database"
	"jobarranger2/src/libs/golibs/logger/logger"
	"jobarranger2/src/libs/golibs/utils"
)

const processName = "flowmanager"

func CheckIconStatus(conn database.DBConnection, eventName common.EventName, innerJobId uint64) error {
	var expectedStatus, currentStatus common.StatusType
	var err error

	funcName := "CheckIconStatus"
	if eventName == common.EventIconResultEnd {
		expectedStatus = common.StatusEnd
	} else if eventName == common.EventIconResultRunErr {
		expectedStatus = common.StatusRunErr
	} else {
		return nil
	}

	currentStatus, err = utils.GetStatusFromRunJobTableByInnerJobId(conn, innerJobId)
	if err != nil {
		logger.JaLog("JAFLOW200000", logger.Logging{}, funcName,
			"GetStatusFromRunJobTableByInnerJobId", err)
		return fmt.Errorf("GetStatusFromRunJobTableByInnerJobId() failed")
	}
	if currentStatus != expectedStatus {
		logger.JaLog("JAFLOW300003", logger.Logging{}, funcName,
			innerJobId, expectedStatus, currentStatus)
		return fmt.Errorf("icon status is not synced")
	}
	return nil
}

func ValidateProcessData(conn database.DBConnection, eventName common.EventName, processData common.FlowProcessData) error {
	var err error = nil
	funcName := "ValidateProcessData"
	logger.JaLog("JAFLOW400001", logger.Logging{}, funcName,
		fmt.Sprintf("inner_jobnet_id: %d, inner_job_id: %d",
			processData.InnerJobnetId, processData.InnerJobId))

	if eventName == common.EventFlowCheckAgent || eventName == common.EventFlowCheckLocal {
		checkJobData := processData.Data.(common.CheckJobData)
		if eventName == common.EventFlowCheckAgent && checkJobData.HostName == "" {
			err = fmt.Errorf("host_name is considered empty")
		}
		if len(checkJobData.CheckJobIdList) == 0 {
			err = fmt.Errorf("check job id list are considered empty")
		}
		if err != nil {
			logger.JaLog("JAFLOW200007", logger.Logging{}, funcName, err)
			return err
		}
		return err
	} else {
		if processData.InnerJobId == 0 {
			err = fmt.Errorf("inner_job_id: %d is considered empty", processData.InnerJobId)
		} else if processData.InnerJobnetId == 0 {
			err = fmt.Errorf("inner_jobnet_id: %d is considered empty", processData.InnerJobnetId)
		} else if len(processData.JobnetId) == 0 {
			err = fmt.Errorf("jobnet_id is considered empty")
		} else if processData.IconType < common.IconTypeStart || processData.IconType > common.IconTypeLink {
			err = fmt.Errorf("icon_type: %d is considered not valid", processData.IconType)
		}
		if err != nil {
			logger.JaLog("JAFLOW200007", logger.Logging{}, funcName, err)
			return err
		}
	}

	//check current icon status
	err = CheckIconStatus(conn, eventName, processData.InnerJobId)
	if err != nil {
		return err
	}

	logger.JaLog("JAFLOW400002", logger.Logging{}, funcName,
		fmt.Sprintf("inner_jobnet_id: %d, inner_job_id: %d",
			processData.InnerJobnetId, processData.InnerJobId))
	return nil
}

func ProcessEventData(data common.Data) {
	var eventStruct common.Event
	var receivedEventData common.EventData
	var processData common.FlowProcessData
	var nextProcessData common.IconExecutionProcessData
	var checkProcessData common.CheckJobData
	var jobnetStatusChange common.JobnetRunData

	var conn database.DBConnection

	var mIconJobId uint64
	var innerJobIdList []uint64

	var hostname string
	var funcName = fmt.Sprintf("ProcessEventData(%s)", processName)
	var processType = common.FlowProcessNormal
	var currentMethodFlag common.JobRunMethod

	var err error
	var ok bool

	logger.JaLog("JAFLOW400001", logger.Logging{}, funcName, receivedEventData.Event.Name)

	if err = utils.UnmarshalEventData(data.EventData, &receivedEventData); err != nil {
		logger.JaLog("JAFLOW200000", logger.Logging{}, funcName, "UnmarshalEventData", err)
		goto MoveToSubFolder
	}
	logger.JaLog("JAFLOW400003", logger.Logging{}, funcName, receivedEventData)

	conn = data.DBConn
	processData, ok = receivedEventData.NextProcess.Data.(common.FlowProcessData)
	if !ok {
		logger.JaLog("JAFLOW200007", logger.Logging{}, funcName,
			fmt.Errorf("invalid received data for %s", receivedEventData.Event.Name))
		goto MoveToSubFolder
	}
	if receivedEventData.Event.Name == common.EventJobnetRun {
		processData.InnerJobId, err = utils.GetRunJobIdByTypeAndInnerJobnetId(conn, processData.IconType, processData.InnerJobnetId)
		if err != nil {
			logger.JaLog("JAFLOW200000", logger.Logging{}, funcName, "GetJobIdByTypeAndInnerJobnetId", err)
			goto MoveToSubFolder
		}
	} else if receivedEventData.Event.Name == common.EventSubJobnetStatusChange {
		processData.InnerJobId, err = utils.GetInnerJobIdFromRunJobnetTableByInnerJobnetId(conn, processData.InnerJobnetId)
		if err != nil {
			logger.JaLog("JAFLOW200008", logger.Logging{}, funcName,
				common.Ja2RunJobnetTable, nextProcessData.RunJobnetData.InnerJobID, err)
			goto MoveToSubFolder
		}
	} else if receivedEventData.Event.Name == common.EventFlowCheckAgent ||
		receivedEventData.Event.Name == common.EventFlowCheckLocal {
		err = utils.Convert(processData.Data, &checkProcessData)
		if err != nil {
			logger.JaLog("JAFLOW200007", logger.Logging{}, funcName,
				fmt.Errorf("data is not for check job process, %v", processData.Data))
			return
		}
		processData.Data = checkProcessData
	}
	if err = ValidateProcessData(conn, receivedEventData.Event.Name, processData); err != nil {
		logger.JaLog("JAFLOW200000", logger.Logging{}, funcName, "ValidateProcessData", err)
		goto MoveToSubFolder
	}

	if receivedEventData.Event.Name == common.EventIconResultEnd {

		currentMethodFlag, err = utils.GetMethodFlagFromRunJobTableByInnerJobId(conn, processData.InnerJobId)
		if err != nil {
			logger.JaLog("JAFLOW200000", logger.Logging{}, funcName,
				"GetMethodFlagFromRunJobTableByInnerJobId", err)
		}
		if currentMethodFlag == common.MethodAbort {

			nextProcessData, ok = processData.Data.(common.IconExecutionProcessData)
			if !ok {
				logger.JaLog("JAFLOW200007", logger.Logging{}, funcName,
					fmt.Errorf("data is not for EventIconResultEnd, received data: %v,"+
						" expected data: IconExecutionProcessData", processData.Data))
				goto MoveToSubFolder
			} else {

				jobnetStatusChange.InnerJobnetId = processData.InnerJobnetId
				jobnetStatusChange.JobnetID = processData.JobnetId
				jobnetStatusChange.Status = common.StatusRunErr
				jobnetStatusChange.JobId = nextProcessData.RunJobData.JobID
				if err = ProcessJobnetStatusChange(common.EventJobnetRunError, jobnetStatusChange); err != nil {
					logger.JaLog("JAFLOW200000", logger.Logging{}, funcName, "ProcessJobnetStatusChange", err)
				}
			}
			goto MoveToSubFolder
		}
	}

	logger.JaLog("JAFLOW400004", logger.Logging{}, funcName, processData)

	if processData.IconType == common.IconTypeReboot &&
		(receivedEventData.Event.Name == common.EventIconResultEnd ||
			receivedEventData.Event.Name == common.EventIconResultRunErr) {
		iconExecData, ok := processData.Data.(common.IconExecutionProcessData)
		if !ok {
			logger.JaLog("JAFLOW200007", logger.Logging{}, funcName,
				fmt.Errorf("invalid received data for %s", receivedEventData.Event.Name))
			goto MoveToSubFolder
		}
		if len(iconExecData.JobResult.Hostname) > 0 || iconExecData.JobResult.Hostname != "" {
			hostname = iconExecData.JobResult.Hostname
		} else {
			var runJobData common.RunJobTable
			runJobData, err = utils.GetRunJobData(conn, processData.InnerJobId)
			if err != nil {
				logger.JaLog("JAFLOW200000", logger.Logging{}, funcName, "GetRunJobData", err)
				goto MoveToSubFolder
			}
			switch runJobData.Data["host_flag"].(float64) {
			case 0:
				hostname = runJobData.Data["host_name"].(string)
			case 1:
				// Extract hostname key
				hostNameKey, ok := runJobData.Data["host_name"].(string)
				if !ok || hostNameKey == "" {
					logger.JaLog("JAFLOW200007", logger.Logging{}, funcName,
						fmt.Errorf("host_name is missing or not a string, received event data: [%v]", receivedEventData))
					goto MoveToSubFolder
				}

				// Unmarshal variable map
				var variableMap map[string]any
				if err := json.Unmarshal(
					[]byte(iconExecData.RunJobVariableData.BeforeVariable),
					&variableMap,
				); err != nil {
					logger.JaLog("JAFLOW200007", logger.Logging{}, funcName,
						fmt.Errorf("failed to unmarshal BeforeVariable: [%v]", iconExecData.RunJobVariableData.BeforeVariable))
					goto MoveToSubFolder
				}

				// Get hostname value from map
				value, exists := variableMap[hostNameKey]
				if !exists {
					logger.JaLog("JAFLOW200007", logger.Logging{}, funcName,
						fmt.Errorf("hostname key [%s] not found in variable map, before variable map: [%v]", hostNameKey, variableMap))
					goto MoveToSubFolder
				}

				// Convert to string
				hostname = fmt.Sprintf("%v", value)
			}
		}

		if hostname == "" {
			logger.JaLog("JAFLOW200007", logger.Logging{}, funcName,
				fmt.Errorf("hostname is consider empty, received event data: [%v] ", receivedEventData))
			goto MoveToSubFolder
		}

		err := os.Remove(
			filepath.Join(
				common.ServerTmpFolderPath, common.FlowManagerFolder, common.HostLockSubFolder, hostname,
			),
		)
		if err != nil && !(os.IsNotExist(err)) {
			logger.JaLog("JAFLOW200000", logger.Logging{}, funcName, "os.Remove()",
				fmt.Errorf("inner_job_id : %d, err: [%w]", processData.InnerJobId, err))
			return
		}

		fromFolder := filepath.Join(common.ServerTmpFolderPath, common.FlowManagerFolder,
			common.FlowManagerSubFolders[1], hostname)
		toFolder := filepath.Join(common.ServerTmpFolderPath, common.FlowManagerFolder,
			common.FlowManagerSubFolders[0])

		if _, err := os.Stat(fromFolder); err == nil {
			err = utils.MoveAllFiles(fromFolder, toFolder)
			if err != nil {
				logger.JaLog("JAFLOW200000", logger.Logging{}, funcName, "MoveAllFiles", err)
				return
			}
		} else if os.IsNotExist(err) {
			logger.JaLog("JAFLOW400007", logger.Logging{}, funcName, hostname)
		} else {
			logger.JaLog("JAFLOW200000", logger.Logging{}, funcName, "os.Stat", err)
			return
		}
	}

	switch receivedEventData.Event.Name {

	case common.EventJobnetRun:
		eventStruct.Name = common.EventIconReady
		innerJobIdList = append(innerJobIdList, processData.InnerJobId)

	case common.EventMIconRun:
		eventStruct.Name = common.EventIconReady
		processType = common.FlowParallelStartRun
		innerJobIdList, err = utils.GetNextFlowJobIDList(conn, processData.InnerJobId, processData.FlowType)
		if err != nil {
			logger.JaLog("JAFLOW200000", logger.Logging{}, funcName, "GetNextFlowJobIDList", err)
			goto MoveToSubFolder
		}

	case common.EventIconRerun, common.EventIconRerunJobnetStatusChange:
		eventStruct.Name = common.EventIconReady
		processType = common.FlowProcessIconRerun
		innerJobIdList = append(innerJobIdList, processData.InnerJobId)

	case common.EventFailoverIconRerun:
		eventStruct.Name = common.EventIconReady
		processType = common.FlowProcessFailoverIconRerun
		innerJobIdList = append(innerJobIdList, processData.InnerJobId)

	case common.EventIconRetry:
		eventStruct.Name = common.EventIconRetry
		err = utils.Convert(processData.Data, &nextProcessData)
		if err != nil {
			logger.JaLog("JAFLOW200000", logger.Logging{}, funcName, "Convert", err)
		}

	case common.EventIconResultRunErr:
		continueFlag, err := utils.GetIconContinueFlag(conn, processData.InnerJobId)
		if err != nil {
			logger.JaLog("JAFLOW200000", logger.Logging{}, funcName, "GetIconContinueFlag", err)
			goto MoveToSubFolder
		} else if continueFlag == int(common.FlagOff) {
			eventStruct.Name = common.EventJobnetRunError
			nextProcessData, ok = processData.Data.(common.IconExecutionProcessData)
			if !ok {
				logger.JaLog("JAFLOW200007", logger.Logging{}, funcName,
					fmt.Errorf("data is not for EventIconResultRunErr, received data: %T,"+
						" expected data: IconExecutionProcessData", processData.Data))
				goto MoveToSubFolder
			}
			eventStruct.Name = common.EventJobnetRunError
			jobnetStatusChange.InnerJobnetId = processData.InnerJobnetId

			jobnetStatusChange.JobnetID = processData.JobnetId
			jobnetStatusChange.Status = common.StatusRunErr
			jobnetStatusChange.JobId = nextProcessData.RunJobData.JobID

		} else {
			eventStruct.Name = common.EventIconReady
			innerJobIdList, err = utils.GetNextFlowJobIDList(conn, processData.InnerJobId, processData.FlowType)
			if err != nil {
				logger.JaLog("JAFLOW200000", logger.Logging{}, funcName, "GetNextFlowJobIDList", err)
				goto MoveToSubFolder
			}
		}

	case common.EventIconResultEnd:
		switch processData.IconType {
		case common.IconTypeEnd:
			eventStruct.Name = common.EventEndIconEnd
			jobnetStatusChange.InnerJobnetId = processData.InnerJobnetId
			jobnetStatusChange.JobnetID = processData.JobnetId

		case common.IconTypeM:
			receivedFrom := receivedEventData.Event.UniqueKey
			idx := strings.LastIndex(receivedFrom, "_")
			if idx == -1 {
				logger.JaLog("JAFLOW200000", logger.Logging{}, funcName,
					"LastIndex", fmt.Errorf("expected 'processType_timestamp', received: %s", receivedFrom))
				return
			}
			receivedFrom = receivedFrom[:idx]
			if receivedFrom == string(common.IconResultManagerProcess) {
				goto MoveToSubFolder
			}

			var runJobData common.RunJobTable
			runJobData, err = utils.GetRunJobData(conn, processData.InnerJobId)
			if err != nil {
				logger.JaLog("JAFLOW200000", logger.Logging{}, funcName, "GetRunJobData", err)
				goto MoveToSubFolder
			}
			innerJobIdList, err = utils.GetNextFlowJobIDListByStartInnerJobIdAndLesserRunCount(
				conn, processData.InnerJobId, runJobData.RunCount)
			if err != nil {
				logger.JaLog("JAFLOW200000", logger.Logging{}, funcName, "GetNextFlowJobIDListByStartInnerJobIdAndLesserRunCount", err)
				goto MoveToSubFolder
			}
			if len(innerJobIdList) > 0 {
				eventStruct.Name = common.EventIconReady
				processType = common.FlowParallelStartRun
				receivedEventData.Event.Name = common.EventMIconRun
			} else {
				goto MoveToSubFolder
			}

		default:
			eventStruct.Name = common.EventIconReady
			innerJobIdList, err = utils.GetNextFlowJobIDList(conn, processData.InnerJobId, processData.FlowType)
			if err != nil {
				logger.JaLog("JAFLOW200000", logger.Logging{}, funcName, "GetNextFlowJobIDList", err)
				goto MoveToSubFolder
			}
		}

	case common.EventIconUnhold:
		eventStruct.Name = common.EventIconReady
		processType = common.FlowProcessUnhold
		innerJobIdList = append(innerJobIdList, processData.InnerJobId)

	case common.EventIconStop, common.EventIconTimeoutStop:
		eventStruct.Name = common.EventIconAbort

	case common.EventIconRunErrSkip:
		eventStruct.Name = common.EventIconSkip

	case common.EventFlowIconSkip, common.EventIconHoldSkip:
		eventStruct.Name = common.EventIconSkip
		processType = common.FlowProcessSkip

	case common.EventEndCountPlus:
		var runJobData common.RunJobTable
		runJobData, err = utils.GetRunJobData(conn, processData.InnerJobId)
		if err != nil {
			logger.JaLog("JAFLOW200000", logger.Logging{}, funcName, "GetRunJobData", err)
			goto MoveToSubFolder
		}
		if runJobData.BootCount == 0 {
			logger.JaLog("JAFLOW200013", logger.Logging{}, funcName,
				processData.InnerJobId, receivedEventData.Event.Name)
			goto MoveToSubFolder
		}
		if runJobData.EndCount < runJobData.BootCount {
			goto MoveToSubFolder
		}
		prevIconCount, err := utils.GetPrevIconCountByStatus(
			conn, processData.InnerJobId, true,
			common.StatusBegin, common.StatusReady, common.StatusRun, common.StatusRunErr, common.StatusAbort, // included status
		)
		if err != nil {
			logger.JaLog("JAFLOW200000", logger.Logging{}, funcName, "GetPrevIconCountByStatus", err)
			goto MoveToSubFolder
		}
		if prevIconCount > 0 {
			logger.JaLog("JAFLOW300007", logger.Logging{}, funcName,
				prevIconCount, processData.InnerJobId)
			goto MoveToSubFolder
		}
		eventStruct.Name = common.EventEndCountPlus
		nextProcessData, ok = processData.Data.(common.IconExecutionProcessData)
		if !ok {
			logger.JaLog("JAFLOW200007", logger.Logging{}, funcName,
				fmt.Errorf("data is not for EventEndCountPlus, received data: %T,"+
					" expected data: IconExecutionProcessData", processData.Data))
			goto MoveToSubFolder
		}
		runJobData.RunCount = nextProcessData.RunJobData.RunCount
		nextProcessData.RunJobData = runJobData

	case common.EventFlowCheckAgent, common.EventFlowCheckLocal:
		if !ok {
			logger.JaLog("JAFLOW200007", logger.Logging{}, funcName,
				fmt.Errorf("data is not for EventCheckJob, received data: %v,"+
					" expected data: CheckJobData", processData.Data))
			goto MoveToSubFolder
		}
		eventStruct.Name = receivedEventData.Event.Name

	case common.EventSubJobnetStatusChange:
		switch processData.Status {
		case common.StatusRun:
			eventStruct.Name = common.EventFlowJobnetIconStatusChange

		default:
			eventStruct.Name = common.EventSubJobnetStatusChange
			processType = common.FlowProcessSubJobnet
			nextProcessData.JobResult.JobRunRequestData.JobID = strconv.FormatUint(processData.InnerJobId, 10)
		}

	case common.EventIconResultEndErr:
		innerJobnetMainId, err := utils.GetInnerJobnetMainIdFromRunJobnetTable(conn, processData.InnerJobnetId)
		if err != nil {

		}
		runJobnetSummaryData, err := utils.GetRunJobnetSummaryTableData(conn, innerJobnetMainId)
		if err != nil {
			logger.JaLog("JAFLOW200000", logger.Logging{}, funcName, "GetRunJobnetSummaryTableData", err)
			goto MoveToSubFolder
		}
		if runJobnetSummaryData.JobnetAbortFlag == 1 || runJobnetSummaryData.EndingFlag == 1 {
			goto MoveToSubFolder
		}

		eventStruct.Name = common.EventJobnetRunError
		jobnetStatusChange.InnerJobnetId = processData.InnerJobnetId
		jobnetStatusChange.JobnetID = processData.JobnetId
		jobnetStatusChange.Status = common.StatusRunErr
		jobnetStatusChange.JobId = nextProcessData.RunJobData.JobID

	case common.EventIconHostUnlock:
		eventStruct.Name = common.EventIconReady
		processType = common.FlowProcessNormal
		innerJobIdList = append(innerJobIdList, processData.InnerJobId)

	default:
		// This should never happens
		logger.JaLog("MANAGER200003", logger.Logging{},
			funcName, receivedEventData.Event.Name, processName,
			processData.InnerJobnetId, processData.InnerJobId)
		return

	}

	//next event data creation starts here
	switch eventStruct.Name {
	case common.EventIconReady:
		if len(innerJobIdList) == 0 {
			logger.JaLog("JAFLOW200003", logger.Logging{}, funcName, processData.InnerJobId)

			jobnetStatusChange.InnerJobnetId = processData.InnerJobnetId
			jobnetStatusChange.JobnetID = processData.JobnetId
			jobnetStatusChange.Status = common.StatusRunErr
			if err = ProcessJobnetStatusChange(common.EventJobnetRunError, jobnetStatusChange); err != nil {
				logger.JaLog("JAFLOW200000", logger.Logging{}, funcName, "ProcessJobnetStatusChange", err)
			}
		} else {
			done := make(chan struct{})
			go utils.StartTicker(10*time.Second, done, func() {
				err := utils.TouchFile(receivedEventData.Transfer.Files[0].Destination)
				if err != nil {
					logger.JaLog("JAFLOW200000", logger.Logging{}, funcName, "TouchFile", err)
				}
			})

			if receivedEventData.Event.Name == common.EventMIconRun {
				mIconJobId = processData.InnerJobId
			}

			var abortFlag bool
			for _, innerJobId := range innerJobIdList {
				if receivedEventData.Event.Name == common.EventMIconRun {
					if MiconAbortFlagExists(mIconJobId) {
						defer func() {
							if err = DeleteMiconAbortFlagFile(mIconJobId); err != nil {
								logger.JaLog("JAFLOW200015", logger.Logging{}, funcName, processData.InnerJobId, err.Error())
							}
						}()
						processData.InnerJobId = mIconJobId
						abortFlag = true
						logger.JaLog("JAFLOW000001", logger.Logging{}, funcName, processData.InnerJobId)
						break
					}
				}
				processData.InnerJobId = innerJobId
				if err = ProcessIcon(conn, processData, &nextProcessData, &processType); err != nil {
					logger.JaLog("JAFLOW200000", logger.Logging{}, funcName, "ProcessIcon", err)
				}
				if processType == common.FlowProcessHostLockWait && receivedEventData.Event.Name == common.EventMIconRun {
					err = HostLockWait(processData, nextProcessData)
					if err != nil {
						logger.JaLog("JAFLOW200000", logger.Logging{}, funcName, "HostLockWait", err)
					}
					processType = common.FlowParallelStartRun
				}
			}
			if processData.IconType == common.IconTypeM && receivedEventData.Event.Name == common.EventMIconRun {
				ProcessMiconStatusChange(processData, abortFlag)
			}
			close(done)
		}

	case common.EventIconRetry, common.EventEndCountPlus:
		err = ProcessDataPassing(conn, eventStruct.Name, nextProcessData)
		if err != nil {
			logger.JaLog("JAFLOW200000", logger.Logging{}, funcName, "ProcessDataPassing", err)
		}

	case common.EventEndIconEnd:
		if err = ProcessJobnetStatusChange(common.EventEndIconEnd, jobnetStatusChange); err != nil {
			logger.JaLog("JAFLOW200000", logger.Logging{}, funcName, "ProcessJobnetStatusChange", err)
		}

	case common.EventIconAbort:
		if err = ProcessIconAbort(conn, processData); err != nil {
			logger.JaLog("JAFLOW200000", logger.Logging{}, funcName, "ProcessIconAbort", err)
		}

	case common.EventJobnetRunError:
		if err = ProcessJobnetStatusChange(common.EventJobnetRunError, jobnetStatusChange); err != nil {
			logger.JaLog("JAFLOW200000", logger.Logging{}, funcName, "ProcessJobnetStatusChange", err)
		}

	case common.EventIconSkip, common.EventSubJobnetStatusChange:
		if err = ProcessIcon(conn, processData, &nextProcessData, &processType); err != nil {
			logger.JaLog("JAFLOW200000", logger.Logging{}, funcName, "ProcessIcon", err)
		}

	case common.EventFlowJobnetIconStatusChange:
		err = ProcessJobnetIconStatusChange(conn, processData)
		if err != nil {
			logger.JaLog("JAFLOW200000", logger.Logging{}, funcName, "ProcessJobnetIconStatusChange", err)
		}

	case common.EventFlowCheckAgent, common.EventFlowCheckLocal:
		err = CheckJobProcess(conn, eventStruct.Name, checkProcessData)
		if err != nil {
			logger.JaLog("JAFLOW200000", logger.Logging{}, funcName, "CheckJobProcess", err)
			goto MoveToSubFolder
		}

	default:
		// This should never happens
		logger.JaLog("MANAGER200004", logger.Logging{},
			funcName, eventStruct.Name, receivedEventData.Event.Name,
			processData.InnerJobnetId, processData.InnerJobId)

	}
MoveToSubFolder:
	var sourceFileName, toFolder string
	switch receivedEventData.Event.Name {
	case common.EventIconRetry, common.EventIconStop,
		common.EventIconUnhold, common.EventIconHoldSkip,
		common.EventFlowCheckAgent, common.EventFlowCheckLocal,
		common.EventFlowIconSkip, common.EventIconRerun,
		common.EventFailoverIconRerun, common.EventIconHostUnlock:
		sourceFileName = receivedEventData.Transfer.Files[0].Source
	default:
		sourceFileName = receivedEventData.Transfer.Files[0].Destination
	}
	if processType == common.FlowProcessHostLockWait {
		hostname := nextProcessData.RunJobData.Data["host_name"].(string)
		toFolder = filepath.Join(common.FlowManagerSubFolders[1], hostname)
	} else if err != nil {
		toFolder = common.FlowManagerSubFolders[3]
	} else {
		toFolder = common.FlowManagerSubFolders[2]
	}
	if err = utils.MoveToSubFolder(sourceFileName, toFolder); err != nil {
		logger.JaLog("JAFLOW200000", logger.Logging{}, funcName, "MoveToFolder", err)
		return
	}
	logger.JaLog("JAFLOW400002", logger.Logging{}, funcName,
		fmt.Sprintf("inner_jobnet_id: %d, inner_job_id: %d",
			processData.InnerJobnetId, processData.InnerJobId))
}

func StartDaemonWorkers(data common.Data) {

}
