/***************************************************************************
                          gphoto_interface.cpp  -  description
                             -------------------
    begin                : Sun Dec 30 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 "gphoto_interface.h"
#include "gphoto_messages.h"

#include <qdir.h>


Gphoto_Interface::Gphoto_Interface(bool setup){

  my_camera = NULL;
  my_cameraModel = "";
  my_cameraPort = "";
  my_cameraPortPath = "";
  my_cameraInitialised=false;

  my_cameraSupportsThumbNails=false;
  my_cameraSupportsDelete=false;
  my_cameraSupportsUpload=false;
  my_cameraSupportsMkDir=false;
  my_cameraSupportsDelDir=false;

  if (setup) 
    setupCamera();

  //gp_log_add_func (GP_LOG_ALL, debug_func, NULL);

}


Gphoto_Interface::~Gphoto_Interface(){

  if (my_cameraInitialised) {
    gp_camera_unref(my_camera);
    my_camera = NULL;
  }

}

int Gphoto_Interface::setupCamera() {

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

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

  my_cameraModel = model;
  my_cameraPort = port;
  

  if (my_cameraModel == "" || my_cameraPort == "") {
    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, &my_cameraAbilities);
  if (gp_camera_set_abilities (my_camera, my_cameraAbilities) != GP_OK) {
    gp_camera_unref(my_camera);
    my_camera = NULL;
    gp_abilities_list_free (abilList);
    gp_port_info_list_free (infoList);
    return -1;
  }

  
  gp_port_info_list_get_info(infoList, portNum, &info);
  if (gp_camera_set_port_info (my_camera, info) != GP_OK) {
    gp_camera_unref(my_camera);
    my_camera = NULL;
    gp_abilities_list_free (abilList);
    gp_port_info_list_free (infoList);
    return -1;
  }


  gp_abilities_list_free (abilList);
  gp_port_info_list_free (infoList);

  setupCameraAbilities();
  
  return 0;

}

void Gphoto_Interface::setupCameraAbilities() {
  
  if (my_cameraAbilities.file_operations & 
      GP_FILE_OPERATION_PREVIEW)
    my_cameraSupportsThumbNails=true;

  if (my_cameraAbilities.file_operations & 
      GP_FILE_OPERATION_DELETE)
    my_cameraSupportsDelete=true;

  if (my_cameraAbilities.folder_operations & 
      GP_FOLDER_OPERATION_PUT_FILE)
    my_cameraSupportsUpload=true;

  if (my_cameraAbilities.folder_operations & 
      GP_FOLDER_OPERATION_MAKE_DIR)
    my_cameraSupportsMkDir=true;

  if (my_cameraAbilities.folder_operations & 
      GP_FOLDER_OPERATION_REMOVE_DIR)
    my_cameraSupportsDelDir=true;

}


int Gphoto_Interface::initCamera() {

  if (my_camera != NULL) {
    gp_camera_unref(my_camera);
    my_camera = NULL;
  }

  if (setupCamera() == -1) 
    return -1;

  qWarning(my_cameraModel);
  qWarning(my_cameraPort);

  if (gp_camera_init(my_camera)<0) {
    gp_camera_unref(my_camera);
    my_camera = NULL;
    return -2;
  } 


  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);


  my_cameraInitialised=true;

  return 0;

}

/*
int Gphoto_Interface:: getSubFolders(QString folder, QStringList& subFolderList,
				     QStringList& subFolderNameList, int& numSubFolders)
{

  numSubFolders = 0;
  subFolderList.clear();
  subFolderNameList.clear();

  QDir folderDir(folder);
  folderDir.setFilter(QDir::Dirs); 
  QStringList folderDirList = folderDir.entryList();

  numSubFolders = folderDir.count();

  int j = 0;
  for (int i=0; i<numSubFolders; i++) {
    if (folderDirList[i] == "." || folderDirList[i] == "..") 
      j++;
    else {
      
      QString subFolderString;
      subFolderString = folderDirList[i];
      subFolderNameList.append(subFolderString);

      if (folder != "/")
	subFolderString = folder + "/" + folderDirList[i];
      else
	subFolderString = "/" + folderDirList[i];
      qWarning(subFolderString);

      subFolderList.append(subFolderString);
    }
  } 

  numSubFolders -= j;
  return 0;

}

*/


int Gphoto_Interface:: getSubFolders(QString folder, QStringList& subFolderList,
				     QStringList& subFolderNameList, int& numSubFolders)
{
  CameraList *folderList;

  numSubFolders=0;
  subFolderList.clear();
  subFolderNameList.clear();

  gp_list_new(&folderList);

  if (gp_camera_folder_list_folders (my_camera, folder, folderList)
      != GP_OK) {
    gp_list_unref(folderList);
    return -1;
  }

  numSubFolders = gp_list_count(folderList);

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

    if (gp_list_get_name (folderList, i, &subFolder) !=GP_OK) {
      gp_list_unref(folderList);      
      return -1;
    }

    subFolderString = subFolder;

    subFolderNameList.append(subFolderString);

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

    subFolderList.append(subFolderString);

  }

  gp_list_unref(folderList);

  return 0;

}



int Gphoto_Interface::getImageNames(QString folder, QStringList& imagesList,  QStringList& imagesInfoList)
{

  CameraList *cameraListFiles;
  const char  *cameraFileName;

  imagesList.clear();
  imagesInfoList.clear();


  gp_list_new(&cameraListFiles);
  if (gp_camera_folder_list_files(my_camera, folder, cameraListFiles)
      != GP_OK) {
    gp_list_unref(cameraListFiles);
    return -1;
  }

  int count = gp_list_count (cameraListFiles);

  for (int i = 0; i < count; i++) {
    if (gp_list_get_name (cameraListFiles, i, &cameraFileName) != GP_OK) {
      gp_list_unref(cameraListFiles);
      return -1;
    }
    imagesList.append(QString(cameraFileName));
    qWarning("In "+ folder + ": " + imagesList[i]);

    CameraFileInfo info;
    if (gp_camera_file_get_info(my_camera, folder, 
				cameraFileName, &info) == GP_OK) {
      if (info.file.fields & GP_FILE_INFO_TYPE)
	imagesInfoList.append(QString(info.file.type));
      else
	imagesInfoList.append(" ");
    }
    else
      imagesInfoList.append(" ");
    qWarning("Mime Type : " + imagesInfoList[i]);
    

  }

  gp_list_unref(cameraListFiles);    

  return 0;

}

QPixmap* Gphoto_Interface::getThumbNail(QString folder, QString imageName)
{

  QPixmap* thumbNail;
  CameraFile *cameraFile;
  const char* data;
  long int size;

  gp_file_new(&cameraFile);

  if (gp_camera_file_get(my_camera, folder, imageName, GP_FILE_TYPE_PREVIEW, 
			 cameraFile) != GP_OK) {
    qWarning("Failed to get preview");
    gp_file_unref(cameraFile);
    return NULL;
  }


  gp_file_get_data_and_size(cameraFile, &data, &size);

  thumbNail = new QPixmap;
  //  thumbNail.setOptimization(QPixmap::BestOptim);
  thumbNail->loadFromData((const uchar*) data, (uint) size);
  
  gp_file_unref (cameraFile);

  return thumbNail;
}


int Gphoto_Interface::downloadImage(QString folder, QString imageName, QString saveFile)
{
  CameraFile *cameraFile;

  gp_file_new(&cameraFile);
  if (gp_camera_file_get(my_camera, folder, imageName,
			 GP_FILE_TYPE_NORMAL, cameraFile) != GP_OK) {
    gp_file_unref(cameraFile);
    return -1;
  }
  if (gp_file_save(cameraFile,saveFile) != GP_OK) {
    gp_file_unref(cameraFile);
    return -1;
  }
  gp_file_unref(cameraFile);

  return 0;

}

int Gphoto_Interface::deleteImage(QString folder, QString imageName)
{
  
  if (gp_camera_file_delete(my_camera, folder, imageName) != GP_OK)
    return -1;
  
  return 0;

}



int Gphoto_Interface :: makeDir(QString folder, QString newFolder)
{

  if (gp_camera_folder_make_dir(my_camera, folder, newFolder) != GP_OK)
    return -1;

  return 0;

}


bool Gphoto_Interface::isCameraInitialised() {
 
  return  my_cameraInitialised;

}

void Gphoto_Interface::setCameraInitialised(bool init) {
  
   my_cameraInitialised=init;

}

bool Gphoto_Interface::cameraSupportsThumbNails() {

  return my_cameraSupportsThumbNails;

}

bool Gphoto_Interface::cameraSupportsDelete() {

  return  my_cameraSupportsDelete;

}

bool Gphoto_Interface::cameraSupportsUpload() {

  return  my_cameraSupportsUpload;

}

bool Gphoto_Interface::cameraSupportsMkDir() {

  return my_cameraSupportsMkDir;

}

bool Gphoto_Interface::cameraSupportsDelDir() {

  return my_cameraSupportsDelDir;

}


void Gphoto_Interface::status_func (Camera *camera, const char *status, void *data)
{

  Gphoto_Messages::gpMessagesWrapper()->emit statusChanged(status);
  
}

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

void Gphoto_Interface::progress_func (Camera *camera, float percentage, void *data)
{
  if (percentage > 0.) 
    
    Gphoto_Messages::gpMessagesWrapper()->emit progressChanged(int(100*percentage));
  

}


void Gphoto_Interface::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 Gphoto_Interface::getSupportedCameras(QStringList& cameraList, int& numSupported) 
{

  cameraList.clear();
  numSupported = 0;

  CameraAbilitiesList *abilList;
  CameraAbilities abil;

  gp_abilities_list_new (&abilList);
  gp_abilities_list_load (abilList);
  
  numSupported = gp_abilities_list_count (abilList);
  if (numSupported < 0) {
    qWarning("failed to get list of cameras");
    return;
  }
  else {
    for (int i=0; i<numSupported; i++) {
      const char *cameraName;
      gp_abilities_list_get_abilities (abilList, i, &abil);
      cameraName=abil.model;
      cameraList.append(QString(cameraName));
    }
  }

  gp_abilities_list_free (abilList);

}

void Gphoto_Interface::getCameraSettings(QString& cameraModel, QString& cameraPort)
{
  char model[64], port[128];

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

  cameraModel = model;
  cameraPort = port;

}

void Gphoto_Interface::saveCameraSettings(QString cameraModel, QString cameraPort)
{

  gp_setting_set ("digikam", "model", cameraModel.local8Bit().data());
  gp_setting_set ("digikam", "port", cameraPort.local8Bit().data());
 
}


void Gphoto_Interface::getSupportedPorts(QStringList& portList)
{
  GPPortInfoList *list;
  GPPortInfo info;

  portList.clear();

  gp_port_info_list_new (&list);
  gp_port_info_list_load (list);

  int numPorts = gp_port_info_list_count (list);

  for (int i = 0; i < numPorts; i++) {
    gp_port_info_list_get_info (list, i, &info);
    portList.append(info.path);
  }

  gp_port_info_list_free(list);

}

void Gphoto_Interface::getCameraPorts(QString cameraModel, QStringList& supportedPorts)
{
  int i = 0;
  supportedPorts.clear();

  CameraAbilities abilities;
  CameraAbilitiesList *abilList;
  
  gp_abilities_list_new (&abilList);
  gp_abilities_list_load (abilList);
  i = gp_abilities_list_lookup_model (abilList, cameraModel.local8Bit().data());
  gp_abilities_list_get_abilities (abilList, i, &abilities);
  gp_abilities_list_free (abilList);

  if (abilities.port & GP_PORT_SERIAL) supportedPorts.append("serial");
  if (abilities.port & GP_PORT_USB) supportedPorts.append("usb");

}

int Gphoto_Interface::autoDetectCamera(QString& cameraModel, QString& cameraPort) 
{

  CameraList camList;
  CameraAbilitiesList *abilList;
  GPPortInfoList *infoList;
  const char *model, *port;

  gp_abilities_list_new (&abilList);
  gp_abilities_list_load (abilList);
  gp_port_info_list_new (&infoList);
  gp_port_info_list_load (infoList);
  gp_abilities_list_detect (abilList, infoList, &camList);
  gp_abilities_list_free (abilList);
  gp_port_info_list_free (infoList);

  int count = gp_list_count (&camList);

  if (count<=0) {
    return -1;
  }

  for (int i = 0; i < count; i++) {
    gp_list_get_name  (&camList, i, &model);
    gp_list_get_value (&camList, i, &port);
  }
  
  cameraModel = model;
  cameraPort = port;

  qWarning(cameraModel);
  qWarning(cameraPort);
  return 0;

}


void Gphoto_Interface::getCameraSummary(QString& cameraSummary) 
{
  CameraText summary;
  
  gp_camera_get_summary(my_camera, &summary);
  cameraSummary = QString(summary.text);

}

void Gphoto_Interface::getCameraManual(QString& cameraManual)
{
  CameraText manual;
  
  gp_camera_get_manual(my_camera, &manual);
  cameraManual = QString(manual.text);

}

void Gphoto_Interface::getCameraAbout(QString& cameraAbout)
{  
  CameraText about;
  
  gp_camera_get_about(my_camera, &about);
  cameraAbout = QString(about.text);

}
