#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
#include "kernel/fs.h"

/* 
// copy from stat.h
struct stat {
  int dev;     // File system's disk device
  uint ino;    // Inode number
  short type;  // Type of file
  short nlink; // Number of links to file
  uint64 size; // Size of file in bytes
};
// copy from fs.h
struct dirent {
  ushort inum;
  char name[DIRSIZ];
};
struct dinode { // On-disk inode structure
  short type;           // File type
  short major;          // Major device number (T_DEVICE only)
  short minor;          // Minor device number (T_DEVICE only)
  short nlink;          // Number of links to inode in file system
  uint size;            // Size of file (bytes)
  uint addrs[NDIRECT+1];   // Data block addresses
};
*/

char* fmtname(char *path) {
  static char buf[DIRSIZ + 1]; // the size is 15
  char *p;
  // Find first character after last slash.
  for (p = path + strlen(path); p >= path && *p != '/';p--);
  p++;
  // Return blank-padded name.
  if (strlen(p) >= DIRSIZ) return p;
  memmove(buf, p, strlen(p));// copy from the tail, similar to memcpy
  memset(buf+strlen(p), ' ', DIRSIZ-strlen(p));// fill the rest of buf with blank
  buf[strlen(p)] = 0;
  return buf;
}

void find(char *path, char *fileName) {
  char buf[512], *p;// buf and p is to store new path iteratively
  int fd;// file discriptor
  struct stat st;
  struct dirent de;// describe the property of files
  // these two ifs copy from ls.h
  if ((fd = open(path, 0)) < 0 ) {
    fprintf(2, "find: cannot open %s\n", path);
    return;
  }
  if (fstat(fd, &st) < 0) {
    fprintf(2, "find: cannot stat %s\n", path);
    close(fd);
    return;
  }
  //printf("%s %s\n",path, fmtname(path));
  switch(st.type) {
  case T_FILE: // when the file is actually a file
    //printf("%s\n", fmtname(path));
    if (strcmp(fmtname(path), fileName) == 0) {
      printf("%s\n", path);
    }
    break;
  case T_DIR:
  // copy from ls.h
    //printf("%s %s\n", path, fmtname(path));
    if(strlen(path) + 1 + DIRSIZ + 1 > sizeof buf) {
      printf("find: path too long\n");
      break;
    }
    strcpy(buf, path);
    p = buf + strlen(buf);
    *p++ = '/';
    while (read(fd, &de, sizeof(de)) == sizeof(de)) {
      if (de.inum == 0 || strcmp(de.name, ".") == 0 || strcmp(de.name, "..") == 0) {
        continue;
      } // skip when the name is "." or ".." and inum is 0(known from ls.h)
      memmove(p, de.name, DIRSIZ); // copy the name to p
      p[DIRSIZ] = 0; // let the str end
      find(buf, fileName); // iteratively call the function util the buf is a T_FILE

    }
    break;
  }
  close(fd);
}

int main(int argc, char *argv[]) {
  if (argc < 3) {
    printf("error\n");
    exit(1);
  }
  find(argv[1], argv[2]);
  exit(0);
}