/***************************************************************************
                         servicelistingurl.h  -  description
                             -------------------
    copyright            : 2009 Friedrich W. H. Kossebau
    email                : kossebau@kde.org
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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                                      *
 *                                                                         *
 ***************************************************************************/

#ifndef SERVICEURL_H
#define SERVICEURL_H

// ioslave
#include "kio_slp.h"
// KDE
#include <KUrl>
// Qt
#include <QtCore/QRegExp>

#include <KDebug>

// URL service:/[<service-type>]/<addrspec>
// examples:
// service:/
class ServiceListingUrl
{
  public:
    enum Type { InvalidUrl, RootDir, NativeRootDir, ServiceDir, Service };

  public:
    static QRegExp* matcher;

  public:
    static const char* protocolName( ProtocolType protocol );
//     static QString root( ProtocolType protocol );
    static QString rawServiceKioUrlFrom( const char* serviceUrl );
    static QString createServiceTypeFrom( const QString& serviceType );
    static bool splitSlpServiceUrl( QString* serviceType, QString* siteNParameter, const char* serviceUrl );
    static QString createKioPath( const QString& serviceType, const QString& hostNPath );
    static QString serviceUrlFromKioUrl( const KUrl& url );
    static bool kioUrlHasServiceProtocol( const KUrl& url );
    static QString toKdeProtocolName( const QString& serviceTypeName );
    static QString createKioUrl( ProtocolType protocol, const QString& serviceTypeName );
    static QString createKioUrl( const QString& protocolName, const QString& hostNPath );

  public:
    explicit ServiceListingUrl( const KUrl& url, bool ignoreProtocol = true );

  public:
    QString serviceType() const;
    QString fullServiceUrl() const;
    ServiceListingUrl::Type dataType( const QHash<QString,bool>& nativeServiceLister ) const;
    ProtocolType protocolType() const;
    QString hostNPath() const;

  private: // data
    QString mServiceType;
    QString mSite;
    ProtocolType mProtocolType;

  private: // static data
    static const char* const ProtocolName[];
};


inline QString ServiceListingUrl::serviceUrlFromKioUrl( const KUrl& url )
{
    QString result = "service:" + url.path().mid(1);
    const int index = result.indexOf( '/' );
    result.insert( index, QLatin1String(":/") );

    return result;
}

inline bool ServiceListingUrl::kioUrlHasServiceProtocol( const KUrl& url )
{
    return url.hasHost();
}


inline bool ServiceListingUrl::splitSlpServiceUrl( QString* serviceType, QString* siteNParameter, const char* serviceUrl )
{
    bool result;

    QString url( serviceUrl );
    if( url.startsWith("service:") )
        url.remove( 0, 8 );

    result = ( matcher->indexIn(url) >= 0 );
    // TODO: when can a service url not match?
    if ( result )
    {
        *serviceType = matcher->cap( 1 );
        *siteNParameter = matcher->cap( 2 );
    }

    return result;
}

inline QString ServiceListingUrl::createServiceTypeFrom( const QString& serviceType )
{
    QString result = serviceType.startsWith("service:") ?
        serviceType.mid( 8 ) :
        serviceType;

    return result;
}

inline QString ServiceListingUrl::createKioUrl( ProtocolType protocol, const QString& serviceTypeName )
{
    QString result = QString( ProtocolName[protocol] ) + "://";

    if( serviceTypeName.contains(":") )
        result += QString('[') + serviceTypeName + "]/";
    else
        result += serviceTypeName + '/';

    return result;
}

inline QString ServiceListingUrl::createKioUrl( const QString& protocolName, const QString& hostNPath )
{
    return protocolName + "://" + hostNPath;
}
inline QString ServiceListingUrl::createKioPath( const QString& serviceType, const QString& hostNPath )
{
    return QString('/') + serviceType + '/' + hostNPath;
}


inline ServiceListingUrl::ServiceListingUrl( const KUrl& url, bool ignoreProtocol )
{
    if( ignoreProtocol )
        mProtocolType = UnknownProtocol;
    else
    {
        const QString protocolName = url.protocol();
        int type = ServiceProtocol;
        for( ; type<UnknownProtocol; ++type )
            if( protocolName == ProtocolName[type] )
                break;
        mProtocolType = (ProtocolType)type;
        if( mProtocolType == UnknownProtocol )
            return;
    }

    mServiceType = url.host();
    if( mServiceType.startsWith('[') )
    {
        mServiceType.chop( 1 );
        mServiceType.remove( 0, 1 );
    }

    mSite = url.path();
}


inline QString ServiceListingUrl::serviceType() const { return mServiceType; }
inline QString ServiceListingUrl::hostNPath() const { return mSite; }

inline QString ServiceListingUrl::fullServiceUrl() const
{
    QString result = toKdeProtocolName( mServiceType ); // toKDE really needed?
    if ( ! result.isEmpty() )
    {
        QString site = mSite;
        while ( site.startsWith('/') ) // strip leading slashes TODO: really needed?
            site.remove( 0, 1 );

        if( site.isEmpty() )
            site = QString( ":///" );
        else
            site.prepend( "://" );

        result += site;
    }
    return result;
}
inline ProtocolType ServiceListingUrl::protocolType() const { return mProtocolType; }

inline const char* ServiceListingUrl::protocolName( ProtocolType protocol ) { return ProtocolName[protocol]; }
// inline QString ServiceListingUrl::root( ProtocolType protocol ) { return QString( protocolName(protocol) + ":/" ); }

// TODO: how is a invalid url defined?
inline ServiceListingUrl::Type ServiceListingUrl::dataType( const QHash<QString,bool>& nativeServiceLister ) const
{
    Type result =
        ( mServiceType.isEmpty() || mServiceType == "BROWSE" ) ? RootDir :
        ( mProtocolType == ServiceProtocol
          && nativeServiceLister.value(mServiceType, false) ) ?  NativeRootDir :
        ( mSite.isEmpty() || mSite == "/" ) ?                    ServiceDir :
        /*else*/                                                 Service;

    return result;
}


#endif
