#include <fcntl.h>
#include <linux/types.h>
#include <linux/cdrom.h>
#include <sys/ioctl.h>
#include <strings.h>
#include <newt.h>
#include <stdlib.h>
#include <unistd.h>

#include "devices.h"
#include "install.h"
#include "log.h"
#include "newt.h"
#include "scsi.h"
#include "windows.h"

#define CD_IDE 1
#define CD_SCSI 2
#define CD_OTHER 3

static struct { char * modname, * devname; } transTable[] = {
	{ "cm206", "cm206cd" },
	{ "sonycd535", "cdu535" },
	{ NULL, NULL }
} ;


int setupCDdevicePanel(int * type) {
    newtComponent form, label, listbox, okay, cancel, answer;

    #ifdef __sparc__
	*type = CD_SCSI;
	return 0;
    #endif

    newtOpenWindow(22, 6, 35, 11, "CDROM type");

    label = newtLabel(1, 1, "What type of CDROM do you have?");
    listbox = newtListbox(10, 3, 0, NEWT_LISTBOX_RETURNEXIT);

    newtListboxAddEntry(listbox, "IDE (ATAPI)", (void *) CD_IDE);
    newtListboxAddEntry(listbox, "SCSI", (void *) CD_SCSI);

    #ifndef __axp__
	newtListboxAddEntry(listbox, "Other CDROM", (void *) CD_OTHER);
    #endif
    
    okay = newtButton(5, 7, "Ok");
    cancel = newtButton(20, 7, "Cancel");

    form = newtForm(NULL, NULL, 0);
    newtFormAddComponents(form, label, listbox, okay, cancel, NULL);

    answer = newtRunForm(form);

    if (answer != cancel)
	*type = (int) newtListboxGetCurrent(listbox);

    newtFormDestroy(form);
    newtPopWindow();

    if (answer == cancel) return INST_CANCEL;

    return 0;
}

int findAtapi(char ** cddev) {
    char * dev;
    int i, fd;
    struct cdrom_volctrl volctrl;

    dev = alloca(105);
    strcpy(dev, "/tmp/hda");

    for (i = 0; i < 8; i++, dev[7]++) {
	logMessage("seeing if %s is ATAPI CD", dev);
	devMakeInode(dev + 5, dev);
	fd = open(dev, O_RDONLY);
	if (fd < 0) {
	    logMessage("	failed to open device");
	    continue;
	}

	unlink(dev);
	if (!ioctl(fd, CDROMVOLREAD, &volctrl)) {
	    logMessage("	CDROMVOLREAD ioctl worked");
	    close(fd);
	    *cddev = strdup(dev + 5);
	    return 0;
	};

	close(fd);
    }

    messageWindow("Error", "No IDE (ATAPI) drives can be found.");

    return INST_ERROR;
}
	
int setupCDdevice(char ** cddev, struct driversLoaded ** dl) {
    int type, rc;
    struct driversLoaded * d;
    int i;

    do {
	rc = setupCDdevicePanel(&type);
	if (rc) return rc;

	switch (type) {
	  case CD_SCSI:
	    setupSCSIInterfaces(1, dl);
	    *cddev = "scd0";
	    break;

	  case CD_IDE:
	    rc = findAtapi(cddev);
	    break;

	  case CD_OTHER:
	    rc = loadDeviceDriver(DRIVER_CDROM, dl);
	    if (!rc) {
		d = *dl;
		*cddev = "bad_device";
		while (d) {
		    if (d->type == DRIVER_CDROM) {
			*cddev = d->module;
			break;
		    }
		    d = d->next;
		}

		for (i = 0; transTable[i].modname; i++) {
		    if (!strcmp(*cddev, transTable[i].modname)) {
			*cddev = transTable[i].devname;
			break;
		    }
		}
	    }
	    break;
	}
    } while (rc);

    winStatus(35, 3, "CDROM", "Initializing CDROM...");
    sleep(2);
    newtPopWindow();

    return 0;
}

int removeCDmodule(struct driversLoaded ** dl) {
    /* this wil fail silently if no CD module has been loaded */
    removeDeviceDriver(DRIVER_CDROM, dl);

    return 0;
}
