/*
 * cbfs-compression-tool, CLI utility for dealing with CBFS compressed data
 *
 * Copyright (C) 2017 Google, Inc.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; version 2 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#include "common.h"

void usage(void);
int benchmark(void);
int compress(char *infile, char *outfile, char *algoname);

const char *usage_text = "cbfs-compression-tool benchmark\n"
	"  runs benchmarks for all implemented algorithms\n"
	"cbfs-compression-tool compress inFile outFile algo\n"
	"  compresses inFile with algo and stores in outFile\n"
	"\n"
	"'compress' file format:\n"
	" 4 bytes little endian: algorithm ID (as used in CBFS)\n"
	" 4 bytes little endian: uncompressed size\n"
	" ...: compressed data stream\n";

void usage()
{
	puts(usage_text);
}

int benchmark()
{
	const int bufsize = 10*1024*1024;
	char *data = malloc(bufsize);
	if (!data) {
		fprintf(stderr, "out of memory\n");
		return 1;
	}
	char *compressed_data = malloc(bufsize);
	if (!compressed_data) {
		fprintf(stderr, "out of memory\n");
		return 1;
	}
	int i, l = strlen(usage_text) + 1;
	for (i = 0; i + l < bufsize; i += l) {
		memcpy(data + i, usage_text, l);
	}
	memset(data + i, 0, bufsize - i);
	const struct typedesc_t *algo;
	for (algo = &types_cbfs_compression[0]; algo->name != NULL; algo++) {
		int outsize = bufsize;
		printf("measuring '%s'\n", algo->name);
		comp_func_ptr comp = compression_function(algo->type);
		if (comp == NULL) {
			printf("no handler associated with algorithm\n");
			return 1;
		}

		struct timespec t_s, t_e;
		clock_gettime(CLOCK_MONOTONIC, &t_s);

		if (comp(data, bufsize, compressed_data, &outsize)) {
			printf("compression failed");
			return 1;
		}

		clock_gettime(CLOCK_MONOTONIC, &t_e);
		printf("compressing %d bytes to %d took %ld seconds\n",
			bufsize, outsize,
			t_e.tv_sec - t_s.tv_sec);
	}
	return 0;
}

int compress(char *infile, char *outfile, char *algoname)
{
	int err = 1;
	FILE *fin = NULL;
	FILE *fout = NULL;
	void *indata = NULL;

	const struct typedesc_t *algo = &types_cbfs_compression[0];
	while (algo->name != NULL) {
		if (strcmp(algo->name, algoname) == 0) break;
		algo++;
	}
	if (algo->name == NULL) {
		fprintf(stderr, "algo '%s' is not supported.\n", algoname);
	}

	comp_func_ptr comp = compression_function(algo->type);
	if (comp == NULL) {
		printf("no handler associated with algorithm\n");
		return 1;
	}

	fin = fopen(infile, "rb");
	if (!fin) {
		fprintf(stderr, "could not open '%s'\n", infile);
		return 1;
	}
	fout = fopen(outfile, "wb");
	if (!fout) {
		fprintf(stderr, "could not open '%s' for writing\n", outfile);
		goto out;
	}

	if (fseek(fin, 0, SEEK_END) != 0) {
		fprintf(stderr, "could not seek in input\n");
		goto out;
	}
	long insize = ftell(fin);
	if (insize < 0) {
		fprintf(stderr, "could not determine input size\n");
		goto out;
	}
	rewind(fin);

	indata = malloc(insize);
	if (!indata) {
		fprintf(stderr, "out of memory\n");
		goto out;
	}

	void *outdata = malloc(insize);
	if (!outdata) {
		fprintf(stderr, "out of memory\n");
		goto out;
	}
	int outsize;

	int remsize = insize;
	while (remsize > 0) {
		int readsz = fread(indata, 1, remsize, fin);
		if (readsz < 0) {
			fprintf(stderr, "failed to read input with %d bytes left\n", remsize);
			goto out;
		}
		remsize -= readsz;
	}

	comp(indata, insize, outdata, &outsize);

	char header[8];
	header[0] = algo->type & 0xff;
	header[1] = (algo->type >> 8) & 0xff;
	header[2] = (algo->type >> 16) & 0xff;
	header[3] = (algo->type >> 24) & 0xff;
	header[4] = insize & 0xff;
	header[5] = (insize >> 8) & 0xff;
	header[6] = (insize >> 16) & 0xff;
	header[7] = (insize >> 24) & 0xff;
	if (fwrite(header, 8, 1, fout) != 1) {
		fprintf(stderr, "failed writing header\n");
		goto out;
	}
	if (fwrite(outdata, outsize, 1, fout) != 1) {
		fprintf(stderr, "failed writing compressed data\n");
		goto out;
	}

	err = 0;
out:
	if (fin) fclose(fin);
	if (fout) fclose(fout);
	if (indata) free(indata);
	return err;
}

int main(int argc, char **argv)
{
	if ((argc == 2) && (strcmp(argv[1], "benchmark") == 0))
		return benchmark();
	if ((argc == 5) && (strcmp(argv[1], "compress") == 0))
		return compress(argv[2], argv[3], argv[4]);
	usage();
	return 1;
}
