/* This file implements the importing tool for kab 1 databases.
 *
 * the KDE addressbook
 * copyright:  (C) Mirko Sucker, 1998, 1999, 2000
 * mail to:    Mirko Sucker <mirko@kde.org>
 * requires:   recent C++-compiler, at least Qt 2.0
 
 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.
 
 * $Revision: 1.10 $
 */

#include "kab_kab1importer.h"
#include <qconfigDB.h>
#include <kabapi.h>
#include <kmessagebox.h>
#include <klocale.h>
#include <qmultilineedit.h>
#include <qstringlist.h>
#include <qdir.h>
#include <kdebug.h>

class Kab1Entry {
public:
  // changed on April 4 1998
  // (added talk-address-list)
  // changed on June 9 1998
  // (added keywords list)
  // ----------------------------------
  QCString name;
  QCString firstname;
  QCString additionalName;
  QCString namePrefix;
  QCString fn; // formatted name 
  QCString comment;
  QCString org; // organization -
  QCString orgUnit; 
  QCString orgSubUnit; 
  QCString title; 
  QCString role; 
  // QPixmap logo;
  QDate birthday; // now implemented
  QStrList talk; // list of talk addresses
  QStrList keywords; // list of form-free keywords
  // QCString sound; // base64 coded wav - file
  // QCString agent; // contains a complete vCard possibly?
  QCString deliveryLabel; // missing in implementation
  // Attention API users: 
  // The email fields will be changed to an unlimited list of
  // email addresses and remarks, see list<QCString> emails below.
  // Do not rely on the availablility of the three QCString 
  // members, I think this is much to inflexible.
  // Currently, the emails-list will be empty, but not for long!
  QCString email; 
  QCString email2; 
  QCString email3; 
  // This list contains the email addresses.
  QStrList emails;
  QCString address; 
  QCString town; 
  // new fields, hint from Preston Brown:
  QCString zip; // zip or postal code
  QCString state; // for state or province
  QCString country; // for federal states
  // -----
  QCString telephone; 
  QCString fax; 
  QCString modem; 
  QCString URL; 
};

/** This method parses a kab 1 section and creates a kab 2 entry from it.
 *  Used to import the kab 1 address book into the program.
 *  @return false if the section does not represent a kab 1 entry
 *  @see QConfigDB
 *  @see Section */
bool makeEntryFromKab1Section(Section* section, AddressBook::Entry& entry)
{
  bool GUARD; GUARD=true;
  QString sTemp;
  kdDebug() << "makeEntryFromKab1Section: called.";
  // -----
  Kab1Entry kab1;
  KeyValueMap* map;
  int count;
  AddressBook::Entry dummy;
  AddressBook::Entry::Address address;
  AddressBook::Entry::Address addressDummy;
  // ----- clear up the old entry: (change on July 19 1998):
  entry=dummy; // dummy is always completely empty
  // -----
  map=section->getKeys();
  // the first 6 keys are required, something went wrong if
  // these are not set:
  if(!map->get("name", kab1.name)
     || !map->get("firstname", kab1.firstname)
     || !map->get("email", kab1.email)
     || !map->get("telephone", kab1.telephone)
     || !map->get("town", kab1.town)
     || !map->get("address", kab1.address))
    {
      return false;
    } else { // the entry should be OK
      map->get("additionalName", kab1.additionalName);
      map->get("namePrefix", kab1.namePrefix);
      map->get("fn", kab1.fn);
      map->get("comment", kab1.comment);
      map->get("org", kab1.org);
      map->get("orgUnit", kab1.orgUnit);
      map->get("orgSubUnit", kab1.orgSubUnit);
      map->get("title", kab1.title);
      map->get("role", kab1.role);
      map->get("deliveryLabel", kab1.deliveryLabel);
      map->get("email2", kab1.email2);
      map->get("email3", kab1.email3);
      map->get("fax", kab1.fax);
      map->get("modem", kab1.modem);
      map->get("URL", kab1.URL);
      map->get("zip", kab1.zip);
      map->get("state", kab1.state);
      map->get("country", kab1.country);
      if(map->get("talk", kab1.talk))
	{
          if ( kab1.talk.isEmpty() )
            sTemp = "no";
          else
            sTemp = "";
	  kdDebug() << "AddressBook::makeEntryFromSection: found " <<
	     sTemp << " talk address(es) (" << kab1.talk.count() << ").";
	}
      if(map->get("keywords", kab1.keywords))
	{
          if ( kab1.keywords.isEmpty() )
            sTemp = "no";
          else
            sTemp = "";
	  kdDebug() << "AddressBook::makeEntryFromSection: found " <<
	     sTemp << " keyword(s) ( " << kab1.keywords.count() << ").";	     
	}
      if(map->get("emails", kab1.emails))
	{
          if ( kab1.emails.isEmpty() )
            sTemp = "no";
          else
            sTemp = "";
	  kdDebug() << "AddressBook::makeEntryFromSection: found " << 
	     sTemp << "email address(es) (" << kab1.emails.count() << ").";
	}
      if(map->get("birthday", kab1.birthday))
	{
	  kdDebug() << "AddressBook::makeEntryFromSection: " <<
	     "found the birthday.";
	}
    }
  // ----- first copy the attributes of the person:
  entry.lastname=kab1.name;
  entry.middlename=kab1.additionalName;
  entry.firstname=kab1.firstname;
  entry.nameprefix=kab1.namePrefix;
  entry.fn=kab1.fn;
  entry.comment=kab1.comment;
  entry.title=kab1.title;
  entry.birthday=kab1.birthday;
  for(count=0; (unsigned)count<kab1.emails.count(); ++count)
    {
      entry.emails.append(kab1.emails.at(count));
    }
  if(!kab1.email.isEmpty()) entry.emails.append(kab1.email);
  if(!kab1.email2.isEmpty()) entry.emails.append(kab1.email2);
  if(!kab1.email3.isEmpty()) entry.emails.append(kab1.email3);
  if(!kab1.URL.isEmpty()) entry.URLs.append(kab1.URL);
  for(count=0; (unsigned)count<kab1.talk.count(); ++count)
    {
      entry.talk.append(kab1.talk.at(count));
    }
  if(!kab1.telephone.isEmpty())
    {
      entry.telephone.append(AddressBook::phoneType(AddressBook::Fixed));
      entry.telephone.append(kab1.telephone);
    }
  if(!kab1.fax.isEmpty())
    {
      entry.telephone.append(AddressBook::phoneType(AddressBook::Fax));
      entry.telephone.append(kab1.fax);
    }
  if(!kab1.modem.isEmpty())
    {
      entry.telephone.append(AddressBook::phoneType(AddressBook::Modem));
      entry.telephone.append(kab1.modem);
    }
  // ----- then copy the attributes of the (one) address of this person:
  address=addressDummy; // clean it up
  address.headline=i18n("Home");
  address.org=kab1.org;
  address.orgUnit=kab1.orgUnit;
  address.orgSubUnit=kab1.orgSubUnit;
  // address.role=kab1.role;
  address.address=kab1.address;
  address.town=kab1.town;
  address.zip=kab1.zip;
  address.state=kab1.state;
  address.country=kab1.country;
  entry.addresses.push_back(address);
  /* The following values where never implemented in kab 1:
     QPixmap logo;
     QCString sound; // base64 coded wav - file
     QCString agent; // contains a complete vCard possibly?
     QStrList keywords; // list of form-free keywords
     QCString deliveryLabel;
  */
  // ----- done:
  kdDebug() << "makeEntryFromKab1Section: done.";
  return true;
}

Kab1Importer::Kab1Importer(KabAPI* api_, QWidget* parent)
  : KDialogBase(parent),
    log(new QMultiLineEdit(this)),
    api(api_)
{
  log->setReadOnly(true);
  log->setWordWrap(QMultiLineEdit::WidgetWidth);
  showButtonApply(false);
  showButtonCancel(false);
}

int Kab1Importer::exec()
{
  if(importKab1Addressbook())
    {
      log->setMinimumSize(2*log->sizeHint().width(), 2*log->sizeHint().height());
      setMainWidget(log);
      resize(minimumSize());
      log->setCursorPosition(log->numLines(), 0);
      emit(setStatus(i18n("Imported kab 1 addressbook.")));
      return KDialogBase::exec();
    } else {
      emit(setStatus(i18n("Rejected.")));
      return 0;
    }
}

bool Kab1Importer::importKab1Addressbook()
{
  bool GUARD; GUARD=true;
  const QCString OldEntriesSection="Entries";
  const QString OldLocalKDEDIR="/.kde/";
  const QString OldLocalKabDir="share/apps/kab/";
  const QString OldDatabaseFilename="addressbook.database";
  const QString OldFilename=QDir::homeDirPath()
    +OldLocalKDEDIR+OldLocalKabDir+OldDatabaseFilename;
  log->insertLine("Importing KDE 1 addressbook.\nYou should not do this more "
		  "than once with the same file.");
  log->insertLine(QString("Filename to import is\n  ")+OldFilename+QString("."));
  QConfigDB database;
  Section *entriesSection;
  Section::StringSectionMap::iterator it;
  QString temp;
  KabKey key;
  AddressBook::Entry entry;
  list<AddressBook::Entry> entries;
  list<AddressBook::Entry>::iterator pos;
  list<AddressBook::Entry>::iterator next;
  bool errors=false;
  // ----- find the file, load it into a QConfigDB object:
  if(database.setFileName(OldFilename, true, true))
    {
      log->insertLine("File opened (no errors).\n  Directory exists. "
		     "File exists.");
    } else {
      log->insertLine("Cannot access the database file. "
		     "You probably never used kab 1.");
      KMessageBox::information
	(this, i18n("Could not access the kab 1 database file.\n"
		    "You most probably never used kab 1."),
	 i18n("Error"));
      return false;
    }
  kdDebug() << "TopLevelWidget::importKab1Addressbook: file found.";
  if(database.load())
    {
      log->insertLine("File read (no errors). "
		     "Database syntax seems to be correct.");
    } else {
      log->insertLine("Database could not be read (syntax error). "
		     "You probably modified your database file manually.");
      KMessageBox::information
	(this, i18n("Could not read the kab 1 database file.\n"
		    "You probably modified your database file manually."),
	 i18n("Error"));
      return false;
    }
  kdDebug() << "TopLevelWidget::importKab1Addressbook: file loaded.";
  // ----- get the pointer to the entries section:
  if(database.get(OldEntriesSection, entriesSection))
    {
      log->insertLine("Entries section found (no errors). "
		     "Database structure seems to be correct.");
    } else {
      log->insertLine("Entries section not found (database structure error)."
		     " You probably modified your database file manually.");
      KMessageBox::information
	(this, i18n("Could not find the entries section in your database.\n"
		    "You probably modified your database file manually."),
	 i18n("Error"));
      return false;
    }
  kdDebug() << "TopLevelWidget::importKab1Addressbook: got entries section.";
  // ----- iterate over "entries" section, creating AddressBook::Entry objects:
  for(it=entriesSection->sectionsBegin(); it!=entriesSection->sectionsEnd();
      ++it)
    {
      temp="Parsing entry ";
      temp+=(*it).first;
      log->insertLine(temp);
      if(makeEntryFromKab1Section((*it).second, entry))
	{
	  api->addressbook()->literalName(entry, temp, true, false);
	  entries.push_back(entry);
	  temp="  Done, no errors (Entry "+temp+").";
	  log->insertLine(temp);
	} else {
	  log->insertLine("  Error. Section could not be parsed as an entry.");
	  errors=true;
	}
    }
  kdDebug() << "TopLevelWidget::importKab1Addressbook: parsed entries.";
  // ----- query the user to really add the entries:
  if(errors)
    {
      temp=i18n("Warning: There where errors importing the KDE 1\n"
		"address database.\n\n");
    } else {
      temp="";
    }
  temp+=i18n("Do you really want to add the entries of your KDE 1\n"
	   "address book to this file?\n"
	    "You will not be able to revert this changes.");
  if(entries.size()>0)
    {
      if(KMessageBox::warningYesNo
	 (this, temp, i18n("Continue"))==KMessageBox::Yes)
	{
	  // ----- do it:
	  log->insertLine("Adding entries to the database.");
	  for(pos=entries.begin(); pos!=entries.end(); ++pos)
	    {
	      api->addressbook()->literalName((*pos), temp, true, false);
	      next=pos;
	      ++next;
	      if(api->add(*pos, key, next==entries.end() ? true : false)
		 !=AddressBook::NoError)
		{
		  temp=QString("  Error: could not add entry ")+temp
		    +".";
		} else {
		  temp=QString("  Success: added entry ")+temp
		    +" to the database (key ";
		  temp+=key.getKey()+").";
		}
	      log->insertLine(temp);
	    }
	  kdDebug() << "TopLevelWidget::importKab1Addressbook: " <<
	     "added entries, database now holds %i entries." <<
	     api->addressbook()->noOfEntries();
	  // ----- now save the database:
	  if(api->save(true)==AddressBook::NoError)
	    {
	      log->insertLine("Database saved successfully.");
	    } else {
	      log->insertLine("Error: could not save database. Possibly "
			      "permission denied.");
	    }
	} else {
	  log->insertLine("Aborted. Entries of the kab 1 address database will"
			  "  not be added to this file.");
	}
    } else {
      log->insertLine("There are no entries in the kab 1 database.");
    }
  // ----- report the results:
  log->insertLine("\n\n-----------\n\nDone. Please read the message above.");
  kdDebug() << "TopLevelWidget::importKab1Addressbook: done.";
  return true;
}


