/*
    This file is part of KAddressBook.
    Copyright (C) 2003 Helge Deller <deller@kde.org>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    version 2 License 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.
*/

/*
 *  - ldifvcardthumbnail -
 *
 *  tdeioslave which generates tumbnails for vCard and LDIF files.
 *  The thumbnails are used e.g. by Konqueror or in the file selection
 *  dialog.
 *
 */

#include <tqdatetime.h>
#include <tqfile.h>
#include <tqpixmap.h>
#include <tqimage.h>
#include <tqpainter.h>
#include <tqtextstream.h>

#include <kdebug.h>
#include <tdeglobal.h>
#include <tdelocale.h>
#include <tdeabc/ldifconverter.h>
#include <tdeabc/vcardconverter.h>
#include <kpixmapsplitter.h>
#include <kstandarddirs.h>
#include <tdeglobalsettings.h>

#include "ldifvcardcreator.h"

extern "C"
{
  ThumbCreator *new_creator()
  {
    TDEGlobal::locale()->insertCatalogue( "kaddressbook" );
    return new VCard_LDIFCreator;
  }
}

VCard_LDIFCreator::VCard_LDIFCreator()
  : mSplitter( 0 )
{
}

VCard_LDIFCreator::~VCard_LDIFCreator()
{
  delete mSplitter;
}


bool VCard_LDIFCreator::readContents( const TQString &path )
{
  // read file contents
  TQFile file( path );
  if ( !file.open( IO_ReadOnly ) )
    return false;

  TQString info;
  text.truncate(0);

  // read the file
#if defined(KABC_VCARD_ENCODING_FIX)
  const TQByteArray data = file.readAll();
  const TQString contents( data );
  const TQCString contentsRaw( data.data(), data.size() );
#else
  TQTextStream s( &file );
  s.setEncoding( TQTextStream::UnicodeUTF8 );
  TQString contents = s.read();
#endif
  file.close();

  // convert the file contents to a TDEABC::Addressee address
  TDEABC::AddresseeList addrList;
  TDEABC::Addressee addr;
  TDEABC::VCardConverter converter;

#if defined(KABC_VCARD_ENCODING_FIX)
  addrList = converter.parseVCardsRaw( contentsRaw );
#else
  addrList = converter.parseVCards( contents );
#endif
  if ( addrList.count() == 0 )
    if ( !TDEABC::LDIFConverter::LDIFToAddressee( contents, addrList ) )
	return false;
  if ( addrList.count()>1 ) {
    // create an overview (list of all names)
    name = i18n("One contact found:", "%n contacts found:", addrList.count());
    unsigned int no, linenr;
    for (linenr=no=0; linenr<30 && no<addrList.count(); ++no) {
       addr = addrList[no];
       info = addr.formattedName().simplifyWhiteSpace();
       if (info.isEmpty())
          info = addr.givenName() + " " + addr.familyName();
       info = info.simplifyWhiteSpace();
       if (info.isEmpty())
         continue;
       text.append(info);
       text.append("\n");
       ++linenr;
    }
    return true;
  }

  // create card for _one_ contact
  addr = addrList[ 0 ];

  // prepare the text
  name = addr.formattedName().simplifyWhiteSpace();
  if ( name.isEmpty() )
    name = addr.givenName() + " " + addr.familyName();
  name = name.simplifyWhiteSpace();


  TDEABC::PhoneNumber::List pnList = addr.phoneNumbers();
  TQStringList phoneNumbers;
  for (unsigned int no=0; no<pnList.count(); ++no) {
    TQString pn = pnList[no].number().simplifyWhiteSpace();
    if (!pn.isEmpty() && !phoneNumbers.contains(pn))
      phoneNumbers.append(pn);
  }
  if ( !phoneNumbers.isEmpty() )
      text += phoneNumbers.join("\n") + "\n";

  info = addr.organization().simplifyWhiteSpace();
  if ( !info.isEmpty() )
    text += info + "\n";

  // get an address
  TDEABC::Address address = addr.address(TDEABC::Address::Work);
  if (address.isEmpty())
    address = addr.address(TDEABC::Address::Home);
  if (address.isEmpty())
    address = addr.address(TDEABC::Address::Pref);
  info = address.formattedAddress();
  if ( !info.isEmpty() )
    text += info + "\n";

  return true;
}


bool VCard_LDIFCreator::createImageSmall()
{
  text = name + "\n" + text;

  if ( !mSplitter ) {
    mSplitter = new KPixmapSplitter;
    TQString pixmap = locate( "data", "konqueror/pics/thumbnailfont_7x4.png" );
    if ( pixmap.isEmpty() ) {
      delete mSplitter;
      mSplitter=0;
      kdWarning() << "VCard_LDIFCreator: Font image \"thumbnailfont_7x4.png\" not found!\n";
      return false;
    }
    mSplitter->setPixmap( TQPixmap( pixmap ) );
    mSplitter->setItemSize( TQSize( 4, 7 ) );
  }

  TQSize chSize = mSplitter->itemSize(); // the size of one char
  int xOffset = chSize.width();
  int yOffset = chSize.height();

  // calculate a better border so that the text is centered
  int canvasWidth = pixmapSize.width() - 2 * xborder;
  int canvasHeight = pixmapSize.height() -  2 * yborder;
  int numCharsPerLine = (int) (canvasWidth / chSize.width());
  int numLines = (int) (canvasHeight / chSize.height());

  // render the information
  TQRect rect;
  int rest = mPixmap.width() - (numCharsPerLine * chSize.width());
  xborder = TQMAX( xborder, rest / 2 ); // center horizontally
  rest = mPixmap.height() - (numLines * chSize.height());
  yborder = TQMAX( yborder, rest / 2 ); // center vertically
  // end centering

  int x = xborder, y = yborder; // where to paint the characters
  int posNewLine  = mPixmap.width() - (chSize.width() + xborder);
  int posLastLine = mPixmap.height() - (chSize.height() + yborder);
  bool newLine = false;
  Q_ASSERT( posNewLine > 0 );
  const TQPixmap *fontPixmap = &(mSplitter->pixmap());

  for ( uint i = 0; i < text.length(); i++ ) {
    if ( x > posNewLine || newLine ) {  // start a new line?
      x = xborder;
      y += yOffset;

      if ( y > posLastLine ) // more text than space
        break;

      // after starting a new line, we also jump to the next
      // physical newline in the file if we don't come from one
      if ( !newLine ) {
        int pos = text.find( '\n', i );
        if ( pos > (int) i )
          i = pos +1;
      }

      newLine = false;
    }

    // check for newlines in the text (unix,dos)
    TQChar ch = text.at( i );
    if ( ch == '\n' ) {
      newLine = true;
      continue;
    } else if ( ch == '\r' && text.at(i+1) == '\n' ) {
      newLine = true;
      i++; // skip the next character (\n) as well
      continue;
    }

    rect = mSplitter->coordinates( ch );
    if ( !rect.isEmpty() )
      bitBlt( &mPixmap, TQPoint(x,y), fontPixmap, rect, TQt::CopyROP );

    x += xOffset; // next character
  }

  return true;
}

bool VCard_LDIFCreator::createImageBig()
{
  TQFont normalFont( TDEGlobalSettings::generalFont() );
  TQFont titleFont( normalFont );
  titleFont.setBold(true);
  // titleFont.setUnderline(true);
  titleFont.setItalic(true);

  TQPainter painter(&mPixmap);
  painter.setFont(titleFont);
  TQFontMetrics fm(painter.fontMetrics());

  // draw contact name
  painter.setClipRect(2, 2, pixmapSize.width()-4, pixmapSize.height()-4);
  TQPoint p(5, fm.height()+2);
  painter.drawText(p, name);
  p.setY( 3*p.y()/2 );

  // draw contact information
  painter.setFont(normalFont);
  fm = painter.fontMetrics();

  const TQStringList list( TQStringList::split('\n', text) );
  for ( TQStringList::ConstIterator it = list.begin();
             p.y()<=pixmapSize.height() && it != list.end(); ++it ) {
     p.setY( p.y() + fm.height() );
     painter.drawText(p, *it);
  }

  return true;
}

bool VCard_LDIFCreator::create(const TQString &path, int width, int height, TQImage &img)
{
  if ( !readContents(path) )
    return false;

  // resize the image if necessary
  pixmapSize = TQSize( width, height );
  if (height * 3 > width * 4)
    pixmapSize.setHeight( width * 4 / 3 );
  else
    pixmapSize.setWidth( height * 3 / 4 );

  if ( pixmapSize != mPixmap.size() )
    mPixmap.resize( pixmapSize );

  mPixmap.fill( TQColor( 245, 245, 245 ) ); // light-grey background

  // one pixel for the rectangle, the rest. whitespace
  xborder = 1 + pixmapSize.width()/16;  // minimum x-border
  yborder = 1 + pixmapSize.height()/16; // minimum y-border

  bool ok;
  if ( width >= 150 /*pixel*/ )
    ok = createImageBig();
  else
    ok = createImageSmall();
  if (!ok)
    return false;

  img = mPixmap.convertToImage();
  return true;
}

ThumbCreator::Flags VCard_LDIFCreator::flags() const
{
  return (Flags)(DrawFrame | BlendIcon);
}
