/*
    This file is part of libkabc.
    Copyright (c) 2004 Ulf Schenk

    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>
#include <unistd.h>

#include <qdir.h>
#include <qfile.h>
#include <qfileinfo.h>
#include <qregexp.h>
//US #include <qtimer.h>

#include <kapplication.h>
#include <kconfig.h>
#include <kdebug.h>
#include <klocale.h>
//US #include <ksavefile.h>
#include <kstandarddirs.h>
#include <kmessagebox.h>

#include <sl/slzdb.h>

#include <libkdepim/ksyncprofile.h>

#include "resourcesharpdtmconfig.h"
#include "resourcesharpdtm.h"

#include "stdaddressbook.h"

#include "sharpdtmconverter.h"
//#define ALLOW_LOCKING
using namespace KABC;
extern "C"
{
  void *init_microkabc_sharpdtm()
  {
    return new KRES::PluginFactory<ResourceSharpDTM,ResourceSharpDTMConfig>();
  }
}

ResourceSharpDTM::ResourceSharpDTM( const KConfig *config  )
  : Resource( config ), mConverter (0)
{
  // we can not choose the filename. Therefore use the default to display

  QString fileName = SlZDataBase::addressbookFileName();
  init( fileName );
}

ResourceSharpDTM::ResourceSharpDTM( const QString &fileName  )
  : Resource( 0 )
{
  init( fileName );
}

void ResourceSharpDTM::init( const QString &fileName )
{

  connect( &mDirWatch, SIGNAL( dirty(const QString&) ), SLOT( fileChanged() ) );
  connect( &mDirWatch, SIGNAL( created(const QString&) ), SLOT( fileChanged() ) );
  connect( &mDirWatch, SIGNAL( deleted(const QString&) ), SLOT( fileChanged() ) );

  setFileName( fileName );
}

ResourceSharpDTM::~ResourceSharpDTM()
{
  if (mConverter != 0)
    delete mConverter;

  if(mAccess != 0)
    delete mAccess;
}

void ResourceSharpDTM::writeConfig( KConfig *config )
{
  Resource::writeConfig( config );
}

Ticket *ResourceSharpDTM::requestSaveTicket()
{
 

  qDebug("ResourceSharpDTM::requestSaveTicket: %s", fileName().latin1());

  if ( !addressBook() ) return 0;

#ifdef ALLOW_LOCKING
  if ( !lock( fileName() ) ) {
      qDebug("ResourceSharpDTM::requestSaveTicket(): Unable to lock file ");
    return 0;
  }
#endif
  return createTicket( this );
}


bool ResourceSharpDTM::doOpen()
{
  qDebug("ResourceSharpDTM::doOpen: %s", fileName().latin1());

  // the last parameter in the SlZDataBase constructor means "readonly"
  mAccess = new SlZDataBase(fileName(),
                        SlZDataBase::addressbookItems(),
                        NULL, false);

  if ( !mAccess ) {
    qDebug("Unable to load file() %s", fileName().latin1());
    return false;
  }

  if (mConverter == 0)
  {
    mConverter = new SharpDTMConverter();
    bool res = mConverter->init(); 
    if ( !res )
    {
	  QString msg("Unable to initialize sharp converter. Most likely a problem with the category file");

      qDebug(msg);
      delete mAccess;
      mAccess = 0;
      return false;
    }
  }

 return true;
}

void ResourceSharpDTM::doClose()
{
  qDebug("ResourceSharpDTM::doClose: %s", fileName().latin1());

  if(mAccess)
  {
    delete mAccess;
    mAccess = 0;
  }
  // it seems so, that deletion of access deletes backend as well
  //delete backend;

  return;
}

bool ResourceSharpDTM::load()
{
  qDebug("ResourceSharpDTM::load: %s", fileName().latin1());

  bool res = false;

  CardId id;

  for (bool res=mAccess->first(); res == true; res=mAccess->next())
  {
    id = mAccess->cardId();

    KABC::Addressee addressee;

    res = mConverter->sharpToAddressee( id, mAccess, addressee );

    if ( !addressee.isEmpty() && res )
    {
      addressee.setResource( this );
      addressBook()->insertAddressee( addressee );
    }
  }

  return true;
}

bool ResourceSharpDTM::save( Ticket *ticket )
{
  qDebug("ResourceSharpDTM::save: %s", fileName().latin1());

  mDirWatch.stopScan();

  KABC::AddressBook::Iterator it;
  bool res;
  KABC::Addressee::List changedAddressees;
  typedef QMap<int,QString> AddresseeMap;
  AddresseeMap map;
  CardId id ;

  for ( it = addressBook()->begin(); it != addressBook()->end(); ++it ) {

      if ( (*it).tempSyncStat() != SYNC_TEMPSTATE_NEW_EXTERNAL ) {
          QString uid = (*it).originalExternalUID();
          bool res;
          if ( uid.isEmpty() )
              id = 0;
          else
              id = uid.toUInt();
          KABC::Addressee addressee = (*it);
          if ( (*it).tempSyncStat() == SYNC_TEMPSTATE_ADDED_EXTERNAL ) {
              res = mAccess->startEditCard(id);
              if (res == true)
                  {
                      res = mConverter->addresseeToSharp( (*it), mAccess, id  );
                      if (res == true)
                          {
                              res = mAccess->finishEditCard(&id);
                              //(*it).setTempSyncStat( SYNC_TEMPSTATE_NEW_ID );
                              //(*it).setExternalUID( QString::number( id ) );
                              //(*it).setOriginalExternalUID( QString::number( id ) ); 
                              map.insert(id,(*it).uid());                           
                              if (res == false)
                                  qDebug("Unable to append Contact: %s", addressee.formattedName().latin1());
                             
                          }
                      else
                          {
                              qDebug("Unable to convert Addressee: %s", addressee.formattedName().latin1());
                              mAccess->cancelEditCard();
                          }
                  }

          } else if ( (*it).tempSyncStat() == SYNC_TEMPSTATE_DELETE ) {
              res = mAccess->deleteCard(&id);
              if ( !res ) 
                  qDebug("delete error ");


          } else if ( (*it).tempSyncStat() != SYNC_TEMPSTATE_NEW_EXTERNAL ) {
              //changed
              res = mAccess->startEditCard(id);
              if (res == true)
                  {
                      res = mConverter->addresseeToSharp( (*it), mAccess, id  );
                      if (res == true)
                          {
                              res = mAccess->finishEditCard(&id);
                              //(*it).setTempSyncStat( SYNC_TEMPSTATE_NEW_CSUM );
                              map.insert(id,(*it).uid());
                              if (res == false)
                                  qDebug("Unable to append Contact: %s", addressee.formattedName().latin1());
                              
                          }
                      else
                          {
                              qDebug("Unable to convert Addressee: %s", addressee.formattedName().latin1());
                              mAccess->cancelEditCard();
                          }
                  }
          }
      }

  }
  AddresseeMap::Iterator itam;
  for ( res=mAccess->first(); res == true; res=mAccess->next())
      {
          id = mAccess->cardId();
          int idint = id;
          itam = map.find( idint );
          if ( itam != map.end() ) {
              KABC::Addressee addressee;
              res = mConverter->sharpToAddressee( id, mAccess, addressee );

              if ( !addressee.isEmpty() && res )
                  {
                      addressee.setResource( this ); 
                      addressee.setUid( itam.data() );
                      addressee.setTempSyncStat( SYNC_TEMPSTATE_NEW_ID );
                      addressBook()->insertAddressee( addressee , false );
                  }
          }
      }

  //US  mAccess->save();

  mDirWatch.startScan();
  delete ticket;
  unlock( fileName() );

  return true;
}

bool ResourceSharpDTM::lock( const QString &lockfileName )
{
#ifdef ALLOW_LOCKING
  qDebug("ResourceSharpDTM::lock: %s", fileName().latin1());

  kdDebug(5700) << "ResourceSharpDTM::lock()" << endl;

  QString fn = lockfileName;

  KURL url(fn);
  QString lockName = locateLocal( "data", "kabc/lock/" + url.fileName() + ".lock" );

  kdDebug(5700) << "-- lock name: " << lockName << endl;

  if (QFile::exists( lockName ))
  {
    qDebug("ResourceSharpDTM::lock: lockfile %s already exists. (Delete it before continuing if nobody else is accessing the resourcefile %s)", lockName.latin1(), fileName());
    return false;
  }


  QString lockUniqueName;
  lockUniqueName = fn + 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 = 0;
#ifndef _WIN32_
  result = ::link( QFile::encodeName( mLockUniqueName ),
                       QFile::encodeName( lockName ) );
#endif
  if ( result == 0 ) {
    addressBook()->emitAddressBookLocked();
    return true;
  }

  // TODO: check stat

  return false;
#else
  return true;
#endif 
}

void ResourceSharpDTM::unlock( const QString &fileName )
{
#ifdef ALLOW_LOCKING
  qDebug("ResourceSharpDTM::unlock() %s", fileName.latin1());

  QString fn = fileName;
  KURL url(fn);
  QString lockName = locateLocal( "data", "kabc/lock/" + url.fileName() + ".lock" );

  QFile::remove( lockName );
  QFile::remove( mLockUniqueName );
  addressBook()->emitAddressBookUnlocked();
#endif 
}

void ResourceSharpDTM::setFileName( const QString &newFileName )
{
  mDirWatch.stopScan();
  mDirWatch.removeFile( fileName() );

  Resource::setFileName( newFileName );

  mDirWatch.addFile( fileName() );
  mDirWatch.startScan();

}

void ResourceSharpDTM::fileChanged()
{
  // There is a small theoretical chance that KDirWatch calls us before
  // we are fully constructed
  if (!addressBook())
    return;

  QString text( i18n( "Sharp DTM resource '%1'<br> has been changed by third party.<br>Do you want to reload?").arg( fileName() ) );
  if ( readOnly() || KMessageBox::questionYesNo( 0, text ) == KMessageBox::Yes ) {
    load();
    addressBook()->emitAddressBookChanged();
  }
}

void ResourceSharpDTM::removeAddressee( const Addressee &addr )
{
}

void ResourceSharpDTM::cleanUp()
{
  unlock( fileName() );
}