package nbi

import (
	"bytes"
	"fmt"
	"net/http"
	"strconv"

	"github.com/gorilla/mux"
	g "github.com/gosnmp/gosnmp"

	"be.ems/lib/log"
	"be.ems/lib/services"
	"be.ems/restagent/config"
)

func init() {
	conf := config.GetYamlConfig()
	// Default is a pointer to a GoSNMP struct that contains sensible defaults
	// eg port 161, community public, etc
	g.Default.Target = conf.NE.Addr
	g.Default.Port = conf.NE.Port
	err := g.Default.Connect()
	if err != nil {
		fmt.Printf("Connect() err: %v", err)
	}
	//defer g.Default.Conn.Close()
	MAX_RMUID_NUM = config.GetRmUIDMaxNumFromConfig()
	MAX_ALARMID_NUM = config.GetAlarmIDMaxNumFromConfig()
	MAX_PMUID_NUM = config.GetPmIDMaxNumFromConfig()
	MAX_SUBID_NUM = config.GetSubIDMaxNumFromConfig()
	MAX_URI_LEN = config.GetUriMaxLenFromConfig()
	RMUID_REGEXP = config.GetRmUIDRegexpFromConfig()
}

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

	// response 414-4 uri too long ? (optional)
	// todo ... ?
	if bytes.Count([]byte(r.RequestURI), nil) > MAX_URI_LEN {
		log.Error("Request Uri too long:", bytes.Count([]byte(r.RequestURI), nil))
		services.ResponseRequestURITooLong414UriTooLong(w)
		return
	}

	// check media type(content type) only support "application/json"
	// response 415-1
	if !services.IsVallidContentType(r, config.GetYamlConfig().OMC.CheckContentType) {
		log.Debug("Invalid Content-Type")
		services.ResponseUnsupportedMediaType415(w)
		return
	}

	// error processing ...
	// 401-1 response
	token, ret := globalSession.IsCarriedToken(r)
	if ret == false {
		log.Error("AccessToken is not carried")
		services.ResponseUnauthorized401AccessTokenNotCarried(w)
		return
	}

	// 401-2 response
	if globalSession.IsValidToken(token) == false {
		log.Error("AccessToken fails or does not exist")
		services.ResponseUnauthorized401AccessTokenNotExist(w)
		return
	}
	// response 403 Forbidden, permissions deny
	// todo...
	plist := globalSession.GetPermissionFromSession(token)
	log.Debug("permission list:", plist)
	if len(plist) == 0 || plist[0] == false {
		log.Error("User permission deny")
		services.ResponseForbidden403NotPermission(w)
		return
	}

	vars := mux.Vars(r)
	qeuryUri := vars["apiCategory"] + "/" + vars["elementTypeValue"] + "/" + vars["objectTypeValue"]
	log.Debug("Get by Uri: ", qeuryUri)

	apiVer := vars["apiVersion"]
	if apiVer != "v1" {
		log.Error("Uri is invalid")
		services.ResponseNotFound404UriNotExist(w, r)
		return
	}

	// response 406-1
	rmUIDValues := GetRmUIDArr(r)
	if rmUIDValues == nil {
		log.Error("missing parameter: rmUIDs")
		services.ResponseNotAcceptable406MissingParam(w)
		return
	}

	// response 406-2
	errorParams := CheckParameterName(r)
	if errorParams != nil {
		log.Error("parameter name error: ", errorParams)
		services.ResponseNotAcceptable406ParamError(w, errorParams)
		return
	}

	// response 400-5
	if len(rmUIDValues) == 0 {
		log.Error("rmUIDs is wrong or NULL")
		services.ResponseBadRequest400WrongParamValue(w)
		return
	}

	// response 414-1
	if len(rmUIDValues) > MAX_RMUID_NUM {
		log.Error("rmUID greater than", MAX_RMUID_NUM)
		services.ResponseRequestURITooLong414NRMNumExceed(w, MAX_RMUID_NUM)
		return
	}

	// response 400-1
	// check rmUID is valid
	// todo ...
	invalidRmUIDs := CheckValidRmUID(rmUIDValues)
	if len(invalidRmUIDs) != 0 {
		log.Error("rmUID is invalid")
		services.ResponseBadRequest400RmUIDsIsInvalid(w, invalidRmUIDs)
		return
	}

	// response 404-2
	rmUID := CheckLocalRmUID(rmUIDValues)
	if rmUID == "" {
		log.Error("rmUID does not exist")
		services.ResponseNotFound404NRMNotExist(w, rmUIDValues)
		return
	}

	// response 404-1, uri is not exist in map
	attrNames := GetAttrNameArr(r)
	var Oids []string
	Oids = *config.GetOidByFileds(qeuryUri, attrNames, &Oids)
	if len(Oids) == 0 {
		log.Error("Nothing of config map")
		services.ResponseNotFound404UriNotExist(w, r)
		return
	}

	// response 404-1, uri is not exist in map
	var nameOids []config.NameOid
	nameOids = *config.GetDataOidByFields(qeuryUri, attrNames, &nameOids)
	if len(nameOids) == 0 {
		log.Error("Nothing of config map")
		services.ResponseNotFound404UriNotExist(w, r)
		return
	}

	result, err2 := g.Default.Get(Oids) // Get() accepts up to g.MAX_OIDS
	if err2 != nil {
		log.Fatalf("Get() err: %v", err2)

	}

	//	var nameValues []config.NameValue
	var nameValue config.NameValue

	nameValues := make(map[string]interface{})
	nameValues["rmUID"] = rmUID
	for i, variable := range result.Variables {
		nameValue.Name = nameOids[i].Name
		log.Debugf("%d: oid: %s name: %s\n", i, variable.Name, nameValue.Name)
		//		if nameOids[i].Oid == variable.Name && global.IsContain(attributeNames, nameValue.Name) {
		if nameOids[i].Oid == variable.Name {
			// the Value of each variable returned by Get() implements
			// interface{}. You could do a type switch...
			switch variable.Type {
			case g.OctetString:
				bytes := variable.Value.([]byte)
				log.Debugf("string: %s\n", string(bytes))
				nameValue.Value = string(bytes)
				nameValues[nameValue.Name] = nameValue.Value
			case g.Integer:
				value := variable.Value.(int)
				log.Debugf("integer: %d\n", value)
				nameValue.Value = strconv.Itoa(value)
				nameValues[nameValue.Name] = nameValue.Value
			case g.IPAddress:
				value := variable.Value.(string)
				log.Debugf("IPAddress: %s\n", variable.Value)
				nameValue.Value = value
				nameValues[nameValue.Name] = nameValue.Value
			default:
				// ... or often you're just interested in numeric values.
				// ToBigInt() will return the Value as a BigInt, for plugging
				// into your calculations.
				log.Debugf("number: %d\n", g.ToBigInt(variable.Value))
			}
		}
	}

	getResponse := services.DataResponse{nameValues}
	services.ResponseWithJson(w, http.StatusOK, getResponse)
}
