// (c) 2004 Mark Kretschmann <markey@web.de>
// (c) 2004 Christian Muehlhaeuser <chris@chris.de>
// (c) 2005 Gábor Lehel <illissius@gmail.com>
// (c) 2005 Christan Baumgart <christianbaumgart@web.de>
// See COPYING file for licensing information.

#ifndef AMAROK_COLLECTIONBROWSER_H
#define AMAROK_COLLECTIONBROWSER_H

#include <tqlabel.h>
#include <tqvaluelist.h>      //stack allocated
#include <tqvbox.h>           //baseclass

#include <tdelistview.h>       //baseclass
#include <tqstringlist.h>     //stack allocated
#include <kurl.h>            //stack allocated
#include <kdialogbase.h>     //baseclass
#include <kprogress.h>

#include "multitabbar.h"     //baseclass
#include "collectiondb.h"
#include "amarok_export.h"

class ClickLineEdit;
class CollectionDB;

class TQCString;
class TQDragObject;
class TQPixmap;
class TQPoint;
class TQStringList;

class TDEAction;
class KComboBox;
class TDEPopupMenu;
class TDERadioAction;
class KTabBar;
class TDEToolBar;
class TDEToggleAction;

class CollectionView;
class CollectionItem;
class DividerItem;
class OrganizeCollectionDialog;

namespace CollectionBrowserIds
{
    enum CatMenuId { IdAlbum = QueryBuilder::tabAlbum,
    IdArtist = QueryBuilder::tabArtist,
    IdComposer = QueryBuilder::tabComposer,
    IdGenre = QueryBuilder::tabGenre,
    IdYear = QueryBuilder::tabYear ,
    IdScan = 32, IdNone = 64,
    IdArtistAlbum = 128, IdGenreArtist = 256, IdGenreArtistAlbum = 512, IdVisYearAlbum = 1024, IdArtistVisYearAlbum = 2048,
    IdLabel = QueryBuilder::tabLabels //=8192
    };
}

class CollectionBrowser: public TQVBox
{
    Q_OBJECT
  
    friend class CollectionView;

    public:
        CollectionBrowser( const char* name );
        virtual bool eventFilter( TQObject*, TQEvent* );
        TDEToolBar* getToolBar() const { return m_toolbar; }
        static CollectionBrowser *instance() { return s_instance; }

    public slots:
        void setupDirs();
        void toggleDivider();

    private slots:
        void slotClearFilter();
        void slotSetFilterTimeout();
        void slotSetFilter();
        void slotSetFilter( const TQString &filter );
        void slotEditFilter();

    private:
        void layoutToolbar();
        void ipodToolbar( bool activate );
        void appendSearchResults();

        //attributes:
        KTabBar* m_tabs; //tree-view, flat-view tabs
        class TDEToolBar    *m_toolbar;
        TDEAction           *m_configureAction;
        // For iPod-style browsing
        TDEAction           *m_ipodIncrement, *m_ipodDecrement;
        class TDEToolBar    *m_ipodToolbar;
        class TQHBox       *m_ipodHbox;

        TDEToggleAction     *m_showDividerAction;
        TDERadioAction      *m_treeViewAction;
        TDERadioAction      *m_flatViewAction;
        TDERadioAction      *m_ipodViewAction;
        class TDEActionMenu *m_tagfilterMenuButton;

        TDEPopupMenu* m_categoryMenu;
        TDEPopupMenu* m_cat1Menu;
        TDEPopupMenu* m_cat2Menu;
        TDEPopupMenu* m_cat3Menu;
        KLineEdit*  m_searchEdit;
        KComboBox* m_timeFilter;
        CollectionView* m_view;
        TQTimer*     m_timer;

        bool m_returnPressed;

        LIBAMAROK_EXPORT static CollectionBrowser *s_instance;

    // for CatMenuId
    friend class CollectionItem;
    friend class DividerItem;
};

class DividerItem : public TDEListViewItem
{
public:
    static TQString createGroup(const TQString& src, int cat);
    static bool shareTheSameGroup(const TQString& a, const TQString& b, int cat);

public:
    DividerItem( TQListView* parent, TQString txt, int cat);

    virtual void paintCell ( TQPainter * p, const TQColorGroup & cg, int column, int width, int align );
    virtual void paintFocus ( TQPainter * p, const TQColorGroup & cg, const TQRect & r );

    virtual TQString text(int column) const;

    void setBlockText(bool block) { m_blockText = block; }

private:
    virtual int compare( TQListViewItem*, int, bool ) const;

private:
    bool m_blockText;
    TQString m_text;
    int m_cat;
};



class CollectionItem : public TDEListViewItem {
    public:
        CollectionItem( TQListView* parent, int cat = 0, bool unknown = false, bool sampler=false )
            : TDEListViewItem( parent )
            , m_cat( cat )
            , m_isUnknown( unknown )
            , m_isSampler( sampler ) {};
        CollectionItem( TQListViewItem* parent, int cat = 0, bool unknown = false, bool sampler=false )
            : TDEListViewItem( parent )
            , m_cat( cat )
            , m_isUnknown( unknown )
            , m_isSampler( sampler ) {};
        void setUrl( const TQString& url ) { m_url.setPath( url ); }
        const KURL& url() const { return m_url; }

        virtual void sortChildItems ( int column, bool ascending ); //reimplemented

        inline TQString getSQLText( int column )
        {
            return ( !column && m_isUnknown ) ? "" : text( column );
        }

        inline bool isUnknown() {return m_isUnknown;}
        inline bool isSampler() {return m_isSampler;}

        virtual void setPixmap(int column, const TQPixmap & pix);

        /// convenience functions
        CollectionView *listView() const { return reinterpret_cast<CollectionView*>( TDEListViewItem::listView() ); }

    private:
        friend class CollectionView;
        virtual void paintCell ( TQPainter * painter, const TQColorGroup & cg, int column, int width, int align );

        //for sorting
        virtual int compare( TQListViewItem*, int, bool ) const; //reimplemented

    //attributes:
        KURL m_url;
        int m_cat;
        bool m_isUnknown;
        bool m_isSampler;
};


class CollectionView : public TDEListView, public DropProxyTarget
{
    Q_OBJECT
  
    friend class CollectionBrowser;

    public:
        enum ViewMode  { modeTreeView, modeFlatView, modeIpodView };

        friend class CollectionItem; // for access to m_cat2
        friend class ContextBrowser; // for setupDirs()

        CollectionView( CollectionBrowser* parent );
        ~CollectionView();

        LIBAMAROK_EXPORT static CollectionView* instance() { return m_instance; }

        void setFilter( const TQString &filter )     { m_filter = filter; }
        void setTimeFilter( const uint timeFilter ) { m_timeFilter = timeFilter; }
        TQString filter()                            { return m_filter; }
        uint    timeFilter()                        { return m_timeFilter; }
        CollectionItem* currentItem() { return static_cast<CollectionItem*>( TDEListView::currentItem() ); }

        int trackDepth() { return m_trackDepth; }
        int viewMode() const { return m_viewMode; }

        // Transform "The Who" -> "Who, The" or the other way
        LIBAMAROK_EXPORT static void manipulateThe( TQString &str, bool reverse );

        void setShowDivider(bool show);

        bool isOrganizingFiles() const;

        //Useful helper function to avoid duplicating code
        static inline void yearAlbumCalc( TQString &year, TQString &text );

    protected:
        // Reimplemented for iPod-style navigation, etc.
        virtual void keyPressEvent( TQKeyEvent *e );


    public slots:
        /** Rebuilds and displays the treeview by querying the database. */
        void renderView(bool force = false);

        void databaseChanged() { m_dirty = true; renderView(); };

        void setTreeMode() { setViewMode( modeTreeView ); };
        void setFlatMode() { setViewMode( modeFlatView ); };
        void setIpodMode() { setViewMode( modeIpodView ); };

        void presetMenu( int id );
        void cat1Menu( int id, bool rerender = true );
        void cat2Menu( int id, bool rerender = true );
        void cat3Menu( int id, bool rerender = true );
        void organizeFiles( const KURL::List &list, const TQString &caption, bool addToCollection=false ) LIBAMAROK_EXPORT;

    private slots:
        void setupDirs();

        void slotEnsureSelectedItemVisible();

        void renderFlatModeView(bool force = false);
        void renderTreeModeView(bool force = false);
        void renderIpodModeView(bool force = false);

        void scanStarted();
        void scanDone( bool changed = true );

        void slotExpand( TQListViewItem* );
        void slotCollapse( TQListViewItem* );
        void enableCat3Menu( bool );
        void invokeItem( TQListViewItem*, const TQPoint &, int column );
        void invokeItem( TQListViewItem* );

        // ipod-style navigation slots
        void ipodItemClicked( TQListViewItem*, const TQPoint&, int );
        void incrementDepth ( bool rerender = true );
        void decrementDepth ( bool rerender = true );

        void rmbPressed( TQListViewItem*, const TQPoint&, int );
        void selectAll() {TQListView::selectAll(true); }
        /** Tries to download the cover image from Amazon.com */
        void fetchCover();
        /** Shows dialog with information on selected track */
        void showTrackInfo();

        /**
        * Cancel Organizing files
        */
        void cancelOrganizingFiles();

        void ratingChanged( const TQString&, int );

    private:
        enum Tag { Title = 0, Artist, Composer, Album, Genre, Length, DiscNumber, Track, Year,
            Comment, Playcount, Score, Rating, Filename, Firstplay, Lastplay, Modified,
            Bitrate, Filesize, BPM, NUM_TAGS };

        void setViewMode( int mode, bool rerender = true );
        void removeDuplicatedHeaders();

        void startDrag();
        TQString getTrueItemText( int, TQListViewItem* ) const;
        TQStringList listSelectedSiblingsOf( int, TQListViewItem* );
        KURL::List listSelected();

        void playlistFromURLs( const KURL::List &urls );
        TQPixmap iconForCategory( const int cat ) const;
        TQString captionForCategory( const int cat ) const;
        inline TQString captionForTag( const Tag ) const;

        // For iPod-style navigation
        TQString allForCategory( const int cat, const int num ) const;
        void resetIpodDepth ( void );
        void buildIpodQuery ( QueryBuilder &qb, int depth, TQStringList filters[3], TQStringList filterYear, bool recursiveSort = false, bool compilationsOnly = false );
        void selectIpodItems ( void );
        TQPixmap ipodIncrementIcon ( void );
        TQPixmap ipodDecrementIcon ( void );

        void setCompilation( const KURL::List &urls, bool compilation );

        /** Rebuild selections, viewport and expanded items after reloads */
        void cacheView();
        void restoreView();

        //Used to store the name of an item (and its parents), so it can be recalled later
        //even if the pointer to the item has been invalidated.
        TQStringList makeStructuredNameList( TQListViewItem* ) const;
        TQListViewItem* findFromStructuredNameList( const TQStringList& ) const;

        // avoid duplicated code
        static inline bool endsInThe( const TQString & text );
        inline void updateTrackDepth();

        uint translateTimeFilter( uint filterMode );

        /**Call when a category has changed **/
        void updateColumnHeader();
        // Reimplemented from TDEListView
        void viewportPaintEvent( TQPaintEvent* );
        void viewportResizeEvent( TQResizeEvent* );
        bool eventFilter( TQObject*, TQEvent* );
        void contentsDragEnterEvent( TQDragEnterEvent* );
        void contentsDragMoveEvent( TQDragMoveEvent* );
        void contentsDropEvent( TQDropEvent *e );
        // Reimplemented from DropProxyTarget
        void dropProxyEvent( TQDropEvent *e );

        void safeClear();

    //attributes:
        LIBAMAROK_EXPORT static CollectionView* m_instance;

        CollectionBrowser* m_parent;

        TQString m_filter;
        uint m_timeFilter;
        int m_cat1;
        int m_cat2;
        int m_cat3;
        int m_trackDepth;
        int m_viewMode;

        // The iPod-style viewing attributes
        int         m_currentDepth;   // Current viewing depth
        TQStringList m_ipodFilters[3]; // Selections at each stage
        TQStringList m_ipodFilterYear; // See the comment for incrementDepth()
        // For auto-selection
        int         m_ipodIncremented; // 0 = nothing, 1 = just incremented, 2 = just decremented
        TQStringList m_ipodSelected[3]; // Saved selections at lower levels
        TQString     m_ipodCurrent[3];  // Saved current selections
        TQString     m_ipodTopItem[3];  // Saved viewport positions

        bool m_dirty; // we use this to avoid re-rendering the view when unnecessary (eg, browser is not visible)

        TQValueList<TQStringList> m_cacheOpenItemPaths;
        TQStringList             m_cacheViewportTopItem;
        TQStringList             m_cacheCurrentItem;
        KURL::List              m_organizeURLs;
        bool                    m_organizeCopyMode;

        bool                    m_organizingFileCancelled;

        bool m_showDivider;
        TQValueList<int>         m_flatColumnWidths;
};

// why is signal detailsClicked() missing from KDialogBase?
class OrganizeCollectionDialogBase : public KDialogBase
{
    Q_OBJECT
  
    public:
    OrganizeCollectionDialogBase( TQWidget *parent=0, const char *name=0, bool modal=true,
            const TQString &caption=TQString(),
            int buttonMask=Ok|Apply|Cancel )
        : KDialogBase( parent, name, modal, caption, buttonMask )
    {
    }

    signals:
        void detailsClicked();
    public slots:
        void slotDetails() { KDialogBase::slotDetails(); emit detailsClicked(); adjustSize(); }
};


#endif /* AMAROK_COLLECTIONBROWSER_H */
