/***************************************************************************
                          cdarchive.cpp  -  description
                             -------------------
    begin                : th Jul 27 2004
    copyright            : (C) 2004 by Richard Groult
    email                : rgroult@jalix.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; 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307   *
 *   USA.                                                                  *
 *                                                                         *
 *   For license exceptions see LICENSE.EXC file, attached with the source *
 *   code.                                                                 *
 *                                                                         *
 ***************************************************************************/

#include "cdarchive.h"

// Local 
#include "imagefileiconitem.h"
#include "directoryview.h"
#include "mainwindow.h"
#include "imageviewer.h"
#include "album.h"

// KDE 
#include <kmimetype.h>
#include <kiconloader.h>
#include <klocale.h>
#include <ktar.h>
#include <kdebug.h>
#include <kstandarddirs.h>
#ifndef Q_WS_WIN
#include <konq_operations.h>
#endif
#include <kprocess.h>
#include <kurl.h>
#include <kapplication.h>

// Qt 
#include <qdir.h>


#define MYDEBUG kdDebug()<<__FILE__<<" " <<__LINE__ << " " << __FUNCTION__ << " "

class CDArchiveItem;
class CDArchiveImageFileIconItem : public ImageFileIconItem
{
public:
	CDArchiveImageFileIconItem(CDArchiveItem *parent, ImageListView *imageList,
	 		QString fullname, ImageViewer *iv);

	CDArchiveItem *parentDir;
};


/////////////////
class CDArchiveItem : public ListItem
{
public:
        CDArchiveItem(CDArchive* parent, QString filename, const KArchiveDirectory *dir,
			DirectoryView* dirView, ImageViewer *iv, 
			ImageListView  *imageList, MainWindow *mw );

        CDArchiveItem(CDArchiveItem *parent, QString filename, const KArchiveDirectory *dir,
			DirectoryView* dirView, ImageViewer *iv,  
			 ImageListView *imageList, MainWindow *mw );


        virtual ~CDArchiveItem();

private:
        void init();
        QString getRelativePath();
        void load(bool);
        void unLoad();
        ListItem* find (QString path);
        const KArchiveDirectory* getKArchiveDirectory();

	const KArchiveDirectory* dir;
	//const KArchiveDirectory* parentDir;

	bool loaded;
	QString relativePath;
	
	QPtrList < CDArchiveImageFileIconItem > list;
};


CDArchiveItem::CDArchiveItem(CDArchive* parent, QString filename, const KArchiveDirectory *dir,
			DirectoryView* dirView, ImageViewer *iv, 
			ImageListView  *imageList, MainWindow *mw )
: ListItem(parent, filename, dirView, iv, imageList, mw)
{
	this->dir = dir;
	relativePath = parent->getRelativePath()+"/"+filename;
	init();
}



CDArchiveItem::CDArchiveItem( CDArchiveItem *parent, QString filename, const KArchiveDirectory *dir,
			DirectoryView* dirView, ImageViewer *iv,  
			 ImageListView *imageList, MainWindow *mw )
: ListItem(parent, filename, dirView, iv, imageList, mw)
{
	this->dir = dir;
	relativePath = parent->getRelativePath()+"/"+filename;
	init();
}

CDArchiveItem::~CDArchiveItem()
{
	//if(isSelected())
	//	unLoad();
}

void
CDArchiveItem::init()
{
	setPixmap(0, BarIcon("folder", dirView->getIconSize() ));
	setDropEnabled(false);
	size="";
	extension = i18n("CD Archive folder");
	setType("CD Archive folder");
	loaded=false;
	//full = "/" + i18n("CD Archive Root") + "/" + relativePath;
	full = locateLocal("tmp", "showimg-arc/"+getRelativePath())+"/";
}

	
void
CDArchiveItem::load(bool)
{
	imageList->stopLoading();
	KApplication::setOverrideCursor( waitCursor ); // this might take time
	mw->setMessage(i18n("Loading %1...").arg(text(0)));
	if(!imageList->hasImages()) { iv->loadImage(); imageList->setContentsPos(0,0); }
	imageList->setUpdatesEnabled( FALSE ); 

	QStringList const & entries(dir->entries());
	QStringList::const_iterator it = entries.begin();
	CDArchiveImageFileIconItem *item;

	if(!loaded)
	{
		QString dest = locateLocal("tmp", "showimg-arc/"+getRelativePath());
		dir->copyTo( dest, false );
	}
	
	for(; it != entries.end(); ++it) 
	{
		const KArchiveEntry * child = dir->entry(*it);
		if( !loaded && child->isDirectory() )
		{ 
			const KArchiveDirectory * childdir;
			childdir = dynamic_cast<const KArchiveDirectory *>(child);
			(void)new CDArchiveItem(this, *it, childdir,
				dirView, iv, 
				imageList, mw );
		}
		else
		if(dirView->isImage(new QFileInfo(*it)))
		{
			item = new CDArchiveImageFileIconItem (
						this,
						imageList,
						locateLocal("tmp", "showimg-arc/")+getRelativePath()+"/"+*it,
						iv);
			list.append(item);
		}
		else
		if( !loaded && QFileInfo(*it).extension().lower()=="sia")
		{
			(void)new Album (
					this, *it,
					dirView, iv,
					imageList, mw);
		}
	}
	imageList->sort();

	mw->slotAddImage(list.count());
	size=QString("%1").arg(list.count());
	loaded=true;
	imageList->setUpdatesEnabled( TRUE ); 
	mw->setMessage(i18n("Ready"));
	imageList->slotLoadFirst();
	KApplication::restoreOverrideCursor();	// restore original cursor
}

void
CDArchiveItem::unLoad ()
{
	if(mw->preview())
		imageList->stopLoading();	
	mw->slotRemoveImage(list.count());
	imageList->setUpdatesEnabled( FALSE ); 
	
	for (CDArchiveImageFileIconItem *item = list.first(); item; item = list.next() )
		imageList->takeItem(item);
	list.clear();

	iv->updateStatus();
	imageList->setUpdatesEnabled( TRUE ); 
	imageList->slotUpdate();
	if(mw->preview())
		imageList->slotLoadFirst();
}

ListItem*
CDArchiveItem::find (QString path)
{
	QStringList list = QStringList::split( "/", path);
	QString dirName = list[0];
	list.pop_front();
	ListItem *rootItems = firstChild ();
	while(rootItems)
	{
		if(rootItems->text(0) == dirName)
			if(list.isEmpty()) 
				return rootItems;
			else 
				return rootItems->find(list.join("/"));
		rootItems = rootItems->nextSibling();
	}
	return NULL;
}

const KArchiveDirectory* 
CDArchiveItem::getKArchiveDirectory()
{
	return dir;
};

QString
CDArchiveItem::getRelativePath()
{
	return 	relativePath;
}



/////////////////////////////////////////////////////

CDArchive::CDArchive( DirectoryView* parent,
			 ImageViewer *iv,  
			 ImageListView *imageList, 
			 MainWindow *mw )
	: ListItem(parent, iv, imageList, mw)
{
	full = CDArchive_ROOTPATH;
	f.setName (i18n("CD Archive Root"));
	isRoot=true;
	init();
	setReadOnly(true);
}

CDArchive::CDArchive(CDArchive* parent, const QString& filename,
			DirectoryView* dirView, ImageViewer *iv,
			ImageListView  *imageList, MainWindow *mw )
	: ListItem(parent, filename, dirView, iv, imageList, mw)
{
	full=this->parent()->fullName()+f.name();
	relativePath = f.name();
	isRoot=false;
	init();
	setReadOnly(false);
}


CDArchive::~CDArchive()
{
}


void
CDArchive::init()
{
	setPixmap(0, BarIcon("cdimage", dirView->getIconSize() ));
	setDropEnabled(false);
	size="";
	extension = i18n("CD Archive");
	setType("CD Archive");
	loaded=false;
}

void 
CDArchive::rename(const QString& newDirName)
{
	if(newDirName.isEmpty()) return;
	
	QString oldN=fullName();
	QString newN=this->parent()->fullName()+"/"+newDirName;

	KURL orgName = KURL("file:"+oldN);
	KURL newName = KURL("file:"+newN);

	f.setName(newDirName);
	updateChildren();
	
	KIO::SimpleJob *renameJob=KIO::rename(orgName, newName, true );
	QObject::connect(renameJob, SIGNAL(result( KIO::Job *)),
		dirView, SLOT(renameDone( KIO::Job *)));

}

ListItem* 
CDArchive::find (QString path)
{
	if(isRoot)
	{
		if(! (   path.startsWith(CDArchive_ROOTPATH) 
		      || path.startsWith(CDArchive_TEMP_ROOTPATH())))
			return NULL;

		if(   QFileInfo(path).isDir() 
		   && QDir(path) == QDir(CDArchive_ROOTPATH))
				return this;
			
		if(path.startsWith(CDArchive_ROOTPATH))
		{
			path = QFileInfo(path).fileName();
		}
		else /* path.startsWith(CDArchive_TEMP_ROOTPATH())) */
		{
			path = path.right(path.length()-CDArchive_TEMP_ROOTPATH().length());
		}
		
		
	}
	QStringList list = QStringList::split( "/", path);
	QString dirName = list[0];
	list.pop_front();
	ListItem *rootItems = firstChild ();
	while(rootItems)
	{
		if(rootItems->text(0) == dirName)
			if(list.isEmpty()) 
				return rootItems;
			else 
				return rootItems->find(list.join("/"));
		rootItems = rootItems->nextSibling();
	}
	return NULL;
}

void
CDArchive::load(bool)
{
	if(loaded) return;
	KApplication::setOverrideCursor( waitCursor ); // this might take time
	if(isRoot)
	{
			mw->setMessage(i18n("Loading CD archives..."));
	
			QDir thisDir( CDArchive_ROOTPATH );
			thisDir.setNameFilter(QString("*.")+CDArchive_EXTENSION);
			const QFileInfoList * files = thisDir.entryInfoList();
			int nbr=0;
			if ( files )
			{
				QFileInfoListIterator it( *files );
				QFileInfo * f;
				while( (f=it.current()) != 0 )
				{
					++it;
					(void)new CDArchive(this, f->fileName(),
								dirView, iv,	
								imageList, mw);
					nbr++;
				}
			}
			size=QString("%1").arg(nbr);
	}
	else
	{
		arc = new KTar( fullName() );
		if(!arc) {KApplication::restoreOverrideCursor(); return;}
		if (!arc->open( IO_ReadOnly )) {KApplication::restoreOverrideCursor(); return;}
		const KArchiveDirectory *dir = arc->directory();
		QStringList const & entries(dir->entries());
		QStringList::const_iterator it = entries.begin();
		for(; it != entries.end(); ++it)
		{
			mw->setMessage(i18n("Loading CD archive %1...").arg(text(0)));
			const KArchiveEntry * child = dir->entry(*it);
			if( child->isDirectory() )
			{
				const KArchiveDirectory * childdir;
				childdir = dynamic_cast<const KArchiveDirectory *>(child);
				(void)new CDArchiveItem(this, *it, childdir,
					dirView, iv,
					imageList, mw );
			}
		}
	}
	KApplication::restoreOverrideCursor();	// restore original cursor
	loaded=true;
	mw->setMessage(i18n("Ready"));
}

void
CDArchive::unLoad()
{
}

bool
CDArchive::refresh(bool)
{
	bool modified = false;
	
	//remove CDArchive
	ListItem *rootItems = firstChild ();
	while(rootItems)
	{
		ListItem *ssrep = rootItems;
		rootItems = rootItems->nextSibling();
		
		QFileInfo *f = new QFileInfo(ssrep->fullName());
		if(!f->exists())
		{
			delete(ssrep);
			modified = true;
		}
	}
	//add CDArchive
	QDir thisDir( CDArchive_ROOTPATH );
	thisDir.setNameFilter(QString("*.")+CDArchive_EXTENSION);
	const QFileInfoList * files = thisDir.entryInfoList();
	if ( files )
	{
		QFileInfoListIterator it( *files );
		QFileInfo * f;
		while( (f=it.current()) != 0 )
		{
			++it;
			if(!find(f-> absFilePath()))
			{
				(void)new CDArchive(this, f->fileName(),
						dirView, iv,	
						imageList, mw);
				modified = true;
			}
		}
	}
	return modified;
}

const KArchiveDirectory* 
CDArchive::getKArchiveDirectory() const 
{
	return arc->directory();
};

KArchive* 
CDArchive::getKArchive() const 
{
	return arc;
};

QString
CDArchive::getRelativePath()
{
	return f.name();
}

QString
CDArchive::CDArchive_TEMP_ROOTPATH()
{
	return locateLocal("tmp", "showimg-arc/");
}

////////////////////////////
/////////////////////////
CDArchiveImageFileIconItem::CDArchiveImageFileIconItem( CDArchiveItem *parent, ImageListView *imageList,
	 		QString fullname, ImageViewer *iv)
	:ImageFileIconItem(imageList,
		parent,
		QFileInfo(fullname).fileName(), 
		QFileInfo(fullname).dirPath(true)+'/',
		iv,
		"",
		false)
{
	setType("CDArchiveImageFileIconItem");
	__ismovable__ = false;
	parentDir = parent;
	setKey(imageList->getCurrentKey());
}

