/*
 * Copyright (c) 2003-2012
 * Distributed Systems Software.  All rights reserved.
 * See the file LICENSE for redistribution information.
 */

/*
 */

#ifndef lint
static const char copyright[] =
"Copyright (c) 2003-2012\n\
Distributed Systems Software.  All rights reserved.";
static const char revid[] =
  "$Id: sched.c 2597 2012-10-19 17:44:18Z brachman $";
#endif

#include "dacs.h"
#include "dacs_api.h"

#ifndef DACS_SCHED_ACLS
#define DACS_SCHED_ACLS	"[sched-acls]dacs-fs:"/**/DACS_HOME/**/"/dacssched/acls"
#endif

#ifndef DACS_SCHED_SCHED
#define DACS_SCHED_SCHED	"[sched]dacs-fs:"/**/DACS_HOME/**/"/dacssched/sched"
#endif

typedef struct Sched {
  char *name;
  char *command;
} Sched;

static const char *log_module_name = "dacssched";

static Dsvec *
load_sched(char *sched_uri)
{
  char *buffer, *command, *line, *name, *p;
  size_t blen;
  Ds *ds;
  Dsvec *dsv;
  Sched *sched;
  Vfs_handle *h;

  if ((h = vfs_open_uri(sched_uri)) == NULL)
	return(NULL);
  if (vfs_get(h, NULL, (void **) &buffer, &blen) == -1) {
	vfs_close(h);
	return(NULL);
  }
  vfs_close(h);

  ds = ds_init(NULL);
  ds->delnl_flag = 1;
  dsio_set(ds, NULL, buffer, blen, 1);
  dsv = dsvec_init(NULL, sizeof(Sched));

  while ((line = dsio_agets(ds)) != NULL) {
	p = line;
	while (*p == ' ' || *p == '\t')
	  p++;
	if (*p == '#' || *p == '\0')
	  continue;

	name = p;
	while (*p != ' ' && *p != '\t' && *p != '\0')
	  p++;
	*p++ = '\0';
	while (*p == ' ' || *p == '\t')
	  p++;
	if (*p == '\0')
	  return(NULL);
	command = p;
	log_msg((LOG_TRACE_LEVEL,
			 "Event: name=\"%s\" command=\"%s\"\n", name, command));

	sched = ALLOC(Sched);
	sched->name = name;
	sched->command = command;
	dsvec_add_ptr(dsv, sched);
  }

  return(dsv);
}

static void
dacs_usage(void)
{

  fprintf(stderr, "Usage: dacssched [flags]\n");
  fprintf(stderr, "flags are composed from:\n");
  fprintf(stderr, "-h|-help:            show this help blurb\n");
  fprintf(stderr, "-ll level:           set logging to level\n");
  fprintf(stderr, "-q:                  be quiet except for error messages\n");
  fprintf(stderr, "-r|-rules rules_uri: where to look for rules\n");
  fprintf(stderr, "-s|-sched sched_uri: where to look for the schedule\n");
  fprintf(stderr, "-v:                  increase verbosity level\n");

  fprintf(stderr, "\n");
  fprintf(stderr, "o The default ruleset location is %s/dacssched/acls\n",
		  DACS_HOME);
  fprintf(stderr,
		  "o The default schedule is %s/dacssched/sched\n", DACS_HOME);

  fprintf(stderr, "\n");
  fprintf(stderr, "Exit status:\n");
  fprintf(stderr, "  0 means processing was successful\n");
  fprintf(stderr, "  anything else means an error occurred\n");

  exit(2);
}

int
main(int argc, char **argv)
{
  int i, quiet_flag, st;
  char *errmsg, *rules_vfs, *sched_uri;
  Dsvec *sched;
  Kwv *kwv;
  Log_desc *ld;
  Vfs_directive *vd;

  errmsg = "Internal error";
  quiet_flag = 0;
  verbose_level = 0;

  if (dacs_init(DACS_STANDALONE_NOARGS, &argc, &argv, &kwv, &errmsg) == -1) {
  fail:
	if (errmsg != NULL)
	  fprintf(stderr, "%s\n", errmsg);
	dacs_usage();
	/*NOTREACHED*/
  }

  ld = log_init(NULL, 0, NULL, "dacssched", LOG_NONE_LEVEL, NULL);
  log_set_level(ld, LOG_WARN_LEVEL);
  log_set_desc(ld, LOG_ENABLED);

  rules_vfs = NULL;
  sched_uri = NULL;
  for (i = 1; i < argc; i++) {
	if (streq(argv[i], "-h") || streq(argv[i], "-help")) {
	  dacs_usage();
	}
	else if (streq(argv[i], "-r") || streq(argv[i], "-rules")) {
      if (++i == argc) {
        errmsg = ds_xprintf("Ruleset VFS expected after %s", argv[i - 1]);
        goto fail;
      }
	  if (rules_vfs != NULL) {
        errmsg = ds_xprintf("Duplicate %s flag", argv[i - 1]);
        goto fail;
	  }
	  if ((vd = vfs_uri_parse(argv[i], NULL)) == NULL) {
		if (argv[i][0] != '/') {
		  errmsg = "Invalid ruleset VFS";
		  goto fail;
		}
		rules_vfs = ds_xprintf("[sched-rules]dacs-fs:%s", argv[i]);
	  }
	  else
		rules_vfs = argv[i];
	}
	else if (streq(argv[i], "-s") || streq(argv[i], "-sched")) {
      if (++i == argc) {
        errmsg = ds_xprintf("Schedule VFS expected after %s", argv[i - 1]);
        goto fail;
      }
	  if (sched_uri != NULL) {
        errmsg = ds_xprintf("Duplicate %s flag", argv[i - 1]);
        goto fail;
	  }
	  if ((vd = vfs_uri_parse(argv[i], NULL)) == NULL) {
		if (argv[i][0] != '/') {
		  errmsg = "Invalid sched VFS";
		  goto fail;
		}
		sched_uri = ds_xprintf("[sched]dacs-fs:%s", argv[i]);
	  }
	  else
		sched_uri = argv[i];
	}
	else if (streq(argv[i], "-ll")) {
	  Log_level ll;

	  i++;
	  if ((ll = log_lookup_level(argv[i])) == LOG_INVALID_LEVEL
		  || log_set_level(ld, ll) == LOG_INVALID_LEVEL) {
		fprintf(stderr, "Invalid log_level: %s", argv[i]);
		dacs_usage();
	  }
	}
	else if (streq(argv[i], "-q")) {
	  quiet_flag = 1;
	}
	else if (streq(argv[i], "-v")) {
	  if (++verbose_level == 1)
	    log_set_level(ld, LOG_DEBUG_LEVEL);
	  else if (verbose_level > 1)
	    log_set_level(ld, LOG_TRACE_LEVEL);
	}
  }

  if (rules_vfs == NULL)
	rules_vfs = DACS_SCHED_ACLS;
  if (sched_uri == NULL)
	sched_uri = DACS_SCHED_SCHED;

  log_msg((LOG_TRACE_LEVEL, "Using rules: %s", rules_vfs));
  log_msg((LOG_TRACE_LEVEL, "Using schedule: %s", sched_uri));

  if ((sched = load_sched(sched_uri)) == NULL) {
	errmsg = "Cannot load schedule";
	goto fail;
  }

  st = 0;
  for (i = 0; i < dsvec_len(sched); i++) {
	int rc;
	char *expr, *res_str;
	Acs_expr_result result;
	Acs_expr_ns_arg ns_args[10];
	Sched *s;

	s = dsvec_ptr(sched, i, Sched *);
	expr = ds_xprintf("rule(\"%s\", \"%s\")", s->name, rules_vfs);
	log_msg((LOG_TRACE_LEVEL, "Expr is: %s", expr));
	ns_args[0].name = NULL;
	ns_args[0].kwv = NULL;
	result = acs_expr_string(expr, ns_args, &res_str);
	if (result == ACS_EXPR_TRUE) {
	  log_msg((LOG_TRACE_LEVEL, "Result: execute command: \"%s\"",
			   s->command));
	  rc = system(s->command);
	  log_msg((LOG_TRACE_LEVEL, "Result code: %d", rc));
	}
	else if (result == ACS_EXPR_FALSE)
	  log_msg((LOG_TRACE_LEVEL, "Result: do not execute command"));
	else {
	  log_msg((LOG_TRACE_LEVEL, "Result: error, ignoring event"));
	  st = 1;
	}
  }

  exit(st);
}
