/*
 * kbiffurl.cpp
 * Copyright (C) 1999 Kurt Granroth <granroth@kde.org>
 * Copyright (C) 1999 Bjorn Hansson <Bjorn.Hansson@signal.uu.se>
 *
 * This file contains the implementation of KBiffURL and
 *
 * $Id: kbiffurl.cpp,v 1.6 1999/12/25 02:12:05 granroth Exp $
 */
#include "kbiffurl.h"

KBiffURL::KBiffURL()
	: KURL()
{
}

KBiffURL::KBiffURL(const QString& _url)
{
    *this = KBiffURL(_url.data());
}

KBiffURL::KBiffURL(const char* _url)
    : KURL(_url)
{
	/**
	 * There exists no search part in the nntp spec; let's go around that
	 */
	if (protocol() == "nntp")
	{
		QString urlStr(_url);
		urlStr.replace(0,4, "imap4");
		*this = KBiffURL(urlStr.data());
		setProtocol("nntp");
	}
}

void KBiffURL::encodeURLStrict(QString& _url)
{
	int old_length = _url.length();

	if (!old_length)
		return;

	// a worst case approximation
	char *new_url = new char[old_length * 3 + 1];
	int new_length = 0;

	for (int i = 0; i < old_length; i++)
	{
		static const char *safe = "$-._!*(),"; /* RFC 1738 */

		char t = _url.data()[i];

		if ( (( t >= 'A') && ( t <= 'Z')) ||
				(( t >= 'a') && ( t <= 'z')) ||
				(( t >= '0') && ( t <= '9')) ||
				(strchr(safe, t))
			)
		{
			new_url[new_length++] = _url.data()[i];
		}
		else
		{
			new_url[new_length++] = '%';

			unsigned char c = ((unsigned char)_url.data()[i]) / 16;
			c += (c > 9) ? ('A' - 10) : '0';
			new_url[new_length++] = c;

			c = ((unsigned char)_url.data()[ i ]) % 16;
			c += (c > 9) ? ('A' - 10) : '0';
			new_url[new_length++] = c;
		}
	}

	new_url[new_length]=0;
	_url = new_url;
	delete [] new_url;
}

/**
 * BNF description of the syntax (see RFC1738, HTTP syntax)
 * ; HTTP
 *
 * httpurl        = "http://" hostport [ "/" hpath [ "?" search ]]
 * hpath          = hsegment *[ "/" hsegment ]
 * hsegment       = *[ uchar | ";" | ":" | "@" | "&" | "=" ]
 * search         = *[ uchar | ";" | ":" | "@" | "&" | "=" ]
 */
QString KBiffURL::searchPar( const char *_parName ) const
{
	const char *_searchPart, *_searchPos, *_parVal;
	int n;

	// Set some initial values
	n = 0;
	_parVal = NULL;

	// Get the search part of the URL, i.e. the stuff after "?"
	_searchPart = query();

	// Try to find the given parameter in the search part string
	if ((n = findPos( _searchPart, _parName )) < 0)
	  	return QString::null;

	/*
	 * Now, we know that the parameter name is found
	 */

	// If no value is assigned, an empty string is returned
	if (_searchPart[n] != '=')
		return QString::null;

	// Set the beginning of the parameter value string
	_parVal = &(_searchPart[n+1]);

	// Find the end of the assigned parameter value
	_searchPos = strpbrk( _parVal, ";:@&=" );

	// Return the assigned parameter value
	if (_searchPos == NULL)
		return QString( _parVal );
	else
		return QString( _parVal ).left(_searchPos - _parVal + 1);
}

void KBiffURL::setSearchPar( const char *_parName, const char *_newParVal )
{
	QString _newSearchPart;
	const char *_searchPart, *_searchPos, *_parVal;
	int index, len;

	// Get the search part of the URL, i.e. the stuff after "?"
	_searchPart = query();

	// Try to find the given parameter in the search part string
	index = findPos( _searchPart, _parName );


	// If the parameter name is not found it is simply appended
	if (index < 0) 
	{
		if (strlen(_searchPart) > 0) 
		{
			_newSearchPart = _searchPart;
			_newSearchPart += "&";
		}
		_newSearchPart += _parName;
		_newSearchPart += "=";
		_newSearchPart += _newParVal;
	}
	else {
		_newSearchPart = _searchPart;

		// If no value is assigned, the new value is inserted
		if (_searchPart[index] != '=') 
		{
			_newSearchPart.insert( index, _newParVal );
			_newSearchPart.insert( index, '=' );
		}

		// Otherwise, the old value is replaced with the new one
		else {
		  	// Point to the first character of the assigned value
			index++;

			// Set the beginning of the parameter value string
			_parVal = &(_searchPart[index]);

			// Get the length of the old parameter value
			_searchPos = strpbrk( _parVal, ";:@&=" );

			if (_searchPos == NULL)
				len = strlen( _parVal );
			else
			  	len = _searchPos - _parVal;

			_newSearchPart.replace( index, len, _newParVal );
		}
	}

	setQuery( _newSearchPart );
}

int KBiffURL::findPos( const char *_searchPart, const char *_parName ) const
{
	const char *_searchPos;
	int n = -1;

	_searchPos = _searchPart;
	while (_searchPos != NULL) {
		_searchPos = strstr( _searchPos, _parName );

		// If not found, a NULL string is returned
		if (_searchPos == NULL)
			return -1;

		// Find the index of the next character
		n = _searchPos - _searchPart + strlen(_parName);

		// Stop searching if this is not a substring
		if ((_searchPos == _searchPart || _searchPos[-1] == '&') &&
		    (_searchPart[n] == '0' || strchr(";:@&=", _searchPart[n]) != NULL))
			return n;
		
		_searchPos = &(_searchPart[n+1]);
	}

	return -1;
}

