/* Copyright 2000 Red Hat, Inc.
 *
 * This software may be freely redistributed under the terms of the GNU
 * public license.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 */

#include "Python.h"
#include <kudzu/kudzu.h>
#include <kudzu/device.h>
#include <kudzu/ddc.h>
#include <kudzu/ide.h>
#include <kudzu/isapnp.h>
#include <kudzu/keyboard.h>
#include <kudzu/parallel.h>
#include <kudzu/pci.h>
#include <kudzu/psaux.h>
#include <kudzu/sbus.h>
#include <kudzu/scsi.h>
#include <kudzu/serial.h>
#include <kudzu/usb.h>

typedef struct {
    char * name;
    int value;
} TableEntry;

static TableEntry classTable[] = {
    { "CLASS_UNSPEC",	CLASS_UNSPEC },
    { "CLASS_OTHER",	CLASS_OTHER },
    { "CLASS_NETWORK",	CLASS_NETWORK },
    { "CLASS_SCSI",	CLASS_SCSI },
    { "CLASS_MOUSE",	CLASS_MOUSE },    
    { "CLASS_AUDIO",	CLASS_AUDIO },
    { "CLASS_CDROM",	CLASS_CDROM },    
    { "CLASS_MODEM",	CLASS_MODEM },    
    { "CLASS_VIDEO",	CLASS_VIDEO },
    { "CLASS_TAPE",	CLASS_TAPE },    
    { "CLASS_FLOPPY",	CLASS_FLOPPY },    
    { "CLASS_SCANNER",	CLASS_SCANNER },    
    { "CLASS_HD",	CLASS_HD },    
    { "CLASS_RAID",	CLASS_RAID },    
    { "CLASS_PRINTER",	CLASS_PRINTER },
    { "CLASS_CAPTURE",	CLASS_CAPTURE },
    { "CLASS_KEYBOARD",	CLASS_KEYBOARD },
    { "CLASS_MONITOR",	CLASS_MONITOR },
    { "CLASS_USB", CLASS_USB },
    { NULL },
} ;

static int numClassEntries = sizeof (classTable) / sizeof (TableEntry);

static TableEntry busTable[] = {
    { "BUS_UNSPEC",	BUS_UNSPEC },
    { "BUS_OTHER",	BUS_OTHER },
    { "BUS_PCI",	BUS_PCI },
    { "BUS_SBUS",	BUS_SBUS },
    { "BUS_PSAUX",	BUS_PSAUX },
    { "BUS_SERIAL",	BUS_SERIAL },
    { "BUS_PARALLEL",	BUS_PARALLEL },
    { "BUS_SCSI",	BUS_SCSI },
    { "BUS_IDE",	BUS_IDE },
    { "BUS_KEYBOARD",	BUS_KEYBOARD },
    { "BUS_DDC",	BUS_DDC },
    { "BUS_USB",	BUS_USB },
    { "BUS_ISAPNP",	BUS_ISAPNP },
    { "BUS_MISC",	BUS_MISC },
    { NULL }
};

static int numBusEntries = sizeof (busTable) / sizeof (TableEntry);

static TableEntry modeTable[] = {
    { "PROBE_ALL",	PROBE_ALL },
    { "PROBE_SAFE",	PROBE_SAFE },
    { "PROBE_ONE",	PROBE_ONE },
    { NULL },
} ;
static int numModeEntries = sizeof (modeTable) / sizeof (TableEntry);


void addDDCInfo(PyObject *dict,struct ddcDevice * device)
{
    PyDict_SetItemString(dict,"id",PyString_FromString(device->id));
    PyDict_SetItemString(dict,"horizSyncMin",PyInt_FromLong(device->horizSyncMin));
    PyDict_SetItemString(dict,"horizSyncMax",PyInt_FromLong(device->horizSyncMax));
    PyDict_SetItemString(dict,"vertRefreshMin",PyInt_FromLong(device->vertRefreshMin));
    PyDict_SetItemString(dict,"vertRefreshMax",PyInt_FromLong(device->vertRefreshMax));
    PyDict_SetItemString(dict,"mem",PyInt_FromLong(device->mem));
}

void addIDEInfo(PyObject *dict,struct ideDevice * device)
{
    PyDict_SetItemString(dict,"physical",PyString_FromString(device->physical));
    PyDict_SetItemString(dict,"logical",PyString_FromString(device->logical));
}

void addParallelInfo(PyObject *dict,struct parallelDevice * device)
{
    PyDict_SetItemString(dict,"pnpmodel",PyString_FromString(device->pnpmodel));
    PyDict_SetItemString(dict,"pnpmfr",PyString_FromString(device->pnpmfr));
    PyDict_SetItemString(dict,"pnpmodes",PyString_FromString(device->pnpmodes));
    PyDict_SetItemString(dict,"pnpdesc",PyString_FromString(device->pnpdesc));
    if(device->pinfo!=NULL){
        PyDict_SetItemString(dict,"xres",PyInt_FromLong(device->pinfo->xres));
        PyDict_SetItemString(dict,"yres",PyInt_FromLong(device->pinfo->yres));
        PyDict_SetItemString(dict,"color",PyInt_FromLong(device->pinfo->color));
        PyDict_SetItemString(dict,"ascii",PyInt_FromLong(device->pinfo->ascii));
        PyDict_SetItemString(dict,"uniprint",PyString_FromString(device->pinfo->uniprint));
    }
}

void addPCIInfo(PyObject *dict,struct pciDevice * device)
{
    PyDict_SetItemString(dict,"vendorId",PyInt_FromLong(device->vendorId));
    PyDict_SetItemString(dict,"deviceId",PyInt_FromLong(device->deviceId));
    PyDict_SetItemString(dict,"subVendorId",PyInt_FromLong(device->subVendorId));
    PyDict_SetItemString(dict,"subDeviceId",PyInt_FromLong(device->subDeviceId));
    PyDict_SetItemString(dict,"pciType",PyInt_FromLong(device->pciType));
}

void addSbusInfo(PyObject *dict,struct sbusDevice * device)
{
    PyDict_SetItemString(dict,"width",PyInt_FromLong(device->width));
    PyDict_SetItemString(dict,"height",PyInt_FromLong(device->height));
    PyDict_SetItemString(dict,"freq",PyInt_FromLong(device->freq));
    PyDict_SetItemString(dict,"monitor",PyInt_FromLong(device->monitor));
}

void addScsiInfo(PyObject *dict,struct scsiDevice * device)
{
    PyDict_SetItemString(dict,"host",PyInt_FromLong(device->host));
    PyDict_SetItemString(dict,"channel",PyInt_FromLong(device->channel));
    PyDict_SetItemString(dict,"id",PyInt_FromLong(device->id));
    PyDict_SetItemString(dict,"lun",PyInt_FromLong(device->lun));
}

void addSerialInfo(PyObject *dict,struct serialDevice * device)
{
    if(device->pnpmfr)
        PyDict_SetItemString(dict,"pnpmfr",PyString_FromString(device->pnpmfr));
    else
        PyDict_SetItemString(dict,"pnpmfr",PyString_FromString("none"));
    if(device->pnpmodel)
        PyDict_SetItemString(dict,"pnpmodel",PyString_FromString(device->pnpmodel));
    else
        PyDict_SetItemString(dict,"pnpmodel",PyString_FromString("none"));
    if(device->pnpcompat)
        PyDict_SetItemString(dict,"pnpcompat",PyString_FromString(device->pnpcompat));
    else
        PyDict_SetItemString(dict,"pnpcompat",PyString_FromString("none"));
    if(device->pnpdesc)
        PyDict_SetItemString(dict,"pnpdesc",PyString_FromString(device->pnpdesc));
    else
        PyDict_SetItemString(dict,"pnpdesc",PyString_FromString("none");
}

void addUsbInfo(PyObject *dict,struct usbDevice * device)
{
    PyDict_SetItemString(dict,"usbclass",PyInt_FromLong(device->usbclass));
    PyDict_SetItemString(dict,"usbsubclass",PyInt_FromLong(device->usbsubclass));
    PyDict_SetItemString(dict,"usbprotocol",PyInt_FromLong(device->usbprotocol));
}

/*
 * These are empty, and just used for consistency and possible
 * future expansion
 */

void addKbdInfo(PyObject *dict,struct keyboardDevice * device)
{
    return;
}

void addPsauxInfo(PyObject *dict,struct psauxDevice * device)
{
    return;
}


PyObject * createDict(struct device * probedDevice)
{
    PyObject *dict;

    dict = PyDict_New();
    PyDict_SetItemString(dict,"desc",PyString_FromString(probedDevice->desc));
    PyDict_SetItemString(dict,"driver",PyString_FromString(probedDevice->driver));
    PyDict_SetItemString(dict,"device",PyString_FromString(probedDevice->device));
    PyDict_SetItemString(dict,"detached",PyInt_FromLong(probedDevice->detached));
    PyDict_SetItemString(dict,"class",PyInt_FromLong(probedDevice->class));
    PyDict_SetItemString(dict,"bus",PyInt_FromLong(probedDevice->bus));
    PyDict_SetItemString(dict,"index",PyInt_FromLong(probedDevice->index));
    switch(probedDevice->bus){
    case BUS_DDC:
        addDDCInfo(dict,(struct ddcDevice*)probedDevice);
        break;
    case BUS_IDE:
        addIDEInfo(dict,(struct ideDevice*)probedDevice);
        break;
    case BUS_KEYBOARD:
        addKbdInfo(dict,(struct keyboardDevice*)probedDevice);
        break;
    case BUS_PARALLEL:
        addParallelInfo(dict,(struct parallelDevice*)probedDevice);
        break;
    case BUS_PCI:
        addPCIInfo(dict,(struct pciDevice*)probedDevice);
        break;
    case BUS_PSAUX:
        addPsauxInfo(dict,(struct psauxDevice*)probedDevice);
        break;
    case BUS_SBUS:
        addSbusInfo(dict,(struct sbusDevice*)probedDevice);
        break;
    case BUS_SCSI:
        addScsiInfo(dict,(struct scsiDevice*)probedDevice);
        break;
    case BUS_SERIAL:
        addSerialInfo(dict,(struct serialDevice*)probedDevice);
        break;
    case BUS_USB:
        addUsbInfo(dict,(struct usbDevice*)probedDevice);
        break;
    default:
        break;
    }
    return dict;
}

static PyObject * doProbe (PyObject * self, PyObject * args) {
    int class, bus, mode;
    struct device ** devices, ** tmp;
    PyObject * list;
    
    if (!PyArg_ParseTuple(args, "iii", &class, &bus, &mode))
	return NULL;

    devices = probeDevices(class, bus, mode);

    list = PyList_New(0);

    if (!devices)
	return list;
    
    tmp = devices;
    while (*tmp) {
	PyList_Append (list, createDict(*tmp));
	tmp++;
    }

    tmp = devices;
    while (*tmp) {
	(*tmp)->freeDevice (*tmp);
	tmp++;
    }

    free(devices);

    return list;
}


static PyMethodDef kudzuMethods[] = {
    { "probe", (PyCFunction) doProbe, METH_VARARGS, NULL },
    { NULL }
} ;

static void registerTable (PyObject * dict, TableEntry * table) {
    int i;
    
    i = 0;
    while (table[i].name) {
	PyDict_SetItemString(dict, table[i].name,
			     PyInt_FromLong (table[i].value));
	i++;
    }
}

void initnewkudzu (void) {
    PyObject * m, * dict;
    
    m = Py_InitModule("newkudzu", kudzuMethods);
    dict = PyModule_GetDict(m);

    registerTable (dict, classTable);
    registerTable (dict, busTable);
    registerTable (dict, modeTable);
	
    initializeDeviceList();
}
