/********************** modified from t2.c *******************/
/********************* kman.c ********************************/

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#ifdef SYS_DIR
#include <sys_dir.h>
#else
#ifdef NDIR

#include <ndir.h>
#else
#include <dirent.h>
#endif
#endif

#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>

#include "mandata.h"
#include "mandatadef.h"
#include "util.h"
#include "context.h"
#include "rtfm.h"

#include <stdlib.h>
#include <glib.h>

void attach (char *dest, const char *dirname, const char *name);
static int section_translate_c_to_n(const char* c);
static int is_zip_suffix(char* c);

char buffer1[BUFFER_SIZE];
char buffer2[BUFFER_SIZE];

/************************* ManPath ************************/
ManPath::ManPath(char* _path_name)
{
	int i;
	active = 1;
	path_name = my_strdup(_path_name);
	for (i=0;i<MAX_MAN_SECTION;i++) section[i] = new List();
	LoadManPath(path_name);
}

ManPath::~ManPath()
{
	int i,j,k;
	for (i = 0;i<MAX_MAN_SECTION;i++) {
		k = section[i]->get_size();
		for(j = 0;j<k;j++) delete ((ManItem*)(section[i]->get_item(j)));
		delete(section[i]);
	}
	if(path_name) free(path_name);
}

int ManPath::GetSize(int section_ID)
{
	int count;
	int i;
	for (count = i = 0;i<MAX_MAN_SECTION;i++)
		if (1<<i & section_ID) count += section[i]->get_size();
	return count;
}

int ManPath::GetItems(int section_ID, ManItem * buffer[])
{
	int count;
	int i;
	for (count = i = 0;i<MAX_MAN_SECTION;i++)
		if (1<<i & section_ID) count += section[i]->get_items((void*)(buffer + count));
	return count;
}

const char * ManPath::GetPath() {return (const char*) path_name;}

struct stat state;

int ManPath::LoadManPath(char * path_name)
{
	DIR *dirp;
	#if defined(SYS_DIR)||defined(NDIR)
		struct direct *item;
	#else
		struct dirent *item;
	#endif

	ManItem * man_item;
	int val,i;
	
	//	printf("LoadManPath: %s\n",path_name);

	dirp = opendir(path_name);
	if (!dirp)
	{
		fprintf(stderr,"Can not open man path %s\n",path_name);
		return 1;  
	}
	for (item = readdir(dirp);item != NULL;item = readdir(dirp))
	{
		if(item->d_name[0] == '.' && (item->d_name[1] == 0 ||(item->d_name[1] == '.'&&item->d_name[2]==0)))
			continue;
		attach(buffer1,path_name,item->d_name);
		//printf("LoadManPath: %s\n",name);
		val = stat (buffer1, &state);
		if (val < 0) fprintf(stderr,"error getting state of %s: %s\n",buffer1,strerror(errno));
		else if (S_ISDIR(state.st_mode) && !strncmp(item->d_name,"man",3)) LoadManSubPath(item->d_name);
		else
		{
			man_item = new ManItem(this,item -> d_name);
			val = man_item->get_section_ID();
			if(!val) delete(man_item);
			else{
				for(i = 0;!(1<<i & val);i++);
				section[i]->add_item(man_item);
			}
			//printf("%d\n",n);
		}
	}
	closedir(dirp);
	return 0;
}

int ManPath::LoadManSubPath(char * sub_name)
{
	DIR *dirp;
	#if defined(SYS_DIR)||defined(NDIR)
		struct direct *item;
	#else
		struct dirent *item;
	#endif

	int val,i;
	ManItem * man_item;

	attach(buffer2,path_name,sub_name);
	//printf("LoadManSubPath: %s\n",buffer2);
	dirp = opendir(buffer2);
	if (!dirp)
	{
		fprintf(stderr,"Can not open man path %s\n",buffer2);
	}
	for (item = readdir(dirp);item != NULL;item = readdir(dirp))
	{
		if(item->d_name[0] == '.' && (item->d_name[1] == 0 ||(item->d_name[1] == '.'&&item->d_name[2]==0)))
			continue;
		attach(buffer1,buffer2,item->d_name);
		//printf("LoadManSubPath: %s\n",full_name);
		val = stat (buffer1, &state);
		if (val < 0) fprintf(stderr,"error getting state of %s: %s\n",buffer1,strerror(errno));
		else if (S_ISDIR(state.st_mode)) continue;
		else
		{
			attach(buffer1,sub_name,item->d_name);
			man_item = new ManItem(this,buffer1);
			val = man_item->get_section_ID();
			if(!val) delete(man_item);
			else{
				for(i = 0;!(1<<i & val);i++);
				section[i]->add_item(man_item);
			}
		}
	}
	closedir(dirp);
	return 0;
}

ManItem * ManPath::search_man_item(char * name, char * sect)
{
	int i,j,k;
	int len;
	ManItem * a;
	char buffer[100];

	len = strlen(name);
	if(section) {
		j = section_translate_c_to_n(sect);
		//printf("point0.1\n");
		if(!j) return NULL;
		for(i = 0;!(1<<i & j);i++);
		//printf("point0.2, section = %x,%d: section[i] = %x\n", j,i,section[i]);
		k = section[i]->get_size();
		//printf("point0.25, k = %d\n",k);
		for(j = 0;j<k;j++) {
			a=(ManItem*)(section[i]->get_item(j));
			if(!strcmp(name,a->get_display_name(buffer))) return a;
		}
		a = NULL;
	}
	return NULL;
}

/************************* ManItem ************************/
inline ManItem::ManItem(ManPath* _man_path, char* _file_name)
{
	file_name = my_strdup(_file_name);
	man_path = _man_path;
	display_name = strrchr(file_name,'/');
	display_name = display_name? display_name + sizeof('/'):file_name;
	section_name = strrchr(display_name,'.');
	if (!section_name) { section_ID = 0; return;}
	for (;is_zip_suffix(section_name) && section_name != display_name;) 
		for(section_name--;section_name != display_name && *section_name != '.';section_name --);
	if (section_name == display_name) {section_ID = 0; return;}
	section_ID = section_translate_c_to_n(++section_name);
	//if(!section_ID) printf("%s\n",display_name);
}

inline ManItem::~ManItem()
{
	if(file_name) free(file_name);
}

char * ManItem::get_display_name(char * buffer)
{
	char * p2 = buffer;
	for(char * p = display_name;p+1 != section_name && *p != '\0';) *buffer++ = *p++;
	*buffer = '\0';
	return p2;
}

char * ManItem::get_section_name(char * buffer)
{
	char * p2 = buffer;
	for(char * p = section_name;*p != '.' && *p != '\0';) *buffer++ = *p++;
	*buffer = '\0';
	return p2;
}

int ManItem::get_section_ID() {return section_ID;}

void * ManItem::get_man_path() {return (void *)man_path;}

void ManItem::active_man_page(void)
{
	int len;
	char buffer[2*BUFFER_SIZE];
	char loc_name[BUFFER_SIZE];
	char buffer2[BUFFER_SIZE];
	switch ((int)context->get_value("show_mode")) {
	case 0:
		sprintf(buffer,"%s -T '%s manual page' -n RTFM -e man ",
				(char*)context->get_value("xterm_command"),
				get_display_name(buffer1));
		len = strlen(buffer);
		attach(buffer+len,man_path->GetPath(),file_name);
		//g_warning(buffer);
		if(!fork())
		{
			//printf(buffer);
			system(buffer);
			_exit(0);
		}
		break;
	case 1:
		sprintf(loc_name," ~/.rtfm.%s.ps ",get_display_name(buffer1));
		sprintf(buffer,"man -t ");
		len = strlen(buffer);
		attach(buffer+len,man_path->GetPath(),file_name);
		strcat(buffer," >> ");
		strcat(buffer,loc_name);
		strcat(buffer," ; ");
		strcat(buffer,(char*)context->get_value("gv_command"));
		strcat(buffer,loc_name);
		strcat(buffer," ; rm ");
		strcat(buffer,loc_name);
		//g_warning(buffer);
		if(!fork())
		{
			//printf(buffer);
			system(buffer);
			_exit(0);
		}
		break;
	case 2:
		sprintf(buffer,"coolman ");
		len = strlen(buffer);
		attach(buffer+len,man_path->GetPath(),file_name);
		//g_warning(buffer);
		if(!fork())
		{
			//printf(buffer);
			system(buffer);
			_exit(0);
		}
		break;
	default:
		if(context->get_value("show_warning"))
			g_print("unexpected \'show_mode\' : %d ",(int)context->get_value("show_mode"));
		return;
	}
	//g_warning(buffer);
	
	
	return;
}
	
/************************* init global data ************************/

/* Put DIRNAME/NAME into DEST, handling `.' and `/' properly. */

void attach (char *dest, const char *dirname, const char *name)
{
	const char *dirnamep = dirname;

    /* Copy dirname if it is not ".". */
	if (dirname[0] != '.' || dirname[1] != 0)
	{
		while (*dirnamep) *dest++ = *dirnamep++;
		/* Add '/' if `dirname' doesn't already end with it. */
		if (dirnamep > dirname && dirnamep[-1] != '/') *dest++ = '/';
	}
	while (*name) *dest++ = *name++;
	*dest = 0;
}

int section_translate_c_to_n(const char *c)
{
	int i;
	for(i=0;sections[i].name && strncmp(sections[i].name,c,sections[i].n);i++);
	if(sections[i].name == NULL) return 0;  // no match
	return 1<<i;
}

int is_zip_suffix(char * s)
{
	int i;
	for (i=0;suffix[i].name && strncmp(suffix[i].name,s,suffix[i].n);i++);
	return suffix[i].n;
}

int man_item_compare(ManItem ** a,ManItem ** b)
{
	return (strcmp((*a)->get_display_name(buffer1),(*b)->get_display_name(buffer2)));
}

/*
int ItemMatch(char * name)
{
	int i;
	for (i=0;i<item_list_count && strcmp(name,item_list[i]->display_name)>0 ;i++);
	return (i >= item_list_count)? i-1:i;
}
*/

	
