/*
** 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"
	"errors"
	"fmt"
	"os"
	"strconv"
	"time"

	"jobarranger2/src/libs/golibs/common"
	"jobarranger2/src/libs/golibs/config_reader/server"
	"jobarranger2/src/libs/golibs/database"
	"jobarranger2/src/libs/golibs/event"
	"jobarranger2/src/libs/golibs/logger/logger"
	wm "jobarranger2/src/libs/golibs/worker_manager"
)

type JobnetManager struct {
	Conn            database.DBConnection
	NextEventData   *common.EventData
	NextProcessData common.JobnetRunData
}

var (
	loaderLog              logger.Logging
	Timezone               string
	ConfigJaLoaderTimeout  = server.Options.JaLoaderTimeout
	ConfigJaLoaderInterval = server.Options.JaLoaderInterval
	ConfigJaLaunchInterval = server.Options.JaLaunchInterval
)
var loaderProcessID string = "Loader Process"

// var eventDate *common.EventData

const (
	DefaultLoadTimeout = 600
	DefaultLoadSpan    = 60
	JobnetLoadSpan     = "JOBNET_LOAD_SPAN"
	DbOk               = 0
	ValidFlagOff       = 0
	ValidFlagOn        = 1

	/* test flag */
	JaJobTestFlagOff = 0
	JaJobTestFlagOn  = 1

	FAIL = -1

	/* count id */
	JaRunIdJobnetLD = 1
	JaRunIdJobnetEX = 3
	JaRunIdJob      = 20
	JaRunIdFlow     = 30

	/* next id */
	MaxJobnetLD   = 1499999999999999999
	MaxJobnetEx   = 1699999999999999999
	StartJobnetEx = 1600000000000000000
	MaxDefault    = 9200000000000000000

	/* invo flag */
	JaJobInvoFlagOff = 0
	JaJobInvoFlagOn  = 1

	/* job method */
	JaJobMethodWait = 1
)

// var jsonFile *os.File

var ErrNoValidFlag = errors.New("no valid flag")

func sign(x int) int {
	if x > 0 {
		return 1
	} else if x < 0 {
		return -1
	}
	return 0
}

func abs(x int) int {
	if x < 0 {
		return -x
	}
	return x
}

func getEndOfMonth(unixTime int64, timezone *time.Location) int {

	funcName := "getEndOfMonth"
	logger.JaLog("JAJOBNETLOADER400024", loaderLog, funcName, unixTime, timezone)

	t := time.Unix(unixTime, 0).In(timezone)
	year := t.Year()
	month := t.Month()

	switch month {
	case time.February:
		if (year%4 == 0 && year%100 != 0) || (year%400 == 0) {
			return 29
		}
		return 28
	case time.April, time.June, time.September, time.November:
		return 30
	default:
		return 31
	}
}

func GetSearchDateWithTimeSpan(spanMinutes int) (int64, int64) {

	funcName := "GetSearchDateWithTimeSpan"
	logger.JaLog("JAJOBNETLOADER400025", loaderLog, funcName, spanMinutes)
	now := time.Now()
	startDate := now
	endDate := now.Add(time.Duration(spanMinutes) * time.Minute)
	return startDate.Unix(), endDate.Unix()
}

func shiftDays(unixTime int64, days int, timezone *time.Location) int64 {

	funcName := "shiftDays"

	logger.JaLog("JAJOBNETLOADER400026", loaderLog, funcName, unixTime, days, timezone)
	// Convert Unix timestamp to time.Time and apply the timezone
	t := time.Unix(unixTime, 0).In(timezone)

	// Add days to the date
	t = t.AddDate(0, 0, days)

	// Return the new Unix timestamp
	return t.Unix()
}

func shiftMonth(unixTime int64, months int, timezone *time.Location) int64 {

	funcName := "shiftMonth"

	logger.JaLog("JAJOBNETLOADER400027", loaderLog, funcName, unixTime, months, timezone)
	// Convert Unix timestamp to time.Time and apply the timezone
	t := time.Unix(unixTime, 0).In(timezone)

	// Add months to the date
	t = t.AddDate(0, months, 0)

	// Return the new Unix timestamp
	return t.Unix()
}

// GetLoadSpan fetches the load span from the database.
func (jm *JobnetManager) GetLoadSpan() (int, error) {
	funcName := "GetLoadSpan"

	if jm.Conn.IsAlive() {
		logger.JaLog("JAJOBNETLOADER400029", loaderLog, funcName)
	} else {
		logger.JaLog("JAJOBNETLOADER300001", loaderLog, funcName)
	}
	result, err := jm.Conn.Select("SELECT value FROM ja_2_parameter_table WHERE parameter_name = '%s'", JobnetLoadSpan)
	if err != nil {
		return DefaultLoadSpan, fmt.Errorf("[%s] failed to fetch parameter data: %w", funcName, err)
	}

	// Check if the result has rows
	if !result.HasNextRow() {
		return DefaultLoadSpan, fmt.Errorf("[%s] schedule details is not found", funcName)
	}

	// Fetch the first row
	row, err := result.Fetch()
	if err != nil {
		return DefaultLoadSpan, fmt.Errorf("[%s] failed to fetch row for ja_2_parameter_table: %w", funcName, err)
	}

	// Extract the value from the row
	value := row["value"]
	span := DefaultLoadSpan

	// If the value length is valid, convert it to integer
	if len(value) <= 10 {
		span, err = strconv.Atoi(value)
		if err != nil {
			logger.JaLog("JAJOBNETLOADER400007", loaderLog, funcName, value, DefaultLoadSpan)
			span = DefaultLoadSpan
		}
	}

	// If the span is less than 1, reset to default
	if span < 1 {
		span = DefaultLoadSpan
	}

	// Free the result set after usage
	result.Free()

	return span, nil
}

func makeEndOperatingDate(startDate int64, timezone *time.Location, bootTime string) (int64, error) {

	funcName := "makeEndOperatingDate"
	logger.JaLog("JAJOBNETLOADER400011", loaderLog, funcName, startDate, timezone, bootTime)
	iBT, err := strconv.Atoi(bootTime)
	if err != nil {
		return 0, fmt.Errorf("[%s] invalid boot time: %s", funcName, bootTime)
	}

	if iBT < 2400 {
		return startDate, nil
	}

	iSDay := iBT / 2400
	t := time.Unix(startDate, 0).In(timezone)
	t = t.AddDate(0, 0, -iSDay)

	return t.Unix(), nil
}

func makeScheduledTime(operatingDate int, timezone *time.Location, bootTime string) (int64, error) {

	funcName := "makeScheduledTime"
	logger.JaLog("JAJOBNETLOADER400013", loaderLog, funcName, operatingDate, timezone, bootTime)

	// Parse operatingDate in yyyymmdd format
	dateStr := fmt.Sprintf("%08d", operatingDate)
	t, err := time.Parse("20060102", dateStr)
	if err != nil {
		return 0, fmt.Errorf("[%s] invalid operating date format: %d", funcName, operatingDate)
	}

	// Parse bootTime (e.g., "0930" or "2400" or greater)
	iBT, err := strconv.Atoi(bootTime)
	if err != nil {
		return 0, fmt.Errorf("[%s] invalid boot time: %s", funcName, bootTime)
	}

	if iBT < 2400 {
		hour := iBT / 100
		min := iBT % 100
		t = time.Date(t.Year(), t.Month(), t.Day(), hour, min, 0, 0, timezone)
		return t.Unix(), nil
	}

	iSDay := iBT / 2400
	wBT := iBT % 2400

	if iBT == 2400 {
		iSDay = 1
		wBT = 0
	}

	t = t.AddDate(0, 0, iSDay)
	hour := wBT / 100
	min := wBT % 100
	t = time.Date(t.Year(), t.Month(), t.Day(), hour, min, 0, 0, timezone)

	return t.Unix(), nil
}

func (jm *JobnetManager) GetScheduleDetail(
	scheduleID string, updateDate, startDate, endDate int64,
) error {
	funcName := "GetScheduleDetail"

	logger.JaLog("JAJOBNETLOADER400008", loaderLog, funcName, scheduleID, updateDate, startDate, endDate)

	// Select the schedule details from the database
	result, err := jm.Conn.Select("select calendar_id, boot_time, object_flag"+
		" from ja_2_schedule_detail_table"+
		" where schedule_id = '%s' and update_date = %d",
		scheduleID, updateDate)
	if err != nil {
		return fmt.Errorf("[%s] failed to fetch schedule details data: %w", funcName, err)
	}
	defer result.Free()

	// Process each row in the result
	for result.HasNextRow() {
		row, err := result.Fetch()
		if err != nil {
			return fmt.Errorf("[%s] schedule details is not found", funcName)
		}

		// Extract the values from the row
		calendarID := row["calendar_id"]
		bootTime := row["boot_time"]
		objectFlag, err := strconv.Atoi(row["object_flag"])
		if err != nil {
			return fmt.Errorf("[%s] failed to parse object_flag: %w", funcName, err)
		}
		// Call GetCalendarDetail with int64 for date parameters
		err = jm.GetCalendarDetail(updateDate, startDate, endDate, scheduleID, calendarID, bootTime, objectFlag)
		if err != nil {
			return fmt.Errorf("[%s] failed to get calendar details: %w", funcName, err)
		}
	}

	return nil
}

func (jm *JobnetManager) GetCalendarDetail(
	updateDate, startDate, endDate int64,
	scheduleID, calendarID, bootTime string,
	objectFlag int,
) error {

	funcName := "GetCalendarDetail"
	logger.JaLog("JAJOBNETLOADER400009", loaderLog, funcName, updateDate, startDate, endDate, scheduleID, calendarID, bootTime, objectFlag)
	if objectFlag == 0 {
		return jm.handleCalendarObject(updateDate, startDate, endDate, scheduleID, calendarID, bootTime)
	}
	return jm.handleFilterObject(updateDate, startDate, endDate, scheduleID, calendarID, bootTime)
}

func (jm *JobnetManager) handleCalendarObject(updateDate, startDate, endDate int64, scheduleID, calendarID, bootTime string) error {
	funcName := "handleCalendarObject"

	logger.JaLog("JAJOBNETLOADER400010", loaderLog, funcName, updateDate, startDate, endDate, scheduleID, calendarID, bootTime)

	result, err := jm.Conn.Select(
		"SELECT update_date, time_zone FROM ja_2_calendar_control_table WHERE calendar_id = '%s' AND valid_flag = %d",
		calendarID, ValidFlagOn)
	if err != nil {
		return fmt.Errorf("[%s] failed to fetch calendar control data: %w", funcName, err)
	}
	defer result.Free()

	if !result.HasNextRow() {
		return fmt.Errorf("[%s] calendar control data is not found", funcName)
	}

	row, err := result.Fetch()
	if err != nil {
		return fmt.Errorf("[%s] failed to fetch row for ja_2_calendar_control_table: %w", funcName, err)
	}

	jcUpdateDate, err := strconv.ParseInt(row["update_date"], 10, 64)
	if err != nil {
		return fmt.Errorf("[%s] invalid update_date: %w", funcName, err)
	}
	timezone := row["time_zone"]
	loc, err := time.LoadLocation(timezone)
	if err != nil {
		return fmt.Errorf("[%s] invalid timezone: %s", funcName, timezone)
	}

	startDateUnix, err := makeEndOperatingDate(startDate, loc, bootTime)
	if err != nil {
		return fmt.Errorf("[%s] failed to get end operating date: %w", funcName, err)
	}

	startTime := time.Unix(startDateUnix, 0).In(loc)
	startDateYYMMDD := startTime.Year()*10000 + int(startTime.Month())*100 + startTime.Day()

	endTime := time.Unix(endDate, 0).In(loc)
	endDateYYMMDD := endTime.Year()*10000 + int(endTime.Month())*100 + endTime.Day()

	logger.JaLog("JAJOBNETLOADER400012", loaderLog, funcName, startDateYYMMDD, endDateYYMMDD)

	opResult, err := jm.Conn.Select(
		`SELECT operating_date FROM ja_2_calendar_detail_table 
		WHERE calendar_id = '%s' AND update_date = %d 
		AND operating_date <= %d AND operating_date >= %d`,
		calendarID, jcUpdateDate, endDateYYMMDD, startDateYYMMDD)
	if err != nil {
		return fmt.Errorf("[%s] failed to fetch calendar details data: %w", funcName, err)
	}
	defer opResult.Free()

	for opResult.HasNextRow() {

		opRow, err := opResult.Fetch()
		if err != nil {
			return fmt.Errorf("[%s] failed to fetch row for ja_2_calendar_detail_table: %w", funcName, err)
		}

		opDate, err := strconv.Atoi(opRow["operating_date"])
		if err != nil {
			return fmt.Errorf("[%s] invalid operating_date: %w", funcName, err)
		}

		scheduledTime, err := makeScheduledTime(opDate, loc, bootTime)
		if err != nil {
			return fmt.Errorf("[%s] failed to get scheduled time: %w", funcName, err)
		}

		if scheduledTime >= startDate && scheduledTime <= endDate {
			if err := jm.GetScheduleJobnet(scheduleID, updateDate, scheduledTime, calendarID, bootTime, timezone); err != nil {
				return fmt.Errorf("[%s] failed to get schedule jobnet: %w", funcName, err)
			}
		}
	}
	return nil
}

func (jm *JobnetManager) handleFilterObject(updateDate, startDate, endDate int64, scheduleID, calendarID, bootTime string) error {

	funcName := "handleFilterObject"

	logger.JaLog("JAJOBNETLOADER400005", loaderLog, funcName, updateDate, startDate, endDate, scheduleID, calendarID, bootTime)
	// Fetch filter control data

	filterResult, err := jm.Conn.Select(
		"SELECT base_date_flag, designated_day, shift_day, base_calendar_id "+
			"FROM ja_2_filter_control_table "+
			"WHERE filter_id = '%s' AND valid_flag = %d",
		calendarID, ValidFlagOn)
	if err != nil {
		return fmt.Errorf("[%s] failed to fetch filter control data: %w", funcName, err)
	}
	defer filterResult.Free()

	// Check if the filter result exists
	if !filterResult.HasNextRow() {
		return fmt.Errorf("[%s] filter control data is not found", funcName)
	}

	// Extract filter values
	filterRow, err := filterResult.Fetch()
	if err != nil {
		return fmt.Errorf("[%s] failed to fetch row for ja_2_filter_control_table: %w", funcName, err)
	}
	baseDateFlag, _ := strconv.Atoi(filterRow["base_date_flag"])
	designatedDay, _ := strconv.Atoi(filterRow["designated_day"])
	shiftDay, _ := strconv.Atoi(filterRow["shift_day"])
	baseCalendarID := filterRow["base_calendar_id"]

	// Adjust the designated and shift day values
	wDesignatedDay := designatedDay
	wShiftDay := abs(shiftDay)
	if baseDateFlag == 0 {
		wDesignatedDay = 1 // If base date flag is 0, use the 1st day
	}

	// Fetch base calendar update date
	baseCalResult, err := jm.Conn.Select(
		"SELECT update_date, time_zone FROM ja_2_calendar_control_table "+
			"WHERE calendar_id = '%s' AND valid_flag = %d",
		baseCalendarID, ValidFlagOn)
	if err != nil {
		return fmt.Errorf("[%s] failed to fetch calendar control data: %w", funcName, err)
	}
	defer baseCalResult.Free()

	// Check if base calendar exists
	if !baseCalResult.HasNextRow() {
		return fmt.Errorf("[%s] calendar control data is not found", funcName)
	}

	baseCalRow, err := baseCalResult.Fetch()
	if err != nil {
		return fmt.Errorf("[%s] failed to fetch row for ja_2_calendar_control_table: %w", funcName, err)
	}
	jcUpdateDate, err := strconv.ParseInt(baseCalRow["update_date"], 10, 64)
	if err != nil {
		return fmt.Errorf("[%s] failed to convert update_date to int: %w", funcName, err)
	}

	timezone := baseCalRow["time_zone"]
	loc, err := time.LoadLocation(timezone)
	if err != nil {
		return fmt.Errorf("[%s] invalid timezone: %s", funcName, timezone)
	}

	// Extract base month start time
	baseTime := time.Unix(startDate, 0)
	baseYear, baseMonth, _ := baseTime.Date()
	baseMonthStart := time.Date(baseYear, baseMonth, 1, 0, 0, 0, 0, loc).Unix()

	// Loop over month offsets
	for offset := -2; offset <= 1; offset++ {
		shiftedMonthTimestamp := shiftMonth(baseMonthStart, offset, loc)

		shiftedMonthTime := time.Unix(shiftedMonthTimestamp, 0).In(loc)
		var day int

		// Handle based on the base date flag
		switch baseDateFlag {
		case 1: // End of the month
			// Get the last day of the month using `getEndOfMonth`
			day = getEndOfMonth(shiftedMonthTime.Unix(), loc)

		case 2: // Designated day
			// Get the end of the current month
			endOfMonth := getEndOfMonth(shiftedMonthTime.Unix(), loc)
			if designatedDay > endOfMonth {
				// If the designated day is after the end of the current month
				if shiftDay >= 0 {
					// Move to the first day of the next month
					shiftedMonthTimestamp = shiftMonth(shiftedMonthTime.Unix(), 1, loc)

					shiftedMonthTime = time.Unix(shiftedMonthTimestamp, 0).In(loc)

					day = 1 // Reset to the first day of next month
				} else {
					// Shift backwards by the difference between designated day and end of month
					day = endOfMonth + (designatedDay - endOfMonth)

				}
			} else {
				// If the designated day is within the current month, use it
				day = designatedDay
			}
		default: // Default to the designated day (wDesignatedDay)
			day = wDesignatedDay
		}

		// Create the edit date for the current offset month
		editDate := time.Date(shiftedMonthTime.Year(), shiftedMonthTime.Month(), day, 0, 0, 0, 0, loc)
		// Process the date in a loop with a limit to avoid infinite loops
		var opDate int
		for cnt, hit := 0, 0; cnt < 30; cnt++ {
			// Convert editDate to Unix timestamp for querying
			editTimestamp := editDate.Unix()

			//Convert YYYYMMDD format
			editYMD := editDate.Year()*10000 + int(editDate.Month())*100 + editDate.Day()

			// Query the operating date for the current edit timestamp
			dateResult, err := jm.Conn.Select(
				"SELECT operating_date FROM ja_2_calendar_detail_table "+
					"WHERE calendar_id = '%s' AND update_date = %d AND operating_date = %d",
				baseCalendarID, jcUpdateDate, editYMD)
			if err != nil {
				logger.JaLog("JAJOBNETLOADER300002", loaderLog, funcName)
				break
			}
			defer dateResult.Free()
			// Process if a matching row exists
			if dateResult.HasNextRow() {
				hit++
				dateRow, err := dateResult.Fetch()
				if err != nil {
					break
				}
				if cnt == 0 || hit >= wShiftDay {
					opDate, err = strconv.Atoi(dateRow["operating_date"])
					if err != nil {
						logger.JaLog("JAJOBNETLOADER300003", loaderLog, funcName)
						break // Invalid timestamp format
					}
					break // Found target operating date
				}
			}

			// If shifting is required, shift the date
			if shiftDay == 0 {
				break // No shifting required
			}
			newTimestamp := shiftDays(editTimestamp, sign(shiftDay), loc) // Move forward/backward

			editDate = time.Unix(newTimestamp, 0).In(loc)

		}

		// Process the scheduled time if an operating date is found
		if opDate > 0 {
			scheduledTime, err := makeScheduledTime(opDate, loc, bootTime)
			if err != nil {
				return fmt.Errorf("[%s] %v", funcName, err)
			}

			if scheduledTime >= startDate && scheduledTime <= endDate {
				// Execute the scheduled job if within the time range
				if err := jm.GetScheduleJobnet(scheduleID, updateDate, scheduledTime, calendarID, bootTime, timezone); err != nil {
					return fmt.Errorf("[%s] %v", funcName, err)
				}
			}
		}
	}
	return nil
}

func (jm *JobnetManager) GetScheduleJobnet(
	scheduleID string,
	updateDate int64,
	scheduledTime int64,
	calendarID string,
	bootTime string,
	timezone string,
) error {
	funcName := "GetScheduleJobnet"

	logger.JaLog("JAJOBNETLOADER400014", loaderLog, funcName, scheduleID, updateDate, scheduledTime, calendarID, bootTime)

	result, err := jm.Conn.Select("SELECT jobnet_id FROM ja_2_schedule_jobnet_table "+
		"WHERE schedule_id = '%s' AND update_date = %d", scheduleID, updateDate)
	if err != nil {
		return fmt.Errorf("[%s] failed to fetch schedule jobnet data: %w", funcName, err)
	}
	defer result.Free()

	for result.HasNextRow() {
		row, err := result.Fetch()
		if err != nil {
			return fmt.Errorf("[%s] failed to fetch row for ja_2_schedule_jobnet_table: %w", funcName, err)
		}
		jobnetID := row["jobnet_id"]

		err = jm.loadJobnetDefinition(jobnetID, scheduledTime, scheduleID, calendarID, bootTime, timezone)
		if err != nil {
			return fmt.Errorf("[%s] failed to load jobnet definition: %w", funcName, err)
		}
	}
	return nil
}

func (jm *JobnetManager) LoadSchedule(loadSpan int) error {

	funcName := "LoadSchedule"
	logger.JaLog("JAJOBNETLOADER400002", loaderLog, funcName, loadSpan)

	result, err := jm.Conn.Select(
		"SELECT schedule_id, update_date FROM ja_2_schedule_control_table WHERE valid_flag = %d",
		ValidFlagOn,
	)
	if err != nil {
		return fmt.Errorf("[%s] failed to fetch schedule control data: %w", funcName, err)
	}
	defer result.Free()

	for result.HasNextRow() {
		row, err := result.Fetch()
		if err != nil {
			return fmt.Errorf("[%s] failed to fetch row for ja_2_schedule_control_table: %w", funcName, err)
		}

		scheduleID := row["schedule_id"]
		updateDate, err := strconv.ParseInt(row["update_date"], 10, 64)
		if err != nil {
			return fmt.Errorf("[%s] invalid update_date format: %w", funcName, err)
		}

		startDate, endDate := GetSearchDateWithTimeSpan(loadSpan)

		logger.JaLog("JAJOBNETLOADER400003", loaderLog, funcName, startDate, endDate)
		// Try to get schedule detail
		err = jm.GetScheduleDetail(scheduleID, updateDate, startDate, endDate)
		if errors.Is(err, ErrNoValidFlag) {
			// Begin transaction
			if err := jm.Conn.Begin(); err != nil {
				return fmt.Errorf("[%s] failed to begin transaction: %w", funcName, err)
			}

			// Attempt to update valid_flag
			jm.NextEventData.AddPQ("UPDATE ja_2_schedule_control_table SET valid_flag = ? WHERE schedule_id = ? AND update_date = ?", ValidFlagOff, scheduleID, updateDate)

			// Commit transaction
			if err := jm.Conn.Commit(); err != nil {
				return fmt.Errorf("[%s] failed to commit transaction: %w", funcName, err)
			}
		}
	}

	return nil
}

func (jm *JobnetManager) loadJobnetDefinition(jobnetID string, scheduledTime int64, scheduleID, calendarID, bootTime, timezone string) error {

	var userNameEsc, memo string
	funcName := "loadJobnetDefinition"
	logger.JaLog("JAJOBNETLOADER400015", loaderLog, funcName, jobnetID, scheduledTime, scheduleID, calendarID, bootTime)
	Timezone = timezone

	//Send heart beat
	select {
	case wm.Wm.MonitorChan <- loaderProcessID:
	default:
	}

	result, err := jm.Conn.Select(`
	SELECT * FROM ja_2_run_jobnet_table
	WHERE jobnet_id = '%s' AND initial_scheduled_time = %d
	AND run_type = %d AND main_flag = %d
	AND schedule_id = '%s' AND calendar_id = '%s' AND invo_flag = %d`,
		jobnetID, scheduledTime, JA_JOBNET_RUN_TYPE_NORMAL, JA_JOBNET_MAIN_FLAG_MAIN,
		scheduleID, calendarID, 1)

	if err != nil {
		return fmt.Errorf("[%s] failed to fetch jobnet data: %w", funcName, err)
	}
	defer result.Free()
	count := 0

	for result.HasNextRow() {
		_, err := result.Fetch()
		if err != nil {
			return fmt.Errorf("[%s] failed to fetch row for ja_2_run_jobnet_table: %w", funcName, err)
		}
		count++
	}

	if count > 0 {
		logger.JaLog("JAJOBNETLOADER400031", loaderLog, funcName, scheduledTime)
		return nil
	}

	innerJobnetMainID, err := jm.getNextID(JaRunIdJobnetLD, 0, 0, jobnetID)
	if err != nil {
		return fmt.Errorf("[%s] failed to get inner_jobnet_main_id: %w", funcName, err)
	}
	if innerJobnetMainID == 0 {
		return fmt.Errorf("[%s] invalid jobnet manin ID", funcName)
	}

	jm.NextProcessData.InnerJobnetMainId = uint64(innerJobnetMainID)
	jm.NextProcessData.InnerJobnetId = uint64(innerJobnetMainID)
	jm.NextProcessData.Timezone = Timezone

	loaderLog.InnerJobnetID = uint64(innerJobnetMainID)

	/* ja_2_jobnet_control_table */
	result, err = jm.Conn.Select(`
	SELECT jobnet_id, update_date, public_flag, user_name, jobnet_name, memo,
	multiple_start_up, jobnet_timeout, timeout_run_type
	FROM ja_2_jobnet_control_table
	WHERE jobnet_id = '%s' AND valid_flag = %d`,
		jobnetID, ValidFlagOn)

	if err != nil {
		return fmt.Errorf("[%s] failed to fetch jobnet control data: %w", funcName, err)
	}
	defer result.Free()

	row, err := result.Fetch()
	if err != nil {
		return fmt.Errorf("[%s] failed to fetch row for ja_2_jobnet_control_table: %w", funcName, err)
	}

	userNameEsc = row["user_name"]
	memo = row["memo"]
	updateDate, err := strconv.ParseInt(row["update_date"], 10, 64)
	if err != nil {
		return fmt.Errorf("[%s] Invalid update_date value", funcName)
	}
	publicFlag, err := strconv.Atoi(row["public_flag"])
	if err != nil {
		return fmt.Errorf("[%s] Invalid public_flag type value", funcName)
	}

	multipleStartUp, err := strconv.Atoi(row["multiple_start_up"])
	if err != nil {
		return fmt.Errorf("[%s] Invalid multiple_start_up value", funcName)
	}
	jobnetTimeout, err := strconv.Atoi(row["jobnet_timeout"])
	if err != nil {
		return fmt.Errorf("[%s] Invalid jobnet_timeout value", funcName)
	}

	timeOutRuntype, err := strconv.Atoi(row["timeout_run_type"])
	if err != nil {
		return fmt.Errorf("[%s] Invalid timeout_run_type value", funcName)
	}

	// Begin transaction
	if err := jm.Conn.Begin(); err != nil {
		return fmt.Errorf("[%s] failed to begin transaction: %w", funcName, err)
	}
	rc, err := jm.Conn.Execute("INSERT INTO ja_2_run_jobnet_table ( inner_jobnet_id, inner_jobnet_main_id, inner_job_id, update_date, run_type, main_flag, timeout_flag, status, scheduled_time, start_time, end_time, public_flag, multiple_start_up, jobnet_id, user_name, jobnet_name, memo, schedule_id, calendar_id, boot_time, execution_user_name, initial_scheduled_time ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?, ?, ?, ?, ?, ?, ?, ?, ?)",
		innerJobnetMainID, innerJobnetMainID, 0, updateDate,
		JA_JOBNET_RUN_TYPE_NORMAL, JA_JOBNET_MAIN_FLAG_MAIN, 0, JA_JOBNET_STATUS_BEGIN,
		scheduledTime, 0, 0, publicFlag, multipleStartUp,
		row["jobnet_id"], userNameEsc, row["jobnet_name"], memo, scheduleID, calendarID, bootTime, userNameEsc,
		scheduledTime)
	if err != nil || rc <= DbOk {
		jm.Conn.Rollback() // rollback on error
		return fmt.Errorf("[%s] failed to execute query for inserting ja_2_run_jobnet_table, inner_jobnet_id = %d [ERROR: %w] ", funcName, innerJobnetMainID, err)
	}

	// Commit transaction
	if err := jm.Conn.Commit(); err != nil {
		jm.Conn.Rollback() // rollback on error
		return fmt.Errorf("[%s] failed to commit transaction: %w", funcName, err)
	}

	// ja_2_run_jobnet_summary_table
	jm.NextEventData.AddPQ("INSERT INTO ja_2_run_jobnet_summary_table ( inner_jobnet_id, update_date, invo_flag, run_type, status, job_status, jobnet_abort_flag, load_status, scheduled_time, start_time, end_time, public_flag, multiple_start_up, jobnet_id, user_name, jobnet_name, memo, schedule_id, calendar_id, boot_time, execution_user_name, start_pending_flag, initial_scheduled_time, jobnet_timeout, timeout_run_type, time_zone ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
		innerJobnetMainID, updateDate, 1, JA_JOBNET_RUN_TYPE_NORMAL, JA_JOBNET_STATUS_BEGIN, 0, 0, common.JA_SUMMARY_LOAD_STATUS_NORMAL,
		scheduledTime, 0, 0, publicFlag, multipleStartUp, row["jobnet_id"], userNameEsc, row["jobnet_name"], memo,
		scheduleID, calendarID, bootTime, userNameEsc,
		JA_SUMMARY_START_PENDING_NONE, scheduledTime, jobnetTimeout, timeOutRuntype, Timezone)
	// jm.NextEventData.Queries = append(jm.NextEventData.Queries, query)

	jm.NextProcessData.ScheduledTime = uint64(scheduledTime)
	jm.NextProcessData.MainFlag = JA_JOBNET_MAIN_FLAG_MAIN
	jm.NextProcessData.RunType = JA_JOBNET_RUN_TYPE_NORMAL
	jm.NextProcessData.MultipleOptions = multipleStartUp
	jm.NextProcessData.JobnetID = row["jobnet_id"]
	jm.NextProcessData.JobnetName = row["jobnet_name"]
	jm.NextProcessData.PublicFlag = publicFlag
	jm.NextProcessData.UserName = row["user_name"]
	jm.NextProcessData.Status = JA_JOBNET_STATUS_BEGIN
	jm.NextProcessData.StartPendingFlag = JA_SUMMARY_START_PENDING_NONE
	jm.NextProcessData.TimeoutRunType = timeOutRuntype
	jm.NextProcessData.JobnetTimeout = int64(jobnetTimeout)
	jm.NextProcessData.LoadStatus = common.JA_SUMMARY_LOAD_STATUS_NORMAL
	jm.NextProcessData.UpdateDate = uint64(updateDate)

	// Load job definitions
	if err := jm.loadJobDefinition(innerJobnetMainID, innerJobnetMainID, updateDate, row["jobnet_id"], userNameEsc, JaJobTestFlagOff, JA_JOBNET_RUN_TYPE_NORMAL); err != nil {
		return fmt.Errorf("[%s] fail to load job definition: %w", funcName, err)
	}

	// Transaction file creation for Run_Process
	err = jm.CreateTransactionFile()
	if err != nil {
		logger.JaLog("JAJOBNETLOADER200003", loaderLog, funcName, jm.NextProcessData.InnerJobnetMainId, err)
	}

	return nil
}

func (jm *JobnetManager) loadSubJobnetDefinition(innerJobnetMainID, innerJobnetID, innerJobID int64, runType int, executionUserName, jobnetID string) error {

	funcName := "loadSubJobnetDefinition"
	logger.JaLog("JAJOBNETLOADER400006", loaderLog, funcName, innerJobnetMainID, runType, executionUserName)
	hit := 1

	for hit == 1 {
		hit = 0

		result3, err := jm.Conn.Select(`
				SELECT jobnet_id, update_date, public_flag, user_name, jobnet_name, memo, multiple_start_up
				FROM ja_2_jobnet_control_table
				WHERE jobnet_id = '%s' AND valid_flag = %d`,
			jobnetID, ValidFlagOn,
		)

		if err != nil {
			return fmt.Errorf("[%s] failed to fetch jobnet control data: %w", funcName, err)
		}
		defer result3.Free()

		row3, err := result3.Fetch()
		if err != nil {
			return fmt.Errorf("[%s] failed to fetch row for ja_2_jobnet_control_table: %w", funcName, err)
		}
		memo := row3["memo"]

		publicFlag, err := strconv.Atoi(row3["public_flag"])
		if err != nil {
			return fmt.Errorf("[%s] Invalid public_flag value: %v", funcName, err)
		}
		multipleStartUp, err := strconv.Atoi(row3["multiple_start_up"])
		if err != nil {
			return fmt.Errorf("[%s] Invalid multiple_start_up value: %v", funcName, err)
		}

		updateDate, err := strconv.ParseInt(row3["update_date"], 10, 64)
		if err != nil {
			return fmt.Errorf("[%s] Invalid update_date value: %v", funcName, err)
		}

		jm.NextEventData.AddPQ("INSERT INTO ja_2_run_jobnet_table ( inner_jobnet_id, inner_jobnet_main_id, inner_job_id, update_date, run_type, invo_flag, main_flag, timeout_flag, status, scheduled_time, start_time, end_time, public_flag, multiple_start_up, jobnet_id, user_name, jobnet_name, memo, execution_user_name, initial_scheduled_time) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?,?)",
			innerJobnetID, innerJobnetMainID, innerJobID, updateDate, runType, JaJobInvoFlagOn, JA_JOBNET_MAIN_FLAG_SUB,
			0, JA_JOBNET_STATUS_BEGIN, 0, 0, 0, publicFlag, multipleStartUp,
			row3["jobnet_id"], row3["user_name"], row3["jobnet_name"], memo, executionUserName, 0)

		var testFlag int

		if runType == JA_JOBNET_RUN_TYPE_TEST {
			testFlag = JaJobTestFlagOn //1 (test execution)
		} else {
			testFlag = JaJobTestFlagOff //0 (normal)
		}

		if err := jm.loadJobDefinition(innerJobnetMainID, innerJobnetID, updateDate, row3["jobnet_id"], executionUserName, testFlag, JA_JOBNET_RUN_TYPE_NORMAL); err != nil {
			return fmt.Errorf("[%s]:  %v", funcName, err)
		}

	}

	return nil
}
func (jm *JobnetManager) loadJobDefinition(innerJobnetMainID, innerJobnetID, updateDate int64, jobnetID, executionUsername string, testFlag, runType int) error {

	funcName := "loadJobDefinition"
	var innerJobIDfsLink int64
	flowmap := make(map[string]int64)

	logger.JaLog("JAJOBNETLOADER400028", loaderLog, funcName, innerJobnetMainID, innerJobnetID, updateDate, jobnetID, testFlag, runType)
	result, err := jm.Conn.Select(`
	SELECT jobnet_id, job_id, update_date, job_type, point_x, point_y,
	job_name, method_flag, force_flag, continue_flag, run_user, run_user_password
	FROM ja_2_job_control_table
	WHERE jobnet_id = '%s' AND update_date = %d`,
		jobnetID, updateDate)

	if err != nil {
		return fmt.Errorf("[%s] failed to fetch job control data: %w", funcName, err)
	}
	defer result.Free()

	for result.HasNextRow() {
		row, err := result.Fetch()
		if err != nil {
			return fmt.Errorf("[%s] failed to fetch row for ja_2_job_control_table: %w", funcName, err)
		}

		updateDate, err = strconv.ParseInt(row["update_date"], 10, 64)
		if err != nil {
			return fmt.Errorf("[%s] Invalid update_date value", funcName)
		}

		innerJobID, err := jm.getNextID(JaRunIdJob, 0, 0, jobnetID)
		if err != nil {
			return fmt.Errorf("[%s] failed to get inner_job_id : %v", funcName, err)
		}

		if innerJobID == 0 {
			return fmt.Errorf("[%s] invalid inner job id", funcName)
		}

		jobType, err := strconv.Atoi(row["job_type"])
		if err != nil {
			return fmt.Errorf("[%s] Invalid job_type value", funcName)
		}

		// inner jobID fs link (using for job stop command)
		innerJobIDfsLink = 0
		if jobType == int(common.IconTypeJob) {
			innerJobIDfsLink, err = jm.getNextID(JaRunIdJob, 0, 0, jobnetID)
			if err != nil {
				return fmt.Errorf("[%s] failed to get inner_job_id_fs_link : %v", funcName, err)
			}
			if innerJobIDfsLink == 0 {
				return fmt.Errorf("[%s] invalid inner jobid fs link", funcName)
			}
		}

		bootCount, err := jm.getBootCount(row["jobnet_id"], row["job_id"], updateDate)
		if err != nil {
			return fmt.Errorf("[%s] %v", funcName, err)
		}
		if bootCount == FAIL {
			return fmt.Errorf("[%s] invalid boot count", funcName)
		}

		jobName := row["job_name"]
		runUser := row["run_user"]
		runUserPwd := row["run_user_password"]

		methodFlag, err := strconv.Atoi(row["method_flag"])
		if err != nil {
			return fmt.Errorf("[%s] Invalid method_flag value", funcName)
		}

		forceFlag, err := strconv.Atoi(row["force_flag"])
		if err != nil {
			return fmt.Errorf("[%s] Invalid force_flag value", funcName)
		}
		pointX, err := strconv.Atoi(row["point_x"])
		if err != nil {
			return fmt.Errorf("[%s] Invalid point_x value", funcName)
		}
		pointY, err := strconv.Atoi(row["point_y"])
		if err != nil {
			return fmt.Errorf("[%s] Invalid point_y value", funcName)
		}
		continueFlag, err := strconv.Atoi(row["continue_flag"])
		if err != nil {
			return fmt.Errorf("[%s] Invalid continue_flag value", funcName)
		}

		jm.NextProcessData.JobType = jobType

		jobID := row["job_id"]

		flowmap[jobID] = innerJobID
		// Handle different job types
		switch jobType {
		// case int(common.IconTypeStart):
		case int(common.IconTypeStart):
			icon := map[string]any{}
			data, err := json.Marshal(icon)
			if err != nil {
				return fmt.Errorf("[%s] failed to marshal icon data: %w", funcName, err)
			}
			jm.insertJobRecord(
				data,
				innerJobID, innerJobnetID, innerJobnetMainID, innerJobIDfsLink,
				jobType, testFlag, methodFlag, forceFlag, bootCount, pointX, pointY, continueFlag,
				row["job_id"], jobName, runUser, runUserPwd,
			)

			if runType == JA_JOBNET_RUN_TYPE_WAIT {
				jm.NextEventData.AddPQ("UPDATE ja_2_run_job_table SET method_flag = ? WHERE inner_job_id = ?", JaJobMethodWait, innerJobID)
			}

		case int(common.IconTypeM):
			{
				icon := map[string]any{}
				data, err := json.Marshal(icon)
				if err != nil {
					return fmt.Errorf("[%s] failed to marshal icon data: %w", funcName, err)
				}
				jm.insertJobRecord(
					data,
					innerJobID, innerJobnetID, innerJobnetMainID, innerJobIDfsLink,
					jobType, testFlag, methodFlag, forceFlag, bootCount, pointX, pointY, continueFlag,
					row["job_id"], jobName, runUser, runUserPwd,
				)

			}

		case int(common.IconTypeW):
			{
				icon := map[string]any{}
				data, err := json.Marshal(icon)
				if err != nil {
					return fmt.Errorf("[%s] failed to marshal icon data: %w", funcName, err)
				}
				jm.insertJobRecord(
					data,
					innerJobID, innerJobnetID, innerJobnetMainID, innerJobIDfsLink,
					jobType, testFlag, methodFlag, forceFlag, bootCount, pointX, pointY, continueFlag,
					row["job_id"], jobName, runUser, runUserPwd,
				)

			}

		case int(common.IconTypeL):
			{
				icon := map[string]any{}
				data, err := json.Marshal(icon)
				if err != nil {
					return fmt.Errorf("[%s] failed to marshal icon data: %w", funcName, err)
				}
				jm.insertJobRecord(
					data,
					innerJobID, innerJobnetID, innerJobnetMainID, innerJobIDfsLink,
					jobType, testFlag, methodFlag, forceFlag, bootCount, pointX, pointY, continueFlag,
					row["job_id"], jobName, runUser, runUserPwd,
				)

			}

		case int(common.IconTypeIfEnd):
			{
				icon := map[string]any{}
				data, err := json.Marshal(icon)
				if err != nil {
					return fmt.Errorf("[%s] failed to marshal icon data: %w", funcName, err)
				}

				jm.insertJobRecord(
					data,
					innerJobID, innerJobnetID, innerJobnetMainID, innerJobIDfsLink,
					jobType, testFlag, methodFlag, forceFlag, bootCount, pointX, pointY, continueFlag,
					row["job_id"], jobName, runUser, runUserPwd,
				)

			}

		case int(common.IconTypeEnd):
			{
				err = jm.loadIconEnd(innerJobID, innerJobnetID, innerJobnetMainID, innerJobIDfsLink, updateDate, jobType, testFlag, methodFlag, forceFlag, bootCount, pointX, pointY, continueFlag, row["job_id"], jobName, runUser, runUserPwd, jobnetID)
				if err != nil {
					return fmt.Errorf("[%s] %v", funcName, err)
				}
			}

		case int(common.IconTypeIf):
			{
				err = jm.loadIconIf(innerJobID, innerJobnetID, innerJobnetMainID, innerJobIDfsLink, updateDate, jobType, testFlag, methodFlag, forceFlag, bootCount, pointX, pointY, continueFlag, row["job_id"], jobName, runUser, runUserPwd, jobnetID)
				if err != nil {
					return fmt.Errorf("[%s] %v", funcName, err)
				}
			}

		case int(common.IconTypeValue):
			{
				err = jm.loadIconValue(innerJobID, innerJobnetID, innerJobnetMainID, innerJobIDfsLink, updateDate, jobType, testFlag, methodFlag, forceFlag, bootCount, pointX, pointY, continueFlag, row["job_id"], jobName, runUser, runUserPwd, jobnetID)
				if err != nil {
					return fmt.Errorf("[%s] %v", funcName, err)
				}
			}

		case int(common.IconTypeJob):
			{
				err = jm.loadIconJob(innerJobID, innerJobnetID, innerJobnetMainID, innerJobIDfsLink, updateDate, jobType, testFlag, methodFlag, forceFlag, bootCount, pointX, pointY, continueFlag, row["job_id"], jobName, runUser, runUserPwd, jobnetID)
				if err != nil {
					return fmt.Errorf("[%s] %v", funcName, err)
				}
			}
		case int(common.IconTypeJobnet):
			{
				err = jm.loadIconJobnet(innerJobID, innerJobnetID, innerJobnetMainID, innerJobIDfsLink, updateDate, jobType, runType, testFlag, methodFlag, forceFlag, bootCount, pointX, pointY, continueFlag, row["job_id"], jobName, runUser, runUserPwd, jobnetID, executionUsername)
				if err != nil {
					return fmt.Errorf("[%s] %v", funcName, err)
				}
			}
		case int(common.IconTypeExtJob):
			{
				err = jm.loadIconExtjob(innerJobID, innerJobnetID, innerJobnetMainID, innerJobIDfsLink, updateDate, jobType, testFlag, methodFlag, forceFlag, bootCount, pointX, pointY, continueFlag, row["job_id"], jobName, runUser, runUserPwd, jobnetID)
				if err != nil {
					return fmt.Errorf("[%s] %v", funcName, err)
				}
			}
		case int(common.IconTypeCalc):
			{
				err = jm.loadIconCalc(innerJobID, innerJobnetID, innerJobnetMainID, innerJobIDfsLink, updateDate, jobType, testFlag, methodFlag, forceFlag, bootCount, pointX, pointY, continueFlag, row["job_id"], jobName, runUser, runUserPwd, jobnetID)
				if err != nil {
					return fmt.Errorf("[%s] %v", funcName, err)
				}
			}
		case int(common.IconTypeTask):
			{
				err = jm.loadIconTask(innerJobID, innerJobnetID, innerJobnetMainID, innerJobIDfsLink, updateDate, jobType, testFlag, methodFlag, forceFlag, bootCount, pointX, pointY, continueFlag, row["job_id"], jobName, runUser, runUserPwd, jobnetID)
				if err != nil {
					return fmt.Errorf("[%s] %v", funcName, err)
				}
			}
		case int(common.IconTypeInfo):
			{
				err = jm.loadIconInfo(innerJobID, innerJobnetID, innerJobnetMainID, innerJobIDfsLink, updateDate, jobType, testFlag, methodFlag, forceFlag, bootCount, pointX, pointY, continueFlag, row["job_id"], jobName, runUser, runUserPwd, jobnetID)
				if err != nil {
					return fmt.Errorf("[%s] %v", funcName, err)
				}
			}
		case int(common.IconTypeFCopy):
			{
				err = jm.loadIconFcopy(innerJobID, innerJobnetID, innerJobnetMainID, innerJobIDfsLink, updateDate, jobType, testFlag, methodFlag, forceFlag, bootCount, pointX, pointY, continueFlag, row["job_id"], jobName, runUser, runUserPwd, jobnetID)
				if err != nil {
					return fmt.Errorf("[%s] %v", funcName, err)
				}
			}
		case int(common.IconTypeFWait):
			{
				err = jm.loadIconFwait(innerJobID, innerJobnetID, innerJobnetMainID, innerJobIDfsLink, updateDate, jobType, testFlag, methodFlag, forceFlag, bootCount, pointX, pointY, continueFlag, row["job_id"], jobName, runUser, runUserPwd, jobnetID)
				if err != nil {
					return fmt.Errorf("[%s] %v", funcName, err)
				}
			}
		case int(common.IconTypeReboot):
			{
				err = jm.loadIconReboot(innerJobID, innerJobnetID, innerJobnetMainID, innerJobIDfsLink, updateDate, jobType, testFlag, methodFlag, forceFlag, bootCount, pointX, pointY, continueFlag, row["job_id"], jobName, runUser, runUserPwd, jobnetID)
				if err != nil {
					return fmt.Errorf("[%s] %v", funcName, err)
				}
			}
		case int(common.IconTypeRel):
			{
				err = jm.loadIconRel(innerJobID, innerJobnetID, innerJobnetMainID, innerJobIDfsLink, updateDate, jobType, testFlag, methodFlag, forceFlag, bootCount, pointX, pointY, continueFlag, row["job_id"], jobName, runUser, runUserPwd, jobnetID)
				if err != nil {
					return fmt.Errorf("[%s] %v", funcName, err)
				}
			}
		case int(common.IconTypeLess):
			{
				err = jm.loadIconLess(innerJobID, innerJobnetID, innerJobnetMainID, innerJobIDfsLink, updateDate, jobType, testFlag, methodFlag, forceFlag, bootCount, pointX, pointY, continueFlag, row["job_id"], jobName, runUser, runUserPwd, jobnetID)
				if err != nil {
					return fmt.Errorf("[%s] %v", funcName, err)
				}
			}
		case int(common.IconTypeLink):
			{
				err = jm.loadIconLink(innerJobID, innerJobnetID, innerJobnetMainID, innerJobIDfsLink, updateDate, jobType, testFlag, methodFlag, forceFlag, bootCount, pointX, pointY, continueFlag, row["job_id"], jobName, runUser, runUserPwd, jobnetID)
				if err != nil {
					return fmt.Errorf("[%s] %v", funcName, err)
				}
			}

		default:
			return fmt.Errorf("[%s] unknown job type: %d", funcName, jobType)
		}

	}
	result, err = jm.Conn.Select(`
	SELECT start_job_id, end_job_id, flow_type, flow_width, flow_style
	FROM ja_2_flow_control_table
	WHERE jobnet_id = '%s' AND update_date = %d`,
		jobnetID, updateDate)

	if err != nil {
		return fmt.Errorf("[%s] %v", funcName, err)
	}
	defer result.Free()

	for result.HasNextRow() {
		row, err := result.Fetch()
		if err != nil {
			return fmt.Errorf("[%s] failed to fetch row for ja_2_flow_control_table: %w", funcName, err)
		}

		innerFlowID, err := jm.getNextID(JaRunIdFlow, 0, 0, jobnetID)
		if err != nil {
			return fmt.Errorf("[%s] fail to get inner_flow_id: %v", funcName, err)
		}
		if innerFlowID == 0 {
			return fmt.Errorf("[%s] invalid flow id", funcName)
		}

		var startInnerJobID, endInnerJobID int64
		for key := range flowmap {

			if row["start_job_id"] == key {
				startInnerJobID = flowmap[key]
			}
			if row["end_job_id"] == key {
				endInnerJobID = flowmap[key]
			}

		}
		flowType, err := strconv.Atoi(row["flow_type"])
		if err != nil {
			return fmt.Errorf("[%s] Invalid flow_type type value", funcName)
		}
		flowWidth, err := strconv.Atoi(row["flow_width"])
		if err != nil {
			return fmt.Errorf("[%s] Invalid flow_width type value", funcName)
		}

		jm.NextEventData.AddPQ("INSERT INTO ja_2_run_flow_table ( inner_flow_id, inner_jobnet_id, start_inner_job_id, end_inner_job_id, flow_type, flow_width, flow_style ) VALUES (?, ?, ?, ?, ?, ?, ?)",
			innerFlowID, innerJobnetID, startInnerJobID, endInnerJobID,
			flowType, flowWidth, row["flow_style"])
		// jm.NextEventData.Queries = append(jm.NextEventData.Queries, query)

	}

	return nil
}
func (jm *JobnetManager) getBootCount(jobnetID, jobID string, updateDate int64) (int, error) {

	funcName := "getBootCount"
	var count int

	logger.JaLog("JAJOBNETLOADER400017", loaderLog, funcName, jobnetID, jobID, updateDate)
	result, err := jm.Conn.Select(`
	SELECT * FROM ja_2_flow_control_table
	WHERE jobnet_id = '%s' AND end_job_id = '%s' AND update_date = %d`,
		jobnetID, jobID, updateDate)

	if err != nil {
		return FAIL, fmt.Errorf("[%s] failed to fetch flow control data: %w", funcName, err)
	}
	defer result.Free()
	count = 0

	for result.HasNextRow() {
		_, err := result.Fetch()
		if err != nil {
			return FAIL, fmt.Errorf("[%s] failed to fetch row for ja_2_flow_control_table: %w", funcName, err)
		}
		count++
	}

	return count, nil
}

func (jm *JobnetManager) getNextID(countID int, innerJobnetID, innerJobID int64, jobnetID string) (int64, error) {
	var nextID int64
	var cycle bool
	funcName := "getNextID"
	logger.JaLog("JAJOBNETLOADER400016", loaderLog, funcName, countID, innerJobnetID, innerJobID, jobnetID)

	// Begin transaction
	if err := jm.Conn.Begin(); err != nil {
		return FAIL, fmt.Errorf("[%s] failed to begin transaction: %w", funcName, err)
	}
	query := fmt.Sprintf(`
	SELECT nextid 
	FROM ja_2_index_table 
	WHERE count_id = %d`,
		countID)

	result, err := jm.Conn.Select(query)
	if err != nil {
		return FAIL, fmt.Errorf("[%s] failed to fetch index data: %w", funcName, err)
	}
	defer result.Free()

	row, err := result.Fetch()
	if err != nil {
		return FAIL, fmt.Errorf("[%s] failed to fetch row for ja_2_index_table: %w", funcName, err)
	}
	nextID, err = strconv.ParseInt(row["nextid"], 10, 64)

	if err != nil {
		return FAIL, fmt.Errorf("[%s] Invalid nextid %v", funcName, err)
	}

	// Apply rules based on count_id
	switch countID {
	case JaRunIdJobnetLD:
		if nextID > MaxJobnetLD {
			nextID = 1
			cycle = true
		}
	case JaRunIdJobnetEX:
		if nextID > MaxJobnetEx {
			nextID = StartJobnetEx
			cycle = true
		}
	default:
		if nextID > MaxDefault {
			nextID = 1
			cycle = true
		}
	}

	// Update table with new nextid
	var updateSQL string
	var args []any

	if cycle {
		updateSQL = "UPDATE ja_2_index_table SET nextid = ? WHERE count_id = ?"
		args = []any{nextID, countID}
	} else {
		updateSQL = "UPDATE ja_2_index_table SET nextid = nextid + 1 WHERE count_id = ?"
		args = []any{countID}
	}

	rc, err := jm.Conn.Execute(updateSQL, args...)
	if err != nil || rc <= DbOk {
		jm.Conn.Rollback() // rollback on error
		return FAIL, fmt.Errorf("[%s] failed to commit transaction: %w", funcName, err)
	}

	// Commit transaction
	if err := jm.Conn.Commit(); err != nil {
		return FAIL, fmt.Errorf("[%s] failed to commit transaction: %w", funcName, err)
	}

	return nextID, nil
}

/* icon loading */
func (jm *JobnetManager) loadIconEnd(innerJobID, innerJobnetID, innerJobnetMainID, innerJobIDfsLink, updateDate int64, jobType, testFlag, methodFlag, forceFlag, bootCount, pointX, pointY, continueFlag int, jobID, jobName, runUser, runUserPwd, jobnetID string) error {

	/* select from control table */
	funcName := "loadIconEnd"
	logger.JaLog("JAJOBNETLOADER400018", loaderLog, funcName, innerJobID, innerJobnetID, innerJobnetMainID, innerJobIDfsLink, updateDate, jobType, testFlag, methodFlag, forceFlag, bootCount, pointX, pointY, continueFlag, jobID, jobName, runUser, runUserPwd, jobnetID)

	result, err := jm.Conn.Select(`
	SELECT jobnet_stop_flag, jobnet_stop_code
	FROM ja_2_icon_end_table
	WHERE jobnet_id = '%s' AND job_id = '%s' AND update_date = %d`,
		jobnetID, jobID, updateDate)

	if err != nil {
		return fmt.Errorf("[%s] failed to fetch end icon data: %w", funcName, err)
	}
	defer result.Free()

	row, err := result.Fetch()
	if err != nil {
		return fmt.Errorf("[%s] failed to fetch row for ja_2_icon_end_table: %w", funcName, err)
	}

	jobnetStopFlag, err := strconv.Atoi(row["jobnet_stop_flag"])
	if err != nil {
		return fmt.Errorf("[%s] Invalid jobnet_stop_flag type value", funcName)
	}

	icon := map[string]any{
		"jobnet_stop_flag": jobnetStopFlag,
		"jobnet_stop_code": row["jobnet_stop_code"],
	}

	data, err := json.Marshal(icon)
	if err != nil {
		return fmt.Errorf("[%s] failed to marshal icon data: %w", funcName, err)
	}

	jm.insertJobRecord(
		data,
		innerJobID, innerJobnetID, innerJobnetMainID, innerJobIDfsLink,
		jobType, testFlag, methodFlag, forceFlag, bootCount, pointX, pointY, continueFlag,
		jobID, jobName, runUser, runUserPwd,
	)

	return nil
}

func (jm *JobnetManager) loadIconIf(innerJobID, innerJobnetID, innerJobnetMainID, innerJobIDfsLink, updateDate int64, jobType, testFlag, methodFlag, forceFlag, bootCount, pointX, pointY, continueFlag int, jobID, jobName, runUser, runUserPwd, jobnetID string) error {

	funcName := "loadIconIf"

	logger.JaLog("JAJOBNETLOADER400018", loaderLog, funcName, innerJobID, innerJobnetID, innerJobnetMainID, innerJobIDfsLink, updateDate, jobType, testFlag, methodFlag, forceFlag, bootCount, pointX, pointY, continueFlag, jobID, jobName, runUser, runUserPwd, jobnetID)
	result, err := jm.Conn.Select(`
	SELECT hand_flag, value_name, comparison_value
	FROM ja_2_icon_if_table
	WHERE jobnet_id = '%s' AND job_id = '%s' AND update_date = %d`,
		jobnetID, jobID, updateDate)

	if err != nil {
		return fmt.Errorf("[%s] failed to fetch IF icon data: %w", funcName, err)
	}
	defer result.Free()

	row, err := result.Fetch()
	if err != nil {
		return fmt.Errorf("[%s] failed to fetch row for ja_2_icon_if_table: %w", funcName, err)
	}

	handFlag, err := strconv.Atoi(row["hand_flag"])
	if err != nil {
		return fmt.Errorf("[%s] Invalid hand_flag type value", funcName)
	}

	icon := map[string]any{
		"hand_flag":        handFlag,
		"value_name":       row["value_name"],
		"comparison_value": row["comparison_value"],
	}

	data, err := json.Marshal(icon)
	if err != nil {
		return fmt.Errorf("[%s] failed to marshal icon data: %w", funcName, err)
	}

	jm.insertJobRecord(
		data,
		innerJobID, innerJobnetID, innerJobnetMainID, innerJobIDfsLink,
		jobType, testFlag, methodFlag, forceFlag, bootCount, pointX, pointY, continueFlag,
		jobID, jobName, runUser, runUserPwd,
	)

	return nil
}

func (jm *JobnetManager) loadIconValue(
	innerJobID, innerJobnetID, innerJobnetMainID, innerJobIDfsLink, updateDate int64,
	jobType, testFlag, methodFlag, forceFlag, bootCount, pointX, pointY, continueFlag int,
	jobID, jobName, runUser, runUserPwd, jobnetID string,
) error {

	funcName := "loadIconValue"
	logger.JaLog("JAJOBNETLOADER400018", loaderLog, funcName, innerJobID, innerJobnetID, innerJobnetMainID, innerJobIDfsLink, updateDate, jobType, testFlag, methodFlag, forceFlag, bootCount, pointX, pointY, continueFlag, jobID, jobName, runUser, runUserPwd, jobnetID)
	result, err := jm.Conn.Select(`
		SELECT value_name, value
		FROM ja_2_icon_value_table
		WHERE jobnet_id = '%s' AND job_id = '%s' AND update_date = %d`,
		jobnetID, jobID, updateDate,
	)
	if err != nil {
		return fmt.Errorf("[%s] failed to fetch ENV icon data: %w", funcName, err)
	}
	defer result.Free()

	variables := make(map[string]string)

	for {
		row, err := result.Fetch()
		if row == nil {
			break
		}
		if err != nil {
			return fmt.Errorf("[%s] failed to fetch row for ja_2_icon_value_table: %w", funcName, err)
		}

		variables[row["value_name"]] = row["value"]

	}

	// Marshal the icon data to JSON
	icon := map[string]any{
		"variables": variables,
	}

	data, err := json.Marshal(icon)
	if err != nil {
		return fmt.Errorf("[%s] failed to marshal icon data: %w", funcName, err)
	}

	jm.insertJobRecord(
		data,
		innerJobID, innerJobnetID, innerJobnetMainID, innerJobIDfsLink,
		jobType, testFlag, methodFlag, forceFlag, bootCount, pointX, pointY, continueFlag,
		jobID, jobName, runUser, runUserPwd,
	)

	return nil
}

func (jm *JobnetManager) loadIconJob(innerJobID, innerJobnetID, innerJobnetMainID, innerJobIDfsLink, updateDate int64, jobType, testFlag, methodFlag, forceFlag, bootCount, pointX, pointY, continueFlag int, jobID, jobName, runUser, runUserPwd, jobnetID string) error {

	funcName := "loadIconJob"
	logger.JaLog("JAJOBNETLOADER400018", loaderLog, funcName, innerJobID, innerJobnetID, innerJobnetMainID, innerJobIDfsLink, updateDate, jobType, testFlag, methodFlag, forceFlag, bootCount, pointX, pointY, continueFlag, jobID, jobName, runUser, runUserPwd, jobnetID)
	result, err := jm.Conn.Select(`
	SELECT host_flag, stop_flag, command_type, timeout, host_name, stop_code, timeout_run_type
	FROM ja_2_icon_job_table
	WHERE jobnet_id = '%s' AND job_id = '%s' AND update_date = %d`,
		jobnetID, jobID, updateDate,
	)

	if err != nil {
		return fmt.Errorf("[%s] failed to fetch JOB icon data: %w", funcName, err)
	}
	defer result.Free()

	row, err := result.Fetch()
	if err != nil {
		return fmt.Errorf("[%s] failed to fetch row for ja_2_icon_job_table: %w", funcName, err)
	}

	hostFlag, err := strconv.Atoi(row["host_flag"])
	if err != nil {
		return fmt.Errorf("[%s] Invalid host_flag type value", funcName)
	}
	stopFlag, err := strconv.Atoi(row["stop_flag"])
	if err != nil {
		return fmt.Errorf("[%s] Invalid stop_flag type value", funcName)
	}
	commandType, err := strconv.Atoi(row["command_type"])
	if err != nil {
		return fmt.Errorf("[%s] Invalid command_type type value", funcName)
	}
	timeout, err := strconv.Atoi(row["timeout"])
	if err != nil {
		return fmt.Errorf("[%s] Invalid timeout type value", funcName)
	}
	timeoutRunType, err := strconv.Atoi(row["timeout_run_type"])
	if err != nil {
		return fmt.Errorf("[%s] Invalid timeout_run_type type value", funcName)
	}

	// adding command and stop_command
	var command, stopCommand string
	commandResult, err := jm.Conn.Select(`SELECT command_cls, command FROM ja_2_job_command_table WHERE jobnet_id = '%s' AND job_id = '%s' AND update_date = %d`,
		jobnetID, jobID, updateDate)
	if err != nil {
		return fmt.Errorf("[%s] failed to fetch job command data: %w", funcName, err)
	}
	defer commandResult.Free()

	for commandResult.HasNextRow() {
		row, err := commandResult.Fetch()
		if err != nil {
			return fmt.Errorf("[%s] failed to fetch row for ja_2_job_command_table: %w", funcName, err)
		}

		commandCls, err := strconv.Atoi(row["command_cls"])
		if err != nil {
			return fmt.Errorf("[%s] Invalid command_cls value", funcName)
		}

		if commandCls == 2 {
			stopCommand = row["command"]
		} else {
			command = row["command"]
		}

	}
	// end adding command and stop_command

	jm.NextProcessData.IconTimeoutRunType = timeoutRunType
	icon := map[string]any{
		"host_flag":        hostFlag,
		"stop_flag":        stopFlag,
		"command_type":     commandType,
		"timeout":          timeout,
		"host_name":        row["host_name"],
		"stop_code":        row["stop_code"],
		"timeout_run_type": timeoutRunType,
		"command":          command,
		"stop_command":     stopCommand,
	}

	data, err := json.Marshal(icon)
	if err != nil {
		return fmt.Errorf("[%s] failed to marshal icon data: %w", funcName, err)
	}
	jm.insertJobRecord(
		data,
		innerJobID, innerJobnetID, innerJobnetMainID, innerJobIDfsLink,
		jobType, testFlag, methodFlag, forceFlag, bootCount, pointX, pointY, continueFlag,
		jobID, jobName, runUser, runUserPwd,
	)

	jm.loadValue(innerJobnetID, innerJobID, updateDate, jobnetID, jobID)

	return nil
}

func (jm *JobnetManager) loadValue(innerJobnetID, innerJobID, updateDate int64, jobnetID, jobID string) {

	funcName := "loadValue"
	logger.JaLog("JAJOBNETLOADER400019", loaderLog, funcName, innerJobnetID, innerJobID, updateDate, jobnetID, jobID)

	jm.NextEventData.AddPQ("INSERT INTO ja_2_run_value_job_table ( inner_job_id, inner_jobnet_id, value_name, value ) SELECT ?, ?, value_name, value FROM ja_2_value_job_table WHERE jobnet_id = ? AND job_id = ? AND update_date = ?",
		innerJobID, innerJobnetID, jobnetID, jobID, updateDate)

	jm.NextEventData.AddPQ("INSERT INTO ja_2_run_value_jobcon_table ( inner_job_id, inner_jobnet_id, value_name ) SELECT ?, ?, value_name FROM ja_2_value_jobcon_table WHERE jobnet_id = ? AND job_id = ? AND update_date = ?",
		innerJobID, innerJobnetID, jobnetID, jobID, updateDate)
	// jm.NextEventData.Queries = append(jm.NextEventData.Queries, query)
}

func (jm *JobnetManager) loadIconJobnet(innerJobID, innerJobnetID, innerJobnetMainID, innerJobIDfsLink, updateDate int64, jobType, runType, testFlag, methodFlag, forceFlag, bootCount, pointX, pointY, continueFlag int, jobID, jobName, runUser, runUserPwd, jobnetID, executionUsername string) error {

	funcName := "loadIconJobnet"
	logger.JaLog("JAJOBNETLOADER400018", loaderLog, funcName, innerJobID, innerJobnetID, innerJobnetMainID, innerJobIDfsLink, updateDate, jobType, testFlag, methodFlag, forceFlag, bootCount, pointX, pointY, continueFlag, jobID, jobName, runUser, runUserPwd, jobnetID)

	result, err := jm.Conn.Select(`
	SELECT link_jobnet_id
	FROM ja_2_icon_jobnet_table
	WHERE jobnet_id = '%s' AND job_id = '%s' AND update_date = %d`,
		jobnetID, jobID, updateDate,
	)

	if err != nil {
		return fmt.Errorf("[%s] failed to fetch JOBNET icon data: %w", funcName, err)
	}
	defer result.Free()

	row, err := result.Fetch()
	if err != nil {
		return fmt.Errorf("[%s] failed to fetch row for ja_2_icon_jobnet_table: %w", funcName, err)
	}

	linkInnerJobnetId, err := jm.getNextID(JaRunIdJobnetLD, 0, 0, jobnetID)
	if err != nil {
		return fmt.Errorf("[%s] fail to get link_inner_jobnet_id: %v", funcName, err)
	}

	icon := map[string]any{
		"link_jobnet_id":       row["link_jobnet_id"],
		"link_inner_jobnet_id": linkInnerJobnetId,
	}

	if err := jm.loadSubJobnetDefinition(innerJobnetMainID, linkInnerJobnetId, innerJobID, runType, executionUsername, row["link_jobnet_id"]); err != nil {
		return fmt.Errorf("[%s] %v", funcName, err)
	}

	data, err := json.Marshal(icon)
	if err != nil {
		return fmt.Errorf("[%s] failed to marshal icon data: %w", funcName, err)
	}

	jm.insertJobRecord(
		data,
		innerJobID, innerJobnetID, innerJobnetMainID, innerJobIDfsLink,
		jobType, testFlag, methodFlag, forceFlag, bootCount, pointX, pointY, continueFlag,
		jobID, jobName, runUser, runUserPwd,
	)
	jm.NextEventData.AddPQ("UPDATE ja_2_run_job_table SET invo_flag = ? WHERE inner_job_id = ?", JaJobInvoFlagOn, innerJobID)

	return nil
}
func (jm *JobnetManager) loadIconExtjob(innerJobID, innerJobnetID, innerJobnetMainID, innerJobIDfsLink, updateDate int64, jobType, testFlag, methodFlag, forceFlag, bootCount, pointX, pointY, continueFlag int, jobID, jobName, runUser, runUserPwd, jobnetID string) error {

	funcName := "loadIconExtjob"
	logger.JaLog("JAJOBNETLOADER400018", loaderLog, funcName, innerJobID, innerJobnetID, innerJobnetMainID, innerJobIDfsLink, updateDate, jobType, testFlag, methodFlag, forceFlag, bootCount, pointX, pointY, continueFlag, jobID, jobName, runUser, runUserPwd, jobnetID)

	result, err := jm.Conn.Select(`
	SELECT command_id, value
	FROM ja_2_icon_extjob_table
	WHERE jobnet_id = '%s' AND job_id = '%s' AND update_date = %d`,
		jobnetID, jobID, updateDate,
	)

	if err != nil {
		return fmt.Errorf("[%s] failed to fetch EXTENSION icon data: %w", funcName, err)
	}
	defer result.Free()

	row, err := result.Fetch()
	if err != nil {
		return fmt.Errorf("[%s] failed to fetch row for ja_2_icon_extjob_table: %w", funcName, err)
	}

	icon := map[string]any{
		"command_id": row["command_id"],
		"value":      row["value"],
		"pid":        0,
		"timezone":   Timezone,
	}

	data, err := json.Marshal(icon)
	if err != nil {
		return fmt.Errorf("[%s] failed to marshal icon data: %w", funcName, err)
	}
	jm.insertJobRecord(
		data,
		innerJobID, innerJobnetID, innerJobnetMainID, innerJobIDfsLink,
		jobType, testFlag, methodFlag, forceFlag, bootCount, pointX, pointY, continueFlag,
		jobID, jobName, runUser, runUserPwd,
	)
	return nil
}
func (jm *JobnetManager) loadIconCalc(innerJobID, innerJobnetID, innerJobnetMainID, innerJobIDfsLink, updateDate int64, jobType, testFlag, methodFlag, forceFlag, bootCount, pointX, pointY, continueFlag int, jobID, jobName, runUser, runUserPwd, jobnetID string) error {

	funcName := "loadIconCalc"
	logger.JaLog("JAJOBNETLOADER400018", loaderLog, funcName, innerJobID, innerJobnetID, innerJobnetMainID, innerJobIDfsLink, updateDate, jobType, testFlag, methodFlag, forceFlag, bootCount, pointX, pointY, continueFlag, jobID, jobName, runUser, runUserPwd, jobnetID)

	result, err := jm.Conn.Select(`
	SELECT hand_flag, formula, value_name
	FROM ja_2_icon_calc_table
	WHERE jobnet_id = '%s' AND job_id = '%s' AND update_date = %d`,
		jobnetID, jobID, updateDate,
	)

	if err != nil {
		return fmt.Errorf("[%s] failed to fetch CAL icon data: %w", funcName, err)
	}
	defer result.Free()

	row, err := result.Fetch()
	if err != nil {
		return fmt.Errorf("[%s] failed to fetch row for ja_2_icon_calc_table: %w", funcName, err)
	}

	handFlag, err := strconv.Atoi(row["hand_flag"])
	if err != nil {
		return fmt.Errorf("[%s] Invalid hand_flag type value", funcName)
	}

	icon := map[string]any{
		"hand_flag":  handFlag,
		"formula":    row["formula"],
		"value_name": row["value_name"],
		"timezone":   Timezone,
	}

	data, err := json.Marshal(icon)
	if err != nil {
		return fmt.Errorf("[%s] failed to marshal icon data: %w", funcName, err)
	}

	jm.insertJobRecord(
		data,
		innerJobID, innerJobnetID, innerJobnetMainID, innerJobIDfsLink,
		jobType, testFlag, methodFlag, forceFlag, bootCount, pointX, pointY, continueFlag,
		jobID, jobName, runUser, runUserPwd,
	)

	return nil
}
func (jm *JobnetManager) loadIconTask(innerJobID, innerJobnetID, innerJobnetMainID, innerJobIDfsLink, updateDate int64, jobType, testFlag, methodFlag, forceFlag, bootCount, pointX, pointY, continueFlag int, jobID, jobName, runUser, runUserPwd, jobnetID string) error {

	var submitInnerJobnetID int64
	funcName := "loadIconTask"
	logger.JaLog("JAJOBNETLOADER400018", loaderLog, funcName, innerJobID, innerJobnetID, innerJobnetMainID, innerJobIDfsLink, updateDate, jobType, testFlag, methodFlag, forceFlag, bootCount, pointX, pointY, continueFlag, jobID, jobName, runUser, runUserPwd, jobnetID)

	result, err := jm.Conn.Select(`
	SELECT submit_jobnet_id
	FROM ja_2_icon_task_table
	WHERE jobnet_id = '%s' AND job_id = '%s' AND update_date = %d`,
		jobnetID, jobID, updateDate,
	)

	if err != nil {
		return fmt.Errorf("[%s] failed to fetch TASK icon data: %w", funcName, err)
	}
	defer result.Free()

	row, err := result.Fetch()
	if err != nil {
		return fmt.Errorf("[%s] failed to fetch row for ja_2_icon_task_table: %w", funcName, err)
	}

	submitInnerJobnetID = 0
	icon := map[string]any{
		"submit_inner_jobnet_id": submitInnerJobnetID,
		"submit_jobnet_id":       row["submit_jobnet_id"],
	}

	data, err := json.Marshal(icon)
	if err != nil {
		return fmt.Errorf("[%s] failed to marshal icon data: %w", funcName, err)
	}

	jm.insertJobRecord(
		data,
		innerJobID, innerJobnetID, innerJobnetMainID, innerJobIDfsLink,
		jobType, testFlag, methodFlag, forceFlag, bootCount, pointX, pointY, continueFlag,
		jobID, jobName, runUser, runUserPwd,
	)

	return nil
}
func (jm *JobnetManager) loadIconInfo(innerJobID, innerJobnetID, innerJobnetMainID, innerJobIDfsLink, updateDate int64, jobType, testFlag, methodFlag, forceFlag, bootCount, pointX, pointY, continueFlag int, jobID, jobName, runUser, runUserPwd, jobnetID string) error {

	funcName := "loadIconInfo"
	logger.JaLog("JAJOBNETLOADER400018", loaderLog, funcName, innerJobID, innerJobnetID, innerJobnetMainID, innerJobIDfsLink, updateDate, jobType, testFlag, methodFlag, forceFlag, bootCount, pointX, pointY, continueFlag, jobID, jobName, runUser, runUserPwd, jobnetID)

	result, err := jm.Conn.Select(`
	SELECT info_flag, get_job_id, get_calendar_id
	FROM ja_2_icon_info_table
	WHERE jobnet_id = '%s' AND job_id = '%s' AND update_date = %d`,
		jobnetID, jobID, updateDate,
	)

	if err != nil {
		return fmt.Errorf("[%s] failed to fetch INFO icon data: %w", funcName, err)
	}
	defer result.Free()

	row, err := result.Fetch()
	if err != nil {
		return fmt.Errorf("[%s] failed to fetch row for ja_2_icon_info_table: %w", funcName, err)
	}

	infoFlag, err := strconv.Atoi(row["info_flag"])
	if err != nil {
		return fmt.Errorf("[%s] Invalid info_flag type value", funcName)
	}

	icon := map[string]any{
		"info_flag":       infoFlag,
		"get_job_id":      row["get_job_id"],
		"get_calendar_id": row["get_calendar_id"],
	}

	data, err := json.Marshal(icon)
	if err != nil {
		return fmt.Errorf("[%s] failed to marshal icon data: %w", funcName, err)
	}

	jm.insertJobRecord(
		data,
		innerJobID, innerJobnetID, innerJobnetMainID, innerJobIDfsLink,
		jobType, testFlag, methodFlag, forceFlag, bootCount, pointX, pointY, continueFlag,
		jobID, jobName, runUser, runUserPwd,
	)

	return nil
}
func (jm *JobnetManager) loadIconFcopy(innerJobID, innerJobnetID, innerJobnetMainID, innerJobIDfsLink, updateDate int64, jobType, testFlag, methodFlag, forceFlag, bootCount, pointX, pointY, continueFlag int, jobID, jobName, runUser, runUserPwd, jobnetID string) error {

	funcName := "loadIconFcopy"
	logger.JaLog("JAJOBNETLOADER400018", loaderLog, funcName, innerJobID, innerJobnetID, innerJobnetMainID, innerJobIDfsLink, updateDate, jobType, testFlag, methodFlag, forceFlag, bootCount, pointX, pointY, continueFlag, jobID, jobName, runUser, runUserPwd, jobnetID)

	result, err := jm.Conn.Select(`
	SELECT from_host_flag,
		to_host_flag, overwrite_flag, from_host_name, from_directory,
		from_file_name, to_host_name, to_directory
	FROM ja_2_icon_fcopy_table
	WHERE jobnet_id = '%s' AND job_id = '%s' AND update_date = %d`,
		jobnetID, jobID, updateDate,
	)

	if err != nil {
		return fmt.Errorf("[%s] failed to fetch FCOPY icon data: %w", funcName, err)
	}
	defer result.Free()

	row, err := result.Fetch()
	if err != nil {
		return fmt.Errorf("[%s] failed to fetch row for ja_2_icon_fcopy_table: %w", funcName, err)
	}

	fromHostFlag, err := strconv.Atoi(row["from_host_flag"])
	if err != nil {
		return fmt.Errorf("[%s] Invalid from_host_flag type value", funcName)
	}
	toHostFlag, err := strconv.Atoi(row["to_host_flag"])
	if err != nil {
		return fmt.Errorf("[%s] Invalid to_host_flag type value", funcName)
	}
	overwriteFlag, err := strconv.Atoi(row["overwrite_flag"])
	if err != nil {
		return fmt.Errorf("[%s] Invalid overwrite_flag type value", funcName)
	}
	icon := map[string]any{
		"from_host_flag": fromHostFlag,
		"to_host_flag":   toHostFlag,
		"overwrite_flag": overwriteFlag,
		"from_host_name": row["from_host_name"],
		"from_directory": row["from_directory"],
		"from_file_name": row["from_file_name"],
		"to_host_name":   row["to_host_name"],
		"to_directory":   row["to_directory"],
	}

	data, err := json.Marshal(icon)
	if err != nil {
		return fmt.Errorf("[%s] failed to marshal icon data: %w", funcName, err)
	}

	jm.insertJobRecord(
		data,
		innerJobID, innerJobnetID, innerJobnetMainID, innerJobIDfsLink,
		jobType, testFlag, methodFlag, forceFlag, bootCount, pointX, pointY, continueFlag,
		jobID, jobName, runUser, runUserPwd,
	)

	return nil
}
func (jm *JobnetManager) loadIconFwait(innerJobID, innerJobnetID, innerJobnetMainID, innerJobIDfsLink, updateDate int64, jobType, testFlag, methodFlag, forceFlag, bootCount, pointX, pointY, continueFlag int, jobID, jobName, runUser, runUserPwd, jobnetID string) error {

	funcName := "loadIconFwait"
	logger.JaLog("JAJOBNETLOADER400018", loaderLog, funcName, innerJobID, innerJobnetID, innerJobnetMainID, innerJobIDfsLink, updateDate, jobType, testFlag, methodFlag, forceFlag, bootCount, pointX, pointY, continueFlag, jobID, jobName, runUser, runUserPwd, jobnetID)

	result, err := jm.Conn.Select(`
	SELECT host_flag, fwait_mode_flag, file_delete_flag, file_wait_time,
		host_name, file_name
	FROM ja_2_icon_fwait_table
	WHERE jobnet_id = '%s' AND job_id = '%s' AND update_date = %d`,
		jobnetID, jobID, updateDate,
	)

	if err != nil {
		return fmt.Errorf("[%s] failed to fetch FWAIT icon data: %w", funcName, err)
	}
	defer result.Free()

	row, err := result.Fetch()
	if err != nil {
		return fmt.Errorf("[%s] failed to fetch row for ja_2_icon_fcopy_table: %w", funcName, err)
	}

	hostFlag, err := strconv.Atoi(row["host_flag"])
	if err != nil {
		return fmt.Errorf("[%s] Invalid host_flag type value", funcName)
	}
	fwaitModeFlag, err := strconv.Atoi(row["fwait_mode_flag"])
	if err != nil {
		return fmt.Errorf("[%s] Invalid fwait_mode_flag type value", funcName)
	}
	fileDeleteFlag, err := strconv.Atoi(row["file_delete_flag"])
	if err != nil {
		return fmt.Errorf("[%s] Invalid file_delete_flag type value", funcName)
	}
	fileWaitTime, err := strconv.Atoi(row["file_wait_time"])
	if err != nil {
		return fmt.Errorf("[%s] Invalid file_wait_time type value", funcName)
	}
	icon := map[string]any{
		"host_flag":        hostFlag,
		"fwait_mode_flag":  fwaitModeFlag,
		"file_delete_flag": fileDeleteFlag,
		"file_wait_time":   fileWaitTime,
		"host_name":        row["host_name"],
		"file_name":        row["file_name"],
	}

	data, err := json.Marshal(icon)
	if err != nil {
		return fmt.Errorf("[%s] failed to marshal icon data: %w", funcName, err)
	}

	jm.insertJobRecord(
		data,
		innerJobID, innerJobnetID, innerJobnetMainID, innerJobIDfsLink,
		jobType, testFlag, methodFlag, forceFlag, bootCount, pointX, pointY, continueFlag,
		jobID, jobName, runUser, runUserPwd,
	)

	return nil
}
func (jm *JobnetManager) loadIconReboot(innerJobID, innerJobnetID, innerJobnetMainID, innerJobIDfsLink, updateDate int64, jobType, testFlag, methodFlag, forceFlag, bootCount, pointX, pointY, continueFlag int, jobID, jobName, runUser, runUserPwd, jobnetID string) error {

	funcName := "loadIconReboot"
	logger.JaLog("JAJOBNETLOADER400018", loaderLog, funcName, innerJobID, innerJobnetID, innerJobnetMainID, innerJobIDfsLink, updateDate, jobType, testFlag, methodFlag, forceFlag, bootCount, pointX, pointY, continueFlag, jobID, jobName, runUser, runUserPwd, jobnetID)

	result, err := jm.Conn.Select(`
	SELECT host_flag, reboot_mode_flag, reboot_wait_time, host_name, timeout
	FROM ja_2_icon_reboot_table
	WHERE jobnet_id = '%s' AND job_id = '%s' AND update_date = %d`,
		jobnetID, jobID, updateDate,
	)

	if err != nil {
		return fmt.Errorf("[%s] failed to fetch REBOOT icon data: %w", funcName, err)
	}
	defer result.Free()

	row, err := result.Fetch()
	if err != nil {
		return fmt.Errorf("[%s] failed to fetch row for ja_2_icon_reboot_table: %w", funcName, err)
	}

	hostFlag, err := strconv.Atoi(row["host_flag"])
	if err != nil {
		return fmt.Errorf("[%s] Invalid host_flag type value", funcName)
	}
	rebootModeFlag, err := strconv.Atoi(row["reboot_mode_flag"])
	if err != nil {
		return fmt.Errorf("[%s] Invalid reboot_mode_flag type value", funcName)
	}
	rebootWaitTime, err := strconv.Atoi(row["reboot_wait_time"])
	if err != nil {
		return fmt.Errorf("[%s] Invalid reboot_wait_time type value", funcName)
	}
	timeout, err := strconv.Atoi(row["timeout"])
	if err != nil {
		return fmt.Errorf("[%s] Invalid timeout type value", funcName)
	}

	icon := map[string]any{
		"host_flag":        hostFlag,
		"reboot_mode_flag": rebootModeFlag,
		"reboot_wait_time": rebootWaitTime,
		"host_name":        row["host_name"],
		"timeout":          timeout,
	}

	data, err := json.Marshal(icon)
	if err != nil {
		return fmt.Errorf("[%s] failed to marshal icon data: %w", funcName, err)
	}

	jm.insertJobRecord(
		data,
		innerJobID, innerJobnetID, innerJobnetMainID, innerJobIDfsLink,
		jobType, testFlag, methodFlag, forceFlag, bootCount, pointX, pointY, continueFlag,
		jobID, jobName, runUser, runUserPwd,
	)

	return nil
}
func (jm *JobnetManager) loadIconRel(innerJobID, innerJobnetID, innerJobnetMainID, innerJobIDfsLink, updateDate int64, jobType, testFlag, methodFlag, forceFlag, bootCount, pointX, pointY, continueFlag int, jobID, jobName, runUser, runUserPwd, jobnetID string) error {

	funcName := "loadIconRel"
	logger.JaLog("JAJOBNETLOADER400018", loaderLog, funcName, innerJobID, innerJobnetID, innerJobnetMainID, innerJobIDfsLink, updateDate, jobType, testFlag, methodFlag, forceFlag, bootCount, pointX, pointY, continueFlag, jobID, jobName, runUser, runUserPwd, jobnetID)

	result, err := jm.Conn.Select(`
	SELECT release_job_id
	FROM ja_2_icon_release_table
	WHERE jobnet_id = '%s' AND job_id = '%s' AND update_date = %d`,
		jobnetID, jobID, updateDate,
	)

	if err != nil {
		return fmt.Errorf("[%s] failed to fetch RELEASE icon data: %w", funcName, err)
	}
	defer result.Free()

	row, err := result.Fetch()
	if err != nil {
		return fmt.Errorf("[%s] failed to fetch row for ja_2_icon_release_table: %w", funcName, err)
	}

	icon := map[string]any{
		"release_job_id": row["release_job_id"],
	}

	data, err := json.Marshal(icon)
	if err != nil {
		return fmt.Errorf("[%s] failed to marshal icon data: %w", funcName, err)
	}

	jm.insertJobRecord(
		data,
		innerJobID, innerJobnetID, innerJobnetMainID, innerJobIDfsLink,
		jobType, testFlag, methodFlag, forceFlag, bootCount, pointX, pointY, continueFlag,
		jobID, jobName, runUser, runUserPwd,
	)

	return nil
}
func (jm *JobnetManager) loadIconLess(innerJobID, innerJobnetID, innerJobnetMainID, innerJobIDfsLink, updateDate int64, jobType, testFlag, methodFlag, forceFlag, bootCount, pointX, pointY, continueFlag int, jobID, jobName, runUser, runUserPwd, jobnetID string) error {

	funcName := "loadIconLess"
	logger.JaLog("JAJOBNETLOADER400018", loaderLog, funcName, innerJobID, innerJobnetID, innerJobnetMainID, innerJobIDfsLink, updateDate, jobType, testFlag, methodFlag, forceFlag, bootCount, pointX, pointY, continueFlag, jobID, jobName, runUser, runUserPwd, jobnetID)

	result, err := jm.Conn.Select(`
	SELECT session_flag, session_id
	FROM ja_2_icon_agentless_table
	WHERE jobnet_id = '%s' AND job_id = '%s' AND update_date = %d`,
		jobnetID, jobID, updateDate,
	)

	if err != nil {
		return fmt.Errorf("[%s] failed to fetch LESS icon data: %w", funcName, err)
	}
	defer result.Free()

	row, err := result.Fetch()
	if err != nil {
		return fmt.Errorf("[%s] failed to fetch row for ja_2_icon_agentless_table: %w", funcName, err)
	}
	sessionFlag, err := strconv.Atoi(row["session_flag"])
	if err != nil {
		return fmt.Errorf("[%s] Invalid session_flag type value", funcName)
	}

	sessionId := row["session_id"]

	if sessionFlag == 0 {
		sessionIDNum, err := jm.getNextID(JaRunIdJobnetLD, 0, 0, jobnetID)
		if err != nil {
			return fmt.Errorf("[%s] fail to get session_id: %v", funcName, err)
		}
		if sessionIDNum == 0 {
			return fmt.Errorf("[%s] invalid jsessionIDNum", funcName)
		}
		sessionId = strconv.FormatInt(sessionIDNum, 10)

	}

	result, err = jm.Conn.Select(`
	SELECT host_flag, connection_method, session_flag,
		auth_method, run_mode, line_feed_code, timeout, login_user, login_password,
		public_key, private_key, passphrase, host_name, stop_code, terminal_type, character_code, prompt_string, command
	FROM ja_2_icon_agentless_table
	WHERE jobnet_id = '%s' AND job_id = '%s' AND update_date = %d`,
		jobnetID, jobID, updateDate,
	)

	if err != nil {
		return fmt.Errorf("[%s] %v", funcName, err)
	}
	defer result.Free()

	row, err = result.Fetch()
	if err != nil {
		return fmt.Errorf("[%s] failed to fetch row for ja_2_icon_agentless_table: %w", funcName, err)
	}

	hostFlag, err := strconv.Atoi(row["host_flag"])
	if err != nil {
		return fmt.Errorf("[%s] Invalid host_flag type value", funcName)
	}
	connectionMethod, err := strconv.Atoi(row["connection_method"])
	if err != nil {
		return fmt.Errorf("[%s] Invalid connection_method type value", funcName)
	}
	authMethod, err := strconv.Atoi(row["auth_method"])
	if err != nil {
		return fmt.Errorf("[%s] Invalid auth_method type value", funcName)
	}
	runMode, err := strconv.Atoi(row["run_mode"])
	if err != nil {
		return fmt.Errorf("[%s] Invalid run_mode type value", funcName)
	}
	lineFeedCode, err := strconv.Atoi(row["line_feed_code"])
	if err != nil {
		return fmt.Errorf("[%s] Invalid line_feed_code type value", funcName)
	}
	timeout, err := strconv.Atoi(row["timeout"])
	if err != nil {
		return fmt.Errorf("[%s] Invalid timeout type value", funcName)
	}

	icon := map[string]any{
		"host_flag":         hostFlag,
		"connection_method": connectionMethod,
		"session_flag":      sessionFlag,
		"auth_method":       authMethod,
		"run_mode":          runMode,
		"line_feed_code":    lineFeedCode,
		"timeout":           timeout,
		"session_id":        sessionId,
		"login_user":        row["login_user"],
		"login_password":    row["login_password"],
		"public_key":        row["public_key"],
		"private_key":       row["private_key"],
		"passphrase":        row["passphrase"],
		"host_name":         row["host_name"],
		"stop_code":         row["stop_code"],
		"terminal_type":     row["terminal_type"],
		"character_code":    row["character_code"],
		"prompt_string":     row["prompt_string"],
		"command":           row["command"],
	}

	data, err := json.Marshal(icon)
	if err != nil {
		return fmt.Errorf("[%s] failed to marshal icon data: %w", funcName, err)
	}
	jm.insertJobRecord(
		data,
		innerJobID, innerJobnetID, innerJobnetMainID, innerJobIDfsLink,
		jobType, testFlag, methodFlag, forceFlag, bootCount, pointX, pointY, continueFlag,
		jobID, jobName, runUser, runUserPwd,
	)

	return nil
}
func (jm *JobnetManager) loadIconLink(innerJobID, innerJobnetID, innerJobnetMainID, innerJobIDfsLink, updateDate int64, jobType, testFlag, methodFlag, forceFlag, bootCount, pointX, pointY, continueFlag int, jobID, jobName, runUser, runUserPwd, jobnetID string) error {

	funcName := "loadIconLink"
	logger.JaLog("JAJOBNETLOADER400018", loaderLog, funcName, innerJobID, innerJobnetID, innerJobnetMainID, innerJobIDfsLink, updateDate, jobType, testFlag, methodFlag, forceFlag, bootCount, pointX, pointY, continueFlag, jobID, jobName, runUser, runUserPwd, jobnetID)

	result, err := jm.Conn.Select(`
	SELECT link_target, link_operation,
		groupid, hostid, itemid, triggerid
	FROM ja_2_icon_zabbix_link_table
	WHERE jobnet_id = '%s' AND job_id = '%s' AND update_date = %d`,
		jobnetID, jobID, updateDate,
	)

	if err != nil {
		return fmt.Errorf("[%s] failed to fetch LINK icon data: %w", funcName, err)
	}
	defer result.Free()

	row, err := result.Fetch()
	if err != nil {
		return fmt.Errorf("[%s] failed to fetch row for ja_2_icon_zabbix_link_table: %w", funcName, err)
	}

	linkTarget, err := strconv.Atoi(row["link_target"])
	if err != nil {
		return fmt.Errorf("[%s] Invalid link_target type value", funcName)
	}
	linkOperation, err := strconv.Atoi(row["link_operation"])
	if err != nil {
		return fmt.Errorf("[%s] Invalid link_operation type value", funcName)
	}

	icon := map[string]any{
		"link_target":    linkTarget,
		"link_operation": linkOperation,
		"groupid":        row["groupid"],
		"hostid":         row["hostid"],
		"itemid":         row["itemid"],
		"triggerid":      row["triggerid"],
	}

	data, err := json.Marshal(icon)
	if err != nil {
		return fmt.Errorf("[%s]failed to marshal icon data: %w", funcName, err)
	}

	jm.insertJobRecord(
		data,
		innerJobID, innerJobnetID, innerJobnetMainID, innerJobIDfsLink,
		jobType, testFlag, methodFlag, forceFlag, bootCount, pointX, pointY, continueFlag,
		jobID, jobName, runUser, runUserPwd,
	)

	return nil
}

// transaction file create
func (jm *JobnetManager) CreateTransactionFile() error {

	funcName := "CreateTransactionFile"
	mainIDValue := jm.NextProcessData.InnerJobnetMainId
	jobnetId := jm.NextProcessData.JobnetID

	logger.JaLog("JAJOBNETLOADER400004", loaderLog, funcName, mainIDValue)
	if mainIDValue > 0 {
		if jm.NextProcessData.RunType == common.JA_JOBNET_RUN_TYPE_JOBALONE {
			jm.NextEventData.Event.Name = common.EventStandAloneJob
			jm.NextEventData.ParameterizedQueries = nil
		} else {
			jm.NextEventData.Event.Name = common.EventJobnetLoad
		}

		jm.NextEventData.Event.UniqueKey = common.GetUniqueKey(common.JobnetManagerProcess)
		jm.NextEventData.NextProcess.Name = common.ProcessType(common.EventJobnetRun)
		jm.NextEventData.NextProcess.Data = jm.NextProcessData

		err := event.CreateNextEvent(*jm.NextEventData, mainIDValue, jobnetId, 0)
		if err != nil {
			return fmt.Errorf("[%s] %v", funcName, err)
		}

		// Begin transaction
		if err := jm.Conn.Begin(); err != nil {
			return fmt.Errorf("[%s] failed to begin transaction: %w", funcName, err)
		}

		rc, err := jm.Conn.Execute("UPDATE ja_2_run_jobnet_table SET invo_flag = ? WHERE inner_jobnet_id = ?", 1, mainIDValue)
		if err != nil || rc <= DbOk {
			jm.Conn.Rollback() // rollback on error
			return fmt.Errorf("[%s] failed to execute query for updating ja_2_run_jobnet_table, inner_jobnet_id = %d [ERROR: %w] ", funcName, mainIDValue, err)
		}

		// Commit transaction
		if err := jm.Conn.Commit(); err != nil {
			return fmt.Errorf("[%s] failed to commit transaction: %w", funcName, err)
		}
	}

	// Reset NextEventData to empty before the next loop
	jm.NextEventData = &common.EventData{}

	// Ensure nested structures are initialized
	jm.NextEventData.NextProcess.Data = make(map[string]any)

	// Assign default values
	jm.NextProcessData.InnerJobnetMainId = 0

	return nil
}

func (jm *JobnetManager) jobnetLoadImmediate() error {

	funcName := "jobnetLoadImmediate"

	result, err := jm.Conn.Select(`SELECT inner_jobnet_id, inner_job_id, update_date, run_type, scheduled_time,
					   public_flag, jobnet_id, user_name, jobnet_name, memo, execution_user_name,
					   multiple_start_up, initial_scheduled_time, test_run_time,created_date
					   FROM ja_2_run_jobnet_table
					   WHERE run_type <> %d and main_flag = %d and status = %d and invo_flag = %d`,
		JA_JOBNET_RUN_TYPE_NORMAL, JA_JOBNET_MAIN_FLAG_MAIN, JA_JOBNET_STATUS_BEGIN, 0)
	if err != nil {
		return fmt.Errorf("[%s] failed to fetch run jobnet data: %w", funcName, err)
	}
	defer result.Free()

	for result.HasNextRow() {
		row, err := result.Fetch()
		if err != nil {
			return fmt.Errorf("[%s] failed to fetch row for ja_2_run_jobnet_table: %w", funcName, err)
		}

		innerJobnetID, err := strconv.ParseInt(row["inner_jobnet_id"], 10, 64)
		if err != nil {
			return fmt.Errorf("[%s] Invalid inner_jobnet_id type value", funcName)
		}
		runType, err := strconv.Atoi(row["run_type"])
		if err != nil {
			return fmt.Errorf("[%s] Invalid run_type value", funcName)
		}

		updateDate, err := strconv.ParseInt(row["update_date"], 10, 64)
		if err != nil {
			return fmt.Errorf("[%s] Invalid update_date value", funcName)
		}

		testRunTime, err := strconv.ParseInt(row["test_run_time"], 10, 64)
		if err != nil {
			return fmt.Errorf("[%s] Invalid test_run_time value", funcName)
		}
		createdDate, err := strconv.ParseInt(row["created_date"], 10, 64)
		if err != nil {
			return fmt.Errorf("[%s] Invalid created_date value", funcName)
		}

		jm.NextProcessData.RunType = runType
		jm.NextProcessData.InnerJobnetMainId = uint64(innerJobnetID)
		jm.NextProcessData.InnerJobnetId = uint64(innerJobnetID)
		loaderLog.InnerJobnetID = uint64(innerJobnetID)
		jm.NextProcessData.JobnetID = row["jobnet_id"]
		jm.NextProcessData.UpdateDate = uint64(updateDate)
		jm.NextProcessData.TestRunTime = uint64(testRunTime)
		jm.NextProcessData.CreatedDate = uint64(createdDate)

		scheduledTime, err := strconv.ParseInt(row["scheduled_time"], 10, 64)
		if err != nil {
			return fmt.Errorf("[%s] Invalid scheduled_time value", funcName)
		}

		jm.NextProcessData.ScheduledTime = uint64(scheduledTime)
		jm.NextProcessData.MainFlag = JA_JOBNET_MAIN_FLAG_MAIN
		// check alreay start immediate jobnet
		err = jm.alreadyStartCheckImmediate(innerJobnetID)
		if err != nil {
			logger.JaLog("JAJOBNETLOADER400020", loaderLog, funcName, innerJobnetID)
			continue
		}

		memo := row["memo"]

		var testFlag int

		if runType == JA_JOBNET_RUN_TYPE_TEST {
			testFlag = JaJobTestFlagOn
		} else {
			testFlag = JaJobTestFlagOff
		}

		if err := jm.loadJobDefinition(innerJobnetID, innerJobnetID, updateDate, row["jobnet_id"], row["execution_user_name"], testFlag, runType); err != nil {
			return fmt.Errorf("[%s] fail to get loadJobDefinition(): %v", funcName, err)
		}

		multipleStartUp, err := strconv.Atoi(row["multiple_start_up"])
		if err != nil {
			return fmt.Errorf("[%s] Invalid multiple_start_up value", funcName)
		}

		publicFlag, err := strconv.Atoi(row["public_flag"])
		if err != nil {
			return fmt.Errorf("[%s] Invalid public_flag value", funcName)
		}

		initialScheduleTime, err := strconv.ParseInt(row["initial_scheduled_time"], 10, 64)
		if err != nil {
			return fmt.Errorf("[%s] Invalid initial_scheduled_time value", funcName)
		}

		jobnetTimeout, timeoutRunType, err := jm.getJobnetTimeout(row["jobnet_id"], updateDate)
		if err != nil {
			return fmt.Errorf("[%s] fail to get getJobnetTimeout(): %v", funcName, err)
		}

		// timezone for immediate run
		timeZone := GetLocalIanaTimezone()

		jm.NextEventData.AddPQ("INSERT INTO ja_2_run_jobnet_summary_table ( inner_jobnet_id, update_date, invo_flag, run_type, status, job_status, jobnet_abort_flag, load_status, scheduled_time, start_time, end_time, public_flag, multiple_start_up, jobnet_id, user_name, jobnet_name, memo, execution_user_name, start_pending_flag, initial_scheduled_time,jobnet_timeout, timeout_run_type, time_zone) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
			row["inner_jobnet_id"], updateDate, 1, runType, JA_JOBNET_STATUS_BEGIN, 0, 0, common.JA_SUMMARY_LOAD_STATUS_NORMAL,
			scheduledTime, 0, 0, publicFlag, multipleStartUp,
			row["jobnet_id"], row["user_name"], row["jobnet_name"], memo, row["execution_user_name"],
			JA_SUMMARY_START_PENDING_NONE, initialScheduleTime, jobnetTimeout, timeoutRunType, timeZone)
		// jm.NextEventData.Queries = append(jm.NextEventData.Queries, query)

		jm.NextProcessData.PublicFlag = publicFlag
		jm.NextProcessData.MultipleOptions = multipleStartUp
		jm.NextProcessData.JobnetName = row["jobnet_name"]
		jm.NextProcessData.UserName = row["user_name"]
		jm.NextProcessData.Status = JA_JOBNET_STATUS_BEGIN
		jm.NextProcessData.StartPendingFlag = JA_SUMMARY_START_PENDING_NONE
		jm.NextProcessData.TimeoutRunType = timeoutRunType
		jm.NextProcessData.JobnetTimeout = int64(jobnetTimeout)
		jm.NextProcessData.LoadStatus = common.JA_SUMMARY_LOAD_STATUS_NORMAL

		// Transaction file creation for Run_Process
		err = jm.CreateTransactionFile()
		if err != nil {
			logger.JaLog("JAJOBNETLOADER200003", loaderLog, funcName, jm.NextProcessData.InnerJobnetMainId, err)
		}
	}
	return nil
}

func (jm *JobnetManager) alreadyStartCheckImmediate(innerJobnetID int64) error {

	funcName := "alreadyStartCheckImmediate"
	logger.JaLog("JAJOBNETLOADER400021", loaderLog, funcName, innerJobnetID)
	count := 0
	result, err := jm.Conn.Select(`SELECT * FROM ja_2_run_jobnet_summary_table
					   WHERE inner_jobnet_id = %d `,
		innerJobnetID)
	if err != nil {
		return fmt.Errorf("[%s] failed to fetch jobnet_summary data: %w", funcName, err)
	}
	defer result.Free()

	for result.HasNextRow() {
		_, err := result.Fetch()
		if err != nil {
			return fmt.Errorf("[%s] failed to fetch row for ja_2_run_jobnet_summary_table: %w", funcName, err)
		}

		count++
	}

	if count > 0 {
		logger.JaLog("JAJOBNETLOADER400032", loaderLog, funcName, innerJobnetID)
	}

	return nil
}

func CurrentTimeToUnix() int64 {
	return time.Now().Unix()
}
func (jm *JobnetManager) getJobnetTimeout(jobnetId string, updateDate int64) (int, int, error) {

	var jobnetTimeout, timeoutRunType int
	funcName := "getJobnetTimeout"
	logger.JaLog("JAJOBNETLOADER400022", loaderLog, funcName, jobnetId, updateDate)

	dbResult, err := jm.Conn.Select(
		`SELECT jobnet_timeout,timeout_run_type FROM ja_2_jobnet_control_table
					   WHERE jobnet_id='%s' and update_date=%d`,
		jobnetId, updateDate,
	)
	if err != nil {
		return FAIL, FAIL, fmt.Errorf("[%s] failed to fetch jobnet control data: %w", funcName, err)
	}
	defer dbResult.Free()

	for dbResult.HasNextRow() {
		row, err := dbResult.Fetch()
		if err != nil {
			return FAIL, FAIL, fmt.Errorf("[%s] failed to fetch row for ja_2_jobnet_control_table: %w", funcName, err)
		}

		jobnetTimeout, err = strconv.Atoi(row["jobnet_timeout"])
		if err != nil {
			return FAIL, FAIL, fmt.Errorf("[%s] Invalid jobnet_timeout type value", funcName)
		}

		timeoutRunType, err = strconv.Atoi(row["timeout_run_type"])
		if err != nil {
			return FAIL, FAIL, fmt.Errorf("[%s] Invalid timeout_run_type type value", funcName)
		}

	}

	return jobnetTimeout, timeoutRunType, nil
}

func (jm *JobnetManager) insertJobRecord(
	data []byte,
	innerJobID, innerJobnetID, innerJobnetMainID, innerJobIDfsLink int64,
	jobType, testFlag, methodFlag, forceFlag, bootCount, pointX, pointY, continueFlag int,
	jobID, jobName, runUser, runUserPwd string,
) {

	funcName := "insertJobRecord"
	logger.JaLog("JAJOBNETLOADER400023", loaderLog, funcName, data, innerJobID, innerJobnetID, innerJobnetMainID, innerJobIDfsLink, jobType, testFlag, methodFlag, forceFlag, bootCount, pointX, pointY, continueFlag, jobID, jobName, runUser, runUserPwd)
	dataString := string(data)

	// Add the query to eventDate
	jm.NextEventData.AddPQ("INSERT INTO ja_2_run_job_table ( inner_job_id, inner_jobnet_id, inner_jobnet_main_id, inner_job_id_fs_link, invo_flag, job_type, data, test_flag, method_flag, force_flag, timeout_flag, status, boot_count, end_count, start_time, end_time, point_x, point_y, job_id, job_name, continue_flag, run_user, run_user_password) VALUES ( ?, ?, ?, ?,  ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
		innerJobID, innerJobnetID, innerJobnetMainID, innerJobIDfsLink,
		JaJobInvoFlagOff, jobType, dataString, testFlag, methodFlag, forceFlag, 0, JA_JOB_STATUS_BEGIN,
		bootCount, 0, 0, 0, pointX, pointY, jobID, jobName,
		continueFlag, runUser, runUserPwd)
	// jm.NextEventData.Queries = append(jm.NextEventData.Queries, query)
}

func StartDaemonWorkers(data common.Data) {
	funcName := "StartDaemonWorkers"
	logger.JaLog("JAJOBNETLOADER400001", loaderLog, funcName, data)

	// Get db connection
	dbConn, err := data.DB.GetConn()
	if err != nil {
		logger.JaLog("JAJOBNETLOADER200002", loaderLog, funcName, err.Error())
		return
	}

	if ConfigJaLoaderTimeout < DefaultLoadTimeout {
		ConfigJaLoaderTimeout = DefaultLoadTimeout
	}

	JobnetManager := JobnetManager{dbConn, &common.EventData{}, common.JobnetRunData{}}
	wm.StartWorker(func() { JobnetManager.jobnetLoader() }, loaderProcessID, ConfigJaLoaderTimeout, 0, string(common.JobnetManagerProcess))
}

func (jm *JobnetManager) jobnetLoader() {

	var (
		sleepCnt1, sleepCnt2, loadSpan int
		err                            error
	)
	sleepCnt1 = 9999999
	sleepCnt2 = 9999999
	funcName := "jobnetLoader"

	if jm.NextEventData == nil {
		jm.NextEventData = &common.EventData{}
	}

	for {

		select {
		case <-wm.Wm.Ctx.Done():
			msg := fmt.Sprintf("[%s] worker stopped... \n", loaderProcessID)
			logger.JaLog("JAJOBNETLOADER400030", loaderLog, funcName, msg)
			os.Exit(0)

		case <-time.After(1 * time.Second):
			wm.Wm.MonitorChan <- loaderProcessID
		}

		loadSpan, err = jm.GetLoadSpan()
		if err != nil {
			logger.JaLog("JAJOBNETLOADER200001", loaderLog, funcName, err)
		}

		/* schedule jobnet start */
		if sleepCnt1 >= ConfigJaLoaderInterval {

			err = jm.LoadSchedule(loadSpan)
			if err != nil {
				logger.JaLog("JAJOBNETLOADER200001", loaderLog, funcName, "LoadSchedule", err)
			}

			sleepCnt1 = 0
		}

		/* immediate jobnet start */
		if sleepCnt2 >= ConfigJaLaunchInterval {
			err = jm.jobnetLoadImmediate()
			if err != nil {
				logger.JaLog("JAJOBNETLOADER200001", loaderLog, funcName, "jobnetLoadImmediate", err)
			}

			sleepCnt2 = 0
		}

		sleepCnt1 = sleepCnt1 + 1
		sleepCnt2 = sleepCnt2 + 1
		time.Sleep(1 * time.Second)
	}
}
