// Transform sales DB struct to an outgoing json
// struct
func transformDbSalesToSalesResponse(ordersDb []*dataservice.OrderDocElkType) []*SaleResponseType {

	var sales []*SaleResponseType

	for i := 0; i < len(ordersDb); i++ {

		// Get the cached config details
		session := dataservice.GetSession(ordersDb[i].Doc.Products[0].SessionId, configuration.GetConfig())

		sale := new(SaleResponseType)
		sale.Id = ordersDb[i].Doc.Code
		sale.EventId = session.Event_id
		sale.EventName = session.Event_name
		sale.TransactionDate = ordersDb[i].Doc.Date.Purchased
		sale.TransactionType = TRANSACTION_SALE_TYPE
		sale.BuyerTypeCode = ordersDb[i].Doc.OrderData.ChannelType
		sale.ProductsNumber = len(ordersDb[i].Doc.Products)
		sale.ChannelId = ordersDb[i].Doc.OrderData.ChannelId
		products := transformProductsDbToProductsResponse(ordersDb[i].Doc.Products, session)
		sale.Products = products

		sales = append(sales, sale)
	}

	return sales
}
// Public method to check the Oauth2 authorization with
// a Bearer token header to the oauth server
func Authorize(authheader string) (*dataservice.Oauthtoken, bool) {

	var oauthtoken *dataservice.Oauthtoken
	isAuthorized := false
	s := strings.Split(authheader, " ")
	token := s[len(s)-1]

	if token != "" {

		oauthtoken = dataservice.GetOauthtoken(token)
		for _, username := range configuration.GetConfig().Authorized_usernames_list {

			if username == oauthtoken.UserName {
				isAuthorized = true
				break
			}
		}
	}

	return oauthtoken, isAuthorized
}
/**
 * Prices resource endpoint
 */
func SalesController(w http.ResponseWriter, request *http.Request) {

	uuid := GetUuid()
	start := time.Now()

	// Check authorization
	oauthtoken, isAuthorized := authorization.Authorize(request.Header.Get(AUTH_HEADER))
	if !isAuthorized {
		w.WriteHeader(http.StatusUnauthorized)
		log.Warningf("/sales request error status 401 unauthorized %v", getIP(w, request))
		return
	}
	log.Infof("{%v} /sales request %v received from: %v %v", uuid, request.URL, oauthtoken.UserName, getIP(w, request))

	// GET request params
	saleId := request.URL.Query().Get(SALE_ID) // Empty error if error
	if saleId == "" {

		vars := mux.Vars(request) // Empty error if error
		saleId = vars[ID]

	}
	startDate = request.URL.Query().Get(START_DATE)
	if startDate == "" {
		startDate = time.Now().AddDate(0, -1, 0).Format(DATE_FORMAT_SHORT)
	}
	endDate = request.URL.Query().Get(END_DATE)
	if endDate == "" {
		endDate = time.Now().Format(DATE_FORMAT_SHORT)
	}
	page, err := strconv.Atoi(request.URL.Query().Get(PAGE))
	if err != nil {
		page = 0
	}
	pageSize, err := strconv.Atoi(request.URL.Query().Get(PAGE_SIZE))
	if err != nil {
		pageSize = configuration.GetConfig().Elasticsearch_limit_items
	}
	if pageSize > 250 { // Security upper page size limit
		pageSize = 250
	}
	eventId, err = strconv.Atoi(request.URL.Query().Get(EVENT_ID)) // Return 0 if error

	// Retrieve requested resource information
	dbSales := dataservice.GetSales(startDate, endDate, eventId, saleId, page, uuid, oauthtoken, pageSize)

	// Set json response struct
	var params ParametersResponseType
	params.StartDate = startDate
	params.EndDate = endDate
	params.Page = page
	params.EventId = eventId
	params.SaleId = saleId
	params.TraceId = uuid
	var salesresponse SalesResponseType
	salesresponse.Parameters = params
	salesresponse.RequestDate = time.Now()
	salesresponse.Version = "1.0"
	sales := transformDbSalesToSalesResponse(dbSales)
	salesresponse.Sales = sales
	salesjson, err := json.Marshal(salesresponse)

	// Set response headers
	w.Header().Set("Content-Type", "application/json")

	// Set response body
	w.Write(salesjson)

	elapsed := time.Since(start)
	log.Infof("{%v} /sales response status 200 in %v", uuid, elapsed)

}
/**
 * Prices resource endpoint
 */
func PricesController(w http.ResponseWriter, request *http.Request) {

	uuid := GetUuid()
	start := time.Now()

	// Check authorization
	oauthtoken, isAuthorized := authorization.Authorize(request.Header.Get(AUTH_HEADER))
	if !isAuthorized {
		w.WriteHeader(http.StatusUnauthorized)
		log.Warningf("/prices request error status 401 unauthorized %v", getIP(w, request))
		return
	}
	log.Infof("{%v} /prices request %v received from: %v %v", uuid, request.URL, oauthtoken.UserName, getIP(w, request))

	// GET request params
	priceId, err := strconv.Atoi(request.URL.Query().Get(PRICE_ID)) // Return 0 if error
	if err != nil {

		vars := mux.Vars(request)
		id := vars[ID]
		if id != "" {
			priceId, err = strconv.Atoi(id) // Return 0 if error
			if err != nil {
				priceId = 0
			}
		}
	}
	startDate = request.URL.Query().Get(START_DATE)
	if startDate == "" {
		startDate = time.Now().AddDate(0, -1, 0).Format(DATE_FORMAT_SHORT)
	}
	endDate = request.URL.Query().Get(END_DATE)
	if endDate == "" {
		endDate = time.Now().Format(DATE_FORMAT_SHORT)
	}
	page, err := strconv.Atoi(request.URL.Query().Get(PAGE))
	if err != nil {
		page = 0
	}
	pageSize, err := strconv.Atoi(request.URL.Query().Get(PAGE_SIZE))
	if err != nil {
		pageSize = configuration.GetConfig().Mysql_limit_items
	}
	if pageSize > 250 { // Security upper page size limit
		pageSize = 250
	}
	eventId, err = strconv.Atoi(request.URL.Query().Get(EVENT_ID)) // Return 0 if error

	// Retrieve requested resource information
	prices := dataservice.GetPrices(startDate, endDate, page, configuration.GetConfig(), priceId, eventId, uuid, oauthtoken, pageSize)

	// Set json response struct
	var params ParametersResponseType
	params.StartDate = startDate
	params.EndDate = endDate
	params.Page = page
	params.TraceId = uuid
	var pricesresponse PricesResponseType
	pricesresponse.Parameters = params
	pricesresponse.RequestDate = time.Now()
	pricesresponse.Version = "1.0"
	pricesresponse.Prices = prices

	pricesjson, err := json.Marshal(pricesresponse)
	if err != nil {
		w.WriteHeader(http.StatusNoContent)
		log.Errorf("/prices error status 204 no content.")
		return
	}

	// Set response headers
	w.Header().Set("Content-Type", "application/json")

	// Set response body
	w.Write(pricesjson)

	elapsed := time.Since(start)
	log.Infof("{%v} /prices response status 200 in %v", uuid, elapsed)

}
	StartDate string `json:"start_date"`
	EndDate   string `json:"end_date"`
	EventId   int    `json:event_id`
	SaleId    string `json:"sale_id"`
	Page      int    `json:"page"`
	PageSize  int    `json:"page_size"`
	TraceId   string `json:"trace_id"`
}

// Global vars and default values
var (
	log       *logging.Logger = configuration.GetLog()
	startDate string
	endDate   string
	eventId   int
	config    = configuration.GetConfig()
)

// https://blog.golang.org/context/userip/userip.go
// Funtion to retrieve the sender IP from request
// or from forwared headers instead
func getIP(w http.ResponseWriter, req *http.Request) string {

	ip, _, err := net.SplitHostPort(req.RemoteAddr)
	if err != nil {
		log.Debugf("userip: %q is not IP:port", req.RemoteAddr)
	}

	userIP := net.ParseIP(ip)
	if userIP == nil {
		return req.RemoteAddr