#include <stdint.h>  /* for uint64_t */

/* set in the tv_nsec field of a node's mtime */
enum {
	/* we haven't stat the file yet */
	MTIME_UNKNOWN = -1,
	/* the file does not exist */
	MTIME_MISSING = -2,
};

struct node {
	/* shellpath is the escaped shell path, and is populated as needed by nodepath */
	struct string *path, *shellpath;

	/* modification time of file (in nanoseconds) and build log entry (in seconds) */
	int64_t mtime, logmtime;

	/* generating edge and dependent edges */
	struct edge *gen, **use;
	size_t nuse;

	/* command hash used to build this output, read from build log */
	uint64_t hash;

	/* ID for .ninja_deps. -1 if not present in log. */
	int32_t id;

	/* does the node need to be rebuilt */
	_Bool dirty;
};

/* build rule, i.e., edge between inputs and outputs */
struct edge {
	struct rule *rule;
	struct pool *pool;
	struct environment *env;

	/* input and output nodes */
	struct node **out, **in;
	size_t nout, nin;

	/* index of first implicit output */
	size_t outimpidx;
	/* index of first implicit and order-only input */
	size_t inimpidx, inorderidx;

	/* command hash */
	uint64_t hash;

	/* how many inputs need to be rebuilt or pruned before this edge is ready */
	size_t nblock;
	/* how many inputs need to be pruned before all outputs can be pruned */
	size_t nprune;

	enum {
		FLAG_WORK      = 1 << 0,  /* scheduled for build */
		FLAG_HASH      = 1 << 1,  /* calculated the command hash */
		FLAG_DIRTY_IN  = 1 << 3,  /* dirty input */
		FLAG_DIRTY_OUT = 1 << 4,  /* missing or outdated output */
		FLAG_DIRTY     = FLAG_DIRTY_IN | FLAG_DIRTY_OUT,
		FLAG_CYCLE     = 1 << 5,  /* used for cycle detection */
		FLAG_DEPS      = 1 << 6,  /* dependencies loaded */
	} flags;

	/* used to coordinate ready work in build() */
	struct edge *worknext;
	/* used for alledges linked list */
	struct edge *allnext;
};

void graphinit(void);

/* create a new node or return existing node */
struct node *mknode(struct string *);
/* lookup a node by name; returns NULL if it does not exist */
struct node *nodeget(const char *, size_t);
/* update the mtime field of a node */
void nodestat(struct node *);
/* get a node's path, possibly escaped for the shell */
struct string *nodepath(struct node *, _Bool);
/* record the usage of a node by an edge */
void nodeuse(struct node *, struct edge *);

/* create a new edge with the given parent environment */
struct edge *mkedge(struct environment *parent);
/* compute the murmurhash64a of an edge command and store it in the hash field */
void edgehash(struct edge *);
/* add dependencies from $depfile or .ninja_deps as implicit inputs */
void edgeadddeps(struct edge *e, struct node **deps, size_t ndeps);

/* a single linked list of all edges, valid up until build() */
extern struct edge *alledges;
