/*
    This file is part of libkabc.
    Copyright (c) 2002 Tobias Koenig <tokoe@kde.org>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library 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
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.
*/

/*
Enhanced Version of the file for platform independent KDE tools.
Copyright (c) 2004 Ulf Schenk

$Id$
*/


#include <sys/types.h>
#include <sys/stat.h>
#ifndef _WIN32_
#include <unistd.h>
#endif

#include <qregexp.h>
#include <qtimer.h>
#include <qwidget.h>

#include <kapplication.h>
#include <kconfig.h>
#include <kdebug.h>
//US #include <kgenericfactory.h>
#include <kglobal.h>
#include <klocale.h>
#include <kstandarddirs.h>
#include <kurlrequester.h>

#include "addressbook.h"

#include "formatfactory.h"

#include "resourcedirconfig.h"
#include "stdaddressbook.h"

//US
#include <qdir.h>
//US #include "../../formats/vcardformatplugin2.h"
//US #include "../../formats/binaryformat.h"

#include "resourcedir.h"

using namespace KABC;

extern "C"
{
//US  void *init_kabc_dir()
  void *init_microkabc_dir()
  {
    return new KRES::PluginFactory<ResourceDir,ResourceDirConfig>();
  }
}


ResourceDir::ResourceDir( const KConfig *config )
    : Resource( config )
{
  QString path;

  KConfig *cfg = (KConfig *)config;
  if ( cfg ) {
//US     path = config->readEntry( "FilePath" );
     path = cfg->readEntry( "FilePath", StdAddressBook::directoryName() );
//US     mFormatName = config->readEntry( "FileFormat" );
     mFormatName = cfg->readEntry( "FileFormat", "vcard" );
  } else {
    path = StdAddressBook::directoryName();
    mFormatName = "vcard";
  }


  FormatFactory *factory = FormatFactory::self();
  mFormat = factory->format( mFormatName );

  if ( !mFormat ) {
    mFormatName = "vcard";
    mFormat = factory->format( mFormatName );
  }

/*US  
//US  qDebug("ResourceDir::ResourceDir initialized with format %s ", mFormatName.latin1());
  if (mFormatName == "vcard")
    mFormat = new VCardFormatPlugin2();
  else if (mFormatName == "binary")
    mFormat = new BinaryFormat();
  else
    qDebug("ResourceFile::init format unknown !!! %s ", mFormatName.latin1());
*/
  
/*US we have no KDirWatch. SO simulate the signals from inside the apropriate methods
  connect( &mDirWatch, SIGNAL( dirty(const QString&) ), SLOT( pathChanged() ) );
  connect( &mDirWatch, SIGNAL( created(const QString&) ), SLOT( pathChanged() ) );
  connect( &mDirWatch, SIGNAL( deleted(const QString&) ), SLOT( pathChanged() ) );
*/

  setPath( path );
}

ResourceDir::~ResourceDir()
{
  delete mFormat;
  mFormat = 0;
}

void ResourceDir::writeConfig( KConfig *config )
{
  Resource::writeConfig( config );

  config->writeEntry( "FilePath", mPath );
  config->writeEntry( "FileFormat", mFormatName );
}

Ticket *ResourceDir::requestSaveTicket()
{
  kdDebug(5700) << "ResourceDir::requestSaveTicket()" << endl;

  if ( !addressBook() ) return 0;

  if ( !lock( mPath ) ) {
    kdDebug(5700) << "ResourceDir::requestSaveTicket(): Unable to lock path '"
                  << mPath << "'" << endl;
    return 0;
  }
  return createTicket( this );
}


bool ResourceDir::doOpen()
{
  QDir dir( mPath );
  if ( !dir.exists() ) { // no directory available
    return dir.mkdir( dir.path() );
  } else {
    QString testName = dir.entryList( QDir::Files )[0];
    if ( testName.isNull() || testName.isEmpty() ) // no file in directory
      return true;

    QFile file( mPath + "/" + testName );
    if ( file.open( IO_ReadOnly ) )
      return true;

    if ( file.size() == 0 )
      return true;

    bool ok = mFormat->checkFormat( &file );
    file.close();
    return ok;
  }
}

void ResourceDir::doClose()
{
}

bool ResourceDir::load()
{
  kdDebug(5700) << "ResourceDir::load(): '" << mPath << "'" << endl;

  QDir dir( mPath );
  QStringList files = dir.entryList( QDir::Files );

  QStringList::Iterator it;
  bool ok = true;
  for ( it = files.begin(); it != files.end(); ++it ) {
    QFile file( mPath + "/" + (*it) );

    if ( !file.open( IO_ReadOnly ) ) {
      addressBook()->error( i18n( "Unable to open file '%1' for reading" ).arg( file.name() ) );
      ok = false;
      continue;
    }

    if ( !mFormat->loadAll( addressBook(), this, &file ) )
      ok = false;

    file.close();
  }

  return ok;
}

bool ResourceDir::save( Ticket *ticket )
{
  kdDebug(5700) << "ResourceDir::save(): '" << mPath << "'" << endl;

  AddressBook::Iterator it;
  bool ok = true;

  for ( it = addressBook()->begin(); it != addressBook()->end(); ++it ) {
    if ( (*it).resource() != this || !(*it).changed() )
      continue;

    QFile file( mPath + "/" + (*it).uid() );
    if ( !file.open( IO_WriteOnly ) ) {
      addressBook()->error( i18n( "Unable to open file '%1' for writing" ).arg( file.name() ) );
      continue;
    }

    mFormat->save( *it, &file );

    // mark as unchanged
    (*it).setChanged( false );

    file.close();
  }

  delete ticket;
  unlock( mPath );

  return ok;
}

bool ResourceDir::lock( const QString &path )
{
  kdDebug(5700) << "ResourceDir::lock()" << endl;

  QString p = path;
//US change the implementation how the lockfilename is getting created
//US  p.replace( QRegExp("/"), "_" );
//US  QString lockName = locateLocal( "data", "kabc/lock/" + p + ".lock" );
  KURL url(p);  
  QString lockName = locateLocal( "data", "kabc/lock/" + url.fileName() + ".lock" );
  
  
  kdDebug(5700) << "-- lock name: " << lockName << endl;

  if ( QFile::exists( lockName ) ) return false;

  QString lockUniqueName;
  lockUniqueName = p + KApplication::randomString( 8 );

  url = lockUniqueName;  
//US  mLockUniqueName = locateLocal( "data", "kabc/lock/" + lockUniqueName );
  mLockUniqueName = locateLocal( "data", "kabc/lock/" + url.fileName() );
    
  kdDebug(5700) << "-- lock unique name: " << mLockUniqueName << endl;

  // Create unique file
  QFile file( mLockUniqueName );
  file.open( IO_WriteOnly );
  file.close();

  // Create lock file
  int result = ::link( QFile::encodeName( mLockUniqueName ),
                       QFile::encodeName( lockName ) );

  if ( result == 0 ) {
    addressBook()->emitAddressBookLocked();
    return true;
  }

  // TODO: check stat

  return false;
}

void ResourceDir::unlock( const QString &path )
{
  QString p = path;
//US change the implementation how the lockfilename is getting created
//US  p.replace( QRegExp( "/" ), "_" );
//US  QString lockName = locate( "data", "kabc/lock/" + p + ".lock" );
  KURL url(p);  
  QString lockName = locate( "data", "kabc/lock/" + url.fileName() + ".lock" );

  ::unlink( QFile::encodeName( lockName ) );
  QFile::remove( mLockUniqueName );
  addressBook()->emitAddressBookUnlocked();
}

void ResourceDir::setPath( const QString &path )
{
/*US ToDo: no synchronization so far. Has to be changed in the future
  mDirWatch.stopScan();
  mDirWatch.removeDir( mPath );
*/
  mPath = path;

/*US ToDo: no synchronization so far. Has to be changed in the future
  mDirWatch.addDir( mPath, true );
  mDirWatch.startScan();
*/  

//US simulate KDirWatch event  
  pathChanged();

}

QString ResourceDir::path() const
{
  return mPath;
}

void ResourceDir::setFormat( const QString &format )
{
  mFormatName = format;

  if ( mFormat )
    delete mFormat;

  FormatFactory *factory = FormatFactory::self();
  mFormat = factory->format( mFormatName );
/*US 
qDebug("ResourceDir::setFormat initialized with format %s ", format.latin1());
  if (mFormatName == "vcard")
    mFormat = new VCardFormatPlugin2();
  else if (mFormatName == "binary")
    mFormat = new BinaryFormat();
  else
    qDebug("ResourceDir::setFormat format unknown !!! %s ", format.latin1());
*/

}

QString ResourceDir::format() const
{
  return mFormatName;
}

void ResourceDir::pathChanged()
{
  if ( !addressBook() )
    return;

  load();
  addressBook()->emitAddressBookChanged();
}

void ResourceDir::removeAddressee( const Addressee& addr )
{
    QFile::remove( mPath + "/" + addr.uid() );
}

void ResourceDir::cleanUp()
{
  unlock( mPath );
}

//US #include "resourcedir.moc"