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

#ifndef MAX_PATH
#define MAX_PATH 1024
#endif

#define BUF_SIZE 256
#define SHORT_SIZE 12

int has_be_ver(const char *filename)
{
    FILE *ver_fh;

    ver_fh = fopen(filename, "r");
    if (ver_fh == NULL)
        return 0;

    fclose(ver_fh);

    return 1;
}

int get_version_info(char *cache_filename,
					 char *node, int node_size,
					 char *date, int date_size,
					 int *revision)
{
    char buf[256];
    char *tmp;
	FILE *ver_fh;
	time_t seconds;
	struct tm * timeinfo;
	size_t tm_len;

    ver_fh = fopen(cache_filename, "r");
    if (ver_fh == NULL)
    {
        return 0;
    }

	/*
	 * Get the node id
	 */

    fgets(buf, BUF_SIZE, ver_fh);

    /* trim the newline */
    if (strlen(buf) < node_size)
        buf[strlen(buf)-1] = 0;
    strncpy(node, buf, node_size);

	/*
	 * Get the revision date
	 */

    fgets(buf, BUF_SIZE, ver_fh);

	/* convert seconds since epoch to a date/time format */
	seconds = (time_t) atol(buf);

	timeinfo = gmtime(&seconds);
	tm_len = strftime(date, date_size, "%Y-%m-%d %H:%M:%S", timeinfo);
	date[tm_len] = 0;

	/*
	 * Get the revision number
	 */

	fgets(buf, BUF_SIZE, ver_fh);

	*revision = atoi(buf);

	fclose(ver_fh);

    return 1;
}

void put_version(const char *output_filename, const char *node,
                 const char *date, const int rev)
{
    FILE *ver_fh;

	ver_fh = fopen(output_filename, "w");
    if (ver_fh == NULL)
    {
        fprintf(stderr, "Could not open for writing %s\n", output_filename);
        exit(1);
    }

    fprintf(ver_fh, "/* auto-generated by mkver, do not edit */\n");
    fprintf(ver_fh, "#ifndef SCM_NODE\n");
    fprintf(ver_fh, "#define SCM_NODE \"%s\"\n", node);
	fprintf(ver_fh, "#define SCM_REV  %i\n", rev);
	fprintf(ver_fh, "#define SCM_DATE \"%s\"\n", date);
    fprintf(ver_fh, "#endif\n");
    fclose(ver_fh);

}

int main(int argc, char **argv)
{
    FILE *ver_fh;
    char tmp[MAX_PATH];
    char *hg_executable, *cache_filename, *output_filename;
    char old_ver[BUF_SIZE], old_date[BUF_SIZE];
	char new_ver[BUF_SIZE], new_date[BUF_SIZE];
	int old_rev = 0, new_rev = 0;
    int had_old_info = 0;

    if (argc < 4)
    {
        fprintf(stderr, "Usage: %s hg-executable cache-file output-filename\n",
                argv[0]);
        exit(1);
    }

	hg_executable = argv[1];
	cache_filename = argv[2];
    output_filename = argv[3];

    /*
     * We get our old information to compare to the new information.
     * If there is no difference, then we do not write a new version
     * file which prevents make dependencies from building be_machine.c
     * over and over.
     */

    had_old_info = get_version_info(cache_filename, old_ver, BUF_SIZE, old_date, BUF_SIZE, &old_rev);

#if defined(__WATCOMC__) || defined(__MINGW32__)
    snprintf(tmp, MAX_PATH,
			 "\"%s\" parents --template {node}\\n{date}\\n{rev} > %s",
			 hg_executable, cache_filename);
#else
    snprintf(tmp, MAX_PATH,
			 "\"%s\" parents --template '{node}\\n{date}\\n{rev}' > %s",
			 hg_executable, cache_filename);
#endif

    if (system(tmp) != 0)
    {
        /*
         * If we do not have a be_ver.h, write a junk one. Otherwise,
         * leave the existing one alone... i.e. from a source-tarball?
		 */
	  if (has_be_ver(output_filename) == 0) {
		fprintf(stderr, "Mercurial seems to not be installed, writing unknown be_ver.h\n");
		put_version(output_filename, "unknown", "unknown", 0);
	  }

	  exit(0);
    }

    if (get_version_info(cache_filename, new_ver, BUF_SIZE, new_date, BUF_SIZE, &new_rev) == 0)
    {
	  fprintf(stderr, "Could not open cache file %s\n  result of hg parents\n",
			  cache_filename);

	  if (has_be_ver(output_filename) == 0) {
		fprintf(stderr, "Mercurial seems to not be installed, writing unknown be_ver.h\n");
		put_version(output_filename, "unknown", "unknown", 0);
	  }

	  exit(0);
    }

    if (has_be_ver(output_filename) == 0 ||
        had_old_info == 0 ||
        strncmp(new_ver, old_ver, BUF_SIZE) != 0)
    {
        put_version(output_filename, new_ver, new_date, new_rev);
    }

    return 0;
}
