/*
NAME
  parseurl.go

DESCRIPTION
  See Readme.md

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

LICENSE
  parseurl.go is Copyright (C) 2017-2019 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.

  Derived from librtmp under the GNU Lesser General Public License 2.1
  Copyright (C) 2005-2008 Team XBMC http://www.xbmc.org
  Copyright (C) 2008-2009 Andrej Stepanchuk
  Copyright (C) 2009-2010 Howard Chu
*/
package rtmp

import (
	"net/url"
	"path"
	"strconv"
	"strings"
)

// parseURL parses an RTMP URL (ok, technically it is lexing).
func parseURL(addr string) (protocol int32, host string, port uint16, app, playpath string, err error) {
	u, err := url.Parse(addr)
	if err != nil {
		return protocol, host, port, app, playpath, err
	}

	switch u.Scheme {
	case "rtmp":
		protocol = protoRTMP
	case "rtmpt":
		protocol = protoRTMPT
	case "rtmps":
		protocol = protoRTMPS
	case "rtmpe":
		protocol = protoRTMPE
	case "rtmfp":
		protocol = protoRTMFP
	case "rtmpte":
		protocol = protoRTMPTE
	case "rtmpts":
		protocol = protoRTMPTS
	default:
		return protocol, host, port, app, playpath, errUnknownScheme
	}

	host = u.Host
	if p := u.Port(); p != "" {
		pi, err := strconv.Atoi(p)
		if err != nil {
			return protocol, host, port, app, playpath, err
		}
		port = uint16(pi)
	}

	if len(u.Path) < 1 || !path.IsAbs(u.Path) {
		return protocol, host, port, app, playpath, errInvalidURL
	}
	elems := strings.SplitN(u.Path[1:], "/", 3)
	if len(elems) < 2 || elems[0] == "" || elems[1] == "" {
		return protocol, host, port, app, playpath, errInvalidURL
	}
	app = elems[0]
	playpath = path.Join(elems[1:]...)

	switch ext := path.Ext(playpath); ext {
	case ".f4v", ".mp4":
		playpath = playpath[:len(playpath)-len(ext)]
		if !strings.HasPrefix(playpath, "mp4:") {
			playpath = "mp4:" + playpath
		}
	case ".mp3":
		playpath = playpath[:len(playpath)-len(ext)]
		if !strings.HasPrefix(playpath, "mp3:") {
			playpath = "mp3:" + playpath
		}
	case ".flv":
		playpath = playpath[:len(playpath)-len(ext)]
	}
	if u.RawQuery != "" {
		playpath += "?" + u.RawQuery
	}

	switch {
	case port != 0:
	case (protocol & featureSSL) != 0:
		return protocol, host, port, app, playpath, errUnimplemented // port = 433
	case (protocol & featureHTTP) != 0:
		port = 80
	default:
		port = 1935
	}

	return protocol, host, port, app, playpath, nil
}