/***************************************************************************
    begin                : Mon Oct 29 2001
    copyright            : (C) 2001 by Mantia Andras
    email                : amantia@kdewebdev.org
 ***************************************************************************/

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

#include <math.h>

 /*Own include files*/
#include "kalleryfunctions.h"
#include "kalleryglobals.h"

/*Utility includes*/
#include <magick/api.h>

/*KDE header files*/
#include <kapplication.h>
#include <kdebug.h>
#include <kfiledialog.h>
#include <kglobal.h>
#include <kiconloader.h>
#include <kio/job.h>
#include <klocale.h>
#include <kmessagebox.h>
#include <kstandarddirs.h>

/*QT header files*/
#include <qdir.h>
#include <qeventloop.h>
#include <qfile.h>
#include <qlabel.h>
#include <qlistbox.h>
#include <qlineedit.h>
#include <qprogressdialog.h>
#include <qregexp.h>
#include <qstring.h>
#include <qstringlist.h>
#include <qtextcodec.h>
#include <qtextstream.h>
#include <qtoolbutton.h>


KalleryFunctions::KalleryFunctions(QWidget* widget)
{
  mainWidget = widget;
}

KalleryFunctions::~KalleryFunctions()
{
}

void KalleryFunctions::moveInListAndBox(QListBox *listBox,QStringList &itemList,
                                        QValueList<OptionType::Description> *descList, int delta, int special)
{
  int currentItem;
  QString currentText;
  QString currentItemText;
  OptionType::Description currentDescText;
  QStringList::Iterator it;
  QValueList<OptionType::Description>::Iterator descIt;

  currentItem = listBox->currentItem();
  currentText = listBox->currentText();
  it = itemList.at(currentItem);
  currentItemText = itemList[currentItem];

  switch (special)
  {
    case -1:
      delta = -currentItem;
      break;
    case 1:
      delta = (itemList.count() - currentItem -1);
      break;
  }

  if (descList !=0)
  {
    currentDescText = (*descList)[currentItem];
    descIt = descList->at(currentItem);
    descIt = descList->remove(descIt);
  }

  listBox->removeItem(currentItem);
  it = itemList.remove(it);

  if ( (currentItem+delta >= 0) && (currentItem + delta <= (int)listBox->count()) )
  {
    currentItem += delta;
    int i = 0;
    while (i != delta)
    {
      if (delta < 0)
      {
        it--;
        if (descList != 0)
          descIt--;
      }
      else
      {
        it++;
        if (descList != 0)
          descIt++;
      }
      i = (delta < 0) ? i-1 : i+1;
    }
  }

  if (descList != 0)
  {
    descList->insert(descIt,currentDescText);
  }
  itemList.insert(it,currentItemText);

  listBox->insertItem(currentText,currentItem);
  listBox->setSelected(currentItem,true);
}

void KalleryFunctions::deleteFromList(QListBox *listBox,QStringList &itemList,QLabel *label, QValueList<OptionType::Description> *descList)
{
  int index;
  QStringList::Iterator it;
  QValueList<OptionType::Description>::Iterator descIt;

  /*FIXME: Multiple deletion is not working correctly, so it is disabled for now
  in the QT Designer */

  int count =  listBox->count();
  for (index=0; index < count; index++)
  {
    if (listBox->isSelected(index))
    {
      listBox->removeItem(index);
      it = itemList.at(index);
      itemList.remove(it);
      if (descList)
      {
        descIt = descList->at(index);
        descList->remove(descIt);
      }
    }
  }
  listBox->setSelected(listBox->currentItem(),true);
  label->setText(i18n("%1 items.").arg(itemList.count()));
}

bool KalleryFunctions::makeRelativePath(const QString &baseDir,QString &dir)
{
  QString firstPath;
  QString secondPath;
  int firstDepth,secondDepth;
  bool endSearch;
  KURL u = KURL::fromPathOrURL(dir);
  if (u.isValid() && u.protocol() != "file")
    return false;

  if (dir[0] != '/')
  {
    dir = QDir::cleanDirPath(dir) +"/";
    return true;
  }

  firstPath = QDir::cleanDirPath(baseDir);
  secondPath  = QDir::cleanDirPath(dir);
  firstDepth = firstPath.contains('/');
  secondDepth = secondPath.contains('/');

  do
  {
    endSearch = true;
    if (firstPath.left(firstPath.find('/',1)) == secondPath.left(secondPath.find('/',1)))
    {
      firstPath.remove(0,firstPath.find('/',1));
      secondPath.remove(0,secondPath.find('/',1));
      endSearch = false;
    }
    if (firstPath.isEmpty() || secondPath.isEmpty())
    {
      endSearch = true;
    }
  } while (! endSearch);

  firstDepth =   firstPath.contains('/');
  for (int i=0; i < firstDepth;i++)
  {
    secondPath. prepend("../");
  }

  secondPath. prepend("./");
  dir = QDir::cleanDirPath(secondPath) +"/";
  return true;
}

bool  KalleryFunctions::makeAbsolutePath(const QString & baseDir, QString &dir)
{
  int depthBase;
  int depthDir;
  int pos = 0;
  QString base;

  KURL u = KURL::fromPathOrURL(dir);
  if (u.isValid() && u.protocol() != "file")
    return false;
  if (dir[0] == '/')
  {
    dir = QDir::cleanDirPath(dir) +"/";
    return true;
  }

  base = QDir::cleanDirPath(baseDir + '/') + '/';
  depthBase = base.contains('/');
  depthDir = dir.contains("../");

  for (int i=1; i < depthBase-depthDir; i++)
  {
    pos = base.find('/',pos+1);
  }

  dir.replace(QRegExp("\\.\\./"),"");

  dir.prepend(base.left(pos)+"/");

  dir = QDir::cleanDirPath(dir) +"/";
  return true;
}


bool KalleryFunctions::saveProject(const QString& projectFileName)
{  
  QFile projectFile;
  KSimpleConfig *config;
  OptionType options = KalleryGlobals::ref()->options;

  projectFile.setName(projectFileName);

  if (! projectFile.open(IO_WriteOnly))
  {
    KMessageBox::error(mainWidget,i18n("Cannot create the project file %1.\nSelect another file and try again.").arg(projectFileName),i18n("Error"));
    return false;
  }
  projectFile.close();

  //Here comes the real Save, using the KSimpleConfig class
  config = new KSimpleConfig(projectFileName,false);
  config->setGroup("General");
  config->writeEntry("Encoding",options.encoding);
  config->writeEntry("RelativePaths",options.relativePaths);
  config->writeEntry("kallery_version","Project_Format_1");
  options.projectFileName = projectFileName;
  config->writeEntry("ProjectName",QFileInfo(options.projectFileName).fileName());

  config->setGroup("Gallery");
  config->writeEntry("GalleryTitle",options.galleryTitle);
  config->writeEntry("GalleryFile",options.galleryFile);
  config->writeEntry("ImageDestDir",options.imageDestDir);
  config->writeEntry("ThumbDestDir",options.thumbDestDir);
  config->writeEntry("Language",options.language);

  config->setGroup("Thumbnails");
  config->writeEntry("ThumbSetting",options.thumbSetting);

  config->writeEntry("ThumbWidth",options.thumbWidth);
  config->writeEntry("ThumbHeight",options.thumbHeight);
  config->writeEntry("ThumbFormat",options.thumbFormat);
  config->writeEntry("ThumbList",options.thumbList);

  config->setGroup("Images");
  config->writeEntry("ConvertImages",options.convertImages);
  config->writeEntry("KeepRatio",options.keepRatio);
  config->writeEntry("OnlyLarger", options.onlyLarger);
  config->writeEntry("Resize",options.resize);
  config->writeEntry("FullWidth",options.fullWidth);
  config->writeEntry("FullHeight",options.fullHeight);
  config->writeEntry("InsertCopyright",options.insertCopyright);
  config->writeEntry("Copyright",options.copyright);
  config->writeEntry("FullFormat",options.fullFormat);
  config->writeEntry("Quality",options.quality);
  config->writeEntry("ImageList",options.imageList);

  config->setGroup("HTML options");
  config->writeEntry("ColumnNum",options.columnNum);
  config->writeEntry("UseHtmlImages",options.useHtmlImages);
  config->writeEntry("TextButtons",options.textButtons);
  config->writeEntry("NextStr",options.nextStr);
  config->writeEntry("PrevStr",options.prevStr);
  config->writeEntry("BackStr",options.backStr);
  config->writeEntry("NextPic",options.nextPic);
  config->writeEntry("PrevPic",options.prevPic);
  config->writeEntry("BackPic",options.backPic);
  config->writeEntry("BackColor",options.backColor.name());
  config->writeEntry("TableColor",options.tableColor.name());
  config->writeEntry("TextColor",options.textColor.name());
  config->writeEntry("VisitedColor",options.visitedColor.name());
  config->writeEntry("ImageBackColor",options.imageBackColor.name());
  config->writeEntry("ImageTextColor",options.imageTextColor.name());
  config->writeEntry("ImageVisitedColor",options.imageVisitedColor.name());
  config->writeEntry("FullsizeTemplate",options.fullsizeTemplate);
  config->writeEntry("GalleryTemplate",options.galleryTemplate);
  config->writeEntry("GalleryCSSFile",options.galleryCSSFile);
  config->writeEntry("BeforeHtmlFile",options.beforeHtmlFile);
  config->writeEntry("AfterHtmlFile",options.afterHtmlFile);
  config->writeEntry("ImageCSSFile",options.imageCSSFile);

  config->setGroup("Descriptions");
  KalleryGlobals::ref()->options.descFile = QFileInfo(options.projectFileName).baseName()+".descriptions";
  config->writeEntry("DescFile", KalleryGlobals::ref()->options.descFile);
  config->writeEntry("DescSetting",options.descSetting);
  config->writeEntry("InfoSetting", options.infoSetting); 

  config->sync();
  delete config;

  return true;
}


bool KalleryFunctions::openProject(const QString& projectFileName)
{
  QFile projectFile;
  KSimpleConfig *config;
  OptionType options = KalleryGlobals::ref()->options;

  projectFile.setName(projectFileName);
  if ( (! projectFile.open(IO_ReadOnly)) ||  (!projectFile.exists()) )
  {
    KMessageBox::error(mainWidget,i18n("Cannot open the project file %1.\nSelect another file and try again.").arg(projectFileName),i18n("Error"));
    return false;
  }
  projectFile.close();

  config = new KSimpleConfig(projectFileName,false);
  config->setGroup("General");
  QString version = config->readEntry("kallery_version");
  if ((version == 0)  || (version != "Project_Format_1"))
  {
    KMessageBox::error(mainWidget,i18n("The file %1 is not a valid Kallery project.\nSelect another file and try again.").arg(projectFileName),i18n("Error"));
    return false;
  }
  options.encoding = config->readEntry("Encoding", "utf8");
  options.relativePaths = config->readBoolEntry("RelativePaths",true);
  options.projectFileName = QFileInfo(projectFileName).dirPath() + "/"+config->readEntry("ProjectName");
  options.fileName = projectFileName;

  config->setGroup("Gallery");
  options.galleryTitle = config->readEntry("GalleryTitle",i18n("Image gallery"));
  options.galleryFile =  config->readPathEntry("GalleryFile",QDir::currentDirPath() + "/myGallery/gallery.html");
  options.imageDestDir = config->readPathEntry("ImageDestDir",QDir::currentDirPath() + "/myGallery/fullsize");
  options.thumbDestDir = config->readPathEntry("ThumbDestDir",QDir::currentDirPath() + "/myGallery/thumbs");
  options.language = config->readEntry("Language", "United Kindom (gb)");

  config->setGroup("Thumbnails");
  options.thumbSetting = (OptionType::ThumbSettings) config->readUnsignedNumEntry("ThumbSetting", OptionType::GenerateThumbnails);
  options.thumbWidth = config->readUnsignedNumEntry("ThumbWidth", 100);
  options.thumbHeight = config->readUnsignedNumEntry("ThumbHeight", 75);
  options.thumbFormat = config->readEntry("ThumbFormat", "jpg");
  options.thumbList = config->readListEntry("ThumbList");

  config->setGroup("Images");
  options.convertImages =(OptionType::ConvertMode) config->readUnsignedNumEntry("ConvertImages", OptionType::Convert);
  options.resize = config->readBoolEntry("Resize", true);
  options.keepRatio = config->readBoolEntry("KeepRatio", true);
  options.onlyLarger = config->readBoolEntry("OnlyLarger", true);
  options.fullWidth = config->readUnsignedNumEntry("FullWidth", 600);
  options.fullHeight = config->readUnsignedNumEntry("FullHeight", 450);
  options.insertCopyright = config->readBoolEntry("InsertCopyright", true);
  options.copyright = config->readEntry("Copyright"," " + i18n("This year, You"));
  options.fullFormat = config->readEntry("FullFormat","jpg");
  options.quality = config->readUnsignedNumEntry("Quality", 80);
  options.imageList = config->readListEntry("ImageList");

  config->setGroup("HTML options");
  options.columnNum = config->readUnsignedNumEntry("ColumnNum",3);
  options.useHtmlImages = config->readBoolEntry("UseHtmlImages",true);
  options.textButtons = config->readBoolEntry("TextButtons",true);
  options.nextStr = config->readEntry("NextStr", i18n("Next"));
  options.prevStr = config->readEntry("PrevStr", i18n("Previous"));
  options.backStr = config->readEntry("BackStr", i18n("Back"));
  options.nextPic = config->readPathEntry("NextPic",KalleryGlobals::ref()->baseDir() + "images/next.png");
  options.prevPic = config->readPathEntry("PrevPic",KalleryGlobals::ref()->baseDir() + "images/prev.png");
  options.backPic = config->readPathEntry("BackPic", KalleryGlobals::ref()->baseDir() + "images/back.png");
  options.backColor.setNamedColor(config->readEntry("BackColor","#000000"));
  options.tableColor.setNamedColor(config->readEntry("TableColor","#000000"));
  options.textColor.setNamedColor(config->readEntry("TextColor","#FFFFFF"));
  options.visitedColor.setNamedColor(config->readEntry("VisitedColor","#AAAAAA"));
  options.imageBackColor.setNamedColor(config->readEntry("ImageBackColor","#000000"));
  options.imageTextColor.setNamedColor(config->readEntry("ImageTextColor","#FFFFFF"));
  options.imageVisitedColor.setNamedColor(config->readEntry("ImageVisitedColor","#AAAAAA"));
  options.fullsizeTemplate = config->readEntry("FullsizeTemplate",i18n("Buttons above the image"));
  options.galleryTemplate = config->readEntry("GalleryTemplate",i18n("Default template"));
  options.galleryCSSFile = config->readPathEntry("GalleryCSSFile");
  options.beforeHtmlFile = config->readPathEntry("BeforeHtmlFile");
  options.afterHtmlFile = config->readPathEntry("AfterHtmlFile");
  options.imageCSSFile = config->readPathEntry("ImageCSSFile");

  config->setGroup("Descriptions");
  options.descSetting = (OptionType::DescSettings)config->readUnsignedNumEntry("DescSetting", OptionType::LoadImageInfo);
  options.infoSetting = config->readUnsignedNumEntry("InfoSetting", OptionType::ImageInfoFileName);
  options.descFile = config->readPathEntry("DescFile");
  readDescriptions(QFileInfo(projectFileName).dirPath()+"/"+options.descFile, options.descList);

  for (uint i = options.descList.count(); i < options.imageList.count(); i ++)
  {
    options.descList.append(OptionType::Description());
  }

  if (options.relativePaths)
  {
    QString baseDir = QFileInfo(options.galleryFile).dirPath();
    QString CSSDir;
    makeAbsolutePath(baseDir,options.imageDestDir);
    makeAbsolutePath(baseDir,options.thumbDestDir);
    if (!options.galleryCSSFile.isEmpty())
    {
      CSSDir = QFileInfo(options.galleryCSSFile).dirPath();
      if (makeAbsolutePath(baseDir,CSSDir))
      {
        options.galleryCSSFile = CSSDir + QFileInfo(options.galleryCSSFile).fileName();
      }
    }
    if (!options.imageCSSFile.isEmpty())
    {
      CSSDir = QFileInfo(options.imageCSSFile).dirPath();
      if (makeAbsolutePath(options.imageDestDir,CSSDir))
      {
        options.imageCSSFile = CSSDir + QFileInfo(options.imageCSSFile).fileName();
      }
    }

    QString thumbDir;
    for (uint i=0; i < options.thumbList.count(); i++)
    {
      thumbDir = QFileInfo(options.thumbList[i]).dirPath();
      makeAbsolutePath(baseDir,thumbDir);
      options.thumbList[i] = thumbDir + QFileInfo(options.thumbList[i]).fileName();
    }
  }
  delete config;
  KalleryGlobals::ref()->options = options;
  return true;
}

#define MagickPI  3.14159265358979323846264338327950288419716939937510

static inline double DegreesToRadians(const double degrees)
{
  return(MagickPI*degrees/180.0);
}


//FIXME: progress should go away...
bool KalleryFunctions::convertImages(QProgressDialog* progress)
{
  QString fullName;
  QString thumbName;
  QString fileFormat;
  QString destDir;
  ExceptionInfo exception;
  Image *source;
  Image *thumbnail;
  ImageInfo *source_info;
  ImageInfo *thumbnail_info;
  OptionType options = KalleryGlobals::ref()->options;

  kdDebug() << "Starting the image conversion." << endl;

  bool printToStdOut = KalleryGlobals::ref()->options.printToStdOut;
  cancelPressed = false;
  connect(progress,SIGNAL(cancelled()),this,SLOT(slotProgressCancelled()));

  
  if (KalleryGlobals::ref()->options.descSetting == OptionType::LoadImageInfo)
      options.descList.clear();
  
  GetExceptionInfo(&exception);

  for (uint i = 0; i < options.imageList.count(); i++)
  {
    if (cancelPressed)
    {
      if (KMessageBox::questionYesNo(mainWidget,i18n("Do you really want to quit?"),
                                     i18n("Quit"), KGuiItem(i18n("&Quit"), BarIconSet("exit")),KGuiItem(i18n("&Don't quit"), BarIconSet("cancel"))) == KMessageBox::Yes)
      {
        return false;
      }
      cancelPressed = false;
    }
    progress->setProgress(i+1);
    progress->setLabelText(i18n("Processing file: [%1]").arg(QFileInfo(options.imageList[i]).fileName()));

    if (QFileInfo(options.imageList[i]).exists())
    {
      source_info = CloneImageInfo((ImageInfo *) 0);
      strcpy(source_info->filename,options.imageList[i].latin1());
      if (!SetImageInfo(source_info, MagickTrue,&exception))
      {
        MagickWarning(exception.severity,exception.reason,exception.description);
        KMessageBox::error(mainWidget,i18n("[%1  %2]\nSeverity %3\nSkipping to next image...") \
                                              .arg(exception.reason).arg(exception.description).arg(exception.severity),
                                              i18n("ImageMagick error"));
        DestroyImageInfo(source_info);
        continue;
       }

      kdDebug() << "source_info->filename = " <<  source_info->filename << endl;
      source  = ReadImage(source_info,&exception);

      if (source == 0)
      {
        MagickWarning(exception.severity,exception.reason,exception.description);
        KMessageBox::error(mainWidget,i18n("[%1  %2]\nSeverity %3\nSkipping to next image...") \
                                              .arg(exception.reason).arg(exception.description).arg(exception.severity),
                                              i18n("ImageMagick error"));
        DestroyImageInfo(source_info);
        continue;
      }
            
      kapp->processEvents(QEventLoop::ExcludeSocketNotifiers);
      if (options.thumbSetting == OptionType::GenerateThumbnails)
      {
        thumbnail = CloneImage(source,0,0, MagickFalse,&exception);
        thumbnail_info = CloneImageInfo(source_info);
        if (thumbnail == 0)
        {
          MagickWarning(exception.severity,exception.reason,exception.description);
          KMessageBox::error(mainWidget,i18n("[%1  %2]\nSeverity %3\nSkipping to next image...") \
                                              .arg(exception.reason).arg(exception.description).arg(exception.severity),
                                              i18n("ImageMagick error"));
          DestroyImageInfo(thumbnail_info);
          DestroyImageInfo(source_info);
          continue;
        }
        fileFormat = QString("%1x%2").arg(options.thumbWidth).arg(options.thumbHeight);
        TransformImage(&thumbnail,"",fileFormat.latin1());
        strcpy(thumbnail->magick,options.thumbFormat.upper().latin1());

        QString thumbName = options.thumbList[i].latin1();
        destDir = QFileInfo(thumbName).dirPath();
        makeAbsolutePath(QFileInfo(options.galleryFile).dirPath(),destDir);
        thumbName = destDir  + QFileInfo(thumbName).fileName();

        if (printToStdOut)
          printf("%s\n",thumbName.latin1());
        strcpy(thumbnail->filename,thumbName);
        if (WriteImage(thumbnail_info,thumbnail) == 0)
        {
          if (KMessageBox::questionYesNo(mainWidget,i18n("%1.  [%2]\nSeverity %3\n\nThe thumbnail was not written!\nDo you want to continue with gallery generation?") \
                                               .arg(thumbnail->exception.reason). \
                                               arg(thumbnail->exception.description). \
                                               arg(thumbnail->exception.severity),
                                               i18n("ImageMagick error")) == KMessageBox::No)
          {
            DestroyImageInfo(thumbnail_info);
            DestroyImage(thumbnail);
            return false;
          }
        }
        DestroyImageInfo(thumbnail_info);
        DestroyImage(thumbnail);
      } // End the thumbnail generation
      kapp->processEvents(QEventLoop::ExcludeSocketNotifiers);
      if (options.convertImages == OptionType::Convert)
      {
        fullName = options.imageDestDir+QFileInfo(options.imageList[i]).baseName()+"."+options.fullFormat;
        strcpy(source->magick,options.fullFormat.upper().latin1());
        if (options.resize)
        {
          fileFormat = QString("%1x%2").arg(options.fullWidth).arg(options.fullHeight);
          if (!options.keepRatio)
            fileFormat += "!";
          if (options.onlyLarger)
            fileFormat += ">";
          TransformImage(&source,"",fileFormat);   
          SetImageAttribute(source, "EXIF:ExifImageWidth", QString("%1").arg(source->columns).latin1());       
          SetImageAttribute(source, "EXIF:ExifImageLength", QString("%1").arg(source->rows).latin1());       
        }
        if (options.insertCopyright)
        {                    
          DrawInfo *drawThis;
          TypeMetric metrics;

          CloneString(&source_info->font,"helvetica");
          source_info->pointsize = 14;

          drawThis = CloneDrawInfo(source_info,0);
          GetExceptionInfo(&exception);
          QueryColorDatabase("white",&drawThis->fill,&exception);
          CloneString(&drawThis->text,(const char *)options.copyright.utf8());
//           GetExceptionInfo(&exception);
          GetTypeMetrics(source,drawThis,&metrics);
          CloneString(&drawThis->primitive,(const char *)QString("text %1,%2 \""+options.copyright+"\"").arg(source->columns-metrics.width-10).arg(source->rows-5).utf8());
          DrawImage(source,drawThis);
          DestroyDrawInfo(drawThis);
        } //end of the copyrigth text addition
        destDir = QFileInfo(fullName).dirPath();
        makeAbsolutePath(QFileInfo(options.galleryFile).dirPath(),destDir);
        fullName = destDir  + QFileInfo(fullName).fileName();
        //Replace the name, so it will point to the generated image
        // when we save the "_generated" project file.
        source_info->quality = options.quality;
        options.imageList[i] = fullName;

        if (printToStdOut)
          printf("%s\n",fullName.latin1());
        strcpy(source->filename,fullName.latin1());
        if (WriteImage(source_info,source) == 0)
        {
          if (KMessageBox::questionYesNo(mainWidget,i18n("%1.  [%2]\nSeverity %3\n\nNew image was not written!\nDo you want to continue with gallery generation?") \
                                               .arg(source->exception.reason). \
                                               arg(source->exception.description). \
                                               arg(source->exception.severity),
                                               i18n("ImageMagick error")) == KMessageBox::No)
          {
            DestroyImageInfo(source_info);
            DestroyImage(source);
            return false;
          }
        }
      } //end of the image convertion
      else
      {
        destDir = options.imageDestDir;
        makeAbsolutePath(QFileInfo(options.galleryFile).dirPath(),destDir);
        if ((options.convertImages == OptionType::CopyOnly) &&
           (destDir != QFileInfo(options.imageList[i]).dirPath()+"/"))
        {
          KIO::Job * job = KIO::file_copy(options.imageList[i],destDir+QFileInfo(options.imageList[i]).fileName(),-1,true,false,false);
          connect( job, SIGNAL( result( KIO::Job * ) ), mainWidget, SLOT( slotResult( KIO::Job * ) ) );
          kapp->ref();
          // Replace the name, so it will point to the generated image
          // when we save the "_generated" project file.
          options.imageList[i] = destDir+QFileInfo(options.imageList[i]).fileName();

          if (printToStdOut)
            printf("%s\n",options.imageList[i].latin1());
        }
      } //end of the image copy
      if (KalleryGlobals::ref()->options.descSetting == OptionType::LoadImageInfo)
        options.descList.append(readImageInfo(source, options.imageList[i]));
      DestroyImageInfo(source_info);
      DestroyImage(source);
    } //end of  "if the file exists"
  } //for

  if (KalleryGlobals::ref()->options.descSetting == OptionType::LoadImageInfo)
  {
    KalleryGlobals::ref()->options.descList = options.descList;
  }
  kdDebug() << "Image conversion ended successfully. " <<  endl;

  return true;
}

void KalleryFunctions::createHtmlForImage(uint imageIndex,const QString &htmlName,const QString& language)
{
  QFile templateFile;
  QFile htmlFile;
  OptionType options = KalleryGlobals::ref()->options;
  QString templateFilename =  options.fullsizeTemplateFile;
  QString htmlFilename;
  QString tmpString;
  QString prevRef;
  QString prevButton;
  QString nextRef;
  QString nextButton;
  QString backRef;
  QString backButton;
  QString backTarget;
  QString imageFileName;
  
  bool printToStdOut = KalleryGlobals::ref()->options.printToStdOut;

  switch (options.convertImages)
  {
    case OptionType::NoCopyConvert:
      imageFileName = options.imageList[imageIndex];
      break;
    case OptionType::CopyOnly:
    case OptionType::UseExisting:
      imageFileName = QFileInfo(options.imageList[imageIndex]).baseName() + "." + QFileInfo(options.imageList[imageIndex]).extension().lower();
      break;
    case OptionType::Convert:
      imageFileName = QFileInfo(options.imageList[imageIndex]).baseName()+"."+options.fullFormat;
      break;
  }

  tmpString = QFileInfo(htmlName).dirPath();
  makeAbsolutePath(QFileInfo(options.galleryFile).dirPath(),tmpString);
  htmlFilename = tmpString+QFileInfo(htmlName).fileName();

  /*Create the next and/or previous text or bitmap buttons, if needed */
  if (imageIndex > 0)
  {
    prevRef = QFileInfo(options.imageList[imageIndex-1]).baseName()+"_"+language+".html";
    if (! options.textButtons)
    {
      if (!options.prevPic.isEmpty())
        prevButton="<img src=\""+QFileInfo(options.prevPic).fileName() +"\" align=\"middle\" alt=\""+options.prevStr+"\" border=0>";
    }
    else
    {
      prevButton = options.prevStr;
    }
  }
  if (imageIndex+1 < options.imageList.count())
  {
    nextRef = QFileInfo(options.imageList[imageIndex+1]).baseName()+"_"+language+".html";
    if (! options.textButtons)
    {
      if (!options.nextPic.isEmpty())
        nextButton="<img src=\""+QFileInfo(options.nextPic).fileName() +"\" align=\"middle\" alt=\""+options.nextStr+"\" border=0>";
    }
    else
    {
      nextButton = options.nextStr;
    }
  }

  /*Set the back button or text*/
  tmpString = options.imageDestDir;
  makeAbsolutePath(QFileInfo(options.galleryFile).dirPath(),tmpString);
  QString tmpString2;
  tmpString2 =  QFileInfo(options.galleryFile).dirPath() + "/";
  if (options.relativePaths)
    makeRelativePath(tmpString,tmpString2);
  backRef = tmpString2 + QFileInfo(options.galleryFile).fileName();

  if (! options.textButtons)
  {
    if (!options.backPic.isEmpty())
      backButton="<img src=\""+QFileInfo(options.backPic).fileName() +"\" align=\"middle\" alt=\""+options.backStr+"\" border=0>";
  }
  else
  {
    backButton = options.backStr;
  }

  if (options.useFrames)
  {
    backTarget = "_parent";
  }
  else
  {
    backTarget = "_self";
  }

  /*Start to build the html, using the selected fullsize template*/
  templateFile.setName(templateFilename);
  if (!templateFile.open(IO_ReadOnly))
  {
    KMessageBox::error(mainWidget,i18n("Cannot open the template file %1 for reading.").arg(templateFilename),i18n("Input/Output error"));
    return;
  }
  htmlFile.setName(htmlFilename);
  if (!htmlFile.open(IO_WriteOnly))
  {
    KMessageBox::error(mainWidget,i18n("Cannot open the file %1 for writing.").arg(htmlFilename),i18n("Input/Output error"));
    templateFile.close();
    return;
  }

  if (printToStdOut)
    printf("%s\n", htmlFilename.latin1());

  QTextStream templateFileStream(&templateFile);
  QTextStream htmlFileStream(&htmlFile);
  templateFileStream.setEncoding(QTextStream::UnicodeUTF8);
  htmlFileStream.setCodec(QTextCodec::codecForName(options.encoding));

  while (! templateFileStream.atEnd())
  {
    tmpString = templateFileStream.readLine();

    tmpString.replace(QRegExp("%CSSFILE%"),options.imageCSSFile);
    tmpString.replace(QRegExp("%BACKCOLOR%"),options.imageBackColor.name());
    tmpString.replace(QRegExp("%TEXTCOLOR%"),options.imageTextColor.name());
    tmpString.replace(QRegExp("%VISITEDCOLOR%"),options.imageVisitedColor.name());
    tmpString.replace(QRegExp("%TITLE%"),imageFileName);
    tmpString.replace(QRegExp("%IMAGENAME%"),imageFileName);
    tmpString.replace(QRegExp("%IMAGEDESC%"),options.descList[imageIndex].full());
    tmpString.replace(QRegExp("%COMMENT%"),options.descList[imageIndex].comment);
    tmpString.replace(QRegExp("%FILESIZE%"),options.descList[imageIndex].fileSize);
    tmpString.replace(QRegExp("%DIMENSION%"),options.descList[imageIndex].dimension);
    tmpString.replace(QRegExp("%DATE%"),options.descList[imageIndex].shootingDate);
    tmpString.replace(QRegExp("%EXPOSURE%"),options.descList[imageIndex].exposureInfo);    tmpString.replace(QRegExp("%IMAGENAME%"),imageFileName);
    tmpString.replace(QRegExp("%CHARSET%"),convertEncodingName(options.encoding));
    tmpString.replace(QRegExp("%PREVREF%"),prevRef);
    tmpString.replace(QRegExp("%PREVNAME%"),options.prevStr);
    tmpString.replace(QRegExp("%PREVBUTTON%"),prevButton);

    tmpString.replace(QRegExp("%NEXTREF%"),nextRef);
    tmpString.replace(QRegExp("%NEXTNAME%"),options.nextStr);
    tmpString.replace(QRegExp("%NEXTBUTTON%"),nextButton);

    tmpString.replace(QRegExp("%BACKREF%"),backRef);
    tmpString.replace(QRegExp("%BACKNAME%"),options.backStr);
    tmpString.replace(QRegExp("%BACKBUTTON%"),backButton);
    tmpString.replace(QRegExp("%BACKTARGET%"),backTarget);
    htmlFileStream << tmpString << "\n";
  }

  templateFile.close();
  htmlFile.close();
}

void KalleryFunctions::createHtmls(QProgressDialog *progress)
{
  QString tmpString;
  QString rowTemplate;
  QString baseName;
  QString fileName;
  KURL::List copySourceList;
  KURL::List copyDestList;
  QString languageString;
  OptionType options = KalleryGlobals::ref()->options;
  QString galleryTemplateFilename = options.galleryTemplateFile;
  QString galleryFilename = options.galleryFile;
  QFile templateFile;
  QFile galleryFile;
  QString mainFrameFileName;

  kdDebug() << "Creating the htmls." << endl;

  bool printToStdOut = KalleryGlobals::ref()->options.printToStdOut;
  languageString = options.language;
  languageString = languageString.mid(languageString.find('(')+1,10);
  languageString.truncate(languageString.find(')'));

  kdDebug() << "The gallery template files is: " << galleryTemplateFilename << endl;
  kdDebug() << "The fullsize template files is: " << options.fullsizeTemplate << endl;

  /*Start to build up the gallery html file, using the template*/
  templateFile.setName(galleryTemplateFilename);
  if (!templateFile.open(IO_ReadOnly))
  {
    KMessageBox::error(mainWidget,i18n("Cannot open the template file %1 for reading.").arg(galleryTemplateFilename),i18n("Input/Output error"));
    return;
  }
  
  QTextStream str(&templateFile);
  str.setEncoding(QTextStream::UnicodeUTF8);
  while (!str.atEnd())
  {
    tmpString = str.readLine();
    if (tmpString.contains("MAINFRAMEFILE="))
    {
      options.useFrames = true;
      KalleryGlobals::ref()->options.useFrames = true;
      mainFrameFileName = tmpString.replace("MAINFRAMEFILE=", "").stripWhiteSpace();
      break;
    }
  }
  templateFile.close();
  if (options.useFrames)
  {
    galleryFilename = QFileInfo(options.galleryFile).dirPath() + "/gallery_frame.html";

    copySourceList.append(KalleryGlobals::ref()->baseDir() + "htmls/" + mainFrameFileName);
    copyDestList.append(options.galleryFile);
    copySourceList.append(KalleryGlobals::ref()->baseDir() + "htmls/description.html");
    copyDestList.append(QFileInfo(options.galleryFile).dirPath() + "/description.html");
  }

  /*Copy the next, previous and back button images to the image directory*/

  if (!options.textButtons)
  {
    tmpString = options.imageDestDir;
    makeAbsolutePath(QFileInfo(options.galleryFile).dirPath(),tmpString);
    if (QFileInfo(options.prevPic).exists())
    {
      copySourceList.append(options.prevPic);
      if (!options.prevPic.contains(languageString))
      {
        KalleryGlobals::ref()->options.prevPic = tmpString + QFileInfo(options.prevPic).baseName()+"_"+
                         languageString + "."+ QFileInfo(options.prevPic).extension();
      }
      else
      {
        KalleryGlobals::ref()->options.prevPic = tmpString + QFileInfo(options.prevPic).fileName();
      }
      copyDestList.append(KalleryGlobals::ref()->options.prevPic);
    }
    if (QFileInfo(options.nextPic).exists())
    {
      copySourceList.append(options.nextPic);
      if (!options.nextPic.contains(languageString))
      {
        KalleryGlobals::ref()->options.nextPic = tmpString + QFileInfo(options.nextPic).baseName()+"_"+
                        languageString + "."+ QFileInfo(options.nextPic).extension();
      }
      else
      {
        KalleryGlobals::ref()->options.nextPic = tmpString + QFileInfo(options.nextPic).fileName();
      }
      copyDestList.append(KalleryGlobals::ref()->options.nextPic);
    }
    if (QFileInfo(options.backPic).exists())
    {
      copySourceList.append(options.backPic);
      if (!options.backPic.contains(languageString))
      {
        KalleryGlobals::ref()->options.backPic = tmpString + QFileInfo(options.backPic).baseName()+"_"+
                        languageString + "."+ QFileInfo(options.backPic).extension();
      }
      else
      {
        KalleryGlobals::ref()->options.backPic = tmpString + QFileInfo(options.backPic).fileName();
      }
      copyDestList.append(KalleryGlobals::ref()->options.backPic);
    }
  }

  for (uint i = 0; i < copySourceList.count(); i++)
  {
    if (copySourceList[i] != copyDestList[i])
    {
      KIO::Job* job= KIO::file_copy(copySourceList[i],copyDestList[i],-1,true,true,false);
      connect( job, SIGNAL( result( KIO::Job * ) ), mainWidget, SLOT( slotResult( KIO::Job * ) ) );
      kapp->ref();
      if (printToStdOut)
        printf("%s\n",copyDestList[i].path().latin1());
    }
  }
  
  templateFile.setName(galleryTemplateFilename);
  if (!templateFile.open(IO_ReadOnly))
  {
    KMessageBox::error(mainWidget,i18n("Cannot open the template file %1 for reading.").arg(galleryTemplateFilename),i18n("Input/Output error"));
    return;
  }

  galleryFile.setName(galleryFilename);
  if (!galleryFile.open(IO_WriteOnly))
  {
    KMessageBox::error(mainWidget,i18n("Cannot open the gallery file %1 for writing.").arg(galleryFilename),i18n("Input/Output error"));
    templateFile.close();
    return;
  }

  if (printToStdOut)
    printf("%s,[MAIN GALLERY]\n",galleryFilename.latin1());

  QTextStream galleryTemplateStream(&templateFile);
  QTextStream galleryFileStream(&galleryFile);

  galleryTemplateStream.setEncoding(QTextStream::UnicodeUTF8);
  galleryFileStream.setCodec(QTextCodec::codecForName(options.encoding));

  while (! galleryTemplateStream.atEnd())
  {
    tmpString = galleryTemplateStream.readLine();
    tmpString.replace(QRegExp("%TITLE%"),options.galleryTitle);
    tmpString.replace(QRegExp("%BACKCOLOR%"),options.backColor.name());
    tmpString.replace(QRegExp("%TABLECOLOR%"),options.tableColor.name());
    tmpString.replace(QRegExp("%TEXTCOLOR%"),options.textColor.name());
    tmpString.replace(QRegExp("%VISITEDCOLOR%"),options.visitedColor.name());
    tmpString.replace(QRegExp("%CSSFILE%"),options.galleryCSSFile);
    tmpString.replace(QRegExp("%CHARSET%"),convertEncodingName(options.encoding));
    /*copy the content of options.beforeHtmlFile to the gallery html*/
    if (tmpString.contains("Html formatted text before the table"))
    {
      insertFile(options.beforeHtmlFile,galleryFileStream);
      tmpString = "";
    }
    /*copy the content of options.afterHtmlFile to the gallery html*/
    if (tmpString.contains("Html formatted text after the table"))
    {
      insertFile(options.afterHtmlFile,galleryFileStream);
      tmpString = "";
    }
    /*Start to build the tables */
    if (tmpString.contains("Table begins here"))
    {
      rowTemplate = galleryTemplateStream.readLine();

      for (uint i=0; i < options.imageList.count(); i++)
      {
        progress->setProgress(i+1+options.imageList.count());
        if ( (options.columnNum !=0) && (i % options.columnNum) == 0)
        {
          galleryFileStream << "<tr>\n";
        }

        tmpString = rowTemplate;
        baseName =  options.imageDestDir+ QFileInfo(options.imageList[i]).baseName() + "_" + languageString + ".";
        /*If we don't convert the images, we must keep the original extension of them,
        otherwise we must replace the extension with the options.fullFormat*/
        if (options.convertImages == OptionType::Convert)
        {
          fileName =  QFileInfo(options.imageList[i]).baseName()+"."+options.fullFormat;
        }
        else
        {
          fileName =  QFileInfo(options.imageList[i]).fileName();
        }

        if (options.useHtmlImages)
        {
          tmpString.replace(QRegExp("%IMAGEREF%"),baseName+"html");
          tmpString.replace(QRegExp("%MIMETYPE%"),"text/html");
          createHtmlForImage(i,baseName+"html",languageString);
        }
        else
        {
          tmpString.replace(QRegExp("%IMAGEREF%"),options.imageDestDir +fileName);
          tmpString.replace(QRegExp("%MIMETYPE%"),"image/"+QFileInfo(fileName).extension());
        }

        /*What to do, if there is no thumbnail used...*/
        if (options.thumbSetting == OptionType::NoThumbnails)
        {
          tmpString.replace(QRegExp("<img src=\"%IMAGESRC%\" alt=\"%ALTNAME%\" border=0><br>"),"");
        }
        /*...and when they are generated...*/
        if (options.thumbSetting == OptionType::GenerateThumbnails)
        {
          tmpString.replace(QRegExp("%IMAGESRC%"),options.thumbDestDir+
                             QFileInfo(options.imageList[i]).baseName()+"."+options.thumbFormat);
        }
        /*...and when we use an already generated thumbnail list.*/
        if (options.thumbSetting == OptionType::LoadThumbnails)
        {
          tmpString.replace(QRegExp("%IMAGESRC%"),options.thumbList[i]);
        }

        tmpString.replace(QRegExp("%ALTNAME%"),fileName);
        tmpString.replace(QRegExp("%IMAGENAME%"), QFileInfo(fileName).fileName());
        tmpString.replace(QRegExp("%IMAGEDESC%"),options.descList[i].full());
        tmpString.replace(QRegExp("%COMMENT%"),options.descList[i].comment);
        tmpString.replace(QRegExp("%FILESIZE%"),options.descList[i].fileSize);
        tmpString.replace(QRegExp("%DIMENSION%"),options.descList[i].dimension);
        tmpString.replace(QRegExp("%DATE%"),options.descList[i].shootingDate);
        tmpString.replace(QRegExp("%EXPOSURE%"),options.descList[i].exposureInfo);    
        if ( (options.columnNum !=0) && ((i+1) % options.columnNum) == 0)
          tmpString += "\n</tr>";
        galleryFileStream << tmpString << "\n";
      }
      if ( (options.columnNum !=0) && (options.imageList.count() % options.columnNum) != 0)
        galleryFileStream <<  "</tr>\n";
      tmpString = "";
    }
    galleryFileStream << tmpString << "\n";
  }
  
  templateFile.close();
  galleryFile.close();
  
  if (options.useFrames)
  {
    QFile mainFrameFile(options.galleryFile);
    if (mainFrameFile.open(IO_ReadOnly))
    {
      QTextStream str(&mainFrameFile);
      str.setEncoding(QTextStream::UnicodeUTF8);
      QString s = str.read();
      s.replace(QRegExp("%TITLE%"),options.galleryTitle);
      mainFrameFile.close();
      if (mainFrameFile.open(IO_WriteOnly))
      { 
        QTextStream str2(&mainFrameFile);
        str2.setEncoding(QTextStream::UnicodeUTF8);
        str2 << s;
        mainFrameFile.close();
      }
    }
    
  }


  kdDebug() << "Html generation successful." << endl;
}

bool KalleryFunctions::readDescriptions(const QString& fileName, QValueList<OptionType::Description>& descList)
{
  QFile inFile(fileName.latin1());
  QString tmpString;

  if (!inFile.open(IO_ReadOnly))
  {
    KMessageBox::error(mainWidget,i18n("Cannot open the description file %1 for reading.").arg(fileName),i18n("Input/Output error"));
    return false;
  }

  descList.clear();
  QTextStream in(&inFile);
  in.setEncoding(QTextStream::UnicodeUTF8);

  while (! in.atEnd())
  {
    tmpString = in.readLine();
    tmpString.replace(QRegExp("<br>"),"\n");
    OptionType::Description desc;
    desc.comment = tmpString;
    descList.append(desc);
  }
  inFile.close();

  return true;
}

OptionType::Description KalleryFunctions::readImageInfo(Image *source, const QString &fileName)
{
  OptionType options = KalleryGlobals::ref()->options;
    
  OptionType::Description description;
  const ImageAttribute *attribute;
  
  if (options.infoSetting & OptionType::ImageInfoComment)
  {
    attribute = GetImageAttribute(source, "comment");
    if ((attribute != 0L) && (attribute->value != 0L))
    {
      description.comment = attribute->value;
    }
  }
  
  if (options.infoSetting & OptionType::ImageInfoFileSize)
  {
    description.fileSize = i18n("Size: %1 bytes").arg(QFileInfo(fileName).size());
  }

  if (options.infoSetting & OptionType::ImageInfoDimensions)
  {
    attribute = GetImageAttribute(source, "EXIF:ExifImageWidth");
    QString s1, s2;
    if ((attribute != 0L) && (attribute->value != 0L))
    {
      s1 = attribute->value;
    }
    attribute = GetImageAttribute(source, "EXIF:ExifImageLength");
    if ((attribute != 0L) && (attribute->value != 0L))
    {
      s2 = attribute->value;
    }
    description.dimension = i18n("Dimensions: %1x%2").arg(s1).arg(s2);
  }
  if (options.infoSetting & OptionType::ImageInfoShootingDate)
  {
    attribute = GetImageAttribute(source, "EXIF:DateTimeOriginal");
    if ((attribute != 0L) && (attribute->value != 0L))
    {
      QString s(attribute->value);
      description.shootingDate = i18n("Date: %1").arg(s.left(s.find(' ')));      
    }
  }
  if (options.infoSetting & OptionType::ImageInfoExposure)
  {
    QString s;
    attribute = GetImageAttribute(source, "EXIF:Model");
    if ((attribute != 0L) && (attribute->value != 0L))
    {
      s.append(i18n("Camera: "));
      s.append(attribute->value);
      s.append("<br>");
    }
    attribute = GetImageAttribute(source, "EXIF:ExposureTime");
    if ((attribute != 0L) && (attribute->value != 0L))
    {
      s.append(i18n("Exposure: "));
      s.append(attribute->value);
      s.append("s<br>");
    }
    attribute = GetImageAttribute(source, "EXIF:FNumber");
    if ((attribute != 0L) && (attribute->value != 0L))
    {
      QString s2(attribute->value);
      float value = s2.left(s2.find('/')).toInt() / s2.mid(s2.find('/') + 1).toInt();
      s.append(i18n("Aperture: "));
      s.append("f");
      s.append(QString("%1").arg(value));
    }
    description.exposureInfo = s;
  }
  return description;
}

bool KalleryFunctions::writeDescriptions(const QString& fileName, QValueList<OptionType::Description>& descList)
{
  QFile outFile(fileName.latin1()) ;
  if (!outFile.open(IO_WriteOnly))
  {
    KMessageBox::error(mainWidget,i18n("Cannot open the description file %1 for writing.").arg(fileName),i18n("Input/Output error"));    
    return false;
  }

  QTextStream out(&outFile);
  out.setEncoding(QTextStream::UnicodeUTF8);

  for (uint i =0; i < descList.count(); i++)
  {
    descList[i].comment.replace(QRegExp("\n"),"<br>");
    out << descList[i].comment << "\n";
  }

  outFile.close();

  return true;
}

void KalleryFunctions::slotProgressCancelled()
{
  cancelPressed = true;
}

void KalleryFunctions::insertFile(QString& sourceName, QTextStream & destStream)
{  
  QString tmpString;

  if (sourceName.isEmpty())
    return;
  QFile sourceFile(sourceName);
  if (!sourceFile.open(IO_ReadOnly))
  {
    KMessageBox::error(mainWidget,i18n("Cannot open the file %1 for reading.").arg(sourceName),i18n("Input/Output error"));
    return;
  }
  QTextStream sourceStream(&sourceFile);
  sourceStream.setEncoding(QTextStream::UnicodeUTF8);

  while (! sourceStream.atEnd())
  {
    tmpString = sourceStream.readLine() + "\n";
    destStream << tmpString;
  }

  sourceFile.close();
}

QString KalleryFunctions::convertEncodingName(const QString &encoding)
{
  QString str = encoding;
  str.replace("iso ", "iso-"); //it's said that "iso-8859-x" is the valid format
  str.replace("utf", "utf-"); //it's said that "utf-x" is the valid format
  str.replace("cp ", "windows-");
  return str;
}

#include "kalleryfunctions.moc"
