/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

package rocketmq

/*
#cgo LDFLAGS: -L/usr/local/lib/ -lrocketmq
#include <rocketmq/CMessage.h>
#include <rocketmq/CMessageExt.h>
#include <stdlib.h>
*/
import "C"
import (
	"fmt"
	"unsafe"
)

//Message used for send
type Message struct {
	Topic          string
	Tags           string
	Keys           string
	Body           string
	DelayTimeLevel int
	Property       map[string]string
	cmsg           *C.struct_CMessage
}

func (msg *Message) String() string {
	return fmt.Sprintf("[Topic: %s, Tags: %s, Keys: %s, Body: %s, DelayTimeLevel: %d, Property: %v]",
		msg.Topic, msg.Tags, msg.Keys, msg.Body, msg.DelayTimeLevel, msg.Property)
}

//GetProperty get message property by key string
func (msg *Message) GetProperty(key string) string {
	ck := C.CString(key)
	defer C.free(unsafe.Pointer(ck))
	return C.GoString(C.GetOriginMessageProperty(msg.cmsg, ck))
}

func goMsgToC(gomsg *Message) *C.struct_CMessage {
	cs := C.CString(gomsg.Topic)
	var cmsg = C.CreateMessage(cs)
	C.free(unsafe.Pointer(cs))

	cs = C.CString(gomsg.Tags)
	C.SetMessageTags(cmsg, cs)
	C.free(unsafe.Pointer(cs))

	cs = C.CString(gomsg.Keys)
	C.SetMessageKeys(cmsg, cs)
	C.free(unsafe.Pointer(cs))

	cs = C.CString(gomsg.Body)
	C.SetMessageBody(cmsg, cs)
	C.free(unsafe.Pointer(cs))

	C.SetDelayTimeLevel(cmsg, C.int(gomsg.DelayTimeLevel))

	for k, v := range gomsg.Property {
		key := C.CString(k)
		value := C.CString(v)
		C.SetMessageProperty(cmsg, key, value)
		C.free(unsafe.Pointer(key))
		C.free(unsafe.Pointer(value))
	}
	return cmsg
}

func cMsgToGo(cMsg *C.struct_CMessage) *Message {
	gomsg := &Message{}

	gomsg.Topic = C.GoString(C.GetOriginMessageTopic(cMsg))
	gomsg.Tags = C.GoString(C.GetOriginMessageTags(cMsg))
	gomsg.Keys = C.GoString(C.GetOriginMessageKeys(cMsg))
	gomsg.Body = C.GoString(C.GetOriginMessageBody(cMsg))
	gomsg.DelayTimeLevel = int(C.GetOriginDelayTimeLevel(cMsg))
	gomsg.cmsg = cMsg

	return gomsg
}

//MessageExt used for consume
type MessageExt struct {
	Message
	MessageID                 string
	QueueId                   int
	ReconsumeTimes            int
	StoreSize                 int
	BornTimestamp             int64
	StoreTimestamp            int64
	QueueOffset               int64
	CommitLogOffset           int64
	PreparedTransactionOffset int64

	// improve: is there is a method convert c++ map to go variable?
	cmsgExt *C.struct_CMessageExt
}

func (msgExt *MessageExt) String() string {
	return fmt.Sprintf("[MessageId: %s, %s, QueueId: %d, ReconsumeTimes: %d, StoreSize: %d, BornTimestamp: %d, "+
		"StoreTimestamp: %d, QueueOffset: %d, CommitLogOffset: %d, PreparedTransactionOffset: %d]", msgExt.MessageID,
		msgExt.Message.String(), msgExt.QueueId, msgExt.ReconsumeTimes, msgExt.StoreSize, msgExt.BornTimestamp,
		msgExt.StoreTimestamp, msgExt.QueueOffset, msgExt.CommitLogOffset, msgExt.PreparedTransactionOffset)
}

//GetProperty get the message property by key from message ext
func (msgExt *MessageExt) GetProperty(key string) string {
	ck := C.CString(key)
	defer C.free(unsafe.Pointer(ck))
	return C.GoString(C.GetMessageProperty(msgExt.cmsgExt, ck))
}

func cmsgExtToGo(cmsg *C.struct_CMessageExt) *MessageExt {
	gomsg := &MessageExt{cmsgExt: cmsg}

	gomsg.Topic = C.GoString(C.GetMessageTopic(cmsg))
	gomsg.Tags = C.GoString(C.GetMessageTags(cmsg))
	gomsg.Keys = C.GoString(C.GetMessageKeys(cmsg))
	gomsg.Body = C.GoString(C.GetMessageBody(cmsg))
	gomsg.MessageID = C.GoString(C.GetMessageId(cmsg))
	gomsg.DelayTimeLevel = int(C.GetMessageDelayTimeLevel(cmsg))
	gomsg.QueueId = int(C.GetMessageQueueId(cmsg))
	gomsg.ReconsumeTimes = int(C.GetMessageReconsumeTimes(cmsg))
	gomsg.StoreSize = int(C.GetMessageStoreSize(cmsg))
	gomsg.BornTimestamp = int64(C.GetMessageBornTimestamp(cmsg))
	gomsg.StoreTimestamp = int64(C.GetMessageStoreTimestamp(cmsg))
	gomsg.QueueOffset = int64(C.GetMessageQueueOffset(cmsg))
	gomsg.CommitLogOffset = int64(C.GetMessageCommitLogOffset(cmsg))
	gomsg.PreparedTransactionOffset = int64(C.GetMessagePreparedTransactionOffset(cmsg))

	return gomsg
}
