/***************************************************************************
                          Digikam.cpp  -  description
                             -------------------
    begin                : Thu Dec 20 12:40:20 CST 2001
    copyright            : (C) 2001 by Renchi Raju
    email                : renchi@green.tam.uiuc.edu
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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 "digikam.h"

#include <qiconview.h>
#include <qdir.h>
#include <qfileinfo.h>
#include <qfile.h>
#include <qimage.h>
#include <qpixmap.h>
#include <qlayout.h>

#include <kmessagebox.h>
#include <kcombobox.h>
#include <kfiledialog.h>
#include <klocale.h>
#include <kstddirs.h>

#include "setup.h"
#include "fileOp.h"

#include <iostream.h>

QMap<Camera *, Digikam *> Digikam::my_cameraMap;

Digikam::Digikam(QWidget *parent, const char *name) : Digikam_MainWindow(parent, name), 
						      my_camera(NULL)
{

  statusBar = new KStatusBar(this);
  statusBar->insertFixedItem("Downloading Image XXXXXXX", 0, false);
  statusBar->setItemAlignment(0, AlignLeft | AlignVCenter);
  Digikam_MainWindowLayout->addMultiCellWidget( statusBar, 5, 7, 0, 3);

  progressBar=new KProgress(this);
  progressBar->setBarStyle(KProgress::Blocked);
  progressBar->setTextEnabled(true);
  Digikam_MainWindowLayout->addMultiCellWidget( progressBar, 5, 7, 3, 6);

  setStatusMsg("Ready.");

  IconView->setGridX(95);
  IconView->setGridY(95);
  IconView->setAutoArrange(true);
  IconView->setSorting(true);
  IconView->setResizeMode(QIconView::Adjust);
  IconView->setWordWrapIconText(true);
  IconView->setSelectionMode(QIconView::Extended);
  IconView->setItemsMovable(false);


  dirBox->insertItem(QDir::currentDirPath(),0);
  dirBox->insertItem(QDir::homeDirPath());  

  initGlobals();


}

Digikam::~Digikam()
{
  if (my_camera) {
    gp_camera_unref(my_camera);
    my_camera = NULL;
  }
  
  delete IconView;
  delete statusBar;
  delete progressBar;

}



void Digikam::initGlobals() {

  /* Initialize camera values */

  my_camera = NULL;
  my_cameraModel = "";
  my_cameraPort = "";
  my_cameraPortPath = "";
  my_cameraFolder = "/";
  my_cameraNumFolders = 0;

  //gp_log_add_func (GP_LOG_ALL, debug_func, NULL);

  /* Create (if not existing already) temp dir for 
     storing thumbnails and clean it */

  globTempDir = QDir::homeDirPath()+"/tmp/digikam";
  QDir dir(globTempDir);

  if (!dir.exists()) {
    if (KStandardDirs::makeDir(globTempDir))
      qWarning("Created dir");
    else
      qWarning("Failed to create dir");
  }
  else {

    const QFileInfoList *fileList;

    fileList = dir.entryInfoList();

    QFileInfoListIterator it(*fileList);
    QFileInfo *fi;
    QString fileNameWithPath;
    
    while(fi = it.current()){
      if(fi->fileName() == "." || fi->fileName() == "..")
	;
      else {
	fileNameWithPath = dir.path()+"/"+fi->fileName();
	qWarning(fileNameWithPath);
	dir.remove(fileNameWithPath);
      }
      ++it;
    }
  }

  my_cameraInitialised=false;
    
  qWarning("Digikam good to go");

}



int Digikam::initCamera() {

  CameraAbilitiesList *abilList;
  GPPortInfoList *infoList;
  CameraAbilities abilities;
  GPPortInfo info;
  char model[64], port[128];
  int modelNum = -1, portNum = -1;

  setStatusMsg("Initializing camera.");

  gp_setting_get ("digikam", "model", model);
  gp_setting_get ("digikam", "port", port);

  
  my_cameraModel = model;
  my_cameraPort = port;

  if (my_cameraModel == "" || my_cameraPort == "") {
        KMessageBox::error(this,"Camera Model or Port Setting\n"
		       "not specified correctly!\n"
		       "Please, run Setup");
    return 1;
  }

  gp_camera_new(&my_camera);
  gp_abilities_list_new (&abilList);
  gp_abilities_list_load (abilList);
  gp_port_info_list_new (&infoList);
  gp_port_info_list_load (infoList);


  modelNum=gp_abilities_list_lookup_model(abilList,my_cameraModel);
  portNum=gp_port_info_list_lookup_path (infoList, my_cameraPort);

  gp_abilities_list_get_abilities (abilList, modelNum, &abilities);
  if (gp_camera_set_abilities (my_camera, abilities) != GP_OK) {
    KMessageBox::error(this,"Failed to initialize camera!\n"
		       "Make sure the camera is connected\n"
		       "properly and powered on.");
    gp_camera_free(my_camera);
    return 1;
  }
  
  gp_port_info_list_get_info(infoList, portNum, &info);
  if (gp_camera_set_port_info (my_camera, info) != GP_OK) {
    KMessageBox::error(this,"Failed to initialize camera!\n"
		       "Make sure the camera is connected\n"
		       "properly and powered on.");
    gp_camera_free(my_camera);
    return 1;
  }
  

  gp_abilities_list_free (abilList);
  gp_port_info_list_free (infoList);

  if (gp_camera_init(my_camera)<0) {
    KMessageBox::error(this,"Failed to initialize camera!\n"
		       "Make sure the settings are correct.\n"
		       "Also ensure the camera is connected\n"
		       "properly and powered on.");
    gp_camera_free(my_camera);
    return 1;
  } 



  if (!(my_cameraMap.contains(my_camera))) {
    my_cameraMap[my_camera]=this;
    qWarning("Inserted camera into cameraMap");
  }
  else {
    qWarning("Camera already present in map. not inserting");
  }  


  gp_camera_set_status_func (my_camera, status_func, NULL);
  gp_camera_set_progress_func (my_camera, progress_func, NULL);
  gp_camera_set_message_func (my_camera, message_func, NULL);

  setStatusMsg("Camera initialized."); 
  my_cameraInitialised=true;

  return 0;

}


void Digikam::slot_connectToCamera()
{
  
  if (!(my_cameraInitialised)) {
    if (initCamera()!=0)  {
      setStatusMsg("Abort.");	
      return;
    }
  }

  my_cameraFolderList.clear();
  my_cameraFolderList += my_cameraFolder;
  getFolderNames(my_cameraFolder);
  my_cameraNumFolders= my_cameraFolderList.count();
  
  getThumbNails();

  updateThumbNails(); 

}


void Digikam::slot_selectAll() {
  IconView->selectAll(true);
}


void Digikam::slot_browse() {
  
  QString result = 
    KFileDialog::getExistingDirectory( dirBox->text(dirBox->currentItem()),
				       this );
  if (!result.isEmpty()) {
    for (int i = 0; i < dirBox->count(); i++)
      if (result == dirBox->text(i)) {
	dirBox->setCurrentItem(i);
	return;
      }
    dirBox->insertItem(result, 0);
    dirBox->setCurrentItem(0);
  }
  
}

void Digikam::slot_downloadImages() {

  const char *my_cameraFile;
  CameraFile *cameraFile;
  CameraList *my_cameraListFiles;
  QString saveFile;
  QString saveDir;
  QString folder;
  QString my_cameraFileString;
  QIconViewItem* iconViewItem;
  bool overwriteallmode=false;
  bool skipallmode=false;
  bool savefilemode=true;

  int j=0;


  saveDir=dirBox->currentText();
  QDir dir(saveDir);
  if (!dir.exists()) {
    KMessageBox::error(this,saveDir+" does not exit!");
    return;
  }

  for ( QIconViewItem *i = IconView->firstItem(); i; i = i->nextItem() )
    if (i->isSelected()) ++j;
  if (j == 0) {
    KMessageBox::error(this,"No images selected!");
    return;
  }

  setStatusTempMsg("Starting Downloads.");

  for (int x=0; x<my_cameraNumFolders; x++) {

    folder = my_cameraFolderList[x];
    qWarning("Downloading from "+folder);
    
    gp_list_new(&my_cameraListFiles);
    gp_camera_folder_list_files(my_camera, folder, my_cameraListFiles);

    for (j=0; j<gp_list_count(my_cameraListFiles); j++) {

      if (skipallmode) break;

      gp_list_get_name  (my_cameraListFiles, j, &my_cameraFile);
      my_cameraFileString=my_cameraFile;
      
      iconViewItem=IconView->findItem(my_cameraFileString);
      if (iconViewItem->isSelected()) {
	
	gp_file_new(&cameraFile);
	gp_camera_file_get(my_camera, folder, my_cameraFile,
			   GP_FILE_TYPE_NORMAL, cameraFile);
	saveFile=saveDir+"/"+my_cameraFile;
	qWarning(saveFile);

	while (QFile::exists(saveFile) && !(overwriteallmode)) {

	  FileOpDialog *dlg = new FileOpDialog(my_cameraFile, saveFile, NULL, NULL);
	
	  if (dlg->exec()== QDialog::Rejected){
	    setStatusTempMsg("Abort.");
	    gp_file_free(cameraFile);
	    gp_list_free (my_cameraListFiles);
	    delete dlg;
	    return;
	  }

	  if (dlg->fileOpSelection() == Skip) {
	    qWarning("Skipped.");
	    delete dlg;
	    savefilemode=false;
	    break;
	  } 
	  else if (dlg->fileOpSelection() == SkipAll) {
	    qWarning("Skipped All.");
	    skipallmode=true;
	    savefilemode=false;
	    delete dlg;
	    break;
	  } 
	  else if (dlg->fileOpSelection() == Overwrite) {
	    qWarning("Overwrite.");	  
	    delete dlg;
	    savefilemode=true;
	    break;
	  }
	  else if (dlg->fileOpSelection() == OverwriteAll) {
	    qWarning("Overwrite All.");	  
	    delete dlg;
	    savefilemode=true;
	    overwriteallmode=true;
	    break; 
	  }
	  else if (dlg->fileOpSelection() == Rename) {
	    qWarning("Rename.");
	    savefilemode=true;
	    saveFile = saveDir+"/"+dlg->renameString();
	    delete dlg;
	    qWarning(saveFile+" New Name");
	  }

	}

	if (savefilemode) {
	  if (gp_file_save(cameraFile,saveFile)<0) {
	    KMessageBox::error(this,"Failed to save images!");
	    gp_file_free(cameraFile);
	    return;
	  }
	}
	savefilemode=true;
    	
	gp_file_free(cameraFile);
      
      }

    }
    gp_list_free (my_cameraListFiles);
  }

  setStatusTempMsg("Finished Downloads.");

}


void Digikam::slot_close() 
{
  close();
}


void Digikam::getFolderNames(QString folder) {

  CameraList folderList;
  int count;

  gp_camera_folder_list_folders (my_camera, folder, &folderList);
  count = gp_list_count(&folderList);

  for (int i=0; i<count; i++) {
    const char* subFolder;
    QString subFolderString;

    gp_list_get_name (&folderList, i, &subFolder);

    subFolderString = subFolder;
    if (folder != "/") 
      subFolderString = folder + "/" + subFolderString;
    else
      subFolderString = "/" + subFolderString;
    qWarning(subFolderString);

    my_cameraFolderList.append(subFolderString);
    getFolderNames(subFolderString);
  }

  return;
}


void Digikam::getThumbNails() {

  const char  *my_cameraFile;
  CameraFile *cameraFile;
  CameraList *my_cameraListFiles;
  QString saveFile;
  QString folder;
 
  setStatusTempMsg("Getting ThumbNail images.");

  for (int x=0; x<my_cameraNumFolders; x++) {

    folder = my_cameraFolderList[x];
    qWarning(folder);

    
    gp_list_new(&my_cameraListFiles);
    if (gp_camera_folder_list_files(my_camera, folder, my_cameraListFiles) 
	!= GP_OK) {
      //KMessageBox::error(this,"Failed to get file listing!");
      //return;
      KMessageBox::error(this,"Failed to get file listing from "+folder);
      gp_list_free(my_cameraListFiles);
      break;
    }

    int count = gp_list_count (my_cameraListFiles);

    for (int i = 0; i < count; i++) {
      gp_list_get_name  (my_cameraListFiles, i, &my_cameraFile);
      qWarning(my_cameraFile);
      gp_file_new(&cameraFile);
      gp_camera_file_get (my_camera, folder, my_cameraFile, 
			  GP_FILE_TYPE_PREVIEW, cameraFile);
      saveFile=globTempDir+"/thumb_"+my_cameraFile;
      if (gp_file_save(cameraFile,saveFile)<0) {
	KMessageBox::error(this,"Failed to save thumbnails!");
	return;
      }
      gp_file_free(cameraFile);
    }

    gp_list_free (my_cameraListFiles); 
  
  }

}

void Digikam::updateThumbNails() {

  QDir dir(globTempDir);
  const QFileInfoList *fileList;
  fileList = dir.entryInfoList();

  IconView->clear();

  QFileInfoListIterator it(*fileList);
  QFileInfo *fi;
  QString fileNameWithPath;
  QString actualImageFileName;

  while(fi = it.current()){
    QIconViewItem *i = NULL;

    if(fi->fileName() == "." || fi->fileName() == "..")
      ;
    else {
      fileNameWithPath = dir.path()+"/"+fi->fileName();
      QImage *thumbnail = new QImage(fileNameWithPath);
      QPixmap thumbnail_pixmap;
      thumbnail_pixmap.convertFromImage(*thumbnail);

      actualImageFileName=(fi->fileName()).remove(0,6);

      i = new QIconViewItem(IconView, actualImageFileName, thumbnail_pixmap);
      i->setDropEnabled(false);
      i->setDragEnabled(false);
      delete thumbnail;

    }

    ++it;
    } 
}



void Digikam::slot_setup()
{
	Setup *setup=new Setup();
	setup->exec();
	my_cameraInitialised=false;
	//slot_connectToCamera();
}


void Digikam::setStatusMsg(const QString &msg) {
  statusBar->changeItem(msg, 0);
}


void Digikam::setStatusTempMsg(const QString &msg) {
  if (!msg.isEmpty()) 
    statusBar->message(msg,1000);
}



void Digikam::setProgressValue(int progress) {
  progressBar->setValue(progress);
}


void Digikam::debug_func (GPLogLevel level, const char *domain, const char *format,
	    va_list args, void *data)
{
	if (level == GP_LOG_ERROR)
		fprintf (stderr, "%s(ERROR): ", domain);
	else
		fprintf (stderr, "%s(%i): ", domain, level);
	vfprintf (stderr, format, args);
	fprintf (stderr, "\n");
}

void Digikam::status_func (Camera *camera, const char *status, void *data)
{
  if (my_cameraMap.contains(camera)) {
    Digikam *object=my_cameraMap[camera];
    object->setStatusTempMsg(status);
  }
}

void Digikam::message_func (Camera *camera, const char *message, void *data)
{
  qWarning(message);
}

void Digikam::progress_func (Camera *camera, float percentage, void *data)
{
  if (my_cameraMap.contains(camera)) {
    Digikam *object=my_cameraMap[camera];
    if (percentage > 0.) {
      object->setProgressValue(int(100.0*percentage));      
    }
  }
}

