/***************************************************************************
 *   Copyright (C) 2008 by Joris Guisson and Ivan Vasic                    *
 *   joris.guisson@gmail.com                                               *
 *   ivasic@gmail.com                                                      *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program 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 this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.          *
 ***************************************************************************/
#ifndef BTHTTPCONNECTION_H
#define BTHTTPCONNECTION_H

#include <QMutex>
#include <QTimer>
#include <QUrl>
#include <net/streamsocket.h>
#include <net/addressresolver.h>

class QUrl;

namespace bt
{

	/**
		@author Joris Guisson
		
		HTTP connection for webseeding. We do not use KIO here, because we want to be able to apply 
		the maximum upload and download rate to webseeds;
	*/
	class HttpConnection : public QObject, public net::SocketReader, public net::StreamSocketListener
	{
		Q_OBJECT
	public:
		HttpConnection();
		virtual ~HttpConnection();
		
		/// Get the last http response code 
		int responseCode() const {return response_code;}
		
		/// Is this connection redirected
		bool isRedirected() const {return redirected;}
		
		/// Get the redirected url
		QUrl redirectedUrl() const {return redirected_url;}
		
		/**
		 * Set the group ID's of the socket
		 * @param up Upload group id
		 * @param down Download group id
		 */
		void setGroupIDs(Uint32 up,Uint32 down);
		
		/**
		 * Connect to a webseed
		 * @param url Url of the webseeder
		 */
		void connectTo(const QUrl &url);
		
		/**
		 * Connect to a proxy.
		 * @param proxy The HTTP proxy to use (null means don't use any)
		 * @param proxy_port The port of the HTTP proxy
		 */
		void connectToProxy(const QString & proxy,Uint16 proxy_port);
		
		/// Check if the connection is OK
		bool ok() const;
		
		/// See if we are connected
		bool connected() const;
		
		/// Has the connection been closed
		bool closed() const;
		
		/// Ready to do another request
		bool ready() const;
		
		/**
		 * Do a HTTP GET request
		 * @param path The path of the file
		 * @param query The query string for the url
		 * @param start Offset into file
		 * @param len Length of data to download
		 */
		bool get(const QString & host,const QString & path,const QString & query,bt::Uint64 start,bt::Uint64 len);

		virtual void onDataReady(Uint8* buf,Uint32 size);
		virtual void connectFinished(bool succeeded);
		virtual void dataSent();
		
		/**
		 * Get some part of the 
		 * @param data Bytearray to copy the data into
		 * @return true if data was filled in
		 */
		bool getData(QByteArray & data);
		
		/// Get the current download rate
		int getDownloadRate() const;
		
		/// Get the status string
		const QString getStatusString() const;
		
	private slots:
		void hostResolved(net::AddressResolver* ar);
		void connectTimeout();
		void replyTimeout();
		
	signals:
		void startReplyTimer(int timeout);
		void stopReplyTimer();
		void stopConnectTimer();
		
	private:
		enum State
		{
			IDLE,RESOLVING,CONNECTING,ACTIVE,ERROR,CLOSED
		};
		
		struct HttpGet
		{
			QString host;
			QString path;
			QString query;
			bt::Uint64 start;
			bt::Uint64 len;
			bt::Uint64 data_received;
			QByteArray buffer;
			QByteArray piece_data;
			bool response_header_received;
			bool request_sent;
			QString failure_reason;
			bool redirected;
			QUrl redirected_to;
			bt::Uint64 content_length;
			int response_code;
			
			HttpGet(const QString & host,const QString & path,const QString & query,bt::Uint64 start,bt::Uint64 len,bool using_proxy);
			virtual ~HttpGet();
			
			bool onDataReady(Uint8* buf,Uint32 size);
			bool finished() const {return data_received >= len;}
		};
		
		net::StreamSocket* sock;
		State state;
		mutable QMutex mutex;
		HttpGet* request;
		bool using_proxy;
		QString status;
		QTimer connect_timer;
		QTimer reply_timer;
		Uint32 up_gid,down_gid;
		bool close_when_finished;
		bool redirected;
		QUrl redirected_url;
		int response_code;
	};
}

#endif
