/* The log command implementation. */
/* $Id: log.c,v 1.25 2003/09/06 15:10:08 pasky Exp $ */

/*
 * PaVS - Pasky's Version System, advanced version control system
 * Copyright (C) 2003  Petr Baudis
 *
 * 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; either version 2 of the License, or
 * (at your option) any later version.
 *
 * 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.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */


#include <libpavs/backsel.h>
#include <librcs/revnum.h>
#include <librev/datetime.h>
#include <librev/inode.h>
#include <librev/list.h>
#include <librev/revision.h>
#include <librev/symbol.h>

#include "args.h"
#include "error.h"
#include "log.h"


/* The implementation is rather crude so far, it is mainly just for testing 
 * so far. */
/* TODO: Parameters like output control. */
/* TODO: Multiple files support. */


static int log_file (char *filename);

enum pa_errcode
pa_log (struct args *args)
{
	char *filename;

	/* Eat 'log'. */
	args_shift (args);

	/* We support just the file argument so far. */
	if (args->argc < 1) return PEARGMISSING;
	if (args->argc > 1) return PEARGMANY;

	filename = args_shift (args);
	assert (filename);

	if (! filename [0]) return PEARGINVAL;

	return log_file (filename);
}

void
pa_log_help (char *cmdname)
{
	printf ("Usage: pa log FILE\n");
	printf ("Print out history informations about the given FILE.\n");
}


static void
log_symbol (struct rev_symbol *sym)
{
	struct rev_objid *r;

	assert (sym);

	r = rev_symbol_get_objid (sym);
	assert (r);
	printf ("\t%s: %s\n", rev_symbol_get_name (sym), rcs_revnum_str (r));
	rev_objid_untie (r);
}

static void log_branch (struct rev_branch *branch);

static void
log_revision (struct rev_revision *rev)
{
	struct rev_objid r = { ROIT_REVISION };
	struct rev_branch *branch;
	struct rev_datetime *dt;
	char *date;
	char *comment;

	rev_list_foreach (rev->offsprings, branch) {
		log_branch (branch);
	} rev_list_foreach_end;

	dt = rev_revision_get_ctime (rev);
	date = dt ? rev_datetime_export_string (dt)
		  : strdup ("????""/??""/?? ??:??:??");

	printf ("----------------------------\n");
	r.data.revision = rev;
	printf ("Revision %s\n", rcs_revnum_str (&r));
	/* TODO: Format ctime nicely. --pasky */
	/* TODO: Delta statistics. --pasky */
	printf ("date: %s;  author: %s;\n",
		date, rev_revision_get_author (rev));

	comment = rev_revision_get_comment (rev);
	printf ("%s", (comment && *comment) ? comment : "\n");

	free (date);
}

static void
log_branch (struct rev_branch *branch)
{
	struct rev_revision *rev;

	rev_list_foreachback (branch->revs, rev) {
		log_revision (rev);
	} rev_list_foreachback_end;
}

static int
log_file (char *filename)
{
	struct rev_inode *inode;
	enum pavs_backend backend;
	struct rev_branch *branch;
	struct rev_symbol *sym;

	assert (filename);

	inode = rev_inode_init ();
	rev_inode_associate (inode);

	backend = rev_inode_attach_backend (inode, filename);
	if (backend < 0 || backend == PBE_NONE) {
		rev_inode_dissociate (inode);
		return PEMISC;
	}

	/* First print info about the file as a whole. */

	rev_inode_load (inode);

	printf ("File: %s\n", filename);
	printf ("Stored as: %s\n", pavs_backendstr (backend));

	printf ("Symbolic names:\n");
	rev_list_foreach (inode->symbols, sym) {
		log_symbol (sym);
	} rev_list_foreach_end;

	printf ("\n");

	/* And now iterate through the revisions. */

	/* XXX: Is this necessary? Well it is safe ;-). --pasky */
	rev_inode_cache (inode);

	rev_list_foreachback (inode->forkrev->offsprings, branch) {
		log_branch (branch);
	} rev_list_foreachback_end;

	printf("=============================================================================\n");

	rev_inode_dissociate (inode);

	return 0;
}
