#ifndef PROC_PROC_H_
#define PROC_PROC_H_

#include <stdint.h>
#include "hal/hal.h"
#include "spinlock/spinlock.h"
#include "bitmap/bitmap.h"
#include "vfs/vfs.h"
#include "ipc/pipe/pipe.h"
#include "sysdefs/proc.h"
#include "sysdefs/time.h"
#include "dev/dev.h"

#define PROC_NAME_MAX 0x100

#define PROC_STACKBLOCKS (1024*1)
#define PROC_STACKSIZE (PROC_STACKBLOCKS * BITMAP_BLOCK_SIZE)

#define PROC_MAX 0x100 // max amount of processes

#define PROC_VFSHANDLES_MAX   0x80
#define PROC_PIPEHANDLES_MAX  0x20
#define PROC_DEVHANDLES_MAX   0x20

#define PROC_MMAN_MAP_BASE  0x0000100000000000ULL
#define PROC_USER_STACK_TOP 0x00007FFFFFFFF000ULL

typedef struct {
  IntrStackFrame trapframe;
  uint8_t *kstack;
  uint8_t *pstack;
  uint64_t cr3;
} ProcPlatformData;

enum {
  PROC_EMBRYO = 0,
  PROC_READY = 1,
  PROC_ZOMBIE = 2,
  PROC_WAITING = 3,
  PROC_DIED = 4,
};

typedef struct ProcArg {
  struct ProcArg *next;
  char string[PROC_ARG_MAX];
} ProcArg;

typedef struct Proc {
  struct Proc *next;

  uint64_t pid;
  char name[PROC_NAME_MAX];

  ProcPlatformData platformdata;
  uint8_t state;
  VasRange *vas;

  VfsObj *vobjs[PROC_VFSHANDLES_MAX];

  IpcPipe *pipes[PROC_PIPEHANDLES_MAX];
  SpinLock pipes_spinlock;

  Dev *devs[PROC_DEVHANDLES_MAX];
  SpinLock devs_spinlock;

  struct {
    ProcArg *list;
    size_t len;
  } procargs;

  uint64_t mman_map_base;

  Time time;
} Proc;

typedef struct {
  SpinLock spinlock;
  Proc *procs;
  Proc *current;
} Procs;

extern Procs PROCS;

void proc_init(void);
void proc_register(Proc *proc);
Proc *proc_spawnuser(char *mountpoint, char *path);
void proc_sched(void *cpustate);
void proc_killself(void);
void proc_kill(Proc *proc);

#define PROC_DIE() \
  do { \
    proc_killself(); \
    for(;;); \
  } while(0)


#define PROC_ARG(proc, str) \
  do { \
    ProcArg *__arg = dlmalloc(sizeof(*__arg)); \
    hal_strcpy(__arg->string, (str)); \
    LL_APPEND((proc)->procargs.list, __arg); \
    (proc)->procargs.len++; \
  } while(0)
#endif // PROC_PROC_H_
