/* This file is part of the KDE project
   Copyright (C) 2004 David Faure <faure@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 version 2 as published by the Free Software Foundation.

   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., 51 Franklin Street, Fifth Floor,
   Boston, MA 02110-1301, USA.
*/

#include "testdistrlist.h"

#include <distributionlist.h>
using KPIM::DistributionList;

#include <config.h>

#include <tdeabc/stdaddressbook.h>
#include <kurl.h>
#include <tdeapplication.h>
#include <tdeio/netaccess.h>
#include <tdeio/job.h>
#include <kdebug.h>
#include <tdecmdlineargs.h>

#include <tqdir.h>
#include <tqfileinfo.h>

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>

int main(int argc, char *argv[])
{
    // Use another directory than the real one, just to keep things clean
    // TDEHOME needs to be writable though, for a tdesycoca database
    setenv( "TDEHOME", TQFile::encodeName( TQDir::homeDirPath() + "/.tde-testdistrlist" ), true );
    setenv( "TDE_FORK_SLAVES", "yes", true ); // simpler, for the final cleanup

    TDEApplication::disableAutoDcopRegistration();
    TDECmdLineArgs::init(argc,argv,"testdistrlist", 0, 0, 0, 0);
    TDEApplication app( false, false );

    TestDistrList test;
    test.setup();
    test.runAll();
    test.cleanup();
    kdDebug() << "All tests OK." << endl;
    return 0;
}

void TestDistrList::setup()
{
    // We need a std addressbook
    TDEABC::AddressBook *ab = TDEABC::StdAddressBook::self();
    TDEABC::StdAddressBook::setAutomaticSave( false );

    // and two contacts
    TDEABC::Addressee addr1;
    addr1.setName( "addr1" );
    addr1.setFormattedName( "addr1" );
    addr1.insertEmail( "addr1@kde.org", true );
    addr1.insertEmail( "addr1-alternate@kde.org" );
    ab->insertAddressee( addr1 );
    assert( addr1.emails().count() == 2 );

    TDEABC::Addressee addr2;
    addr2.setName( "addr2" );
    addr2.insertEmail( "addr2@kde.org", true );
    addr2.insertEmail( "addr2-alternate@kde.org" );
    ab->insertAddressee( addr2 );
    assert( addr2.emails().count() == 2 );

    assert( !ab->findByName( "addr1" ).isEmpty() );
    assert( !ab->findByName( "addr2" ).isEmpty() );
}

void TestDistrList::runAll()
{
    testEmpty();
    testNewList();
    testInsertEntry();
    testRemoveEntry();
    testDuplicate();
    testDeleteList();
}

bool TestDistrList::check(const TQString& txt, TQString a, TQString b)
{
    if (a.isEmpty())
        a = TQString();
    if (b.isEmpty())
        b = TQString();
    if (a == b) {
        kdDebug() << txt << " : checking '" << a << "' against expected value '" << b << "'... " << "ok" << endl;
    }
    else {
        kdDebug() << txt << " : checking '" << a << "' against expected value '" << b << "'... " << "KO !" << endl;
        cleanup();
        exit(1);
    }
    return true;
}

// taken from KMail
#include <sys/types.h>
#include <dirent.h>
static bool removeDirAndContentsRecursively( const TQString & path )
{
  kdDebug() << k_funcinfo << path << endl;
  bool success = true;

  TQDir d;
  d.setPath( path );
  d.setFilter( TQDir::Files | TQDir::Dirs | TQDir::Hidden );

  const TQFileInfoList *list = d.entryInfoList();
  TQFileInfoListIterator it( *list );
  TQFileInfo *fi;

  while ( (fi = it.current()) != 0 ) {
    if( fi->isDir() && !fi->isSymLink() ) {
      if ( fi->fileName() != "." && fi->fileName() != ".." )
        success = success && removeDirAndContentsRecursively( fi->absFilePath() );
    } else {
      success = success && d.remove( fi->absFilePath() );
    }
    ++it;
  }

  if ( success ) {
    success = success && d.rmdir( path ); // nuke ourselves, we should be empty now
  }
  return success;
}

void TestDistrList::cleanup()
{
    kdDebug() << k_funcinfo << endl;
    TDEABC::AddressBook *ab = TDEABC::StdAddressBook::self();
    ab->clear();
    TDEABC::StdAddressBook::close();

    TQString tdehome = TQFile::decodeName( getenv("TDEHOME") );
    KURL urltdehome; urltdehome.setPath( tdehome );
    // don't use TDEIO::NetAccess here since it needs X
    // TDEIO::NetAccess::del( urltdehome, 0 )i;
    assert( removeDirAndContentsRecursively( tdehome ) );
}

void TestDistrList::testEmpty()
{
    kdDebug() << k_funcinfo << endl;
    DistributionList dl;
    assert( dl.isEmpty() );
}

void TestDistrList::testNewList()
{
    kdDebug() << k_funcinfo << endl;
    DistributionList dl;
    dl.setName( "foo" );
    assert( !dl.isEmpty() );
    check( "name set", dl.formattedName(), "foo" );
    assert( DistributionList::isDistributionList( dl ) );

    TDEABC::AddressBook *ab = TDEABC::StdAddressBook::self();
    ab->insertAddressee( dl );
#if 0 // can't do that until we have TDEABC::AddressBook::findByFormattedName, or we use setName()
    TDEABC::Addressee::List addrList = ab->findByName( "foo" );
    assert( addrList.count() == 1 );
    TDEABC::Addressee addr = addrList.first();
    assert( !addr.isEmpty() );
    check( "correct name", addr.name(), "foo" );
    assert( DistributionList::isDistributionList( addr ) );
#else
    TDEABC::Addressee addr = dl;
#endif

    DistributionList dl2 = DistributionList::findByName( ab, "foo" );
    assert( !dl2.isEmpty() );
    check( "correct name", dl2.formattedName(), "foo" );
    assert( DistributionList::isDistributionList( dl2 ) );

    // Test the ctor that takes an addressee
    DistributionList dl3( addr );
    assert( !dl3.isEmpty() );
    assert( DistributionList::isDistributionList( dl3 ) );
    check( "correct name", dl3.formattedName(), "foo" );
}

void TestDistrList::testInsertEntry()
{
    kdDebug() << k_funcinfo << endl;
    TDEABC::AddressBook *ab = TDEABC::StdAddressBook::self();
    DistributionList dl = DistributionList::findByName( ab, "foo" );
    assert( !dl.isEmpty() );

#if 0 // the usual method
    TDEABC::Addressee addr1 = ab->findByName( "addr1" ).first();
    assert( !addr1.isEmpty() );
    dl.insertEntry( addr1 );
#else // the kolab-resource method
    dl.insertEntry( "addr1" );
#endif

    TDEABC::Addressee addr2 = ab->findByName( "addr2" ).first();
    assert( !addr2.isEmpty() );
    dl.insertEntry( addr2, "addr2-alternate@kde.org" );

    // Try inserting it again, should do nothing
    dl.insertEntry( addr2, "addr2-alternate@kde.org" );

    // And insert it with another email address
    dl.insertEntry( addr2, "addr2@kde.org" );

    // Test entries()
    DistributionList::Entry::List entries = dl.entries( ab );
    check( "entries count", TQString::number( entries.count() ), "3" );
    check( "first entry", entries[0].addressee.name(), "addr1" );
    check( "first entry", entries[0].email, TQString() );
    check( "second entry", entries[1].addressee.name(), "addr2" );
    check( "second entry", entries[1].email, "addr2-alternate@kde.org" );
    check( "third entry", entries[2].addressee.name(), "addr2" );
    check( "third entry", entries[2].email, "addr2@kde.org" );

    // Test emails()
    TQStringList emails = dl.emails( ab );
    kdDebug() << emails << endl;
    assert( emails.count() == 3 );
    check( "first email", emails[0], "addr1 <addr1@kde.org>" );
    check( "second email", emails[1], "addr2 <addr2-alternate@kde.org>" );
    check( "third email", emails[2], "addr2 <addr2@kde.org>" );

    // Commit changes to the addressbook !!
    ab->insertAddressee( dl );
}

void TestDistrList::testRemoveEntry()
{
    kdDebug() << k_funcinfo << endl;
    TDEABC::AddressBook *ab = TDEABC::StdAddressBook::self();
    DistributionList dl = DistributionList::findByName( ab, "foo" );
    assert( !dl.isEmpty() );
    DistributionList::Entry::List entries = dl.entries( ab );
    check( "entries count before removeEntry", TQString::number( entries.count() ), "3" );

    // Removing an empty entry shouldn't do anything
    dl.removeEntry( TDEABC::Addressee() );
    check( "entries count after removing empty entry", TQString::number( dl.entries(ab).count() ), "3" );

    TDEABC::Addressee addr1 = ab->findByName( "addr1" ).first();
    assert( !addr1.isEmpty() );
    // Removing an entry with the wrong email passed, shouldn't do anything
    dl.removeEntry( addr1, "foo@foobar.com" );
    check( "entries count after removing entry with invalid email", TQString::number( dl.entries(ab).count() ), "3" );

    // Now remove entry correctly
    dl.removeEntry( addr1 );
    check( "removeEntry(addr1) worked", TQString::number( dl.entries(ab).count() ), "2" );
    TQStringList emails = dl.emails( ab );
    assert( emails.count() == 2 );
    check( "first email", emails[0], "addr2 <addr2-alternate@kde.org>" );

    // Now move on to addr2. First remove with no or a wrong email (nothing should happen)
    TDEABC::Addressee addr2 = ab->findByName( "addr2" ).first();
    assert( !addr2.isEmpty() );
    dl.removeEntry( addr2 );
    check( "entries count after removing entry with no email", TQString::number( dl.entries(ab).count() ), "2" );

    // Now remove addr2 correctly
    dl.removeEntry( addr2, "addr2@kde.org" );
    check( "entries count after removing addr2", TQString::number( dl.entries(ab).count() ), "1" );
    dl.removeEntry( addr2, "addr2-alternate@kde.org" );
    check( "entries count after removing alternate addr2", TQString::number( dl.entries(ab).count() ), "0" );
    assert( dl.entries(ab).isEmpty() );
    assert( dl.emails(ab).isEmpty() );
    assert( DistributionList::isDistributionList( dl ) );

    ab->insertAddressee( dl );
}

void TestDistrList::testDuplicate()
{
    kdDebug() << k_funcinfo << endl;
    // This is a special test for the case where we have a contact and a distr list with the same name
    TDEABC::AddressBook *ab = TDEABC::StdAddressBook::self();
    TDEABC::Addressee addr;
    addr.setName( "foo" );
    addr.insertEmail( "foo@kde.org", true );
    ab->insertAddressee( addr );

#if 0 // we need a findByFormattedName
    TDEABC::Addressee::List addrList = ab->findByName( "foo" );
    assert( addrList.count() == 2 );

    bool a = DistributionList::isDistributionList( addrList.first() );
    bool b = DistributionList::isDistributionList( addrList.last() );
    // one is a distr list, but not both
    assert( a || b );
    //
    assert( ! ( a && b ) );
#endif

    DistributionList dl = DistributionList::findByName( ab, "foo" );
    assert( !dl.isEmpty() );
    assert( DistributionList::isDistributionList( dl ) );
    assert( dl.formattedName() == "foo" );
}

void TestDistrList::testDeleteList()
{
    kdDebug() << k_funcinfo << endl;

    TDEABC::AddressBook *ab = TDEABC::StdAddressBook::self();
    DistributionList dl = DistributionList::findByName( ab, "foo" );
    assert( !dl.isEmpty() );
    ab->removeAddressee( dl );
    dl = DistributionList::findByName( ab, "foo" );
    assert( dl.isEmpty() );
}

#include "testdistrlist.moc"
