/*
NAME
  rtmp.go

DESCRIPTION
  See Readme.md

AUTHOR
  Saxon Nelson-Milton <saxon@ausocean.org>
  Dan Kortschak <dan@ausocean.org>

LICENSE
  rtmp.go is Copyright (C) 2017 the Australian Ocean Lab (AusOcean)

  It is free software: you can redistribute it and/or modify them
  under the terms of the GNU General Public License as published by the
  Free Software Foundation, either version 3 of the License, or (at your
  option) any later version.

  It is distributed in the hope that it will be useful, but WITHOUT
  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
  for more details.

  You should have received a copy of the GNU General Public License
  along with revid in gpl.txt.  If not, see http://www.gnu.org/licenses.
*/

package rtmp

/*
#cgo CFLAGS: -I/usr/local/include/librtmp
#cgo LDFLAGS: -lrtmp -lz -Wl,-rpath=/usr/local/lib

#include <stdlib.h>
#include <rtmp.h>

RTMP* start_session(RTMP* rtmp, char* url, uint connect_timeout);
int write_frame(RTMP* rtmp, char* data, uint data_length);
int end_session(RTMP* rtmp);
*/
import "C"

import (
	"errors"
	"strconv"
	"unsafe"
)

// Session provides an interface for sending flv tags over rtmp.
type Session interface {
	Open() error
	Write([]byte) (int, error)
	Close() error
}

// session provides parameters required for an rtmp communication session.
type session struct {
	rtmp *C.RTMP

	url     string
	timeout uint
}

var _ Session = (*session)(nil)

// NewSession returns a new session.
func NewSession(url string, connectTimeout uint) Session {
	return &session{
		url:     url,
		timeout: connectTimeout,
	}
}

// Open establishes an rtmp connection with the url passed into the
// constructor
func (s *session) Open() error {
	if s.rtmp != nil {
		return errors.New("rtmp: attempt to start already running session")
	}
	var err error
	s.rtmp, err = C.start_session(s.rtmp, C.CString(s.url), C.uint(s.timeout))
	if s.rtmp == nil {
		return err
	}
	return nil
}

// Write writes a frame (flv tag) to the rtmp connection
func (s *session) Write(data []byte) (int, error) {
	if s.rtmp == nil {
		return 0, Err(3)
	}
	ret := C.write_frame(s.rtmp, (*C.char)(unsafe.Pointer(&data[0])), C.uint(len(data)))
	if ret != 0 {
		return 0, Err(ret)
	}
	return len(data), nil
}

// Close terminates the rtmp connection
func (s *session) Close() error {
	if s.rtmp == nil {
		return Err(3)
	}
	ret := C.end_session(s.rtmp)
	s.rtmp = nil
	if ret != 0 {
		return Err(ret)
	}
	return nil
}

var rtmpErrs = [...]string{
	1: "rtmp: not connected",
	2: "rtmp: write error",
	3: "rtmp: not started",
}

type Err uint

func (e Err) Error() string {
	if 0 <= int(e) && int(e) < len(rtmpErrs) {
		s := rtmpErrs[e]
		if s != "" {
			return s
		}
	}
	return "rtmp: " + strconv.Itoa(int(e))
}