package Nrestful

import (
	"net/http"
	"fmt"
	"log"
	"encoding/json"
	mysql "proxy/Nmysql"

	//"strconv"
	"time"
	
	l4g "proxy/logger"//"github.com/sirupsen/logrus"
)

func StartHttpServer(addr string) {
	http.HandleFunc("/", handler)
	http.HandleFunc("/authcode", authcodeHandler)
	http.HandleFunc("/query_userdata", query_userdataHandler)
	http.HandleFunc("/bundle_subs", bundle_subsHandler)
	//http.HandleFunc("/bundle_usage", bundle_usageHandler)
	http.HandleFunc("/recharge", rechargeHandler)
	http.HandleFunc("/transfer", transferHandler)
	//http.HandleFunc("/recharge_card", recharge_cardHandler)
	//http.HandleFunc("/check_balance", check_balanceHandler)
	http.HandleFunc("/query_balane", query_balanceHandler)// query_balane in Pcap from CRM
	http.HandleFunc("/openPackage", openPackageHandler)
	http.HandleFunc("/updateSubs", updateSubsHandler)
	http.HandleFunc("/deleteSubs", deleteSubsHandler)

	log.Fatal(http.ListenAndServe(addr, nil))
}

// handler echoes the Path component of the requested URL.
func handler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintf(w, "URL.Path = %q\n", r.URL.Path)
}

func authcodeHandler(w http.ResponseWriter, r *http.Request) {
	rsp := RestRsp{MsgType: REST_SEND_AUTHCODE_RSP}
	var pRsp *RestRsp = &rsp
	if r.Body == nil {
		rsp.AuthCodeRsp.Message = "request body missing"
		sendAuthCodeRsp(w, http.StatusBadRequest, pRsp)
		return
	}
	
	var req RestReq
	req.MsgType = REST_SEND_AUTHCODE_REQ
	err := json.NewDecoder(r.Body).Decode(&req.AuthCodeReq)
	if err != nil {
		rsp.AuthCodeRsp.Message = "err decode authCodeReq"
		sendAuthCodeRsp(w, http.StatusBadRequest, pRsp)
		return
	}
	l4g.RestLog.Debugf("Got authcode request: %v", req.AuthCodeReq)
	
	// handle ==========================================
	port := AssignPort(&req)
	if port == nil {
		rsp.AuthCodeRsp.Message = "err port full"
		sendAuthCodeRsp(w, http.StatusInternalServerError, pRsp)
		return
	}
	l4g.RestLog.Debugf("Assign port for authcode request, src[%d], dst[%d]", req.Src_id, req.Dst_id)
	
	ocsRsp := getOcsRsp(&req, port)
	if ocsRsp == nil {
		rsp.AuthCodeRsp.Message = "ocs rsp timeout"
		sendAuthCodeRsp(w, http.StatusInternalServerError, pRsp)	
	} else {
		sendAuthCodeRsp(w, http.StatusOK, ocsRsp)
	}
	
	return
}

func query_userdataHandler(w http.ResponseWriter, r *http.Request) {
	rsp := RestRsp{MsgType: REST_QUERY_USERDATA_RSP}
	var pRsp *RestRsp = &rsp
	if r.Body == nil {
		rsp.QueryUserDataRsp.Message = "request body missing"
		sendQueryUserDataRsp(w, http.StatusBadRequest, pRsp)
		return
	}
	
	var req RestReq
	req.MsgType = REST_QUERY_USERDATA_REQ
	err := json.NewDecoder(r.Body).Decode(&req.QueryUserDataReq)
	if err != nil {
		rsp.QueryUserDataRsp.Message = "err decode QueryUserDataReq"
		sendQueryUserDataRsp(w, http.StatusBadRequest, pRsp)
		return
	}
	l4g.RestLog.Debugf("Got query_userdata request: %v", req.QueryUserDataReq)
	
	// handle ==========================================
	port := AssignPort(&req)
	if port == nil {
		rsp.QueryUserDataRsp.Message = "err port full"
		sendQueryUserDataRsp(w, http.StatusInternalServerError, pRsp)
		return
	}
	l4g.RestLog.Debugf("Assign port for query_userdata request, src[%d], dst[%d]", req.Src_id, req.Dst_id)
	
	ocsRsp := getOcsRsp(&req, port)
	if ocsRsp == nil {
		rsp.QueryUserDataRsp.Message = "ocs rsp timeout"
		sendQueryUserDataRsp(w, http.StatusInternalServerError, pRsp)	
	} else {
		sendQueryUserDataRsp(w, http.StatusOK, ocsRsp)
	}
	
	return
}

func bundle_subsHandler(w http.ResponseWriter, r *http.Request) {
	rsp := RestRsp{MsgType: REST_BUNDLE_SUBS_RSP}
	var pRsp *RestRsp = &rsp
	if r.Body == nil {
		rsp.BundleSubsRsp.Message = "request body missing"
		sendBundleSubsRsp(w, http.StatusBadRequest, pRsp)
		return
	}
	
	var req RestReq
	req.MsgType = REST_BUNDLE_SUBS_REQ
	err := json.NewDecoder(r.Body).Decode(&req.BundleSubsReq)
	if err != nil {
		rsp.BundleSubsRsp.Message = "err decode BundleSubsReq"
		sendBundleSubsRsp(w, http.StatusBadRequest, pRsp)
		return
	}
	l4g.RestLog.Debugf("Got BundleSubs request: %v", req.BundleSubsReq)
	
	// handle ==========================================
	port := AssignPort(&req)
	if port == nil {
		rsp.BundleSubsRsp.Message = "err port full"
		sendBundleSubsRsp(w, http.StatusInternalServerError, pRsp)
		return
	}
	l4g.RestLog.Debugf("Assign port for BundleSubs request, src[%d], dst[%d]", req.Src_id, req.Dst_id)
	
	ocsRsp := getOcsRsp(&req, port)
	if ocsRsp == nil {
		rsp.BundleSubsRsp.Message = "ocs rsp timeout"
		sendBundleSubsRsp(w, http.StatusInternalServerError, pRsp)	
	} else {
		sendBundleSubsRsp(w, http.StatusOK, ocsRsp)
	}
	
	return
}

func rechargeHandler(w http.ResponseWriter, r *http.Request) {
	rsp := RestRsp{MsgType: REST_RECHARGE_RSP}
	var pRsp *RestRsp = &rsp
	if r.Body == nil {
		rsp.RechargeRsp.Message = "request body missing"
		sendRechargeRsp(w, http.StatusBadRequest, pRsp)
		return
	}
	
	var req RestReq
	req.MsgType = REST_RECHARGE_REQ
	err := json.NewDecoder(r.Body).Decode(&req.RechargeReq)
	if err != nil {
		rsp.RechargeRsp.Message = "err decode RechargeReq"
		sendRechargeRsp(w, http.StatusBadRequest, pRsp)
		return
	}
	l4g.RestLog.Debugf("Got query_userdata request: %v", req.RechargeReq)
	
	// handle ==========================================
	port := AssignPort(&req)
	if port == nil {
		rsp.RechargeRsp.Message = "err port full"
		sendRechargeRsp(w, http.StatusInternalServerError, pRsp)
		return
	}
	l4g.RestLog.Debugf("Assign port for query_userdata request, src[%d], dst[%d]", req.Src_id, req.Dst_id)
	
	ocsRsp := getOcsRsp(&req, port)
	if ocsRsp == nil {
		rsp.RechargeRsp.Message = "ocs rsp timeout"
		sendRechargeRsp(w, http.StatusInternalServerError, pRsp)	
	} else {
		sendRechargeRsp(w, http.StatusOK, ocsRsp)
	}
	
	return
}

func transferHandler(w http.ResponseWriter, r *http.Request) {
	rsp := RestRsp{MsgType: REST_TRANSFER_RSP}
	var pRsp *RestRsp = &rsp
	if r.Body == nil {
		rsp.TransferRsp.Message = "request body missing"
		sendTransferRsp(w, http.StatusBadRequest, pRsp)
		return
	}
	
	var req RestReq
	req.MsgType = REST_TRANSFER_REQ
	err := json.NewDecoder(r.Body).Decode(&req.TransferReq)
	if err != nil {
		rsp.TransferRsp.Message = "err decode TransferReq"
		sendTransferRsp(w, http.StatusBadRequest, pRsp)
		return
	}
	l4g.RestLog.Debugf("Got Transfer request: %v", req.TransferReq)
	
	// handle ==========================================
	port := AssignPort(&req)
	if port == nil {
		rsp.TransferRsp.Message = "err port full"
		sendTransferRsp(w, http.StatusInternalServerError, pRsp)
		return
	}
	l4g.RestLog.Debugf("Assign port for Transfer request, src[%d], dst[%d]", req.Src_id, req.Dst_id)
	
	ocsRsp := getOcsRsp(&req, port)
	if ocsRsp == nil {
		rsp.TransferRsp.Message = "ocs rsp timeout"
		sendTransferRsp(w, http.StatusInternalServerError, pRsp)	
	} else {
		sendTransferRsp(w, http.StatusOK, ocsRsp)
	}
	
	return
}

func query_balanceHandler(w http.ResponseWriter, r *http.Request) {
	rsp := RestRsp{MsgType: REST_QUERY_BALANCE_RSP}
	var pRsp *RestRsp = &rsp
	if r.Body == nil {
		rsp.QueryBalanceRsp.Message = "request body missing"
		sendQueryBalanceRsp(w, http.StatusBadRequest, pRsp)
		return
	}
	
	var req RestReq
	req.MsgType = REST_QUERY_BALANCE_REQ
	err := json.NewDecoder(r.Body).Decode(&req.QueryBalanceReq)
	if err != nil {
		rsp.QueryBalanceRsp.Message = "err decode QueryBalanceReq"
		sendQueryBalanceRsp(w, http.StatusBadRequest, pRsp)
		return
	}
	l4g.RestLog.Debugf("Got QueryBalance request: %v", req.QueryBalanceReq)
	
	// handle ==========================================
	port := AssignPort(&req)
	if port == nil {
		rsp.QueryBalanceRsp.Message = "err port full"
		sendQueryBalanceRsp(w, http.StatusInternalServerError, pRsp)
		return
	}
	l4g.RestLog.Debugf("Assign port for QueryBalance request, src[%d], dst[%d]", req.Src_id, req.Dst_id)
	
	ocsRsp := getOcsRsp(&req, port)
	if ocsRsp == nil {
		rsp.QueryBalanceRsp.Message = "ocs rsp timeout"
		sendQueryBalanceRsp(w, http.StatusInternalServerError, pRsp)	
	} else {
		sendQueryBalanceRsp(w, http.StatusOK, ocsRsp)
	}
	
	return
}

func openPackageHandler(w http.ResponseWriter, r *http.Request) {
	rsp := RestRsp{MsgType: REST_CRM_CREATE_ACCT_RES}
	var pRsp *RestRsp = &rsp
	if r.Body == nil {
		rsp.CreateAccountRsp.Message = "request body missing"
		sendCreateAccountRsp(w, http.StatusBadRequest, pRsp)
		return
	}
	
	var req RestReq
	req.MsgType = REST_CRM_CREATE_ACCT_REQ
	err := json.NewDecoder(r.Body).Decode(&req.CreateAccountReq)
	if err != nil {
		rsp.CreateAccountRsp.Message = "err decode CreateAccountReq"
		sendCreateAccountRsp(w, http.StatusBadRequest, pRsp)
		return
	}
	l4g.RestLog.Debugf("Got CreateAccount request: %v", req.CreateAccountReq)
	
	// handle ==========================================
	port := AssignPort(&req)
	if port == nil {
		rsp.CreateAccountRsp.Message = "err port full"
		sendCreateAccountRsp(w, http.StatusInternalServerError, pRsp)
		return
	}
	l4g.RestLog.Debugf("Assign port for CreateAccount request, src[%d], dst[%d]", req.Src_id, req.Dst_id)
	
	ocsRsp := getOcsRsp(&req, port)
	if ocsRsp == nil {
		rsp.CreateAccountRsp.Message = "ocs rsp timeout"
		sendCreateAccountRsp(w, http.StatusInternalServerError, pRsp)	
	} else {
		sendCreateAccountRsp(w, http.StatusOK, ocsRsp)
	}
	
	return
}

func updateSubsHandler(w http.ResponseWriter, r *http.Request) {
	rsp := RestRsp{MsgType: REST_CRM_UPDATE_SUBS_RES}
	var pRsp *RestRsp = &rsp
	if r.Body == nil {
		rsp.UpdateSubsRsp.Message = "request body missing"
		sendUpdateSubsRsp(w, http.StatusBadRequest, pRsp)
		return
	}
	
	var req RestReq
	req.MsgType = REST_CRM_UPDATE_SUBS_REQ
	err := json.NewDecoder(r.Body).Decode(&req.UpdateSubsReq)
	if err != nil {
		rsp.UpdateSubsRsp.Message = "err decode UpdateSubsReq"
		sendUpdateSubsRsp(w, http.StatusBadRequest, pRsp)
		return
	}
	l4g.RestLog.Debugf("Got UpdateSubs request: %v", req.UpdateSubsReq)
	
	// handle ==========================================
	port := AssignPort(&req)
	if port == nil {
		rsp.UpdateSubsRsp.Message = "err port full"
		sendUpdateSubsRsp(w, http.StatusInternalServerError, pRsp)
		return
	}
	l4g.RestLog.Debugf("Assign port for UpdateSubs request, src[%d], dst[%d]", req.Src_id, req.Dst_id)
	
	ocsRsp := getOcsRsp(&req, port)
	if ocsRsp == nil {
		rsp.UpdateSubsRsp.Message = "ocs rsp timeout"
		sendUpdateSubsRsp(w, http.StatusInternalServerError, pRsp)	
	} else {
		sendUpdateSubsRsp(w, http.StatusOK, ocsRsp)
	}
	
	return
}

func deleteSubsHandler(w http.ResponseWriter, r *http.Request) {
	rsp := RestRsp{MsgType: REST_CRM_DELETE_SUBS_RES}
	var pRsp *RestRsp = &rsp
	if r.Body == nil {
		rsp.DeleteSubsRsp.Message = "request body missing"
		sendDeleteSubsRsp(w, http.StatusBadRequest, pRsp)
		return
	}

	var req RestReq
	req.MsgType = REST_CRM_DELETE_SUBS_REQ
	err := json.NewDecoder(r.Body).Decode(&req.DeleteSubsReq)
	if err != nil {
		rsp.DeleteSubsRsp.Message = "err decode DeleteSubsReq"
		sendDeleteSubsRsp(w, http.StatusBadRequest, pRsp)
		return
	}
	l4g.RestLog.Debugf("Got DeleteSubs request: %v", req.DeleteSubsReq)

	mysql.CrmDeleteSubsProfile(req.DeleteSubsReq.TelNumber, req.DeleteSubsReq.AcctType, req.DeleteSubsReq.AcctId)
	if req.DeleteSubsReq.AcctType != "1" {// not mobile
		pRsp.DeleteSubsRsp.Result = 0
		pRsp.DeleteSubsRsp.ErrorCode = 2001
		sendDeleteSubsRsp(w, http.StatusOK, pRsp)
		return
	}

	// handle ==========================================
	port := AssignPort(&req)
	if port == nil {
		rsp.DeleteSubsRsp.Message = "err port full"
		sendDeleteSubsRsp(w, http.StatusInternalServerError, pRsp)
		return
	}
	l4g.RestLog.Debugf("Assign port for DeleteSubs request, src[%d], dst[%d]", req.Src_id, req.Dst_id)

	ocsRsp := getOcsRsp(&req, port)
	if ocsRsp == nil {
		rsp.DeleteSubsRsp.Message = "ocs rsp timeout"
		sendDeleteSubsRsp(w, http.StatusInternalServerError, pRsp)
	} else {
		sendDeleteSubsRsp(w, http.StatusOK, ocsRsp)
	}

	return
}

func getOcsRsp(req *RestReq, port *Port) (*RestRsp) {
	c := make(chan RestRsp)
	//port.Rsp = make(chan RestRsp)
	port.Rsp = c
	
	go SendOcsUdpReq(req)

	defer ReleasePort(req.Src_id)
	
	timeout := time.After(5 * time.Second)
	select {
	case rsp, ok := <-c:
		if !ok {// chan closed
			l4g.RestLog.Warnf("chan getOcsRsp closed by other!")
			return nil
		} else {
			close(c)
			l4g.RestLog.Debugf("getOcsRsp succ, close chan.")
			return &rsp
		}
	case <-timeout:
		l4g.RestLog.Warnf("chan getOcsRsp timeout, close chan!")
		close(c)
		return nil
	}
}
