#include "BrowserDelegate.h"

#include <stdlib.h>
#include <string.h>

#include <dirent.h>
#include <errno.h>
#include <signal.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/param.h>
#include "appkit/Matrix.h"
#include "appkit/MList.h"
#include "appkit/NXBrowser.h"
#include "appkit/NXBrowserCell.h"
#include "appkit/ScrollView.h"
#include "appkit/stdmacros.h"
#include <objc/List.h>
#include <ctype.h>

@implementation BrowserDelegate :Object

static void exec(char **argv)
{
    int p[2];
    int pid;

    if (pipe(p) == -1) {
        perror("error creating pipe");
        exit(1);
    }
    pid = fork();
    if (pid == -1) {
        perror("bad pid number\n");
        exit(1);
    }
    if (pid == 0) {
        close(p[0]);
        dup2(p[1], 1);
        close(p[1]);
	printf("%s %s %s\n", argv[0], argv[1], argv[2]);
        if (argv[1] == NULL) {
          execl(argv[0], argv[0], (char *)0);
        } else {
          execl(argv[0], argv[0], argv[1], (char *)0);
        }
        perror("error in exec call\n");
        exit(1);
    } else {
        close(p[1]);
        dup2(p[0], 0);
        close(p[0]);
    }
}

int findexec(const char *filename, char *pathptr)
{
  char *path, *patho, *cur;
  struct stat buf;

  patho = getenv("PATH");
  path = alloca(strlen(patho)+1);
  strcpy(path, patho);
  if (path == 0)
    return -1;
  cur = strtok(path, "=:");
  while(1) {
    if (cur == 0)
      break;
    strcpy(pathptr, cur);
    strcat(pathptr, "/");
    strcat(pathptr, filename);
    stat(pathptr, &buf);
    if (S_ISREG(buf.st_mode)) {
      uid_t uid, euid;
      gid_t gid, egid;
      mode_t mask = S_IXOTH;

      uid = getuid();
      euid = geteuid();
      gid = getgid();
      egid = getegid();

      if (uid == buf.st_uid || euid == buf.st_uid)
        mask = S_IXUSR;
      else if (gid == buf.st_gid || egid == buf.st_gid)
        mask = S_IXGRP;

      if (buf.st_mode | mask)
        return 0;
    }
    cur = strtok(0, ":");
  }
  return -1;
}

static BOOL isExec(char *dirpath)
{
    struct stat stbuf;

    if (stat(dirpath, &stbuf) == -1) {
       fprintf(stderr, "can't access %s\n", dirpath);
    }
    return (stbuf.st_mode & 0111);
}

static int is_lower( NXBrowserCell **cellOne, NXBrowserCell **cellTwo )
{
    int 	i = 0;
    const char	*wordOne, *wordTwo;
    char 	one, two;
    BOOL 	isLetterOne, isLetterTwo;

    wordOne = [*cellOne stringValue];
    wordTwo = [*cellTwo stringValue];
    while ((wordOne[i] != '\0') && (wordTwo[i] != '\0')) {
	one = tolower(wordOne[i]);
	isLetterOne = ((one >= 'a') && (one <= 'z'));
	two = tolower(wordTwo[i]);
	isLetterTwo = ((two >= 'a') && (two <= 'z'));
	if ((isLetterOne) && (!isLetterTwo))
		return -1;
	if ((!isLetterOne) && (isLetterTwo))
		return +1;
	if (one < two)
		return -1;
	if (one > two)
		return +1;
	i++;
    }
    if (wordOne[i] == '\0')
	return +1;
    return -1;
}
/* the browser passes an empty matrix for this delegate to fill in */

- (int)browser:sender fillMatrix:matrix inColumn:(int)column
{
    List		*list;
    NXBrowserCell	*aCell;
    NXBrowserCell	**listPtr;
    DIR			*dirp;
    struct dirent	*entry;
    struct stat 	statbuf;
    char		dir_path[MAXPATHLEN];
    char		file_path[MAXPATHLEN];
    char		cell_entry[MAXPATHLEN];
    char		*p;
    int                 numRows = 0;
    int			i = 0;;

    if (column == 0) {
        strcpy( dir_path, "/" );
    } else {
	[sender getPath:dir_path toColumn:column-1];
    }
    if ( (dirp = opendir(dir_path) ) == NULL ) {
        return 0;
    }
    strcpy( file_path, dir_path );
    if ( column != 0 ) 
	strcat( file_path, "/" );
    p = file_path + strlen(file_path);
    while( (entry = readdir(dirp) ) != NULL ) {
	if (strcmp(entry->d_name, ".") == 0 || 
	    strcmp(entry->d_name, "..") == 0) {
	    continue; /* skip self and parent */
	}
	[matrix addRow];
	aCell = [matrix cellAt:i :0];
	strcpy(cell_entry, entry->d_name);
	*p = '\0';
	strcat( p, entry->d_name );
	stat( file_path, &statbuf );
	if ( (statbuf.st_mode & S_IFMT) == S_IFDIR ) {
	    strcat(cell_entry, "/");
	    [aCell setStringValue:cell_entry];
	    [aCell setLeaf:NO];
	} else {
	    [aCell setStringValue:cell_entry];
	    [aCell setLeaf:YES];
	}
	[aCell setLoaded:YES];
	i++;
    }
    numRows = i;
    list = [matrix cellList];
    listPtr = NX_ADDRESS(list);
    qsort(listPtr, numRows, sizeof(id), is_lower );
    return numRows;
}
- execute:sender
{
    char	filename[MAXPATHLEN];
    char	*editor;
    char	**argv;
    int		column;

    column = [sender selectedColumn];
    [sender getPath:filename toColumn:column];
    
    if ( isExec(filename) ) {
       printf("this is a exectutable\n");
       argv = alloca(2 * sizeof argv[0]);
       argv[0] = filename;
       argv[1] = NULL;
    } else {
       argv = alloca(3 * sizeof argv[0]);
       editor = getenv("EDITOR");
       if ( !editor ) 
           return self;
       argv[0] = malloc(MAXPATHLEN);
       if (findexec(editor, argv[0])) {
         fprintf(stderr, "%s not in path\n", editor);
         return self;
       }
       argv[1] = filename;
       argv[2] = NULL;
    }
    exec(argv);
   
    return self;
}
 
@end



