/*
 * Copyright (C) 2009,2010  Barracuda Networks, Inc.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 * 02110-1301  USA
 *
 */

#ifndef ICE176_H
#define ICE176_H

#include <QObject>
#include <QString>
#include <QHostAddress>
#include "turnclient.h"

namespace QCA {
	class SecureArray;
}

namespace XMPP {

class UdpPortReserver;

class Ice176 : public QObject
{
	Q_OBJECT

public:
	enum Error
	{
		ErrorGeneric
	};

	enum Mode
	{
		Initiator,
		Responder
	};

	class LocalAddress
	{
	public:
		QHostAddress addr;
		int network; // -1 = unknown
		bool isVpn;

		LocalAddress() :
			network(-1),
			isVpn(false)
		{
		}
	};

	class ExternalAddress
	{
	public:
		LocalAddress base;
		QHostAddress addr;
		int portBase; // -1 = same as base

		ExternalAddress() :
			portBase(-1)
		{
		}
	};

	class Candidate
	{
	public:
		int component;
		QString foundation;
		int generation;
		QString id;
		QHostAddress ip;
		int network; // -1 = unknown
		int port;
		int priority;
		QString protocol;
		QHostAddress rel_addr;
		int rel_port;
		QHostAddress rem_addr;
		int rem_port;
		QString type;

		Candidate() :
			component(-1),
			generation(-1),
			network(-1),
			port(-1),
			priority(-1),
			rel_port(-1),
			rem_port(-1)
		{
		}
	};

	Ice176(QObject *parent = nullptr);
	~Ice176();

	void reset();

	void setProxy(const TurnClient::Proxy &proxy);

	// if set, ports will be drawn from the reserver if possible, before
	//   binding to random ports
	// note: ownership is not passed
	void setPortReserver(UdpPortReserver *portReserver);

	void setLocalAddresses(const QList<LocalAddress> &addrs);

	// one per local address.  you must set local addresses first.
	void setExternalAddresses(const QList<ExternalAddress> &addrs);

	void setStunBindService(const QHostAddress &addr, int port);
	void setStunRelayUdpService(const QHostAddress &addr, int port, const QString &user, const QCA::SecureArray &pass);
	void setStunRelayTcpService(const QHostAddress &addr, int port, const QString &user, const QCA::SecureArray &pass);

	// these all start out enabled, but can be disabled for diagnostic
	//   purposes
	void setUseLocal(bool enabled);
	void setUseStunBind(bool enabled);
	void setUseStunRelayUdp(bool enabled);
	void setUseStunRelayTcp(bool enabled);

	void setComponentCount(int count);
	void setLocalCandidateTrickle(bool enabled); // default false

	void start(Mode mode);
	void stop();

	QString localUfrag() const;
	QString localPassword() const;

	void setPeerUfrag(const QString &ufrag);
	void setPeerPassword(const QString &pass);

	void addRemoteCandidates(const QList<Candidate> &list);

	bool hasPendingDatagrams(int componentIndex) const;
	QByteArray readDatagram(int componentIndex);
	void writeDatagram(int componentIndex, const QByteArray &datagram);

	// this call will ensure that TURN headers are minimized on this
	//   component, with the drawback that packets might not be able to
	//   be set as non-fragmentable.  use this on components that expect
	//   to send lots of very small packets, where header overhead is the
	//   most costly but also where fragmentation is impossible anyway.
	//   in short, use this on audio, but not on video.
	void flagComponentAsLowOverhead(int componentIndex);

	// FIXME: this should probably be in netinterface.h or such
	static bool isIPv6LinkLocalAddress(const QHostAddress &addr);

signals:
	// indicates that the ice engine is started and is ready to receive
	//   peer creds and remote candidates
	void started();

	void stopped();
	void error(XMPP::Ice176::Error e);

	void localCandidatesReady(const QList<XMPP::Ice176::Candidate> &list);
	void componentReady(int index);

	void readyRead(int componentIndex);
	void datagramsWritten(int componentIndex, int count);

private:
	class Private;
	friend class Private;
	Private *d;
};

}

#endif
