#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);						\
    }

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

/* 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 *package_identifier;	/* The identifier 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 *identifier_label	 = "30||VSX_NAME=";
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 warning_num[SECTION_MAX];
size_t info_num[SECTION_MAX];
size_t untested_num[SECTION_MAX];
size_t unresolved_num[SECTION_MAX];
size_t unreported_num[SECTION_MAX];

/* Total of each results. */
size_t executed_total;
size_t succeeded_total;
size_t failed_total;
size_t warning_total;
size_t info_total;
size_t untested_total;
size_t unresolved_total;
size_t unreported_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;


/* 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];
		  strcpy (tr_tag, "<tr bgcolor=\"#ff8080\">");
		  strcpy (result, "Failed");
		}
	      else if (strncmp (p, "WARNING", 4) == 0)
		{
		  ++warning_num[section];
		  strcpy (tr_tag, "<tr bgcolor=\"#c0c0ff\">");
		  strcpy (result, "Warning");
		}
	      else if (strncmp (p, "FIP", 3) == 0)
		{
		  ++info_num[section];
		  strcpy (tr_tag, "<tr bgcolor=\"#ffff80\">");
		  strcpy (result, "Further Information Provided");
		}
	      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];
		  strcpy (tr_tag, "<tr bgcolor=\"#ff8080\">");
		  strcpy (result, "Unresolved");
		}
	      else	/* if (strncmp (p, "NORESULT", 8) == 0) */
		{
		  ++unreported_num[section];
		  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 identifier. */
void print_identifier (void)
{
  printf ("<h2>1. The identifier of executed test suite.</h2>\n");
  printf ("Package identifier: %s<br>\n", package_identifier);
}

/* 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;

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

  /* Output the index of column. */
  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);
  print_row_of_summary ("Failed", failed_num, failed_total);
  print_row_of_summary ("Warning", warning_num, warning_total);
  print_row_of_summary ("Further Information", info_num, info_total);
  print_row_of_summary ("Untested", untested_num, untested_total);
  print_row_of_summary ("Unresolved", unresolved_num, unresolved_total);
  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>Warning:</b><br>\n"
	  "Implementation does not satisfy the assertion. "
	  "But the assertion is waived currently.<br>\n");
  printf ("<b>Further Information:</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>3. 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 (failed_num[i] > 0)
	printf (", Warning %d", warning_num[i]);
      if (info_num[i] > 0)
	printf (", Further Information %d", info_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)
    {
      fprintf (stderr, "Usage: %s jounal_file\n", 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, identifier_label, package_identifier);
	  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];
      warning_total	+= warning_num[i];
      info_total        += info_num[i];
      untested_total    += untested_num[i];
      unresolved_total  += unresolved_num[i];
      unreported_total  += unreported_num[i];
    }

  /* Output html. */
  printf ("<html>\n");
    print_header ();
    printf ("<body>\n");
      print_headline ();
      print_identifier ();
      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);

  fclose (journal_fp);

  return 0;
}
