/***************************************************************************
                          directory.cpp  -  description
                             -------------------
    begin                : Sat Dec 1 2001
    copyright            : (C) 2001 by Richard Groult, 2003 OGINO Tomonori
    email                : rgroult@jalix.org ogino@nn.iij4u.or.jp
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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 "directory.h"

// Local 
#include "directoryview.h"
#include "imageviewer.h"
#include "imagefileiconitem.h"
#include "dirfileiconitem.h"
#include "compressedimagefileiconitem.h"
#include "compressedfileitem.h"
#include "fileiconitem.h"
#include "imagelistview.h"
#include "mainwindow.h"
#include "directoryview.h"
#include "album.h"
#include "extract.h"

#include <unistd.h>

// Qt 
#include <qlistview.h>
#include <qstring.h>
#include <qdir.h>
#include <qfile.h>
#include <qfileinfo.h>
#include <qpixmapcache.h>

// KDE 
#include <kio/job.h>
#include <kiconloader.h>
#include <klineeditdlg.h>
#include <klocale.h>
#include <kstandarddirs.h>
#include <kapplication.h>
#ifndef Q_WS_WIN
#include <konq_operations.h>
#endif

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

Directory::Directory( DirectoryView* parent,
			 ImageViewer *iv,  
			 ImageListView *imageList, 
			 MainWindow *mw )
	: ListItem(parent, iv, imageList, mw)
{
	full=( "/" );
	init();
}

Directory::Directory(Directory* 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()+"/";
	init();
}


Directory::~Directory()
{
}


void
Directory::init()
{
	readable = TRUE;
	setPixmap(0, BarIcon(KMimeType::iconForURL(getURL()), dirView->getIconSize() ));
	setDropEnabled(true);
	size=-1;
	setType("Directory");
	setReadOnly(FALSE);
	loaded=false;
}


ListItem*
Directory::find(const QString& dir_)
{
	QString dir(dir_);
	while(dir.startsWith("/")) dir = dir.right(dir.length()-1);
	QStringList list = QStringList::split( "/", dir);
	QString dirName = list[0];
	ListItem* dirt = firstChild();
	while(dirt)
	{
		if(dirName == dirt->text(0)) break;
		dirt = dirt->nextSibling ();
	}
	if(dirt) 
		if(list.count()==1) 
			return dirt;
		else
			return dirt->find(dir.right(dir.length()-dir.find("/")-1));
	return dirt;
}

void 
Directory::recursivelyOpen()
{
	setOpen(true);
	QListViewItem* dirt=firstChild();
	while(dirt != 0)
	{
		if(dirt->text(1)==i18n("Directory")) ((Directory*)dirt)->recursivelyOpen();
		dirt = dirt->nextSibling ();
	}
	kapp->processEvents();
}

void
Directory::setOpen( bool o )
{
	if ( !isOpen() && o && !childCount() && !loaded)
	{
		KApplication::setOverrideCursor( waitCursor ); // this might take time
		
		QString s( fullName() );
		QDir thisDir( s );
		if(dirView->showHiddenDir())
			thisDir.setFilter(QDir::All|QDir::Hidden);
		else
			thisDir.setFilter(QDir::All);
		 const QFileInfoList * files = thisDir.entryInfoList();
		 if ( files )
		 {
		 	QFileInfoListIterator it( *files );
		 	QFileInfo * f;

		 	while( (f=it.current()) != 0 )
		 	{
				++it;
		 		  if ( f->fileName() == "." || f->fileName() == ".." )
		 		      ; // nothing
		 		  else
		 		  {
		 		  	  if ( f->isDir() || (f->isSymLink() && QFileInfo(f->readLink()).isDir()) )
		 		  	    	  (void)new Directory( this, f->fileName(), dirView, iv, imageList, mw);
		 		  	  else
		 		  	  {
		 		  	   	   if ( Extract::canExtract(f->absFilePath()))
		 		  	   	   	(void)new CompressedFileItem(this, f->fileName(), fullName(),  mw, dirView, iv, imageList);
		 		  	   	   else if(QFileInfo(f->fileName()).extension().lower() == "sia")				   
		 		  	   	   	(void)new Album(this, f->fileName(), dirView, iv, imageList, mw);
		 		  	  }
		 		  }
		 	}
			dirView->sort();
		}
		if(!childCount()) setExpandable(false);
		KApplication::restoreOverrideCursor();      // restore original cursor

		dirView->startWatchDir(fullName());
		loaded=true;
	}
	else
	if(!o && childCount() )
	{
	}

	if ( o )
	{
		if(KMimeType::iconForURL(getURL())== "folder")
		{
			setPixmap(0, BarIcon("folder_open", dirView->getIconSize() ));
		}
	}
	else
	{
		setPixmap(0, BarIcon(KMimeType::iconForURL(getURL()), dirView->getIconSize() ));
	}

	QListViewItem::setOpen( o );
	repaint();
	listView()->setUpdatesEnabled( TRUE );
}


bool
Directory::refresh(bool )
{
	QString s( fullName() );
	QDir thisDir( s );
	bool isS=isSelected();
	thisDir.setFilter(dirView->filter() | QDir::Dirs);
	
	const QFileInfoList * files = thisDir.entryInfoList();	
	if (!files)
		return false;
	
	//////////////////
	QStringList after;
	QStringList news;
	QStringList deleted;

	QFileInfoListIterator it( *files );
	QFileInfo * f;
	QString ext;

	QString filename;
	FileIconItem *item;
	while( (f=it.current()) != 0 )
	{
		++it;
		if(
			(f->isDir() && f->fileName()!=".")
			||
			(f->isFile () &&
				(dirView->showAllFile() || 
				 dirView->isImage(f) || 
				 Extract::canExtract(f->absFilePath())))
		)
		{
			item=imageList->findItem(f->fileName());
			if(!item) news.append(f->fileName());
			after.append(f->fileName());
		}
	}

	QPoint tl(imageList->contentsX(), imageList->contentsY());

	bool add=false, del=false;
	for ( item=list.first();  item!= 0; item=list.next() )
	{
		if(!after.contains(item->text()))
		{
			deleted.append(item->text());
			del=true;
		}
	}
	ListItem* dirt=firstChild();
	while(dirt != 0)
	{
		if(!after.contains(dirt->text(0)))
		{
			deleted.append(dirt->text(0));
			del=true;
		}
		dirt = dirt->nextSibling ();
	}

	int nbrAddedFiles=0;
	///
	for ( QStringList::Iterator it = news.begin(); it != news.end(); ++it )
	{
		QFileInfo fi(fullName()+*it);
		if(isS &&
		  (dirView->isImage(&fi) ||
		  (dirView->showAllFile() &&
		  	(!fi.isDir() || Extract::canExtract(fi.absFilePath()))))
		)
		{
			item = new ImageFileIconItem(imageList, this, *it, fullName(), iv);
			list.append(item);
			nbrAddedFiles++;
			size++;
			add=true;
		}
		if(fi.fileName()!="." && !find(*it))
		{
			if(fi.isDir() && fi.fileName()!="..")
			{
				(void)new Directory(this, *it, dirView, iv, imageList, mw);
				setExpandable( TRUE );
			}
			if(isS && fi.isDir() && dirView->showDir() )
			{
				item = new DirFileIconItem(imageList, this, *it, fullName(), iv);
				list.append(item);
				nbrAddedFiles++;
				size++;
				add=true;
			}
			if (!fi.isDir() && Extract::canExtract(fi.absFilePath()))
			{
		 		(void)new CompressedFileItem(this, fi.fileName(), fullName(),  mw, dirView, iv, imageList);
				setExpandable( TRUE );
				setOpen(true);
			}
		}
	}
	int toDel=0;
	for ( QStringList::Iterator it = deleted.begin(); it != deleted.end(); ++it )
	{
		if(QFileInfo(fullName()+*it).exists())
			continue;
		dirView->removeDir(fullName()+*it);
		if(isS)
		{
			if( (item=imageList->findItem(*it)) != NULL)
			{
				list.remove(item);
				delete(item);
				toDel++;
			}
		}
	}
	if(!del && !add) return false;
  
	if(isOpen() && !childCount()) setExpandable( false );
	if(isS)
	{
		size -= toDel;
		mw->slotRemoveImage(toDel);
		mw->slotAddImage(nbrAddedFiles);

		imageList->sort();
		imageList->ensureVisible(tl.x(), tl.y());
	}
	repaint();
	return true;
}

void
Directory::goTo(const QString&)
{
	kdWarning()<<"Directory::goTo(const QString&) TODO"<<endl;
}

void
Directory::setup()
{
	setExpandable( TRUE );
	ListItem::setup();
}


QString
Directory::path()
{
	QDir dir=QFileInfo(fullName()).dir();
	if (dir.cdUp())
		return dir.absPath();
	else
		return QString();
}

QString
Directory::text( int column ) const
{
	if ( column == DirectoryView::COLUMN_NAME )
		return f.name();
	else
	if(column == DirectoryView::COLUMN_SIZE )
	{
		if(size>=0)
			return  QString("%1").arg(size);
		else
			return "";
	}
	else
	if(column == DirectoryView::COLUMN_TYPE)
	{
		if ( readable )
			return i18n("Directory");
		else
			return i18n("Locked");
	}
	return "";
}

void
Directory::loadFirst()
{
}


void
Directory::removeImage(ImageFileIconItem *imf)
{
	if(!imf)
		return;

	if(list.find(imf)!=-1)
	{
		delete(imf);
		mw->slotRemoveImage(1);
	}
}

void
Directory::unLoad()
{
	if(mw->preview()) imageList->stopLoading();
	mw->slotRemoveImage(size);
	imageList->setUpdatesEnabled( FALSE ); 
	for (FileIconItem *item = list.first(); item; item = list.next() )
		delete(item);
	list.clear();
	iv->updateStatus();
	imageList->setUpdatesEnabled( TRUE ); 
	imageList->slotUpdate();
}


void
Directory::load(bool )
{
	bool hasIm=imageList->hasImages();

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

	QString s( fullName() );
	QDir thisDir( s );
	thisDir.setFilter(dirView->filter());
	const QFileInfoList * files = thisDir.entryInfoList();
	
	if ( files )
	{
		QFileInfoListIterator it( *files );
		QFileInfo * f;
		QString ext;
		size=0;
		FileIconItem *item=NULL;

		while( (f=it.current()) != 0 )
		{
			++it;
			if(
				f->isFile () &&
					(dirView->showAllFile() ||
					(!dirView->showAllFile() && dirView->isImage(f))))
			{
				item = new ImageFileIconItem(imageList, this, f->fileName(), fullName(), iv);
				size+=(item->isImage()?1:0);
			}
			else
			if(f->isDir() && f->fileName()!=".")
			{
				item = new DirFileIconItem(imageList, this, f->fileName(), fullName(), iv);
			}

			if(item) list.append(item);
			item=NULL;
		}
		mw->slotAddImage(size);
		imageList->sort();
		repaint();		
		imageList->setUpdatesEnabled( TRUE );
		imageList->slotUpdate() ;				
		
		KApplication::restoreOverrideCursor();	// restore original cursor
		repaint();kapp->processEvents();		
		
		
		iv->updateStatus();
		if(!hasIm && dirView->loadFirstImage()) imageList->first();
		imageList->slotLoadFirst();
	}
	else
	{
		KApplication::restoreOverrideCursor();	// restore original cursor
	}
	mw->setMessage(i18n("Ready"));
}


void
Directory::createDir(const QString& dirName)
{
#ifndef Q_WS_WIN
	KURL url = KURL("file:"+fullName()+dirName);
	KonqOperations::mkdir(mw, url);
	setExpandable(true);
#endif
}

void
Directory::createAlbum(const QString& albumName)
{
	KURL urld = KURL("file:"+fullName()+albumName);
	KURL urlo = KURL("file:"+KStandardDirs().findResource("templates",".source/TextFile.txt"));
	KIO::copy(urlo, urld, false);
	setExpandable(true);
	mw->addToBookmark(i18n("Albums"),fullName()+albumName);
	if(isOpen())
		new Album(this, albumName, dirView, iv, imageList, mw);
}

void
Directory::rename()
{
	if(!newDirName.isEmpty())
	{	
		f.setName(newDirName);
		full=path()+"/"+newDirName+"/";
		repaint();
	}
}

void
Directory::rename(const QString& newDirName)
{
	this->newDirName=newDirName;

	QString oldN=fullName();
	QString newN=path()+"/"+newDirName;

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

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

	f.setName(newDirName);
	updateChildren();
}


void
Directory::properties()
{
}

void
Directory::updateChildren()
{
	ListItem::updateChildren();	
	if(isSelected())
	{
		FileIconItem *item;
		for ( item = list.first(); item; item = list.next() )
		{
			item->setPath(fullName());
		}
	}
}







