/* smal.c
 *
 * Copyright (C) 2003 Lee Benfield <lee@benf.org>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA  02110-1301  USA
 */
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <gphoto2/gphoto2-library.h>
#include <gphoto2/gphoto2-result.h>
#include <libgphoto2/bayer.h>
#include <libgphoto2/gamma.h>

#include "smal.h"
#include "ultrapocket.h"

#include "libgphoto2/i18n.h"

int
camera_id (CameraText *id)
{
	strcpy(id->text, "smal");
	return (GP_OK);
}


static const struct smal_cameras {
	char * name;
	unsigned short idVendor;
	unsigned short idProduct;
} smal_cameras [] = {
	{ "Fuji:Axia Slimshot",      USB_VENDOR_ID_SMAL,     USB_DEVICE_ID_ULTRAPOCKET },
	{ "Fuji:Axia Eyeplate",      USB_VENDOR_ID_SMAL,     USB_DEVICE_ID_ULTRAPOCKET },
	{ "Logitech:Pocket Digital", USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_POCKETDIGITAL },
	{ "SMaL:Ultra-Pocket",       USB_VENDOR_ID_SMAL,     USB_DEVICE_ID_ULTRAPOCKET },
	{ "Radioshack:Flatfoto",     USB_VENDOR_ID_SMAL,     USB_DEVICE_ID_FLATFOTO },
	{ "Creative:CardCam",        USB_VENDOR_ID_CREATIVE, USB_DEVICE_ID_CARDCAM },
	{ NULL, 0, 0 }
};

int
camera_abilities (CameraAbilitiesList *list)
{
	CameraAbilities a;
	int i;

	memset(&a, 0, sizeof(a));
	a.status = GP_DRIVER_STATUS_EXPERIMENTAL; /* highly! */
	a.port     		= GP_PORT_USB;
	a.speed[0] 		= 0;
	a.operations		= GP_OPERATION_NONE;
	a.file_operations	= GP_FILE_OPERATION_DELETE;
	a.folder_operations	= GP_FOLDER_OPERATION_DELETE_ALL;
	for (i = 0; smal_cameras[i].name; i++) {
		strcpy(a.model, smal_cameras[i].name);
		a.usb_vendor	= smal_cameras[i].idVendor;
		a.usb_product     = smal_cameras[i].idProduct;
		gp_abilities_list_append(list, a);
	}
	return (GP_OK);
}

static int
camera_exit (Camera *camera, GPContext *context)
{
	if (camera->pl) {
		free(camera->pl);
		camera->pl = NULL;
	}
	return ultrapocket_exit(camera->port, context);
}

static int
get_file_func (CameraFilesystem *fs, const char *folder, const char *filename,
		CameraFileType type, CameraFile *file, void *user_data,
		GPContext *context)
{
	Camera *camera = user_data;
	int size, image_no, result;
	unsigned char *data;

	image_no = gp_filesystem_number(fs, folder, filename, context);
	if (image_no < GP_OK)
		return image_no;

	switch (type) {
	case GP_FILE_TYPE_NORMAL:
		result = ultrapocket_getpicture(camera, context, &data, &size, filename);
		gp_file_set_mime_type (file, GP_MIME_PPM);
		break;
	case GP_FILE_TYPE_RAW:
		result = ultrapocket_getrawpicture(camera, context,
			&data, &size, filename);
		gp_file_set_mime_type (file, GP_MIME_PPM);
		break;
	case GP_FILE_TYPE_PREVIEW:
	default:
		return (GP_ERROR_NOT_SUPPORTED);
	}
	if (result < 0)
		return result;

	CHECK_RESULT(gp_file_set_data_and_size (file, (char *)data, size));

	return (GP_OK);
}

static int
delete_file_func (CameraFilesystem *fs, const char *folder,
		  const char *filename, void *data, GPContext *context)
{
	Camera *camera = data;
	int image_no;

	image_no = gp_filesystem_number(fs, folder, filename, context);
	if (image_no < GP_OK)
		return image_no;

	CHECK_RESULT(ultrapocket_deletefile(camera, filename));

	return (GP_OK);
}

static int
delete_all_func (CameraFilesystem *fs, const char* folder, void *data, GPContext *context)
{
	Camera *camera = data;
	if (strcmp (folder, "/"))
		return (GP_ERROR_DIRECTORY_NOT_FOUND);
	return ultrapocket_deleteall(camera);
}

static int
camera_about (Camera *camera, CameraText *about, GPContext *context)
{
	strcpy (about->text, _("Smal Ultrapocket\n"
			  "Lee Benfield <lee@benf.org>\n"
			  "Driver for accessing the Smal Ultrapocket camera, and OEM versions (slimshot)"));

	return (GP_OK);
}

static int
file_list_func (CameraFilesystem *fs, const char *folder, CameraList *list,
		void *data, GPContext *context)
{
	Camera *camera = data;
	int count, result;

	result =  ultrapocket_getpicsoverview(camera, context, &count, list);
	if (result != GP_OK)
		return result;

	return (GP_OK);
}

static CameraFilesystemFuncs fsfuncs = {
	.file_list_func = file_list_func,
	.get_file_func = get_file_func,
	.del_file_func = delete_file_func,
	.delete_all_func = delete_all_func,
};

int
camera_init (Camera *camera, GPContext *context)
{
	CameraAbilities cab;
	up_badge_type badge;

	camera->functions->exit                 = camera_exit;
	camera->functions->about                = camera_about;
	gp_filesystem_set_funcs (camera->fs, &fsfuncs, camera);
	badge = BADGE_UNKNOWN;
	gp_camera_get_abilities(camera, &cab);
	switch (cab.usb_vendor) {
	case USB_VENDOR_ID_SMAL:
	case USB_VENDOR_ID_CREATIVE:
		switch (cab.usb_product) {
		case USB_DEVICE_ID_ULTRAPOCKET:
			/* could be an axia eyeplate or a slimshot
			 * figure it out later, when we get the image
			 * catalogue.
			 */
			badge = BADGE_GENERIC;
			break;
		case USB_DEVICE_ID_FLATFOTO:
			badge = BADGE_FLATFOTO;
			break;
		case USB_DEVICE_ID_CARDCAM:
			badge = BADGE_CARDCAM;
			break;
		default:
			break;
		}
		break;
	case USB_VENDOR_ID_LOGITECH:
		switch (cab.usb_product) {
		case USB_DEVICE_ID_POCKETDIGITAL:
			badge = BADGE_LOGITECH_PD;
			break;
		default:
			break;
		}
		break;
	default:
		break;
	}

	if (badge == BADGE_UNKNOWN) {
		/* can't happen.  Otherwise, how'd we get to camera_init, neh? */
		return GP_ERROR;
	}

	camera->pl = malloc (sizeof (CameraPrivateLibrary));
	camera->pl->up_type = badge;
	/* don't need to do any exciting init stuff until we get pic numbers */
	return GP_OK;
}
