package irc

import (
	"bufio"
	"fmt"
	"io"
	"strings"
)

// Conn represents a simple IRC client.
type Conn struct {
	// DebugCallback is a callback for every line of input and
	// output. It is meant for debugging and is not guaranteed to
	// be stable.
	DebugCallback func(line string)

	// Internal things
	conn io.ReadWriteCloser
	in   *bufio.Reader
}

// NewConn creates a new Conn
func NewConn(rwc io.ReadWriteCloser) *Conn {
	// Create the client
	c := &Conn{
		func(line string) {},
		rwc,
		bufio.NewReader(rwc),
	}

	return c
}

// Write is a simple function which will write the given line to the
// underlying connection.
func (c *Conn) Write(line string) {
	c.DebugCallback("--> " + line)
	c.conn.Write([]byte(line))
	c.conn.Write([]byte("\r\n"))
}

// Writef is a wrapper around the connection's Write method and
// fmt.Sprintf. Simply use it to send a message as you would normally
// use fmt.Printf.
func (c *Conn) Writef(format string, args ...interface{}) {
	c.Write(fmt.Sprintf(format, args...))
}

// WriteMessage writes the given message to the stream
func (c *Conn) WriteMessage(m *Message) {
	c.Write(m.String())
}

// ReadMessage returns the next message from the stream or an error.
func (c *Conn) ReadMessage() (*Message, error) {
	line, err := c.in.ReadString('\n')
	if err != nil {
		return nil, err
	}

	c.DebugCallback("<-- " + strings.TrimRight(line, "\r\n"))

	// Parse the message from our line
	m := ParseMessage(line)

	// Now that we have the message parsed, do some preprocessing on it
	lastArg := m.Trailing()

	// Clean up CTCP stuff so everyone
	// doesn't have to parse it manually
	if m.Command == "PRIVMSG" && len(lastArg) > 0 && lastArg[0] == '\x01' {
		m.Command = "CTCP"

		if i := strings.LastIndex(lastArg, "\x01"); i > -1 {
			m.Params[len(m.Params)-1] = lastArg[1:i]
		}
	}

	return m, nil
}
