// Author: Max Howell (C) Copyright 2003-4
// Author: Mark Kretschmann (C) Copyright 2004
// Copyright: See COPYING file that comes with this distribution
//

#ifndef UrlLoader_H
#define UrlLoader_H

#include "amarok.h"
#include "debug.h"        //stack allocated
#include <tqptrlist.h>
#include <tqxml.h>         //baseclass
#include <kurl.h>         //KURL::List
#include "metabundle.h"   //stack allocated
#include "threadmanager.h" //baseclass
#include "xmlloader.h"    //baseclass

class TQListViewItem;
class TQTextStream;
class PlaylistItem;
class PLItemList;
class XMLData;

namespace TDEIO { class Job; }


/**
 * @class PlaylistFile
 * @author Max Howell
 * @short Allocate on the stack, the contents are immediately available from bundles()
 *
 * Note, it won't do anything with XML playlists
 *
 * TODO be able to load directories too, it's in the spec
 * TODO and playlists within playlists, remote and local
 */
class PlaylistFile
{
public:
    PlaylistFile( const TQString &path );

    enum Format { M3U, PLS, XML, RAM, SMIL, ASX, XSPF, Unknown, NotPlaylist = Unknown };

    /// the bundles from this playlist, they only contain
    /// the information that can be extracted from the playlists
    BundleList &bundles() { return m_bundles; }

    /// the name of the playlist. often stored in the document (eg xspf) or derived from the filename
    TQString &title() { return m_title; }

    ///@return true if couldn't load the playlist's contents
    bool isError() const { return !m_error.isEmpty(); }

    /// if start returns false this has a translated error description
    TQString error() const { return m_error; }


    static inline bool isPlaylistFile( const KURL &url ) { return isPlaylistFile( url.fileName() ); }
    static inline bool isPlaylistFile( const TQString &fileName ) { return format( fileName ) != Unknown; }
    static inline Format format( const TQString &fileName );
    static TQTime stringToTime(const TQString&);

protected:
    /// make these virtual if you need to
    bool loadM3u( TQTextStream& );
    bool loadPls( TQTextStream& );
    unsigned int loadPls_extractIndex( const TQString &str ) const;
    bool loadRealAudioRam( TQTextStream& );
    bool loadASX( TQTextStream& );
    bool loadSMIL( TQTextStream& );
    bool loadXSPF( TQTextStream& );
    TQString m_path;
    TQString m_error;
    BundleList m_bundles;
    TQString m_title;
};

inline PlaylistFile::Format
PlaylistFile::format( const TQString &fileName )
{
    const TQString ext = Amarok::extension( fileName );

    if( ext == "m3u" ) return M3U;
    if( ext == "pls" ) return PLS;
    if( ext == "ram" ) return RAM;
    if( ext == "smil") return SMIL;
    if( ext == "asx" || ext == "wax" ) return ASX;
    if( ext == "xml" ) return XML;
    if( ext == "xspf" ) return XSPF;

    return Unknown;
}

/**
 * @author Max Howell
 * @author Mark Kretschmann
 * @short Populates the Playlist-view with URLs
 *
 * + Load playlists, remote and local
 * + List directories, remote and local
 * + Read tags, from file:/// and from DB
 */
#ifdef Q_MOC_RUN
// MOC_SKIP_BEGIN
class UrlLoader : public JobBase
// MOC_SKIP_END
#else // Q_MOC_RUN
class UrlLoader : public ThreadManager::DependentJob
#endif // Q_MOC_RUN
{
  TQ_OBJECT
  

public:
    UrlLoader( const KURL::List&, TQListViewItem*, int options = 0 );
   ~UrlLoader();

    static const uint OPTIMUM_BUNDLE_COUNT = 200;

signals:
    void queueChanged( const PLItemList &, const PLItemList & );

protected:
    /// reimplemented from ThreadManager::Job
    virtual bool doJob();
    virtual void completeJob();
    virtual void customEvent( TQCustomEvent* );

    void loadXml( const KURL& );

private slots:
    void slotNewBundle( const MetaBundle& bundle, const XmlAttributeList& attributes );
    void slotPlaylistInfo( const TQString &product, const TQString &version, const TQString &dynamicMode );

private:
    KURL::List recurse( const KURL& );

private:
    KURL::List    m_badURLs;
    KURL::List    m_URLs;
    PlaylistItem *m_markerListViewItem;
    bool          m_playFirstUrl;
    bool          m_coloring;
    int           m_options;
    Debug::Block  m_block;
    TQPtrList<PlaylistItem> m_oldQueue;
    TQXmlInputSource  *m_xmlSource;
    TQValueList<XMLData> m_xml;
    KURL m_currentURL;
    TQString m_dynamicMode;

protected:
    UrlLoader( const UrlLoader& ); //undefined
    UrlLoader &operator=( const UrlLoader& ); //undefined
};



/**
 * @author Max Howell
 * @short Populates the Playlist-view using the result of a single SQL query
 *
 * The format of the query must be in a set order, see doJob()
 */
class SqlLoader : public UrlLoader
{
    const TQString m_sql;

public:
    SqlLoader( const TQString &sql, TQListViewItem *after, int options = 0 );

    virtual bool doJob();
};



/**
 * @author Max Howell
 * @short Fetches a playlist-file from any location, and then loads it into the Playlist-view
 */
class RemotePlaylistFetcher : public TQObject
{
    TQ_OBJECT
  

    const KURL m_source;
    KURL m_destination;
    TQListViewItem *m_after;
    bool m_playFirstUrl;
    int m_options;
    class KTempFile *m_temp;

public:
    RemotePlaylistFetcher( const KURL &source, TQListViewItem *after, int options = 0 );
   ~RemotePlaylistFetcher();

private slots:
    void result( TDEIO::Job* );
    void abort() { delete this; }
};

// PRIVATE -- should be in the .cpp, but moc.

class MyXmlLoader: public MetaBundle::XmlLoader
{
    TQ_OBJECT
  
public:
    MyXmlLoader() { }
    virtual bool startElement( const TQString&, const TQString&, const TQString &, const TQXmlAttributes& );
signals:
    void playlistInfo( const TQString &product, const TQString &version, const TQString &dynamicMode );
};


#endif
