/* $Id: user.c,v 1.6 2002/06/23 20:28:31 richdawe Exp $ */

/*
 * user.c - Test program to check the dependencies in the user's pakke d'base.
 * Copyright (C) 2000-2002 by Richard Dawe
 *
 * Since all dependencies may not be satisfied in the user's database, this
 * test should not be expected to pass, when run as part of the automated
 * test suite, since it may fail.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <unistd.h>

#include <libpakke/package.h>
#include <libpakke/packlist.h>
#include <libpakke/packdep.h>
#include <libpakke/dsm.h>
#include <libpakke/util.h>

/* Context for dependency-checking browser. */
typedef struct {
  PACKAGE_INFO *packages;
  int quiet;
  int failed;
} dep_check_context_t;

/* ------------
 * - show_dep -
 * ------------ */

static int
show_dep (PACKAGE_INFO *p, PACKAGE_DEP *dep, int satisfied)
{
  printf("%s %s %s: %s: %s\n",
	 satisfied ? "+" : "-",
	 p->name,
	 package_version_string(&p->version),
	 package_dep_type_string(dep->dep_type),
	 package_dep_string(dep));

  /* OK */
  return(1);
}

/* ---------------------
 * - dep_check_browser -
 * --------------------- */

static int
dep_check_browser (PACKAGE_INFO *p, void *context_in)
{
  dep_check_context_t *context = (dep_check_context_t *) context_in;
  int                  quiet   = context->quiet;

#define MAX_FAILED_DEP MAX_PACKAGES
  PACKAGE_DEP *failed_dep[MAX_FAILED_DEP + 1]; /* Leave space for NULL */
  int          failed_dep_max = MAX_FAILED_DEP;
  int          i;

#if 0
  if (!quiet)
    printf(". %s %s (%s)\n",
	   p->name,
	   package_version_string(&p->version),
	   package_type_string(&p->version));
#endif

  /* Check all the different types of dependency. */
  if (!package_check_deps(p, PACKAGE_DEP_REQUIRES,
			  failed_dep, failed_dep_max)) {
    if (!quiet && (failed_dep != NULL)) {
      for (i = 0; failed_dep[i] != NULL; i++) {
	show_dep(p, failed_dep[i], 0);
      }
    }
    context->failed = 1;
  }

  if (!package_check_deps(p, PACKAGE_DEP_DEPENDS_ON,
			  failed_dep, failed_dep_max)) {
    if (!quiet && (failed_dep != NULL)) {
      for (i = 0; failed_dep[i] != NULL; i++) {
	show_dep(p, failed_dep[i], 0);
      }
    }
    /* Non-fatal - don't fail on depends-on being unsatisfied. */
  }

  if (!package_check_deps(p, PACKAGE_DEP_CONFLICTS_WITH,
			  failed_dep, failed_dep_max)) {
    if (!quiet && (failed_dep != NULL)) {
      for (i = 0; failed_dep[i] != NULL; i++) {
	show_dep(p, failed_dep[i], 0);
      }
    }
    context->failed = 1;
  }

  if (!package_check_deps(p, PACKAGE_DEP_REPLACES,
			  failed_dep, failed_dep_max)) {
    if (!quiet && (failed_dep != NULL)) {
      for (i = 0; failed_dep[i] != NULL; i++) {
	show_dep(p, failed_dep[i], 0);
      }
    }
    context->failed = 1;
  }

  if (!package_check_deps(p, PACKAGE_DEP_PROVIDES,
			  failed_dep, failed_dep_max)) {
    if (!quiet && (failed_dep != NULL)) {
      for (i = 0; failed_dep[i] != NULL; i++) {
	show_dep(p, failed_dep[i], 0);
      }
    }
    context->failed = 1;
  }

  if (!package_check_deps(p, PACKAGE_DEP_INSTALL_BEFORE,
			  failed_dep, failed_dep_max)) {
    if (!quiet && (failed_dep != NULL)) {
      for (i = 0; failed_dep[i] != NULL; i++) {
	show_dep(p, failed_dep[i], 0);
      }
    }
    context->failed = 1;
  }

  if (!package_check_deps(p, PACKAGE_DEP_INSTALL_AFTER,
			  failed_dep, failed_dep_max)) {
    if (!quiet && (failed_dep != NULL)) {
      for (i = 0; failed_dep[i] != NULL; i++) {
	show_dep(p, failed_dep[i], 0);
      }
    }
    context->failed = 1;
  }

  /* Carry on checking */
  return(0);
}

/* --------
 * - main -
 * -------- */

int
main (int argc, char *argv[])
{
  dep_check_context_t  context;
  DSM_FILE_ERROR      *dfe          = NULL;
  DSM_FILE_ERROR      *ndfe         = NULL;	
  PACKAGE_INFO        *packages     = NULL;
  char                 dsm_path[PATH_MAX];
  char                *dsm_paths[2] = { dsm_path, NULL };
  int                  quiet        = 0;
  int                  i;

  /* Parse arguments. */
  for (i = 1; i < argc; i++) {
    /* Quiet operation, for automatic testing. */
    if (   (strcmp(argv[i], "--quiet") == 0)
	|| (strcmp(argv[i], "-q") == 0))
      quiet = 1;
  }

  /* Get the DSM paths */
  strcpy(dsm_path, getenv("DJDIR"));
  strcat(dsm_path, "/share/pakke/db");

  if (isdir(dsm_path) <= 0) {
    if (!quiet)
      fprintf(stderr, "Unable to access DSM database directory '%s'\n",
	      dsm_path);

    return(EXIT_FAILURE);
  }

  if (!quiet) {
    for (i = 0; (dsm_paths != NULL) && (dsm_paths[i] != NULL); i++) {
      printf(". Installed DSM path [%i]: '%s'\n", i + 1, dsm_paths[i]);
    }
  }

  /* Load all DSMs */
  packages = dsm_load_all((const char **) dsm_paths, NULL, &dfe);

  if (packages == NULL) {
    /* No packages => nothing to do */
    return(EXIT_SUCCESS);
  }

  /* Display DSM errors */
  if (!quiet) {
    for (ndfe = dfe; ndfe != NULL; ndfe = ndfe->q_forw) {
      dsm_perror(ndfe->name, ndfe->de);
    }
  }
  dsm_free_file_error_list(dfe);
  dfe = NULL;

  /* Generate cross-references */
  packlist_xref(packages);

  /* Run the dependency checking browser function on the list. */
  memset(&context, 0, sizeof(context));
  context.packages = packages;
  context.quiet    = quiet;
  context.failed   = 0;

  packlist_browse(packages, dep_check_browser, (void *) &context);

  /* Tidy up */
  packlist_free(packages);

  if (!context.failed)
    return(EXIT_SUCCESS);

  return(EXIT_FAILURE);
}
