#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 }
} ;


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

    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, "SCSI", (void *) CD_SCSI);
    newtListboxAddEntry(listbox, "Other CDROM", (void *) CD_OTHER);
    
    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;
}
#endif /* __i386__ */

#ifndef __sparc__
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);
    }

    return INST_ERROR;
}
#endif /* ! __sparc__ */
	
int setupCDdevice(char ** cddev, struct driversLoaded ** dl) {
    int type, rc = 0;
    struct driversLoaded * d;
    int i;
    int done = 0;

    #ifndef __sparc__
	/* Let's see if any CDROM's are already available */
	if (!findAtapi(cddev)) {
	    logMessage("using device %s", *cddev);
	    done = 1;
	}
    #endif

    if (!done) {
	#if defined(__sparc__) || defined(__alpha__)
	    /* It must be SCSI -- we'll give an error later if this is wrong */
	    setupSCSIInterfaces(1, dl);
	    *cddev = "scd0";
	    done =1;
	#else
	    if (!findSCSIcdrom(cddev)) done = 1;
	#endif
    }

    #ifdef __i386__
	while (rc || !done) {
	    rc = setupCDdevicePanel(&type);
	    if (rc) return rc;

	    switch (type) {
	      case CD_SCSI:
		setupSCSIInterfaces(1, dl);
		*cddev = "scd0";
		done = 1;
		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;
			}
		    }
		    done = 1;
		}
		break;
	    }
	} 
    #endif /* __i386__ */

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

int findSCSIcdrom(char ** cddev) {
    int fd;
    int rc = INST_ERROR;

    /* If they have a SCSI CDROM already available, use it */
    devMakeInode("scd0", "/tmp/scd0");
    fd = open("/tmp/scd0", O_RDONLY);
    if (fd >= 0) {
	logMessage("found SCSI CDROM scd0");
	*cddev = strdup("scd0");
	close(fd);
	rc = 0;
    }
    unlink("/tmp/scd0");

    return rc;
}
