package cm

import (
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"os"
	"os/exec"
	"strings"
	"time"

	"be.ems/lib/dborm"
	"be.ems/lib/global"
	"be.ems/lib/log"
	"be.ems/lib/services"
	"be.ems/restagent/config"
	tokenConst "be.ems/src/framework/constants/token"
	neService "be.ems/src/modules/network_element/service"

	"github.com/go-resty/resty/v2"
	"github.com/gorilla/mux"
)

var (
	// NE CM export/import
	NeCmUri = config.DefaultUriPrefix + "/systemManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/cm"
	// NE info
	UriNeInfo = config.DefaultUriPrefix + "/systemManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/neInfo"
	// NE backup file
	UriNeCmFile = config.DefaultUriPrefix + "/systemManagement/{apiVersion}/{neType}/neBackup/{fileName}"
	// service action uri, action: start/stop/restart
	UriNeService = config.DefaultUriPrefix + "/systemManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/service/{action}"
	// nf instance action uri, action: start/stop/restart
	UriNeInstance = config.DefaultUriPrefix + "/systemManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/instance/{action}"

	CustomNeCmUri     = config.UriPrefix + "/systemManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/cm"
	CustomUriNeInfo   = config.UriPrefix + "/systemManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/neInfo"
	CustomUriNeCmFile = config.UriPrefix + "/systemManagement/{apiVersion}/{neType}/neBackup/{fileName}"
	// service action uri, action: start/stop/restart
	CustomUriNeService = config.UriPrefix + "/systemManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/service/{action}"
	// nf instance action uri, action: start/stop/restart
	CustomUriNeInstance = config.UriPrefix + "/systemManagement/{apiVersion}/elementType/{elementTypeValue}/objectType/instance/{action}"
)

const (
	NEStatusActive   = 0
	NEStatusOffline  = 1
	NEStatusStandby  = 2
	NEStatusMaintain = 3
)

var client = resty.New()

func init() {
	/*
		client.
			SetTimeout(10 * time.Second).
			SetRetryCount(1).
			SetRetryWaitTime(1 * time.Second).
			SetRetryMaxWaitTime(2 * time.Second).
			SetRetryAfter(func(client *resty.Client, resp *resty.Response) (time.Duration, error) {
				return 0, errors.New("quota exceeded")
			})
	*/
	client.
		SetTimeout(time.Duration(1 * time.Second))
}

func GetNeInfo(w http.ResponseWriter, r *http.Request) {
	log.Debug("GetNeInfo processing... ")

	_, err := services.CheckFrontValidRequest(w, r)
	if err != nil {
		log.Error("Request error:", err)
		return
	}

	vars := mux.Vars(r)
	neType := vars["elementTypeValue"]
	if neType == "" {
		log.Error("elementTypeValue is empty")
		services.ResponseNotFound404UriNotExist(w, r)
		return
	}
	neId := services.GetUriParamString(r, "ne_id", ",", false, false)

	//	no, _ := strconv.ParseInt(neId, 10, 64)
	neInfo, err := dborm.XormGetNeInfo(neType, neId)
	if err != nil {
		log.Error("dborm.XormGetNeInfo is failed:", err)
		services.ResponseInternalServerError500ProcessError(w, err)
		return
	}

	var response services.DataResponse
	response.Data = neInfo
	services.ResponseWithJson(w, http.StatusOK, response)
}

type OmcNeConfig struct {
	NeId       string `json:"neId" xorm:"ne_id"`             // 网元标识(内部),
	RmUID      string `json:"rmUID" xorm:"rm_uid"`           // rmUID 网元唯一标识
	NeName     string `json:"neName" xorm:"ne_name"`         // 网元名称(内部)/友好名称(北向资源/性能等使用)
	PvFlag     string `json:"pvFlag" xorm:"pv_flag"`         // 网元虚实性标识 VNF/PNF: 虚拟/物理
	Province   string `json:"province" xorm:"province"`      // 网元所在省份
	VendorName string `json:"vendorName" xorm:"vendor_name"` // 厂商名称
	//	ManagedBy  string `json:"managedBy" xorm:"managed_by"`   // 管理ManagedElement的ManagementNode对象类的DN值
	Dn string `json:"dn" xorm:"dn"` // 资源里边的ManagedBy，性能的Dn，网络唯一标识
}

func PostNeInfo(w http.ResponseWriter, r *http.Request) {
	log.Debug("PostNeInfo processing... ")

	_, err := services.CheckFrontValidRequest(w, r)
	if err != nil {
		log.Error("Request error:", err)
		return
	}

	vars := mux.Vars(r)
	neType := vars["elementTypeValue"]
	if neType == "" {
		log.Error("elementTypeValue is empty")
		services.ResponseNotFound404UriNotExist(w, r)
		return
	}
	neTypeUpper := strings.ToUpper(neType)
	syncFlag := services.GetUriParamString(r, "sync2ne", ",", false, false)
	body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen))
	if err != nil {
		log.Error("Failed to o.ReadAll:", err)
		services.ResponseNotFound404UriNotExist(w, r)
		return
	}
	log.Trace("Body:", string(body))

	neInfo := new(dborm.NeInfo)
	err = json.Unmarshal(body, neInfo)
	if err != nil {
		log.Error("Failed to json.Unmarshal:", err)
		services.ResponseInternalServerError500ProcessError(w, err)
		return
	}
	neInfo.UpdateTime = time.Now().Format(time.DateTime)
	log.Debug("NE info:", neInfo)

	//if !config.GetYamlConfig().OMC.Chk2Ne {
	if syncFlag == "false" || neTypeUpper == config.GetYamlConfig().OMC.NeType {
		neInfo.Status = NEStatusMaintain
		affected, err := dborm.XormInsertNeInfo(neInfo)
		if err != nil {
			log.Error("Failed to insert Ne info:", err)
			services.ResponseInternalServerError500ProcessError(w, err)
			return
		}

		// 刷新缓存，不存在结构体网元Id空字符串
		neService.NewNeInfoImpl.RefreshByNeTypeAndNeID(neInfo.NeType, neInfo.NeId)

		mapRow := make(map[string]interface{})
		row := map[string]interface{}{"affectedRows": affected}
		mapRow["data"] = row
		services.ResponseWithJson(w, http.StatusOK, mapRow)
		return
	} else {
		hostUri := global.CombineHostUri(neInfo.Ip, neInfo.Port)
		//hostUri := fmt.Sprintf("http://%s:%v", neInfo.Ip, neInfo.Port)
		apiUri := fmt.Sprintf("%s/systemManagement/v1/elementType/%s/objectType/config/omcNeConfig", config.DefaultUriPrefix, strings.ToLower(neInfo.NeType))
		requestURI2NF := fmt.Sprintf("%s%s", hostUri, apiUri)
		log.Debug("requestURI2NF:", requestURI2NF)

		omcNeConfig := &OmcNeConfig{
			NeId:       neInfo.NeId,
			RmUID:      neInfo.RmUID,
			NeName:     neInfo.NeName,
			PvFlag:     neInfo.PvFlag,
			Province:   neInfo.Province,
			VendorName: neInfo.VendorName,
			Dn:         neInfo.Dn,
		}
		body, _ = json.Marshal(omcNeConfig)
		response, err := client.R().
			EnableTrace().
			SetHeaders(map[string]string{"User-Agent": config.GetDefaultUserAgent()}).
			SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}).
			SetBody(body).
			Put(requestURI2NF)
		if err != nil {
			log.Error("Failed to Put:", err)
			services.ResponseInternalServerError500ProcessError(w, err)
			return
		}
		log.Info("StatusCode: ", response.StatusCode())

		respMsg := make(map[string]interface{})
		switch response.StatusCode() {
		case http.StatusOK, http.StatusCreated, http.StatusNoContent, http.StatusAccepted:
			neInfo.Status = NEStatusActive
			affected, err := dborm.XormInsertNeInfo(neInfo)
			if err != nil {
				log.Error("Failed to dborm.XormInsertNeInfo:", err)
				services.ResponseInternalServerError500ProcessError(w, err)
				return
			} else if affected <= 0 {
				log.Infof("Not record affected to insert ne_info")
			}

			// 刷新缓存，不存在结构体网元Id空字符串
			neService.NewNeInfoImpl.RefreshByNeTypeAndNeID(neInfo.NeType, neInfo.NeId)

			services.ResponseStatusOK204NoContent(w)
			return
		default:
			log.Info("response body:", string(response.Body()))
			body := new(map[string]interface{})
			_ = json.Unmarshal(response.Body(), &body)
			respMsg["error"] = body
		}

		services.ResponseWithJson(w, response.StatusCode(), respMsg)
		return
	}
}

func PutNeInfo(w http.ResponseWriter, r *http.Request) {
	log.Debug("PutNeInfo processing... ")

	_, err := services.CheckFrontValidRequest(w, r)
	if err != nil {
		log.Error("Request error:", err)
		return
	}

	vars := mux.Vars(r)
	neType := vars["elementTypeValue"]
	if neType == "" {
		log.Error("elementTypeValue is empty")
		services.ResponseNotFound404UriNotExist(w, r)
		return
	}
	neTypeLower := strings.ToLower(neType)
	neTypeUpper := strings.ToUpper(neType)
	syncFlag := services.GetUriParamString(r, "sync2ne", ",", false, false)
	body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen))
	if err != nil {
		log.Error("Failed to io.ReadAll:", err)
		services.ResponseNotFound404UriNotExist(w, r)
		return
	}

	neInfo := new(dborm.NeInfo)
	_ = json.Unmarshal(body, neInfo)
	neInfo.NeType = strings.ToUpper(neType)
	neInfo.UpdateTime = time.Now().Format(time.DateTime)
	log.Debug("NE info:", neInfo)

	//if !config.GetYamlConfig().OMC.Chk2Ne {
	if syncFlag == "false" || neTypeUpper == config.GetYamlConfig().OMC.NeType {
		neInfo.Status = NEStatusMaintain
		affected, err := dborm.XormUpdateNeInfo(neInfo)
		if err != nil {
			log.Error("Failed to update Ne info:", err)
			services.ResponseInternalServerError500ProcessError(w, err)
			return
		}

		// 刷新缓存，不存在结构体网元Id空字符串
		neService.NewNeInfoImpl.RefreshByNeTypeAndNeID(neInfo.NeType, neInfo.NeId)

		mapRow := make(map[string]interface{})
		row := map[string]interface{}{"affectedRows": affected}
		mapRow["data"] = row
		services.ResponseWithJson(w, http.StatusOK, mapRow)
		return
	} else {
		hostUri := global.CombineHostUri(neInfo.Ip, neInfo.Port)
		//hostUri := fmt.Sprintf("http://%s:%v", neInfo.Ip, neInfo.Port)
		apiUri := fmt.Sprintf("%s/systemManagement/v1/elementType/%s/objectType/config/omcNeConfig", config.DefaultUriPrefix, neTypeLower)
		requestURI2NF := fmt.Sprintf("%s%s", hostUri, apiUri)
		log.Debug("requestURI2NF:", requestURI2NF)

		omcNeConfig := &OmcNeConfig{
			NeId:       neInfo.NeId,
			RmUID:      neInfo.RmUID,
			NeName:     neInfo.NeName,
			PvFlag:     neInfo.PvFlag,
			Province:   neInfo.Province,
			VendorName: neInfo.VendorName,
			Dn:         neInfo.Dn,
		}
		body, _ = json.Marshal(omcNeConfig)
		response, err := client.R().
			EnableTrace().
			SetHeaders(map[string]string{tokenConst.HEADER_KEY: r.Header.Get(tokenConst.HEADER_KEY)}).
			SetHeaders(map[string]string{"User-Agent": config.GetDefaultUserAgent()}).
			SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}).
			SetBody(body).
			Put(requestURI2NF)
		if err != nil {
			log.Error("Failed to Put:", err)
			services.ResponseInternalServerError500ProcessError(w, err)
			return
		}
		log.Info("StatusCode: ", response.StatusCode())

		respMsg := make(map[string]interface{})
		switch response.StatusCode() {
		case http.StatusOK, http.StatusCreated, http.StatusNoContent, http.StatusAccepted:
			neInfo.Status = NEStatusActive
			affected, err := dborm.XormUpdateNeInfo(neInfo)
			if err != nil {
				log.Error("Failed to dborm.XormUpdateNeInfo:", err)
				services.ResponseInternalServerError500ProcessError(w, err)
				return
			} else if affected <= 0 {
				log.Infof("Not record affected to insert ne_info")
			}

			// 刷新缓存，不存在结构体网元Id空字符串
			neService.NewNeInfoImpl.RefreshByNeTypeAndNeID(neInfo.NeType, neInfo.NeId)

			services.ResponseStatusOK204NoContent(w)
			return
		default:
			log.Info("response body:", string(response.Body()))
			body := new(map[string]interface{})
			_ = json.Unmarshal(response.Body(), &body)
			respMsg["error"] = body
		}

		services.ResponseWithJson(w, response.StatusCode(), respMsg)
		return
	}
}

func DeleteNeInfo(w http.ResponseWriter, r *http.Request) {
	log.Debug("DeleteNeInfo processing... ")

	_, err := services.CheckFrontValidRequest(w, r)
	if err != nil {
		log.Error("Request error:", err)
		return
	}

	vars := mux.Vars(r)
	neType := vars["elementTypeValue"]
	if neType == "" {
		log.Error("elementTypeValue is empty")
		services.ResponseNotFound404UriNotExist(w, r)
		return
	}

	body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen))
	if err != nil {
		log.Error("io.ReadAll is failed:", err)
		services.ResponseNotFound404UriNotExist(w, r)
		return
	}

	neInfo := new(dborm.NeInfo)
	_ = json.Unmarshal(body, neInfo)
	neInfo.NeType = strings.ToUpper(neType)
	neInfo.NeId = services.GetUriParamString(r, "ne_id", ",", false, false)
	neInfo, err = dborm.XormGetNeInfo(neInfo.NeType, neInfo.NeId)
	if err != nil || neInfo == nil {
		log.Error("Failed to delete Ne info:", err)
		services.ResponseInternalServerError500ProcessError(w, err)
		return
	}
	log.Debug("NE info:", neInfo)

	// if NE in active status, can't delete NE
	if !IsActiveNF(neInfo) {
		affected, err := dborm.XormDeleteNeInfo(neInfo)
		if err != nil {
			log.Error("Failed to delete Ne info:", err)
			services.ResponseInternalServerError500ProcessError(w, err)
			return
		}

		// 刷新缓存，不存在结构体网元Id空字符串
		neService.NewNeInfoImpl.RefreshByNeTypeAndNeID(neInfo.NeType, neInfo.NeId)

		mapRow := make(map[string]interface{})
		row := map[string]interface{}{"affectedRows": affected}
		mapRow["data"] = row
		services.ResponseWithJson(w, http.StatusOK, mapRow)
		return
	}
	err = global.ErrCMCannotDeleteActiveNE
	log.Error(err)
	services.ResponseInternalServerError500ProcessError(w, err)
}

func IsActiveNF(neInfo *dborm.NeInfo) bool {
	log.Debug("IsActiveNF processing... ")

	hostUri := fmt.Sprintf("http://%s:%v", neInfo.Ip, neInfo.Port)
	requestURI := fmt.Sprintf(config.UriPrefix+"/systemManagement/v1/elementType/%s/objectType/systemState",
		strings.ToLower(neInfo.NeType))

	response, err := client.R().
		EnableTrace().
		SetHeaders(map[string]string{"User-Agent": config.GetDefaultUserAgent()}).
		SetHeaders(map[string]string{"Content-Type": "application/json;charset=UTF-8"}).
		Get(hostUri + requestURI)
	if err != nil {
		log.Error("Failed to Get:", err)
		return false
	}

	switch response.StatusCode() {
	case http.StatusOK, http.StatusCreated, http.StatusNoContent, http.StatusAccepted:
		return true
	}
	return false
}

func ExportCmFromNF(w http.ResponseWriter, r *http.Request) {
	log.Debug("ExportCmFromNF processing... ")

	_, err := services.CheckFrontValidRequest(w, r)
	if err != nil {
		log.Error("Request error:", err)
		return
	}

	vars := mux.Vars(r)
	neType := vars["elementTypeValue"]
	if neType == "" {
		log.Error("elementTypeValue is empty")
		services.ResponseNotFound404UriNotExist(w, r)
		return
	}
	neTypeUpper := strings.ToUpper(neType)
	neTypeLower := strings.ToLower(neType)

	neId := services.GetUriParamString(r, "ne_id", ",", false, false)

	//	neInfo := new(dborm.NeInfo)
	neInfo, err := dborm.XormGetNeInfo(neType, neId)
	if err != nil {
		log.Errorf("Failed to get ne_info:", err)
		services.ResponseInternalServerError500ProcessError(w, err)
		return
	}
	log.Debug("neInfo:", neInfo)
	nePath := fmt.Sprintf("%s/etc/%s", config.GetYamlConfig().OMC.Backup, neTypeLower)
	isExist, err := global.PathExists(nePath)
	if err != nil {
		log.Errorf("Failed to stat:", err)
		services.ResponseInternalServerError500ProcessError(w, err)
		return
	}
	if isExist {
		err = os.RemoveAll(nePath)
		if err != nil {
			log.Errorf("Failed to RemoveAll:", err)
			services.ResponseInternalServerError500ProcessError(w, err)
			return
		}
	}
	err = os.MkdirAll(nePath, os.ModePerm)
	if err != nil {
		log.Errorf("Failed to MkdirAll:", err)
		services.ResponseInternalServerError500ProcessError(w, err)
		return
	}

	var scpCmd string
	ipType := global.ParseIPAddr(neInfo.Ip)
	omcNetypeLower := strings.ToLower(config.GetYamlConfig().OMC.NeType)
	etcListIMS := "{*.yaml,mmtel,vars.cfg}"
	if config.GetYamlConfig().NE.EtcListIMS != "" {
		etcListIMS = config.GetYamlConfig().NE.EtcListIMS
	}
	switch neTypeLower {
	case omcNetypeLower:
		if ipType == global.IsIPv4 {
			scpCmd = fmt.Sprintf("scp -r %s@%s:%s/etc/*.yaml %s/etc/%s", config.GetYamlConfig().NE.User,
				neInfo.Ip, config.GetYamlConfig().NE.OmcDir, config.GetYamlConfig().OMC.Backup, neTypeLower)
		} else {
			scpCmd = fmt.Sprintf("scp -r %s@[%s]:%s/etc/*.yaml %s/etc/%s", config.GetYamlConfig().NE.User,
				neInfo.Ip, config.GetYamlConfig().NE.OmcDir, config.GetYamlConfig().OMC.Backup, neTypeLower)
		}

	case "ims":
		if ipType == global.IsIPv4 {
			scpCmd = fmt.Sprintf("scp -r %s@%s:%s/%s/%s %s/etc/%s", config.GetYamlConfig().NE.User,
				neInfo.Ip, config.GetYamlConfig().NE.EtcDir, neTypeLower,
				etcListIMS, config.GetYamlConfig().OMC.Backup, neTypeLower)
		} else {
			scpCmd = fmt.Sprintf("scp -r %s@[%s]:%s/%s/%s %s/etc/%s", config.GetYamlConfig().NE.User,
				neInfo.Ip, config.GetYamlConfig().NE.EtcDir, neTypeLower,
				etcListIMS, config.GetYamlConfig().OMC.Backup, neTypeLower)
		}

	case "mme":
		if ipType == global.IsIPv4 {
			scpCmd = fmt.Sprintf("scp -r %s@%s:%s/%s/*.conf %s/etc/%s", config.GetYamlConfig().NE.User,
				neInfo.Ip, config.GetYamlConfig().NE.EtcDir,
				neTypeLower, config.GetYamlConfig().OMC.Backup, neTypeLower)
		} else {
			scpCmd = fmt.Sprintf("scp -r %s@[%s]:%s/%s/*.conf %s/etc/%s", config.GetYamlConfig().NE.User,
				neInfo.Ip, config.GetYamlConfig().NE.EtcDir,
				neTypeLower, config.GetYamlConfig().OMC.Backup, neTypeLower)
		}

	default:
		if ipType == global.IsIPv4 {
			scpCmd = fmt.Sprintf("scp -r %s@%s:%s/%s/*.yaml %s/etc/%s", config.GetYamlConfig().NE.User,
				neInfo.Ip, config.GetYamlConfig().NE.EtcDir,
				neTypeLower, config.GetYamlConfig().OMC.Backup, neTypeLower)
		} else {
			scpCmd = fmt.Sprintf("scp -r %s@[%s]:%s/%s/*.yaml %s/etc/%s", config.GetYamlConfig().NE.User,
				neInfo.Ip, config.GetYamlConfig().NE.EtcDir,
				neTypeLower, config.GetYamlConfig().OMC.Backup, neTypeLower)
		}

	}

	zipFile := fmt.Sprintf("%s-%s-etc-%s.zip", neTypeLower, strings.ToLower(neInfo.NeId), time.Now().Format(global.DateData))
	zipFilePath := config.GetYamlConfig().OMC.Backup + "/" + zipFile
	zipCmd := fmt.Sprintf("cd %s/etc && zip -r %s %s/*", config.GetYamlConfig().OMC.Backup, zipFilePath, neTypeLower)

	command := fmt.Sprintf("%s&&%s", scpCmd, zipCmd)

	log.Debug("command:", command)
	err = ExecCmd(command)
	if err != nil {
		log.Error("Faile to exec command:", err)
		services.ResponseInternalServerError500ProcessError(w, err)
		return
	}

	md5Sum, err := global.GetFileMD5Sum(zipFilePath)
	if err != nil {
		log.Error("Faile to md5sum:", err)
		services.ResponseInternalServerError500ProcessError(w, err)
		return
	}
	//log.Debug("md5Str:", md5Sum)
	path := config.GetYamlConfig().OMC.Backup
	neBackup := dborm.NeBackup{NeType: neTypeUpper, NeId: neId, FileName: zipFile, Path: path, Md5Sum: md5Sum}
	_, err = dborm.XormInsertTableOne("ne_backup", neBackup)
	if err != nil {
		log.Error("Faile to XormInsertTableOne:", err)
		services.ResponseInternalServerError500ProcessError(w, err)
		return
	}

	//services.ResponseFileWithNameAndMD5(w, http.StatusOK, zipFile, path, md5Sum)
	services.ResponseStatusOK204NoContent(w)
}

type ImportCMJson struct {
	FileName string `json:"fileName"`
}

func ImportCmToNF(w http.ResponseWriter, r *http.Request) {
	log.Debug("ImportCmToNF processing... ")

	_, err := services.CheckFrontValidRequest(w, r)
	if err != nil {
		log.Error("Request error:", err)
		return
	}

	vars := mux.Vars(r)
	neType := vars["elementTypeValue"]
	if neType == "" {
		log.Error("elementTypeValue is empty")
		services.ResponseNotFound404UriNotExist(w, r)
		return
	}
	neTypeUpper := strings.ToUpper(neType)
	neTypeLower := strings.ToLower(neType)

	neId := services.GetUriParamString(r, "ne_id", ",", false, false)

	var fileName, path string
	if services.IsJsonContentType(r) {
		body, err := io.ReadAll(io.LimitReader(r.Body, global.RequestBodyMaxLen))
		if err != nil {
			log.Error("io.ReadAll is failed:", err)
			services.ResponseNotFound404UriNotExist(w, r)
			return
		}
		log.Debug("Body:", string(body))

		importCMJson := new(ImportCMJson)
		_ = json.Unmarshal(body, importCMJson)
		fileName = importCMJson.FileName
		path = config.GetYamlConfig().OMC.Backup
	} else {
		path = config.GetYamlConfig().OMC.Upload
		fileName, err = services.HandleUploadFile(r, path, "")
		if err != nil {
			log.Error("Faile to HandleUploadFile:", err)
			services.ResponseInternalServerError500ProcessError(w, err)
			return
		}
	}
	filePath := fmt.Sprintf("%s/%s", path, fileName)

	//	neInfo := new(dborm.NeInfo)
	neInfo, err := dborm.XormGetNeInfo(neType, neId)
	if err != nil {
		log.Errorf("Failed to get ne_info:", err)
		services.ResponseInternalServerError500ProcessError(w, err)
		return
	}
	log.Debug("neInfo:", neInfo)

	md5Sum, err := global.GetFileMD5Sum(filePath)
	if err != nil {
		log.Error("Faile to GetFileMD5Sum:", err)
		services.ResponseInternalServerError500ProcessError(w, err)
		return
	}

	//neBackup := dborm.NeBackup{NeType: neType, NeId: neId, Md5Sum: md5Sum}
	//log.Debug("neBackup:", neBackup)
	where := fmt.Sprintf("ne_type='%s' and ne_id='%s' and md5_sum='%s'", neTypeUpper, neId, md5Sum)
	has, err := dborm.XormExistTableOne("ne_backup", where)
	if err != nil {
		log.Error("Faile to XormInsertTableOne:", err)
		services.ResponseInternalServerError500ProcessError(w, err)
		return
	} else if !has {
		err = global.ErrCMInvalidBackupFile
		log.Error(err)
		services.ResponseInternalServerError500ProcessError(w, err)
		return
	}

	// nePath := fmt.Sprintf("%s/etc/%s", config.GetYamlConfig().OMC.Upload, neTypeLower)
	// isExist, err := global.PathExists(nePath)
	// if err != nil {
	// 	log.Errorf("Failed to stat:", err)
	// 	services.ResponseInternalServerError500ProcessError(w, err)
	// 	return
	// }
	// if isExist {
	// 	err = os.RemoveAll(nePath)
	// 	if err != nil {
	// 		log.Errorf("Failed to remove:", err)
	// 		services.ResponseInternalServerError500ProcessError(w, err)
	// 		return
	// 	}
	// }
	// unzipCmd := fmt.Sprintf("unzip -o %s -d %s", filePath, config.GetYamlConfig().OMC.Upload)

	// var scpCmd string
	// ipType := global.ParseIPAddr(neInfo.Ip)
	// if ipType == global.IsIPv4 {
	// 	scpCmd = fmt.Sprintf("scp -r %s/etc/%s %s@%s:%s", config.GetYamlConfig().OMC.Upload,
	// 		neTypeLower, config.GetYamlConfig().NE.User, neInfo.Ip, config.GetYamlConfig().NE.EtcDir)
	// } else {
	// 	scpCmd = fmt.Sprintf("scp -r %s/etc/%s %s@[%s]:%s", config.GetYamlConfig().OMC.Upload,
	// 		neTypeLower, config.GetYamlConfig().NE.User, neInfo.Ip, config.GetYamlConfig().NE.EtcDir)
	// }

	// err = ExecCmd(fmt.Sprintf("%s && %s", unzipCmd, scpCmd))
	// if err != nil {
	// 	log.Errorf("Faile to scp NF: neType=%s, neId=%s, ip=%s", neType, neId, neInfo.Ip)
	// 	services.ResponseInternalServerError500ProcessError(w, err)
	// 	return
	// }

	// nePath := fmt.Sprintf("%s/etc/%s", config.GetYamlConfig().OMC.Upload, neTypeLower)
	// isExist, err := global.PathExists(nePath)
	// if err != nil {
	// 	log.Errorf("Failed to stat:", err)
	// 	services.ResponseInternalServerError500ProcessError(w, err)
	// 	return
	// }
	// if isExist {
	// 	err = os.RemoveAll(nePath)
	// 	if err != nil {
	// 		log.Errorf("Failed to remove:", err)
	// 		services.ResponseInternalServerError500ProcessError(w, err)
	// 		return
	// 	}
	// }
	var scpZipCmd string
	ipType := global.ParseIPAddr(neInfo.Ip)
	if ipType == global.IsIPv4 {
		scpZipCmd = fmt.Sprintf("scp -r %s %s@%s:%s", filePath,
			config.GetYamlConfig().NE.User, neInfo.Ip, config.GetYamlConfig().NE.ScpDir)
	} else {
		scpZipCmd = fmt.Sprintf("scp -r %s %s@[%s]:%s", filePath,
			config.GetYamlConfig().NE.User, neInfo.Ip, config.GetYamlConfig().NE.ScpDir)
	}
	err = ExecCmd(scpZipCmd)
	if err != nil {
		log.Errorf("Faile to scp NF: neType=%s, neId=%s, ip=%s", neType, neId, neInfo.Ip)
		services.ResponseInternalServerError500ProcessError(w, err)
		return
	}
	neFilePath := config.GetYamlConfig().NE.ScpDir + "/" + fileName
	var unzipCmd string
	if neTypeLower != "omc" {
		unzipCmd = fmt.Sprintf("sudo unzip -o %s -d %s", neFilePath, config.GetYamlConfig().NE.EtcDir)
	} else {
		unzipCmd = fmt.Sprintf("sudo unzip -oj %s -d %s/etc", neFilePath, config.GetYamlConfig().NE.OmcDir)
	}
	sshHost := fmt.Sprintf("%s@%s", config.GetYamlConfig().NE.User, neInfo.Ip)
	cmd := exec.Command("ssh", sshHost, unzipCmd)
	out, err := cmd.CombinedOutput()
	log.Tracef("Exec output: %v", string(out))
	if err != nil {
		log.Error("Faile to execute command:", err)
		services.ResponseInternalServerError500ProcessError(w, err)
		return
	}

	services.ResponseStatusOK204NoContent(w)
}

func DownloadNeBackupFile(w http.ResponseWriter, r *http.Request) {
	log.Debug("DownloadNeBackupFile processing... ")

	_, err := services.CheckFrontValidRequest(w, r)
	if err != nil {
		log.Error("Request error:", err)
		return
	}

	vars := mux.Vars(r)
	neType := vars["neType"]
	if neType == "" {
		log.Error("neType is empty")
		services.ResponseNotFound404UriNotExist(w, r)
		return
	}
	neTypeUpper := strings.ToUpper(neType)
	//neTypeLower := strings.ToLower(neType)

	fileName := vars["fileName"]
	if fileName == "" {
		log.Error("fileName is empty")
		services.ResponseNotFound404UriNotExist(w, r)
		return
	}

	sql := fmt.Sprintf("select * from ne_backup where ne_type='%s' and file_name='%s'", neTypeUpper, fileName)
	neBackup, err := dborm.XormGetDataBySQL(sql)
	if err != nil {
		log.Error("Faile to XormGetDataBySQL:", err)
		services.ResponseInternalServerError500ProcessError(w, err)
		return
	} else if len(*neBackup) == 0 {
		err := global.ErrCMNotFoundTargetBackupFile
		log.Error(err)
		services.ResponseInternalServerError500ProcessError(w, err)
		return
	}

	path := (*neBackup)[0]["path"]
	md5Sum := (*neBackup)[0]["md5_sum"]

	services.ResponseFileWithNameAndMD5(w, http.StatusOK, fileName, path, md5Sum)
}

func DeleteNeBackupFile(w http.ResponseWriter, r *http.Request) {
	log.Debug("DeleteNeBackupFile processing... ")

	_, err := services.CheckFrontValidRequest(w, r)
	if err != nil {
		log.Error("Request error:", err)
		return
	}

	vars := mux.Vars(r)
	neType := vars["neType"]
	if neType == "" {
		log.Error("neType is empty")
		services.ResponseNotFound404UriNotExist(w, r)
		return
	}
	neTypeUpper := strings.ToUpper(neType)
	//neTypeLower := strings.ToLower(neType)

	fileName := vars["fileName"]
	if fileName == "" {
		log.Error("fileName is empty")
		services.ResponseNotFound404UriNotExist(w, r)
		return
	}

	sql := fmt.Sprintf("select * from ne_backup where ne_type='%s' and file_name='%s'", neTypeUpper, fileName)
	neBackup, err := dborm.XormGetDataBySQL(sql)
	if err != nil {
		log.Error("Faile to XormGetDataBySQL:", err)
		services.ResponseInternalServerError500ProcessError(w, err)
		return
	} else if len(*neBackup) == 0 {
		err := global.ErrCMNotFoundTargetBackupFile
		log.Error(err)
		services.ResponseInternalServerError500ProcessError(w, err)
		return
	}

	where := fmt.Sprintf("ne_type='%s' and file_name='%s'", neTypeUpper, fileName)
	affected, err := dborm.XormDeleteDataByWhere(where, "ne_backup")
	if err != nil || affected == 0 {
		log.Error("Faile to XormGetDataBySQL:", err)
		services.ResponseInternalServerError500ProcessError(w, err)
		return
	}

	path := (*neBackup)[0]["path"]
	filePath := fmt.Sprintf("%s/%s", path, fileName)
	err = os.Remove(filePath)
	if err != nil {
		log.Error("Faile to Remove:", err)
		services.ResponseInternalServerError500ProcessError(w, err)
		return
	}

	services.ResponseStatusOK204NoContent(w)
}

func PostNeServiceAction(w http.ResponseWriter, r *http.Request) {
	log.Debug("PostNeServiceAction processing... ")

	_, err := services.CheckFrontValidRequest(w, r)
	if err != nil {
		log.Error("Request error:", err)
		return
	}

	vars := mux.Vars(r)
	neType := vars["elementTypeValue"]
	if neType == "" {
		log.Error("elementTypeValue is empty")
		services.ResponseNotFound404UriNotExist(w, r)
		return
	}
	//neTypeUpper := strings.ToUpper(neType)
	neTypeLower := strings.ToLower(neType)
	action := vars["action"]

	neId := services.GetUriParamString(r, "neId", ",", false, false)

	//	neInfo := new(dborm.NeInfo)
	neInfo, err := dborm.XormGetNeInfo(neType, neId)
	if err != nil {
		log.Error("Failed to get ne_info:", err)
		services.ResponseInternalServerError500ProcessError(w, err)
		return
	}
	log.Debug("neInfo:", neInfo)

	sshHost := fmt.Sprintf("%s@%s", config.GetYamlConfig().NE.User, neInfo.Ip)
	switch neTypeLower {
	case "omc":
		actionCmd := fmt.Sprintf("sudo %s/bin/omcsvc.sh %s", config.GetYamlConfig().NE.OmcDir, action)
		cmd := exec.Command("ssh", sshHost, actionCmd)
		out, err := cmd.CombinedOutput()
		log.Debugf("Exec output: %v", string(out))
		if err != nil {
			log.Errorf("Faile to execute ssh %s omc:%v", action, err)
			services.ResponseInternalServerError500ProcessError(w, err)
			return
		}
	case "ims":
		switch action {
		case "start", "stop":
			actionCmd := fmt.Sprintf("sudo ims-%s", action)
			cmd := exec.Command("ssh", sshHost, actionCmd)
			out, err := cmd.CombinedOutput()
			log.Debugf("Exec output: %v", string(out))
			if err != nil {
				log.Errorf("Faile to execute %s command:%v", actionCmd, err)
				services.ResponseInternalServerError500ProcessError(w, err)
				return
			}
		case "restart":
			actionCmd := "sudo ims-stop && sudo ims-start"
			cmd := exec.Command("ssh", sshHost, actionCmd)
			out, err := cmd.CombinedOutput()
			log.Debugf("Exec output: %v", string(out))
			if err != nil {
				log.Errorf("Faile to execute %s command:%v", actionCmd, err)
				services.ResponseInternalServerError500ProcessError(w, err)
				return
			}
		default:
			err = global.ErrCMUnknownServiceAction
			log.Errorf("%v, action:%s", err, action)
			services.ResponseInternalServerError500ProcessError(w, err)
			return
		}
	default:
		actionCmd := fmt.Sprintf("sudo systemctl %s %s.service", action, neTypeLower)
		cmd := exec.Command("ssh", sshHost, actionCmd)
		out, err := cmd.CombinedOutput()
		log.Debugf("Exec output: %v", string(out))
		if err != nil {
			log.Error("Faile to execute command:", err)
			services.ResponseInternalServerError500ProcessError(w, err)
			return
		}
	}

	services.ResponseStatusOK204NoContent(w)
}

func PostNeInstanceAction(w http.ResponseWriter, r *http.Request) {
	log.Debug("PostNeInstanceAction processing... ")

	_, err := services.CheckFrontValidRequest(w, r)
	if err != nil {
		log.Error("Request error:", err)
		return
	}

	vars := mux.Vars(r)
	neType := vars["elementTypeValue"]
	if neType == "" {
		log.Error("elementTypeValue is empty")
		services.ResponseNotFound404UriNotExist(w, r)
		return
	}
	//neTypeUpper := strings.ToUpper(neType)
	//neTypeLower := strings.ToLower(neType)
	action := vars["action"]

	neId := services.GetUriParamString(r, "neId", ",", false, false)

	//	neInfo := new(dborm.NeInfo)
	neInfo, err := dborm.XormGetNeInfo(neType, neId)
	if err != nil {
		log.Errorf("Failed to get ne_info:", err)
		services.ResponseInternalServerError500ProcessError(w, err)
		return
	}
	log.Debug("neInfo:", neInfo)

	sshHost := fmt.Sprintf("%s@%s", config.GetYamlConfig().NE.User, neInfo.Ip)
	switch action {
	case "poweron":
		actionCmd := "sudo poweron"
		cmd := exec.Command("ssh", sshHost, actionCmd)
		out, err := cmd.CombinedOutput()
		log.Debugf("Exec output: %v", string(out))
		if err != nil {
			log.Error("Faile to execute ssh %s omc:", action, err)
			services.ResponseInternalServerError500ProcessError(w, err)
			return
		}
	case "poweroff":
		actionCmd := "sudo poweroff"
		cmd := exec.Command("ssh", sshHost, actionCmd)
		out, err := cmd.CombinedOutput()
		log.Debugf("Exec output: %v", string(out))
		if err != nil {
			log.Error("Faile to execute ssh sudo poweroff:", err)
			services.ResponseInternalServerError500ProcessError(w, err)
			return
		}
	case "reboot":
		actionCmd := "sudo reboot"
		cmd := exec.Command("ssh", sshHost, actionCmd)
		out, err := cmd.CombinedOutput()
		log.Debugf("Exec output: %v", string(out))
		if err != nil {
			log.Error("Faile to execute ssh sudo reboot:", err)
			services.ResponseInternalServerError500ProcessError(w, err)
			return
		}
	default:
		err = global.ErrCMUnknownInstanceAction
		log.Errorf("%v, action:%s", err, action)
		services.ResponseInternalServerError500ProcessError(w, err)
		return
	}

	services.ResponseStatusOK204NoContent(w)
}
