package rmi

import (
	"bytes"
	"encoding/binary"
	"git.loafle.net/overflow/overflow_probe/matcher/packet"
	"git.loafle.net/overflow/overflow_probe/model/scaninfo"
)

const (
	MAGIC_NUMBER    = 0x4a524d49
	STREAM_PROTOCOL = 0x4b
	VERSION         = 0x0002
	ACK_PROTOCOL    = 0x4e
)

type RMI_SEND_MESSAGE struct {
	magic    uint32
	version  uint16
	protocol uint8
}

type RMI_RECV_MESSAGE struct {
	streamMessage uint8
	packetLen     uint16
	host          []byte
	port          [2]byte
}
type RMIMatcher struct {
	sendPackets []*packet.Packet
}

func (r *RMIMatcher) Match(index int, packet *packet.Packet, info scaninfo.ServiceScanInfo) bool {
	result := false

	if packet == nil || packet.Buffer == nil || packet.Len == 0 {
		return result
	}

	//fmt.Println("packet :", packet)
	rmiRecv := RMI_RECV_MESSAGE{}

	buf := bytes.NewReader(packet.Buffer)
	binary.Read(buf, binary.BigEndian, &rmiRecv.streamMessage)
	binary.Read(buf, binary.BigEndian, &rmiRecv.packetLen)

	lenInt := int(rmiRecv.packetLen)

	var tempHost = make([]byte, lenInt, lenInt)
	copy(rmiRecv.host, tempHost)

	rmiRecv.host = tempHost

	binary.Read(buf, binary.BigEndian, &rmiRecv.host)
	binary.Read(buf, binary.BigEndian, &rmiRecv.port)

	hostIp := string(rmiRecv.host[:lenInt])
	//fmt.Println(hostIp)

	//hostPort := binary.BigEndian.Uint16(rmiRecv.port[:2])

	if rmiRecv.streamMessage == ACK_PROTOCOL && lenInt == len(hostIp) {
		result = true
	}

	return result
}

func (r *RMIMatcher) PacketCount() int {
	return len(r.sendPackets)
}

func (r *RMIMatcher) Packet(index int) *packet.Packet {
	return r.sendPackets[index]
}

func (r *RMIMatcher) ServiceName() string {
	return "RMI"
}

func (r *RMIMatcher) IsError(index int, packet *packet.Packet, info scaninfo.ServiceScanInfo) bool {
	return false
}

func (r *RMIMatcher) IsNoResponse(index int) bool {
	return false
}

func (r *RMIMatcher) IsPrePacket() bool {
	return false
}

func NewRMIMatcher() *RMIMatcher {

	r := RMIMatcher{}
	rsm := RMI_SEND_MESSAGE{
		magic:    MAGIC_NUMBER,
		version:  VERSION,
		protocol: STREAM_PROTOCOL,
	}

	mCache := new(bytes.Buffer)
	binary.Write(mCache, binary.BigEndian, rsm)

	sendByte1 := mCache.Bytes()
	pp := packet.NewPacket(sendByte1, len(sendByte1))

	r.sendPackets = append(r.sendPackets, pp)

	return &r
}
