package mgenetlink

import (
	nl "github.com/mame82/P4wnP1_aloa/mnetlink"
	"errors"
	"golang.org/x/sys/unix"
	"log"
)

var (
	ENlClient = errors.New("Netlink client not connected, maybe not created with NewGeNl")
)

func NewGeNl() (res *Client, err error) {
	nlcl,err := nl.NewNl(unix.NETLINK_GENERIC)
	if err != nil { return nil, err }
	res = &Client{
		nlclient: nlcl,
	}
	return
}

func (c *Client) Open() (err error) {
	if c.nlclient == nil { return ENlClient }
	return c.nlclient.Open()
}

func (c *Client) Close() (err error) {
	if c.nlclient == nil { return ENlClient }
	return c.nlclient.Close()
}

func (c *Client) AddGroupMembership(groupid uint32) (err error) {
	return c.nlclient.AddGroupMembership(int(groupid))
}

func (c *Client) DropGroupMembership(groupid uint32) (err error) {
	return c.nlclient.DropGroupMembership(int(groupid))
}

func (c *Client) Receive() (msgs []nl.Message, err error) {
	return c.nlclient.Receive()
}


// This refers to generic netlink families, not netlink families (netlink family is always NETLINK_GENERIC)
func (c *Client) GetFamilies() (families []Family, err error) {
	nlmsg := nl.Message{
		Flags: unix.NLM_F_REQUEST | unix.NLM_F_DUMP, // + dump request to get all
		Type: unix.GENL_ID_CTRL,
	}
	genlmsg := Message{
		Cmd: unix.CTRL_CMD_GETFAMILY,
		Version: 1, // control version 1 ??
	}

	genlmsg.Data = []byte{}
	if err != nil { return }

	nlmsg_data,err := genlmsg.MarshalBinary()
	if err != nil { return }
	nlmsg.SetData(nlmsg_data)



	err = c.nlclient.Send(nlmsg)
	if err != nil { return }

	// read answer (or sth else)
	msgs,err := c.nlclient.Receive()
	if err != nil { return }

	//fmt.Printf("Answer: %+v\n", msgs)

	for _,msg := range msgs {

		genl_msg := Message{} //genl message
		genl_msg.UnmarshalBinary(msg.GetData()) //parse NL message payload as genl message
		attrs,err := genl_msg.AttributesFromData() // parse genl_msg payload as attr array
		if err != nil {
			log.Println("Error parsing message data as attributes")
			continue
		}
		//fmt.Printf("Msg %d attributes: %+v\n", idx, attrs)
		curFamily,err := ParseAttrsToFamily(attrs) // parse attr array as data for a single family
		if err != nil {
			log.Println("Error parsing attributes as family")
			continue
		}
		families = append(families, curFamily)


	}
	return
}

func (c *Client) GetFamily(familyName string) (family *Family, err error) {
	nlmsg := nl.Message{
		Flags: unix.NLM_F_REQUEST,
		Type: unix.GENL_ID_CTRL,
		//Seq: seq,
		//Pid: pid,
	}
	genlmsg := Message{
		Cmd: unix.CTRL_CMD_GETFAMILY,
		Version: 1, // control version 1 ??
	}
	genlmsg_attr := nl.Attr{
		Type: unix.CTRL_ATTR_FAMILY_NAME,
	}
	genlmsg_attr.SetData(nl.Str2Bytes(familyName))

	genlmsg.Data,err = genlmsg_attr.MarshalBinary()
	if err != nil { return }

	nlmsg_data,err := genlmsg.MarshalBinary()
	if err != nil { return }
	nlmsg.SetData(nlmsg_data)



	err = c.nlclient.Send(nlmsg)
	if err != nil { return }

	// read answer (or sth else)
	msgs,err := c.nlclient.Receive()
	if err != nil { return }

	//fmt.Printf("Answer: %+v\n", msgs)

	for _,msg := range msgs {
		if family != nil {
			// multiple valid families in response
			return nil,errors.New("Multiple valid families in resposne to GETFAMILY command")
		}

		genl_msg := Message{} //genl message
		genl_msg.UnmarshalBinary(msg.GetData()) //parse NL message payload as genl message
		attrs,err := genl_msg.AttributesFromData() // parse genl_msg payload as attr array
		if err != nil {
			log.Println("Error parsing message data as attributes")
			continue
		}
		//fmt.Printf("Msg %d attributes: %+v\n", idx, attrs)
		curFamily,err := ParseAttrsToFamily(attrs) // parse attr array as data for a single family
		if err != nil {
			log.Println("Error parsing attributes as family")
			continue
		}
		family = &curFamily


	}
	return
}

type Client struct {
	nlclient *nl.Client
}
