/*
 * This file is part of DesktopBSD, see the README file.
 *
 * Author: Peter Hofer <ph@desktopbsd.net>
 *			(C) 2004, 2005
 *
 * Copyright: BSD, see the COPYING file included in this distribution
 *
 */

#include <X11/Xlib.h>

#include <dbsdglobal.h>
#include <device.h>
#include <dialogs.h>
#include <mntdevice.h>
#include <size.h>
#include <sysctl.h>

static  modDevInfo  *object = NULL;

void  setObject(modDevInfo  *obj) {
	object = obj;
}


int  wrapper(devinfo_dev *dev,  void *arg) {
	if(object != NULL)
		return  object->insertDevice(dev, arg);

	return -1;
}


int  modDevInfo::insertDevice(devinfo_dev  *dev,  void  *arg) {
	static  QListViewItem  *parents[32];

	if(dev->dd_name[0] != '\0' && dev->dd_state >= DIS_ATTACHED) {
		Device  device(dev->dd_name);
		uint64_t level = (uint64_t) arg;

		/* Check the index in parents[], even if it is
		 * highly unlikely that it is > 32.
		 */
		if(level < sizeof(parents) / sizeof(parents[0])) {
			if(level != 0)
				parents[level] = new QListViewItem(parents[level - 1],
															  (grpDisplayMode->selectedId() == 0) ?
															  device.getDesc() : device.getName());
			else
				parents[0] = new QListViewItem(lstDevices,
														 (grpDisplayMode->selectedId() == 0) ?
														 device.getDesc() : device.getName());
			parents[level]->setOpen(true);
		}
	}

	return(devinfo_foreach_device_child(dev, wrapper, ((char *) arg + 1)));
}


void  modDevInfo::readDevices() {
	devinfo_dev  *rootdev;

	if(devinfo_init() == 0 && (rootdev = devinfo_handle_to_device(DEVINFO_ROOT_DEVICE)) != NULL) {
		lstDevices->clear();
		devinfo_foreach_device_child(rootdev, wrapper, NULL);
	} else
		Dialogs::warnDlg(tr("Unable to obtain device list."));
}


void  modDevInfo::initModule() {
	setObject(this);
	readDevices();
	initOverview();
}


void modDevInfo::initOverview()
{
	/* CPU and memory */
	lblDetectedCPU->setText(QString(tr("%1 Processor(s) with <b>%2 MHz</b>, Memory: <b>%3</b>"))
										.arg(SysCtl::getIntCtl("hw.ncpu"))
										.arg(SysCtl::getIntCtl("hw.clockrate"))
										.arg(Size(SysCtl::getLongCtl("hw.physmem"), Size::Byte).toString(Size::MB)));

	/* Display */
	Display *dsp = XOpenDisplay(NULL);
	int scr = DefaultScreen(dsp),
		 dw = DisplayWidth(dsp, scr),
		 dwmm = DisplayWidthMM(dsp, scr),
		 dh = DisplayHeight(dsp, scr),
		 dhmm = DisplayHeightMM(dsp, scr);
	
	lblGraphics->setText(tr("Screen Resolution: <b>%1x%2</b>, <b>%3x%4 DPI</b>")
									.arg(dw).arg(dh)
									.arg((uint) (dw * 25.4 / dwmm)).arg((uint) (dh * 25.4 / dhmm)));
	XCloseDisplay(dsp);
	
	/* Devices */
	int otherdrives = 0, hdd = 0, cddvd = 0;
	QPtrList<MntDevice> devs = MntDevice::getAllDevices();
	for(QPtrList<MntDevice>::Iterator i = devs.begin(); i != devs.end(); ++i)
	{
		MntDevice *m = *i;
		switch(m->getDeviceType())
		{		
			case Device::SCSI_CD:
				if(m->isATAPICAMDevice())
					/* Only count "real" SCSI CD/DVD drives */
					break;
				
			/* fall-through */
			case Device::ATAPI_CD:
				++cddvd;
				break;
				
			case Device::ATA_Disk:
			case Device::IDE_WD100:
			case Device::SCSI_DirectAccess:
			case Device::ATA_RAID:
				++hdd;
				break;
				
			default:
				/* e.g. floppy disk */
				++otherdrives;
				break;
		}
	}
	
	QString drivestr;
	if(hdd)
		drivestr += tr("<b>%1 Hard disk(s)</b>").arg(hdd);

	if(cddvd)
	{
		if(!drivestr.isEmpty())
			drivestr += ", ";
			
		drivestr += tr("<b>%2 CD/DVD drive(s)</b>").arg(cddvd);
	}
	
	if(otherdrives)
	{
		if(!drivestr.isEmpty())
			drivestr += ", ";
			
		drivestr += tr("<b>%3 other (e.g. Floppy)</b>").arg(otherdrives);
	}
	
	lblDrives->setText(drivestr);

	/* ACPI */
	bool acpi = SysCtl::ctlExists("hw.acpi"),
		  cpupowersaving = SysCtl::ctlExists("dev.cpu.0.freq");
	lblACPI->setText(tr("ACPI: <b>%1</b>, Power Saving: <b>%2</b>")
								.arg(acpi ? tr("Supported") : tr("Not supported"))
								.arg(cpupowersaving ? tr("Supported") : tr("Not supported")));
}


void modDevInfo::init() {
	/* Initialize Graphics */
	DBSDIconLoader *iloader = DBSDGlobal::getIconLoader();
	pixCPU->setPixmap(iloader->loadIcon("kcmmemory", DBSDIconLoader::Size32x32));
	pixGraphics->setPixmap(iloader->loadIcon("randr", DBSDIconLoader::Size32x32));
	pixDrives->setPixmap(iloader->loadIcon("kcmdevices", DBSDIconLoader::Size32x32));
	pixACPI->setPixmap(iloader->loadIcon("energy", DBSDIconLoader::Size32x32));
	btnRefresh->setIconSet(iloader->loadIcon("reload", DBSDIconLoader::Button));
}
