#include "UserClasses.moc"
#include "NewClass.h"
#include "EditLimit.h"
#include <klocale.h>
#include <kapplication.h>
#include <qlistbox.h>
#include <qlabel.h>
#include <qwhatsthis.h>
#include <iostream.h>

#include <sys/types.h>
#include <grp.h>
#include <kmessagebox.h>

UserClasses::UserClasses(QWidget * parent, const char * name): QWidget(parent,name)
{
	int x=5, y=5;
	int h=380;	// 380 is the height of the tab; should be
			// this->height(), but for some reason,
			// kTabCtl->height() returns the height of the
			// label rather than the tab. :/
			// So we have to use a hard-coded size for now. :/
	ftpxs=0;
	classes=new QListBox(this, "Classlist");
	classes->setGeometry(x,y,120,h-2*height()-10);
	connect(classes,SIGNAL(highlighted(const QString &)),SLOT(classSelected(const QString &)));
	QWhatsThis::add(classes, i18n("User classes can be used to control access from specific hosts/users. Use the <b>Add class</b> and <b>Delete class</b> buttons on the right of this box to add or remove classes. Use the other buttons to control the access rights of users in the class selected here."));
	x+=classes->width()+5;
	anon=new QCheckBox(i18n("&Anonymous"), this);
	QWhatsThis::add(anon,i18n("Anonymous users (login=ftp or anonymous) can belong to this class"));
	guest=new QCheckBox(i18n("&Guest"), this);
	QWhatsThis::add(guest,i18n("Guest users (restricted real users) can belong to this class"));
	real=new QCheckBox(i18n("&Real"), this);
	QWhatsThis::add(real,i18n("Real users can belong to this class"));
	anon->move(x,y);	y+=anon->height();
	guest->move(x,y);	y+=guest->height();
	real->move(x,y);	y+=real->height();
	QLabel *lbl1=new QLabel(i18n("A&ddresses:"), this);
	addrs=new QLineEdit(this);
	QWhatsThis::add(addrs,i18n("Specify the addresses for this user class here;\nmay be globbed:\n* = any address\n*.localdomain.com = any address in localdomain.com\n127.0.0.* = IPs 127.0.0.1-127.0.0.255\n..."));
	QWhatsThis::add(lbl1,i18n("Specify the addresses for this user class here;\nmay be globbed:\n* = any address\n*.localdomain.com = any address in localdomain.com\n127.0.0.* = IPs 127.0.0.1-127.0.0.255\n..."));
	lbl1->setBuddy(addrs);
	lbl1->move(x,y);	y+=lbl1->height();
	addrs->move(x,y);	y+=addrs->height()+5;
	newclass=new QPushButton(i18n("Add &Class"), this);
	connect(newclass, SIGNAL(clicked()), SLOT(newClassPressed()));
	QWhatsThis::add(newclass, i18n("Add a new user class"));
	newclass->move(x,y);	y+=newclass->height()+5;
	deleteclass=new QPushButton(i18n("D&elete Class"), this);
	QWhatsThis::add(deleteclass, i18n("Delete the currently selected user class"));
	deleteclass->move(x,y);
	connect(deleteclass, SIGNAL(clicked()), SLOT(deleteClassPressed()));
	x+=deleteclass->width()+5; y=5;
	autogroup=new QCheckBox(i18n("Aut&ogroup to:"), this);
	autogroup->move(x,y); y+=autogroup->height();
	QWhatsThis::add(autogroup,i18n("Users from this class are automatically members\nof the group selected here.\nThat way, you can (for example) grant local users\nanonymous access to files remote users\ncan't download."));
	connect(autogroup, SIGNAL(clicked()), SLOT(autogroupSelected()));
	groups=new QListBox(this, "Grouplist");
	groups->setGeometry(x,y,classes->width(),classes->height()-autogroup->height());
	QWhatsThis::add(groups,i18n("Users from this class are automatically members\nof the group selected here.\nThat way, you can (for example) grant local users\nanonymous access to files remote users\ncan't download."));
	{
		group *g;
		while((g=getgrent())!=0)
			groups->insertItem(g->gr_name);
		endgrent();
	}	
	connect(groups,SIGNAL(highlighted(const QString &)),SLOT(groupSelected(const QString &)));
	x+=groups->width()+5; y=5;
	QLabel *lbl2=new QLabel(i18n("L&imits:"), this);
	QWhatsThis::add(lbl2, i18n("You can use limits to restrict the number of simultaneous connections of users in this class at specific times. Use the <b>Add Limit</b>, <b>Edit Limit</b> and <b>Delete Limit</b> buttons on the right to control limits."));
	lbl2->move(x,y); y+=lbl2->height();
	limits=new QListBox(this, "Limitlist");
	limits->setGeometry(x,y,classes->width(),classes->height()-lbl2->height());
	QWhatsThis::add(limits, i18n("You can use limits to restrict the number of simultaneous connections of users in this class at specific times. Use the <b>Add Limit</b>, <b>Edit Limit</b> and <b>Delete Limit</b> buttons on the right to control limits."));
	lbl2->setBuddy(limits);
	x+=limits->width()+5;
	y=limits->y();
	addLimit=new QPushButton(i18n("Add &Limit"), this);
	addLimit->move(x,y); y+=addLimit->height()+5;
	connect(addLimit, SIGNAL(clicked()), SLOT(addLimitPressed()));
	editLimit=new QPushButton(i18n("Edi&t Limit"), this);
	editLimit->move(x,y); y+=editLimit->height()+5;
	connect(editLimit, SIGNAL(clicked()), SLOT(editLimitPressed()));
	rmLimit=new QPushButton(i18n("Delete Li&mit"), this);
	rmLimit->move(x,y); y+=rmLimit->height()+5;
	connect(rmLimit, SIGNAL(clicked()), SLOT(deleteLimitPressed()));
	QWhatsThis::add(addLimit, i18n("You can use limits to restrict the number of simultaneous connections of users in this class at specific times. Use the <b>Add Limit</b>, <b>Edit Limit</b> and <b>Delete Limit</b> buttons on the right to control limits."));
	QWhatsThis::add(editLimit, i18n("You can use limits to restrict the number of simultaneous connections of users in this class at specific times. Use the <b>Add Limit</b>, <b>Edit Limit</b> and <b>Delete Limit</b> buttons on the right to control limits."));
	QWhatsThis::add(rmLimit, i18n("You can use limits to restrict the number of simultaneous connections of users in this class at specific times. Use the <b>Add Limit</b>, <b>Edit Limit</b> and <b>Delete Limit</b> buttons on the right to control limits."));
	x+=rmLimit->width()+5; y=5;
}
UserClasses::~UserClasses()
{
}
void UserClasses::redrawList()
{
	ftpclass *f=0;
	classes->clear();
	while((f=ftpxs->getNextClass(f))!=0)
		classes->insertItem(f->getName());
	classes->update();
	classes->setSelected(0,true);
	classSelected(classes->text(0));
}
void UserClasses::redrawLimits()
{
		ftpclass *c=ftpxs->seekClass(current);
		limits->clear();
		ftplimit *fl=0;
		while((fl=c->getNextLimit(fl)))
			limits->insertItem(fl->getId());
		limits->update();
}
void UserClasses::newClassPressed() // SLOT
{
	NewClass *n;
	n=new NewClass;
	connect(n,SIGNAL(classAdded(ftpclass *)),SLOT(classAdded(ftpclass *)));
}
void UserClasses::deleteClassPressed() // SLOT
{
	// find name of selected class...
	QString name;
	for(unsigned int i=0; i<classes->count() && name==0; i++)
		if(classes->isSelected(i)) name=classes->text(i);
	if(name!=0) {
		ftpxs->removeClass(name);
		redrawList();
	}
}
void UserClasses::addLimitPressed() // SLOT
{
	if(current==0)
		KMessageBox::sorry(this, i18n("Limits are specific to user classes - create a class first."));
	else {
		EditLimit *el;
		el=new EditLimit(0, ftpxs->seekClass(current));
		connect(el,SIGNAL(EditLimitOk(ftplimit *, ftpclass *)), SLOT(limitChanged(ftplimit *, ftpclass *)));
	}
}
void UserClasses::editLimitPressed() // SLOT
{
	if(current==0)
		KMessageBox::sorry(this, i18n("Limits are specific to user classes - create a class first."));
	else {
		EditLimit *el;
		// Find currently selected limit...
		QString ID=QString::null;
		for(unsigned int i=0; i<limits->count() && ID==QString::null; i++)
			if(limits->isSelected(i))
				ID=limits->text(i);
		ftplimit *f=0, *thislimit=0;
		ftpclass *c=ftpxs->seekClass(current);
		if(c!=0) {
			while((f=c->getNextLimit(f)) && thislimit==0) {
				if(f->getId()==ID)
					thislimit=f;
			}
		}
		if(thislimit==0)
			KMessageBox::sorry(this, i18n("You must select a limit first."));
		else {
			el=new EditLimit(thislimit, ftpxs->seekClass(current));
			connect(el,SIGNAL(EditLimitOk(ftplimit *, ftpclass *)), SLOT(limitChanged(ftplimit *, ftpclass *)));
		}
	}
}
void UserClasses::deleteLimitPressed() // SLOT
{
	if(current==0)
		KMessageBox::sorry(this, i18n("Select a class first."));
	else {
// EditLimit *el;
		// Find currently selected limit...
		QString ID=QString::null;
		for(unsigned int i=0; i<limits->count() && ID==QString::null;i++)
			if(limits->isSelected(i))
				ID=limits->text(i);
		ftplimit *f=0, *thislimit=0;
		ftpclass *c=ftpxs->seekClass(current);
		if(c!=0)
			while((f=c->getNextLimit(f)) && thislimit==0)
				if(f->getId()==ID)
					thislimit=f;
		if(thislimit==0)
			KMessageBox::sorry(this, i18n("You must select a limit first."));
		else {
			c->deleteLimit(thislimit);
			redrawLimits();
		}
	}
}
void UserClasses::limitChanged(ftplimit *l, ftpclass *c) // SLOT
{
	bool	 isNewLimit=true;
	ftplimit *fl=0;
	while((fl=c->getNextLimit(fl)) && isNewLimit)
		if(fl==l)
			isNewLimit=false;
	if(isNewLimit)
		c->addLimit(l);
	if (current == c->getName()) { // We're still displaying the class this limit is for...
		redrawLimits();
		for(unsigned int i=0; i<limits->count(); i++)
			limits->setSelected(i, false);
		limits->setSelected(limits->count()-1, true);
	}
}
void UserClasses::classAdded(ftpclass *c) // SLOT
{
	update();
	ftpxs->addClass(c);
	redrawList();
	int num=0;	// select new class...
	ftpclass *f=0;
	while((f=ftpxs->getNextClass(f))!=0)
		num++;
	classes->setSelected(num-1,true);
	classSelected(c->getName());
}
void UserClasses::classDeleted(char const * const c) // SLOT
{
}

void UserClasses::groupSelected(const QString &item) // SLOT
{
	if(!autogroup->isChecked())
		autogroup->setChecked(true);
	QString name=QString::null;
	if(!autogroup->isChecked())
		autogroup->setChecked(true);
	for(unsigned int i=0; i<classes->count() && name==QString::null; i++)
		if(classes->isSelected(i)) name=classes->text(i);
	if(name.isNull()) { // Theoretically, this can't happen... But apparently it happens occasionally.
		name=classes->text(0);
		classes->setSelected(0, true);
		classSelected(classes->text(0));
	}
	ftpclass *f=ftpxs->seekClass(name);
	if(f)
	  f->setAutogroup(item);
}
void UserClasses::autogroupSelected() // SLOT
{
	if(!autogroup->isChecked())
		for(unsigned int i=0; i<groups->count(); i++)
			groups->setSelected(i,false);
}
void UserClasses::classSelected(const QString &item) // SLOT
{
	ftpclass *c=0;
	ftpclass *thisclass=0;
	update();
	while((c=ftpxs->getNextClass(c))!=0 && thisclass==0)
		if(item == c->getName())
			thisclass=c;
	if(thisclass!=0) {
		anon->setChecked(thisclass->isAnon());
		guest->setChecked(thisclass->isGuest());
		real->setChecked(thisclass->isReal());
		addrs->setText(thisclass->getAddrs());
		current=thisclass->getName();
		if(thisclass->getAutogroup()==0) {
			autogroup->setChecked(false);
			for(unsigned int i=0; i<groups->count(); i++)
				groups->setSelected(i, false);
		} else {
			autogroup->setChecked(true);
			for(unsigned int i=0; i<groups->count(); i++)
				if(groups->text(i).lower() == thisclass->getAutogroup().lower())
					groups->setSelected(i, true);
		}
		limits->clear();
		ftplimit *fl=0;
		while((fl=thisclass->getNextLimit(fl)))
			limits->insertItem(fl->getId());
	} else
		current= QString::null;
}
void UserClasses::ftpaccessLoaded(ftpaccess *xs) // SLOT
{
	ftpxs=xs;
	limits->clear();
	redrawList();
}
void UserClasses::update() // SLOT
{
	ftpclass *c=0;
	ftpclass *thisclass=0;
	if(current!=0) {	// store current changes
		while((c=ftpxs->getNextClass(c))!=0 && thisclass==0)
			if(current == c->getName())
				thisclass=c;
		if(thisclass!=0) {
			thisclass->setAnon(anon->isChecked());
			thisclass->setGuest(guest->isChecked());
			thisclass->setReal(real->isChecked());
			thisclass->setAddrs(addrs->text());
			if(autogroup->isChecked()) {
				QString gr;
				for(unsigned int i=0; i<groups->count() && gr==0; i++)
					if(groups->isSelected(i)) gr=groups->text(i);
				thisclass->setAutogroup(gr);
			} else
				thisclass->setAutogroup(0);
		}
	}
}
