#include <config.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
#include <iostream.h>
#include <grp.h>
#include <pwd.h>

#include <qtstream.h>
#include <qimage.h>
#include "fileinfo.h"

char	*monthes[] = {"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};

int getMonthNumber(const QString& name)
{
	int	result = 0;
	while (result < 12 && name != monthes[result]) result++;
	return (result != 12 ? (result+1) : -1);
}

int getMonth(const QDict<int>& dict)
{
	int	index(0), *p;
	while (index < 12 && (p = dict.find(monthes[index++])) == 0) ;
	return (p ? *p : -1);
}

FileInfo::FileInfo(const char *file, int val)
{
	switch (val) {
	   case 0: parseFileString(file); break;
	   case 1:
	   case 2: parseFTPString(file,(val==1)); break;
	   case 3: parseTarString(file); break;
	   case 4: parseZipString(file); break;
	   case 5: parseRpmString(file); break;
	}
}

void FileInfo::parseFileString(const char *file)
{
// if file is a directory, it must contain a trailing /
	QString		File(file);
	struct stat	st;
	lstat(file,&st);
	Path = file;
	Name = File.right(File.length()-File.findRev('/',File.length()-2)-1);
	if (Name[Name.length()-1] == '/') Name.truncate(Name.length()-1);
	struct group	*st_g = getgrgid(st.st_gid);
	Group = (st_g ? st_g->gr_name : "");
	struct passwd	*st_pw = getpwuid(st.st_uid);
	Owner = (st_pw ? st_pw->pw_name : "");
	Mode = (0xFFFF & st.st_mode);
	Permissions.resize(10);
	if (Mode & S_IRUSR) Permissions[0] = 'r'; else Permissions[0] = '-';
	if (Mode & S_IWUSR) Permissions[1] = 'w'; else Permissions[1] = '-';
	if (Mode & S_IXUSR) Permissions[2] = 'x'; else Permissions[2] = '-';
	if (Mode & S_IRGRP) Permissions[3] = 'r'; else Permissions[3] = '-';
	if (Mode & S_IWGRP) Permissions[4] = 'w'; else Permissions[4] = '-';
	if (Mode & S_IXGRP) Permissions[5] = 'x'; else Permissions[5] = '-';
	if (Mode & S_IROTH) Permissions[6] = 'r'; else Permissions[6] = '-';
	if (Mode & S_IWOTH) Permissions[7] = 'w'; else Permissions[7] = '-';
	if (Mode & S_IXOTH) Permissions[8] = 'x'; else Permissions[8] = '-';
	UserMode = 0;
	Size = st.st_size;
	Date.setTime_t(st.st_mtime);
	if (isSymLink()) {
		LinkPath.resize(1025);
		int n = ::readlink(Path.data(),LinkPath.data(),1024);
		LinkPath.resize(n+1);
		stat(file,&st);
		RealMode = (0xFFFF & st.st_mode);
	}
	else {
		LinkPath = "";
		RealMode = Mode;
	}
	nLinks = st.st_nlink;
	if (::access(file,R_OK) == 0) UserMode |= READ_OK;
	if (::access(file,W_OK) == 0) UserMode |= WRITE_OK;
	if (::access(file,X_OK) == 0) UserMode |= EXEC_OK;
	Icon = MiniIcon = 0;
	MimeType = 0;
	Cutted = FALSE;
	Local = TRUE;
	MiniImage = QPixmap();
	YetSearchedForMiniImage = false;
}

FileInfo::FileInfo(QFileInfo *fi)
{
	struct stat	st;
	lstat(fi->absFilePath().data(),&st);
	Name = fi->fileName();
	Path = fi->absFilePath().data();
	Owner = fi->owner();
	Group = fi->group();
	Mode = (0xFFFF & st.st_mode);
	Permissions.resize(10);
	if (Mode & S_IRUSR) Permissions[0] = 'r'; else Permissions[0] = '-';
	if (Mode & S_IWUSR) Permissions[1] = 'w'; else Permissions[1] = '-';
	if (Mode & S_IXUSR) Permissions[2] = 'x'; else Permissions[2] = '-';
	if (Mode & S_IRGRP) Permissions[3] = 'r'; else Permissions[3] = '-';
	if (Mode & S_IWGRP) Permissions[4] = 'w'; else Permissions[4] = '-';
	if (Mode & S_IXGRP) Permissions[5] = 'x'; else Permissions[5] = '-';
	if (Mode & S_IROTH) Permissions[6] = 'r'; else Permissions[6] = '-';
	if (Mode & S_IWOTH) Permissions[7] = 'w'; else Permissions[7] = '-';
	if (Mode & S_IXOTH) Permissions[8] = 'x'; else Permissions[8] = '-';
	UserMode = 0;
	Size = st.st_size;
	Date.setTime_t(st.st_mtime);
	if (isSymLink()) {
		LinkPath.resize(1025);
		int n = ::readlink(Path.data(),LinkPath.data(),1024);
		LinkPath.resize(n+1);
		stat(fi->absFilePath().data(),&st);
		RealMode = (0xFFFF & st.st_mode);
	}
	else {
		LinkPath = "";
		RealMode = Mode;
	}
	nLinks = st.st_nlink;
	if (fi->isReadable()) UserMode |= READ_OK;
	if (fi->isWritable()) UserMode |= WRITE_OK;
	if (fi->isExecutable()) UserMode |= EXEC_OK;
	Icon = MiniIcon = 0;
	MimeType = 0;
	Cutted = FALSE;
	Local = TRUE;
	MiniImage = QPixmap();
	YetSearchedForMiniImage = false;
}

void FileInfo::parseFTPString(const char *str, bool Unix)
{
cout << "fileinfo : " << str << endl;
	QString	Str(str);
	Str += ' ';
	QStrList	list(TRUE);
	QDict<int>	dict;
	int		index(0);
	char	*last;
	char	*c = strtok_r(Str.data()," \r",&last);
	while (c) {
		list.append(c);
		dict.insert(c,new int(index++));
		c = strtok_r(0," \r",&last);
	}
	Str.truncate(0);
	Str = list.at(0);
	Mode = RealMode = 0;
	UserMode = 0;
	switch(Str[0]) {
	   case 'd': RealMode |= S_IFDIR; break;
	   case 'l': Mode |= S_IFLNK; if (!Unix) RealMode |= S_IFDIR; break;
	   case 'p': RealMode |= S_IFIFO; break;
	   case 'b': RealMode |= S_IFBLK; break;
	   case 'c': RealMode |= S_IFCHR; break;
	   case '-': RealMode |= S_IFREG; break;
	}
	int	mod = S_IRUSR;
	for (int i=1;i<10;i++) {
		if (Str[i] != '-') RealMode |= mod;
		mod >>= 1;
	}
	Permissions = Str.right(9);
	nLinks = QString(list.at(1)).toInt();
	int	nMonth = getMonth(dict);
	if (nMonth != -1) {
		if (nMonth > 3) Owner = list.at(2);
		if (nMonth > 4) Group = list.at(3);
		Size = QString(list.at(nMonth-1)).toInt();
		QDate	date;
		if (QString(list.at(nMonth+2)).find(':') < 0) {
			date.setYMD(QString(list.at(nMonth+2)).toInt(),getMonthNumber(QString(list.at(nMonth))),QString(list.at(nMonth+1)).toInt());
			Date.setDate(date);
		}
		else {
			const long int	timeval = time(0);
			struct tm	*t = localtime(&timeval);
			date.setYMD(t->tm_year+1900,getMonthNumber(QString(list.at(nMonth))),QString(list.at(nMonth+1)).toInt());
			Date.setDate(date);
			QString		Time(list.at(nMonth+2));
			QString		h = Time.mid(0,2), m = Time.mid(3,2);
			QTime		tmpTime(h.toInt(),m.toInt());
			Date.setTime(tmpTime);
		}
		Name = "";
		int	end = (isSymLink() ? (Unix ? *dict.find("->") : list.count()) : list.count());
		for (int i=nMonth+3;i<end;i++) {
			Name += list.at(i);
			if (i<end-1) Name += " ";
		}
		switch (Name[Name.length()-1]) {
		   case '*': mod = 1; UserMode |= EXEC_OK; break;
		   case '/': mod = 1; break;
		   case '@': mod = 1; break;
		   default: mod = 0; break;
		}
		Name.truncate(Name.length()-mod);
		if (isSymLink() && Unix) {
			UserMode |= (READ_OK | WRITE_OK);
			for (int i=end+1;i<(int)(list.count());i++) {
				LinkPath += list.at(i);
				if (i<(int)(list.count()-1)) LinkPath += " ";
			}
			switch (LinkPath[LinkPath.length()-1]) {
			   case '*': mod = 1; UserMode |= EXEC_OK; break;
			   case '/': mod = 1; RealMode |= S_IFDIR; UserMode |= EXEC_OK; break;
			   default : mod = 0; break;
			}
			LinkPath.truncate(LinkPath.length()-mod);
		}
		else {
			if ((RealMode & S_IROTH)) UserMode |= READ_OK;
			if ((RealMode & S_IROTH)) UserMode |= WRITE_OK;
			if ((RealMode & S_IROTH)) UserMode |= EXEC_OK;
			LinkPath = "";
		}
	}
	Icon = MiniIcon = 0;
	MimeType = 0;
	Cutted = Local = FALSE;
	MiniImage = QPixmap();
	YetSearchedForMiniImage = false;
}

void FileInfo::parseTarString(const char *file)
{
	QStrList	list;
	QString		Str(file);
	char	*last, *c = strtok_r(Str.data()," ",&last);
	while (c) {
		list.append(c);
		c = strtok_r(0," ",&last);
	}
	Str.truncate(0);
	Str = list.at(0);
	Mode = RealMode = 0;
	UserMode = 0;
	switch(Str[0]) {
	   case 'd': RealMode |= S_IFDIR; break;
	   case 'l': Mode |= S_IFLNK; break;
	   case 'p': RealMode |= S_IFIFO; break;
	   case 'b': RealMode |= S_IFBLK; break;
	   case 'c': RealMode |= S_IFCHR; break;
	   case '-': RealMode |= S_IFREG; break;
	}
	int	mod = S_IRUSR;
	for (int i=1;i<10;i++) {
		if (Str[i] != '-') RealMode |= mod;
		mod >>= 1;
	}
	Permissions = Str.right(9);
	Str = list.at(1);
	mod = Str.find('/');
	Owner = Str.left(mod);
	Group = Str.right(Str.length()-mod-1);
	Size = QString(list.at(2)).toInt();
	Str = list.at(3);
	int	y,m,d;
	y = Str.left(4).toInt();
	d = Str.right(2).toInt();
	m = Str.mid(5,2).toInt();
	QDate	date;
	date.setYMD(y,m,d);
	Str = list.at(4);
	y = Str.left(2).toInt();
	m = Str.right(2).toInt();
	QTime	ti(y,m);
	Date.setDate(date);
	Date.setTime(ti);
	Name = list.at(5);
	if (isSymLink()) LinkPath = list.at(7);
	if ((RealMode & S_IRUSR)) UserMode |= READ_OK;
	if ((RealMode & S_IRUSR)) UserMode |= WRITE_OK;
	if ((RealMode & S_IRUSR)) UserMode |= EXEC_OK;
	Icon = MiniIcon = 0;
	MimeType = 0;
	Cutted = Local = FALSE;
}

void FileInfo::parseZipString(const char *file)
{
	QStrList	list;
	QString		Str(file);
	Str += ' ';
	char	*last, *c = strtok_r(Str.data()," ",&last);
	while (c) {
		list.append(c);
		c = strtok_r(0," ",&last);
	}
	Str.truncate(0);
	Size = QString(list.at(0)).toInt();
	Str = list.at(1);
	int	y,m,d;
	m = Str.left(2).toInt();
	y = Str.right(2).toInt();
	d = Str.mid(3,2).toInt();
	y += (y<60 ? 2000 : 1900);
	QDate	date;
	date.setYMD(y,m,d);
	Str = list.at(2);
	y = Str.left(2).toInt();
	m = Str.right(2).toInt();
	QTime	ti(y,m);
	Date.setDate(date);
	Date.setTime(ti);
	Name = list.at(3);
	RealMode = 0;
	RealMode |= (Name[Name.length()-1] == '/' ? S_IFDIR : S_IFREG);
	LinkPath = "";
	RealMode |= (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
	UserMode = (READ_OK | WRITE_OK);
	if (isDir()) {
		RealMode |= (S_IXUSR | S_IXGRP | S_IXOTH);
		UserMode |= EXEC_OK;
		Permissions = "rwxr-xr-x";
	}
	else Permissions = "rw-r--r--";
	Mode = RealMode;
	Icon = MiniIcon = 0;
	MimeType = 0;
	Cutted = Local = FALSE;
}

void FileInfo::parseRpmString(const char *file)
{
	QStrList	list;
	QString		Str(file);
	Str += ' ';
	char	*last, *c = strtok_r(Str.data()," ",&last);
	while (c) {
		list.append(c);
		c = strtok_r(0," ",&last);
	}
	Str.truncate(0);
	Name = list.at(0);
	Size = QString(list.at(1)).toInt();
	Date.setTime_t(QString(list.at(2)).toInt());
	int	pos = list.count()-7;
	Owner = list.at(pos+1);
	Group = list.at(pos+2);
	LinkPath = list.last();
	sscanf(list.at(pos),"%o",&Mode);
	RealMode = Mode;
	if (!isSymLink()) LinkPath.truncate(0);
	if (isDir() && Name[Name.length()-1] != '/') Name += '/';
	Permissions.truncate(0);
	Permissions += (Mode & S_IRUSR ? "r" : "-");
	Permissions += (Mode & S_IWUSR ? "w" : "-");
	Permissions += (Mode & S_IXUSR ? "x" : "-");
	Permissions += (Mode & S_IRGRP ? "r" : "-");
	Permissions += (Mode & S_IWGRP ? "w" : "-");
	Permissions += (Mode & S_IXGRP ? "x" : "-");
	Permissions += (Mode & S_IROTH ? "r" : "-");
	Permissions += (Mode & S_IWOTH ? "w" : "-");
	Permissions += (Mode & S_IXOTH ? "x" : "-");
	UserMode = 0;
	if ((RealMode & S_IROTH)) UserMode |= READ_OK;
	if ((RealMode & S_IROTH)) UserMode |= WRITE_OK;
	if ((RealMode & S_IROTH)) UserMode |= EXEC_OK;
	Icon = MiniIcon = 0;
	MimeType = 0;
	Cutted = Local = FALSE;
}

FileInfo::FileInfo(const FileInfo& kfi)
	: Name(kfi.Name.data()), Path(kfi.Path.data()), Owner(kfi.Owner.data()), Group(kfi.Group.data()),
	  Mode(kfi.Mode), RealMode(kfi.RealMode), UserMode(kfi.UserMode), Size(kfi.Size), Date(kfi.Date), LinkPath(kfi.LinkPath.data()),
	  Icon(kfi.Icon), MiniIcon(kfi.MiniIcon), Desc(kfi.Desc.data()), OpenAppl(kfi.OpenAppl.data()),
	  Index(kfi.Index), Permissions(kfi.Permissions), MimeType(kfi.MimeType), Cutted(kfi.Cutted),
	  nLinks(kfi.nLinks), Local(kfi.Local), MiniImage(kfi.MiniImage),YetSearchedForMiniImage(kfi.YetSearchedForMiniImage)
{
}

FileInfo::~FileInfo()
{
}

QString FileInfo::extension() const
{
	QString		ext;
	int	p = Name.find('.');
	if (p < 0) return ext;
	ext = Name.mid(p+1,Name.length());
	return ext;
}

QString FileInfo::lastExtension() const
{
	QString		ext;
	int	p = Name.findRev('.');
	if (p < 0) return ext;
	ext = Name.mid(p+1,Name.length());
	return ext;
}

QString FileInfo::dirPath() const
{
	int	p = Path.findRev('/',Path.length()-2);
	return Path.left(p+1);
}

bool FileInfo::isReadable() const
{
	return (S_ISDIR(Mode) ? ((UserMode & READ_OK) && (UserMode & EXEC_OK)) : (UserMode & READ_OK));
}

