/tools/blerglatest.c
/* Blerg is (C) 2011 The Dominion of Awesome, and is distributed under a
 * BSD-style license.  Please see the COPYING file for details.
 */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>
#include <yajl/yajl_gen.h>
#include "database.h"
#include "json.h"
#include "config.h"
#include "configuration.h"

yajl_gen_config yajl_config = {0, 0};

struct thing {
	time_t t;
	char *name;
	int len;
};

struct things {
	struct thing *arr;
	unsigned int len;
	unsigned int size;
};

struct things * things_alloc() {
	struct things *things = malloc(sizeof(struct things));
	things->len = 0;
	things->size = 65536;
	things->arr = malloc(sizeof(struct thing) * things->size);
	return things;
}

void things_free(struct things *things) {
	int i;

	for (i = 0; i < things->len; i++) {
		free(things->arr[i].name);
	}

	free(things->arr);
	free(things);
}

void things_add(struct things *things, time_t t, char *name) {
	things->arr[things->len].t = t;
	things->arr[things->len].len = strlen(name);
	things->arr[things->len].name = malloc(things->arr[things->len].len + 1);
	strcpy(things->arr[things->len].name, name);
	things->len++;
	if (things->len == things->size) {
		things->size *= 2;
		things->arr = realloc(things->arr, sizeof(struct thing) * things->size);
	}
}

int thing_compare(const void *a, const void *b) {
	struct thing * aa = (struct thing *) a;
	struct thing * bb = (struct thing *) b;

	if (aa->t == bb->t)
		return 0;
	else if (aa->t > bb->t)
		return -1;
	else
		return 1;
}

void things_sort(struct things *things) {
	qsort(things->arr, things->len, sizeof(struct thing), thing_compare);
}

struct things * latest_things(const char *path, const char *file, int minlen) {
	DIR* d;
	struct dirent *f;
	struct things * things = things_alloc();
	char filename[512];
	struct stat st;

	d = opendir(path);
	if (d == NULL) {
		fprintf(stderr, "Could not open %s: ", path);
		perror("");
		exit(1);
	}
	while ((f = readdir(d)) != NULL) {
		if (f->d_name[0] == '.') continue;
		if (minlen > 0 && strlen(f->d_name) < minlen) continue;
		if (file) {
			snprintf(filename, 512, "%s/%s/%s", path, f->d_name, file);
		} else {
			snprintf(filename, 512, "%s/%s", path, f->d_name);
		}
		stat(filename, &st);
		things_add(things, st.st_mtime, f->d_name);
	}
	closedir(d);

	things_sort(things);

	return things;
}

void latest_tags(yajl_gen g) {
	int i;
	struct things * things = latest_things(blergconf.hash_tags_path, NULL, 3);

	unsigned int count = (things->len >= 50 ? 50 : things->len);
	yajl_gen_array_open(g);
	for (i = 0; i < count; i++) {
		yajl_gen_string(g, (unsigned char *)things->arr[i].name, things->arr[i].len);
	}
	yajl_gen_array_close(g);

	things_free(things);
}

void latest_records(yajl_gen g) {
	int i;
	struct things * things = latest_things(blergconf.data_path, "meta", 0);

	unsigned int count = (things->len >= 50 ? 50 : things->len);
	yajl_gen_array_open(g);
	for (i = 0; i < count; i++) {
		struct blerg * b = blerg_open(things->arr[i].name);
		if (b == NULL) {
			fprintf(stderr, "Could not open blerg for %s\n", things->arr[i].name);
			continue;
		}
		uint64_t record_count = blerg_get_record_count(b);
		if (record_count > 0)
			json_generate_one_record(g, things->arr[i].name, b, record_count - 1, 1);
		blerg_close(b);
	}
	yajl_gen_array_close(g);
	things_free(things);
}

int main(int argc, char *argv[]) {
	const unsigned char *buf;
	unsigned int len;

	if (!blerg_init())
		exit(1);

	yajl_gen g = yajl_gen_alloc(&yajl_config, NULL);

	yajl_gen_map_open(g);
	yajl_gen_string(g, (unsigned char *)"tags", 4);

	latest_tags(g);

	yajl_gen_get_buf(g, &buf, &len);
	fwrite(buf, len, 1, stdout);
	yajl_gen_clear(g);

	yajl_gen_string(g, (unsigned char *)"records", 7);

	latest_records(g);

	yajl_gen_map_close(g);
	yajl_gen_get_buf(g, &buf, &len);
	fwrite(buf, len, 1, stdout);

	yajl_gen_free(g);

	return 0;
}