#include <time.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <dirent.h>
#include <limits.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include "myc_str.h"
#include "myc_fortran.h"

typedef struct NameList {
  struct NameList *next;
  int l;
  char name[16];
} NameList;

typedef struct {
  char path[PATH_MAX];
  int start;
  time_t newestTime;
  char newestPath[PATH_MAX];
  char newestItem[PATH_MAX];
  int numor;
  int cnt;
  int mode;
  int level;
  int maxlevel;
} TascomDirScan;

void TascomScanDir(TascomDirScan *scan, int length, char *name) {
  DIR *dir;
  struct dirent *ent;
  struct stat st;
  int l, n;
  char rp[PATH_MAX];
  int cnt;
  char *ename;
  NameList *list, *p, *q;
  
  l = strlen(name);
  if (length+l > PATH_MAX-2) {
    printf(" filename too long\n");
    exit(1);
  }
  if (strcmp(name, ".") != 0) {
    scan->path[length]='/';
    length++;
    strcpy(scan->path+length, name);
    length += l;
  }
  realpath(scan->path, rp);
  if (strcmp(scan->path, rp) != 0) return; /* check for symbolic link */
  if (0>stat(scan->path, &st)) return;
  if (! S_ISDIR(st.st_mode)) return;
  dir=opendir(scan->path);
  if (dir == NULL) return;
  ent = readdir(dir);
  cnt = scan->cnt;
  list = NULL;
  while (ent != NULL) {
    ename = ent->d_name;
    if (strchr(ename,'.') == NULL) {
      scan->level++;
      TascomScanDir(scan, length, ename);
      scan->level--;
      scan->path[length+1]='\0';
    } else {
      l = strlen(ename);
      if (l == 12 && strcmp(ename+8,".dat") == 0) {
        l = 7;
        while (l>0 && ename[l] >= '0' && ename[l] <= '9') {
          l--;
        }
        l++;
        if (l != 8) {
          p = list;
          while (p != NULL && (p->l != l || strncmp(p->name, ename, l) != 0)) {
            p = p->next;
          }
          if (!p) {
            p = calloc(1, sizeof *p);
            p->next = list;
            list = p;
            p->l = l;
            if (scan->level > scan->maxlevel) scan->maxlevel = scan->level;
          }
          if (strcmp(ename, p->name) > 0) {
            strncpy(p->name, ename, 12);
            p->name[12]='\0';
          }
        }
      }
    }
    ent = readdir(dir);
  }
  p = list;
  while (p != NULL) {
    scan->path[length]='/';
    scan->path[length+1]='\0';
    str_copy(rp, scan->path);
    str_append(rp, p->name);
    n=0;
    sscanf(p->name + p->l, "%d", &n);
    if (stat(rp, &st) >= 0) {
      if (st.st_mtime > scan->newestTime) {
        scan->newestTime = st.st_mtime;
        str_copy(scan->newestPath, rp);
        snprintf(scan->newestItem, sizeof scan->newestItem,
          "%.*s%.*s", length-scan->start+1, scan->path+scan->start, p->l, p->name);
        scan->numor = n;
      }
    }
    if (scan->mode == 0) {
      printf(" %.*s%.*s (%d)\n", length-scan->start+1, scan->path+scan->start, p->l, p->name, n);
    }
    scan->cnt++;
    q = p;
    p = p->next;
    free(q);
  }
  if (scan->mode == 1 && scan->level == 1 && scan->cnt > cnt) {
    scan->path[length]='\0';
    printf(" %s\n", scan->path + scan->start);
  }
}

char *TascomGetDir(char *path) {
  char answer[128];
  char *nl, *slash;
  DIR *dir;
  static TascomDirScan scan;
  static char subdir[PATH_MAX];
  int start;
  
  realpath(path, scan.path);
  dir=opendir(scan.path);
  if (dir == NULL) return NULL;
  closedir(dir);
  start = strlen(scan.path) + 1;
  scan.start = start;
  scan.newestTime = 0;
  scan.newestPath[0] = '\0';
  scan.mode = 1;
  scan.level = 0;
  scan.maxlevel = 0;
  scan.cnt = 0;
  printf("\n User directories on %s:\n", path);
  printf("\n");
  TascomScanDir(&scan, start-1, ".");
  slash = strchr(scan.newestPath+scan.start+1, '/');
  if (slash) *slash = '\0';
  
  printf("\n user directory [%s]: ", scan.newestPath+scan.start);
  answer[0]='\0';
  fgets(answer, sizeof answer, stdin);
  nl = strchr(answer, '\n');
  if (nl) *nl='\0';
  if (answer[0] == '\0') {
    str_copy(subdir, scan.newestPath+start);
  } else {
    scan.path[start]='/';
    scan.path[start+1]='\0';
    str_append(scan.path, answer);
    dir = opendir(scan.path);
    if (!dir) {
      perror(answer);
      return "";
    }
    closedir(dir);
    str_copy(subdir, answer);
  }
  printf("\n");

  scan.start = start + strlen(subdir) + 1;
  scan.newestTime = 0;
  scan.newestPath[0] = '\0';
  scan.mode = 0;
  scan.level = 0;
  scan.maxlevel = 0;
  scan.cnt = 0;
  TascomScanDir(&scan, start-1, subdir);
  
  scan.newestPath[scan.start+strlen(scan.newestItem)]='\0';
  printf("\n");
  if (scan.cnt == 0) {
    return "";
  }
  if (scan.cnt == 1) {
    return scan.newestPath + start;
  }
  printf(" ");
  if (scan.maxlevel > 0) {
    printf("(subdirectory/)");
  }
  printf("filename [%s]: ", scan.newestItem);
  answer[0]='\0';
  fgets(answer, sizeof answer, stdin);
  printf("\n");
  nl = strchr(answer, '\n');
  if (nl) *nl='\0';
  if (answer[0] == '\0') {
    return scan.newestPath + start;
  } else {
    scan.path[scan.start+1]='\0';
    str_append(scan.path, answer);
    return scan.path + start;
  }
}

void F_FUN(dat_tascom_datadir)(F_CHAR(root), F_CHAR(path) F_CLEN(root) F_CLEN(path)) {
  char rootc[PATH_MAX];
  char *out;
  
  STR_TO_C(rootc, root);
  out=TascomGetDir(rootc);
  if (out) {
    STR_TO_F(path, out);
  } else {
    STR_TO_F(path, "0");
  }
}
