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

/* Usual strings size. */
#define STR_LEN 64

#if !defined BUFSIZ || BUFSIZ < 1024
# undef BUFSIZ
# define BUFSIZ 1024
#endif

/* Macro to get package, operater, organzation and system name */
#define PICK_NAME(string, label, name)					\
  if (strncmp (string, label, strlen (label)) == 0)			\
    {									\
      char *pt;								\
									\
      pt = string + strlen (label);					\
      name = (char *) malloc (strlen (pt) + 1);				\
      strcpy (name, pt);						\
    }

/* The declaration of Structure for waived item. */
struct waived
{
  char *name;		/* Function or utility name. */
  int  *array;		/* Waived assertion numbers of each one. */
};

/* Files */
FILE *journal_fp;	/* File pointer to journal file. */
FILE *waiver_fp;	/* File pointer to waiver list file. */

/* If this variable is non zero, waiver list file is refferred. */
int use_waiver_list;

/* The declaration of Structure for waived item. */
struct waived *waived_test;

/* The amount of waived item. */
size_t waived_test_num;

/* Variables for headers and headline. */
char date_string[12];		/* The string which shows the date. */
char time_string[10];		/* The string which shows the time. */
char *package_name;		/* The name of testsuite package. */
char *operator_name;		/* The name of operator. */
char *organization_name;	/* The name of organization. */
char *system_name;		/* The name of the system. */

char *package_label      = "30||TEST_PACKAGES=";
char *operator_label     = "30||VSX_OPER=";
char *organization_label = "30||VSX_ORG=";
char *system_label       = "30||VSX_SYS=";

/* enum type to show the section. */
#define SECTION_MAX 8
enum section_type {annex, base, utils, lang, gui, im, om, internet, none};
char *section_name[] = {"annex", "base", "utils", "lang",
			"gui", "im", "om", "internet"};

char *section_title[] = {
      "Annex A. Environment Variables &amp; Annex B. Supported locales and codesets",
      "3. Base Libraries",
      "4. Shells and Utilities",
      "5. Programming Languages",
      "6. Graphical User Interface",
      "7. Input Methods",
      "8. Output Methods",
      "10. Internet Tools"
};

/* The number of each results. */
size_t executed_num[SECTION_MAX];
size_t succeeded_num[SECTION_MAX];
size_t failed_num[SECTION_MAX];
size_t fail_waiv_num[SECTION_MAX];
size_t info_num[SECTION_MAX];
size_t unsupported_num[SECTION_MAX];
size_t untested_num[SECTION_MAX];
size_t unresolved_num[SECTION_MAX];
size_t unrslv_waiv_num[SECTION_MAX];
size_t unreported_num[SECTION_MAX];
size_t unrprt_waiv_num[SECTION_MAX];

/* Total of each results. */
size_t executed_total;
size_t succeeded_total;
size_t failed_total;
size_t fail_waiv_total;
size_t info_total;
size_t unsupported_total;
size_t untested_total;
size_t unresolved_total;
size_t unrslv_waiv_total;
size_t unreported_total;
size_t unrprt_waiv_total;

/* Temporary files for test message. */
FILE *tmp_fp[SECTION_MAX];

/* Current target. */
enum section_type section = none;
char test_name[STR_LEN];
size_t assertion_num;


/* Read a waiver list. */
void read_waiver_list (char *filename)
{
  int i, pos;
  size_t test_num;
  size_t assert_max;
  size_t assert_num, next_assert_num;
  char str[BUFSIZ];		/* The string gotten from a input file. */
  char tmp[BUFSIZ], *p, *next;
  
  use_waiver_list = 1;

  if ((waiver_fp = fopen (filename, "r")) == NULL)
    {
      fprintf (stderr, "The file `%s' can not be opened.\n", filename);
      exit (EXIT_FAILURE);
    }

  while (fgets (str, BUFSIZ, waiver_fp) != NULL)
    ++waived_test_num;

  if (waived_test_num < 1)
    return;

  rewind (waiver_fp);
  waived_test = malloc (sizeof(struct waived) * waived_test_num);

  test_num = 0;
  while (fgets (str, BUFSIZ, waiver_fp) != NULL)
    {
      /* Get the test name. */
      strcpy (tmp, str);
      p = strchr (tmp, ':');
      if (p == NULL)
	{
	  fprintf (stderr, "The file `%s' may not be wailver list file.\n", filename);
	  exit (EXIT_FAILURE);
	}
      *p = '\0';
      waived_test[test_num].name = (char *) malloc (strlen (tmp) + 1);
      strcpy (waived_test[test_num].name, tmp);

      assert_max = 0;
      ++p;

      /* Get the number of assertions. */
      while (1)
	{
	  assert_num = (int)strtol (p, &next, 10);
	  if (assert_num == 0)
	    break;

	  if (*next == '-')
	    {
	      p = next + 1;
	      next_assert_num = (int)strtol (p, &next, 10);
	      if (next_assert_num == 0 || assert_num > next_assert_num)
		{
		  fprintf (stderr,
		   "The file `%s' may not be wailver list file.\n", filename);
		  exit (EXIT_FAILURE);
		}

	      assert_max += next_assert_num - assert_num + 1;
	      p = next + 1;
	    }
	  else
	    {
	      ++assert_max;
	      p = next + 1;
	    }
	}

      waived_test[test_num].array = (int *) malloc (sizeof(int) * (assert_max + 1));
      strcpy (tmp, str);
      p = strchr (tmp, ':') + 1;

      /* Get the assertion numbers. */
      pos = 0;
      while (1)
	{
	  assert_num = (int)strtol (p, &next, 10);
	  if (assert_num == 0)
	    break;

	  if (*next == '-')
	    {
	      p = next + 1;
	      next_assert_num = (int)strtol (p, &next, 10);
	      p = next + 1;

	      for (i = assert_num; i <= next_assert_num; i++)
		waived_test[test_num].array[pos++] = i;
	    }
	  else
	    {
	      p = next + 1;
	      waived_test[test_num].array[pos++] = assert_num;
	    }
	}

      waived_test[test_num].array[pos] = -1;
      ++test_num;
    }
}


/* Free waiver list data. */
void free_waived_list (void)
{
  int i;
  
  for (i = 0; i < waived_test_num; i++)
    {
      free (waived_test[i].name);
      free (waived_test[i].array);
    }

  free (waived_test);
}


/* Check the assertion is waived or not. */
int is_waived (char *testname, int num)
{
  int i, pos;

  for (i = 0; i < waived_test_num; i++)
    {
      if (strcmp (waived_test[i].name, testname))
	continue;

      for (pos = 0; waived_test[i].array[pos] != -1; pos++)
	if (waived_test[i].array[pos] == num)
	  return 1;
    }

  return 0;
}


/* Get results of each test.
   If the test is not succeeded, prepare to output the message. */
void get_result (void)
{
  char str[BUFSIZ];		/* The string gotten from a input file. */
  char *msg;			/* Store the message. */
  char tr_tag[STR_LEN];		/* <TR> tag with color. */
  char *p;
  size_t msg_len = 0;
  size_t msg_max = BUFSIZ;

  ++executed_num[section];
  ++assertion_num;
  msg = (char *)calloc (msg_max, sizeof (char));

  while (1)
    {
      if (fgets (str, BUFSIZ, journal_fp) == NULL)
	{
	  fprintf (stderr, "The journal file has something wrong.\n");
	  exit (EXIT_FAILURE);
	}

      if (strncmp (str, "520|", 4) == 0)
	{
	  while (msg_len + strlen (str) > msg_max)
	    {
	      msg_max += BUFSIZ;
	      msg = (char *) realloc (msg, msg_max);
	    }

	  if (msg_len > 0)
	    strcat (msg, "<br>");

	  p = strchr (str, '|') + 1;
	  p = strchr (p, '|') + 1;

	  strcat (msg, p);
	  msg_len += strlen (p);
	}
      else if (strncmp (str, "220|", 4) == 0)
	{
	  p = strchr (str, '|') + 1;
	  p = strchr (p, '|') + 1;

	  if (strncmp (p, "PASS", 4) == 0)
	    ++succeeded_num[section];
	  else
	    {
	      char result[STR_LEN];

	      if (strncmp (p, "FAIL", 4) == 0)
		{
		  ++failed_num[section];
		  if (use_waiver_list && is_waived (test_name, assertion_num))
		    {
		      ++fail_waiv_num[section];
		      strcpy (tr_tag, "<tr bgcolor=\"#c0c0ff\">");
		      strcpy (result, "Failed (waiver)");
		    }
		  else
		    {
		      strcpy (tr_tag, "<tr bgcolor=\"#ff8080\">");
		      strcpy (result, "Failed");
		    }
		}
	      else if (strncmp (p, "FIP", 3) == 0)
		{
		  ++info_num[section];
		  strcpy (tr_tag, "<tr>");
		  strcpy (result, "Further Information");
		}
	      else if (strncmp (p, "UNSUPPORTED", 11) == 0)
		{
		  ++unsupported_num[section];
		  strcpy (tr_tag, "<tr bgcolor=\"#ffff80\">");
		  strcpy (result, "Unsupported");
		}
	      else if (strncmp (p, "UNTESTED", 8) == 0)
		{
		  ++untested_num[section];
		  strcpy (tr_tag, "<tr>");
		  strcpy (result, "Untested");
		}
	      else if (strncmp (p, "UNRESOLVED", 10) == 0)
		{
		  ++unresolved_num[section];
		  if (use_waiver_list && is_waived (test_name, assertion_num))
		    {
		      ++unrslv_waiv_num[section];
		      strcpy (tr_tag, "<tr>");
		      strcpy (result, "Unresolved (Waiver)");
		    }
		  else
		    {
		      strcpy (tr_tag, "<tr bgcolor=\"#ff8080\">");
		      strcpy (result, "Unresolved");
		    }
		}
	      else if (strncmp (p, "NORESULT", 8) == 0)
		{
		  ++unreported_num[section];
		  if (use_waiver_list && is_waived (test_name, assertion_num))
		    {
		      ++unrprt_waiv_num[section];
		      strcpy (tr_tag, "<tr>");
		      strcpy (result, "Unreported (Waiver)");
		    }
		  else
		    {
		      strcpy (tr_tag, "<tr bgcolor=\"#ff8080\">");
		      strcpy (result, "Unreported");
		    }
		}

	      fprintf (tmp_fp[section], "%s\n", tr_tag);
	      fprintf (tmp_fp[section], "  <td>%s</td>\n", test_name);
	      fprintf (tmp_fp[section], "  <td>%d</td>\n", assertion_num);
	      fprintf (tmp_fp[section], "  <td>%s</td>\n", result);
	      fprintf (tmp_fp[section], "  <td>%s</td>\n", msg);
	      fprintf (tmp_fp[section], "</tr>\n");
	    }
	  
	  break;
	}
    }
  free (msg);
}

/* Print header. */
void print_header (void)
{
  printf ("<head>\n");
  printf ("<title>%s result</title>\n", system_name);
  printf ("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n");
  printf ("</head>\n");
}

/* Print summary. */
void print_headline (void)
{
  printf ("<center><h1>The result of %s Test Suite for %s</h1></center>\n",
		package_name, system_name);
  printf ("<div align='right'>\n");
  printf ("Date: %s %s<br>\n", date_string, time_string);
  printf ("Operator: %s<br>\n", operator_name);
  printf ("Organization: %s<br>\n", organization_name);
  printf ("</div>\n");
}

/* Print one row of the sammary. */
void print_row_of_summary(char *name, size_t *array, size_t total)
{
  int i;

  printf ("<tr>\n");
  printf ("<td><b>%s</b></td>\n", name);
  for (i = 0; i < SECTION_MAX; i++)
    printf ("<td align=\"right\">%d</td>\n", array[i]);
  printf ("<td align=\"right\">%d</td>\n", total);
  printf ("</tr>");
}


/* Print Summary. */
void print_summary (void)
{
  int i;
  size_t not_waiv_num[SECTION_MAX], not_waiv_total;

  printf ("<h2>1. The output of non-interactive test suites.</h2>\n");
  printf ("<table border='1'>\n");
  printf ("<tbody>\n");

  printf ("<tr>\n");
  printf ("<td>&nbsp;</td>");
  for (i = 0; i < SECTION_MAX; i++)
    printf ("<td align=\"center\">%s</td>\n", section_name[i]);
  printf ("<td align=\"center\">Total</td>\n");
  printf ("</tr>");

  print_row_of_summary ("Test Executed", executed_num, executed_total);
  print_row_of_summary ("Succeeded", succeeded_num, succeeded_total);

  if (use_waiver_list && fail_waiv_total > 0)
    {
      for (i = 0; i < SECTION_MAX; i++)
        not_waiv_num[i] = failed_num[i] - fail_waiv_num[i];
      not_waiv_total = failed_total - fail_waiv_total;

      print_row_of_summary ("Failed (waived)", fail_waiv_num, fail_waiv_total);
      print_row_of_summary ("Failed (not waived)", not_waiv_num, not_waiv_total);

    }
  else
    print_row_of_summary ("Failed", failed_num, failed_total);

  print_row_of_summary ("Further Information", info_num, info_total);
  print_row_of_summary ("Unsupported", unsupported_num, unsupported_total);
  print_row_of_summary ("Untested", untested_num, untested_total);

  if (use_waiver_list && unrslv_waiv_total > 0)
    {
      for (i = 0; i < SECTION_MAX; i++)
        not_waiv_num[i] = unresolved_num[i] - unrslv_waiv_num[i];
      not_waiv_total = unresolved_total - unrslv_waiv_total;

      print_row_of_summary ("Unresolved (waived)",
			    unrslv_waiv_num, unrslv_waiv_total);
      print_row_of_summary ("Unresolved (not waived)",
			    not_waiv_num, not_waiv_total);

    }
  else
    print_row_of_summary ("Unresolved", unresolved_num, unresolved_total);

 if (use_waiver_list && unrprt_waiv_total > 0)
    {
      for (i = 0; i < SECTION_MAX; i++)
        not_waiv_num[i] = unreported_num[i] - unrprt_waiv_num[i];
      not_waiv_total = unreported_total - unrprt_waiv_total;

      print_row_of_summary ("Unreported (waived)",
			    unrprt_waiv_num, unrprt_waiv_total);
      print_row_of_summary ("Unreported (not waived)",
			    not_waiv_num, not_waiv_total);

    }
  else
    print_row_of_summary ("Unreported", unreported_num, unreported_total);

  printf ("</tbody>");
  printf ("</table>");

  /* Print which name shows which section. */
  printf ("<p><font size=\"-1\">\n");
  for (i = 0; i < SECTION_MAX; i++)
    printf ("<b>%s</b>: %s<BR>\n", section_name[i], section_title[i]);
  printf ("</font></p>\n");

  /* Print the deatil of result. */
  printf ("<p><font size=\"-1\">\n");
  printf ("<b>Succeeded:</b><br>\n"
	  "Implementation satisfies the assertion.<br>\n");
  printf ("<b>Failed:</b><br>\n"
	  "Implementation does not satisfy the assertion.<br>\n");
  printf ("<b>Further Information:</b><br>\n"
	  "Implementation does not satisfy the assertion, but the situation "
	  "described in the assertion is not occurred in reality.<br>\n");
  printf ("<b>Unsupported:</b><br>\n"
	  "The specification does not require the implementation always "
	  "satisfies the assertion.<br>\n"
	  "But a document which explains how to satisfy the assertion is "
	  "required when the implementation does not satisfy assertion.<br>\n");
  printf ("<b>Untested:</b><br>\n"
	  "The situation described in the assertion is not occurred. "
	  "So the test program does not exist.<br>\n");
  printf ("<b>Unresolved:</b><br>\n"
	  "The test program of the assertion is terminated abnormally.<br>\n");
  printf ("<b>Unreported:</b><br>\n"
	  "The test program of the assertion is terminated, \n"
	  "and the reason why it is terminated is ambiguous.<br>\n");
  printf ("</font></p>\n");
}

void print_unsucceeded (void)
{
  int i; 
  char str[BUFSIZ];

  if (executed_total == succeeded_total)
    return;

  printf ("<hr width=\"10%%\">");
  printf ("<h2>2. A List of Unsucceeded tests.</h2>\n");

  printf ("<table border=\"0\">\n");
  printf ("<tbody>\n");
  printf ("<tr><td><font size=\"-1\"><b>"
	  "[Need some actions]"
	  "</b></font></td></tr>\n");
  printf ("<tr bgcolor=\"#ff8080\"><td><font size=\"-1\">"
	  "&nbsp;<b>Red Rows</b>:\n"
	  "&nbsp;&nbsp;The problem which you shall remove."
	  "</font></td></tr>\n");
  printf ("<tr bgcolor=\"#ffff80\"><td><font size=\"-1\">"
	  "&nbsp;<b>Yellow Rows</b>:\n"
	  "&nbsp;&nbsp;You shall prepare a document which explains "
	  "how to satisfy the assertion."
	  "</font></td></tr>\n");
  printf ("<tr><td>&nbsp;</td></tr>");
  printf ("<tr><td><font size=\"-1\"><b>"
	  "[Does not need actions]"
	  "</b></font></td></tr>\n");
  printf ("<tr bgcolor=\"#c0c0ff\"><td><font size=\"-1\">"
	  "&nbsp;<b>Blue Rows</b>:\n"
	  "&nbsp;&nbsp;The problem which you should remove "
	  "in the future.\n"
	  "</font></td></tr>\n");
  printf ("<tr bgcolor=\"#ffffff\"><td><font size=\"-1\">"
	  "&nbsp;<b>White Rows</b>:\n"
	  "&nbsp;&nbsp;Just information."
	  "</font></td></tr>\n");
  printf ("</tbody>");
  printf ("</table>");



  for (i = 0; i < SECTION_MAX; i++)
    {
      if (executed_num[i] == 0 || executed_num[i] == succeeded_num[i])
	continue;

      printf ("<center><h3>%s</h3></center>\n", section_title[i]);
      printf ("Total %d", executed_num[i]);
      if (succeeded_num[i] > 0)
	printf (", Succeeded %d", succeeded_num[i]);
      if (failed_num[i] > 0)
	printf (", Failed %d", failed_num[i]);
      if (info_num[i] > 0)
	printf (", Further Information %d", info_num[i]);
      if (unsupported_num[i] > 0)
	printf (", Unsupported %d", unsupported_num[i]);
      if (untested_num[i] > 0)
	printf (", Untested %d", untested_num[i]);
      if (unresolved_num[i] > 0)
	printf (", Unresolved %d", unresolved_num[i]);
      if (unreported_num[i] > 0)
	printf (", Unreported %d", unreported_num[i]);

      printf ("<table border='1'>\n");
      printf ("<tr>\n");
      printf ("  <td>Test name</td>\n");
      printf ("  <td>No.</td>\n");
      printf ("  <td>Result</td>\n");
      printf ("  <td>Information</td>\n");
      printf ("</tr>\n");

      rewind (tmp_fp[i]);
      while (fgets (str, BUFSIZ, tmp_fp[i]) != NULL)
	fputs (str, stdout);

      printf ("</table>\n");
    }
}


int main (int argc, char *argv[])
{
  int i;
  char str[BUFSIZ];	/* The string gotten from a input file. */

  if (argc == 2)
    use_waiver_list = 0;
  else if (argc == 3)
    read_waiver_list (argv[2]);
  else
    {
      fprintf (stderr,
	      "Usage:\n"
	      " %s jounal_file                  (Waiver List is not used)\n"
	      " %s jounal_file waiver_list_file (Waiver List is used)\n",
	      argv[0], argv[0]);
      exit (EXIT_FAILURE);
    }
  
  /* Open jounal_file. */
  if ((journal_fp = fopen (argv[1], "r")) == NULL)
    {
      fprintf (stderr, "The file `%s' can not be opened.\n", argv[1]);
      exit (EXIT_FAILURE);
    }

  /* Open temporary file to store message of each test. */
  for (i = 0; i < SECTION_MAX; i++)
    tmp_fp[i] = tmpfile ();
  
  /* Get the information from the journal file. */
  while (fgets (str, BUFSIZ, journal_fp) != NULL)
    {
      /* Get the information of Date and Time. */
      if (strncmp (str, "0|", 2) == 0)
	{
	  char *p;

	  memset (date_string, '\0', 12);
	  memset (time_string, '\0', 10);

	  if ((p = strchr (str, ' ')) == NULL)
	    {
	      fprintf (stderr,
		       "The file `%s' may not be journal file.", argv[1]);
	      exit (EXIT_FAILURE);
	    }
	  ++p;

	  memcpy (time_string, p, 8);

	  p += 9;
	  memcpy (date_string, p, 4);
	  strcat (date_string, "/");
	  p += 4;
	  strncat (date_string, p, 2);
	  strcat (date_string, "/");
	  p += 2;
	  strncat (date_string, p, 2);
	}
      /* Get the information of package name, operator name, organization name,
	 and system name. */
      else if (strncmp (str, "30|", 3) == 0)
	{
	  char *p;

	  if ((p = strchr (str, '\n')) != NULL)
	    *p = '\0';

	  PICK_NAME (str, package_label, package_name);
	  PICK_NAME (str, operator_label, operator_name);
	  PICK_NAME (str, organization_label, organization_name);
	  PICK_NAME (str, system_label, system_name);
	}
      /* Initialize for next result. */
      else if (strncmp (str, "10|", 3) == 0)
	{
	  int i;
	  char cmp[STR_LEN];
	  char *p;

	  for (i = 0; i < SECTION_MAX; i++)
	    {
	      strcpy (cmp, "LI18NUX2K.L1/");
	      strcat (cmp, section_name[i]);
	      if ((p = strstr (str, cmp)) != NULL)
		break;
	    }

	  if (p == NULL)
	    {
	      fprintf (stderr, "Undefined section is found.");
	      exit (EXIT_FAILURE);
	    }

	  p += strlen (cmp) + 1;
	  memcpy (test_name, p, STR_LEN);
	  p = strchr (test_name, '/');
	  *p = '\0';

	  section = i;
	  assertion_num = 0;
	}
      /* Get the result of each test. */
      else if (strncmp (str, "200|", 4) == 0)
	get_result ();
    }

  /* total. */
  for (i = 0; i < SECTION_MAX; i++)
    {
      executed_total    += executed_num[i];
      succeeded_total   += succeeded_num[i];
      failed_total      += failed_num[i];
      fail_waiv_total   += fail_waiv_num[i];
      info_total        += info_num[i];
      unsupported_total += unsupported_num[i];
      untested_total    += untested_num[i];
      unresolved_total  += unresolved_num[i];
      unrslv_waiv_total += unrslv_waiv_num[i];
      unreported_total  += unreported_num[i];
      unrprt_waiv_total += unrprt_waiv_num[i];
    }

  /* Output html. */
  printf ("<html>\n");
    print_header ();
    printf ("<body>\n");
      print_headline ();
      print_summary ();
      print_unsucceeded ();
    printf ("</body>\n");
  printf ("</html>\n");


  /* Close temporary file to store message of each test. */
  for (i = 0; i < SECTION_MAX; i++)
    fclose (tmp_fp[i]);

  free (package_name);
  free (operator_name);
  free (organization_name);
  free (system_name);

  if (use_waiver_list)
    {
      free_waived_list ();
      fclose (waiver_fp);
    }

  fclose (journal_fp);

  return 0;
}
