/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

/*
 * file: timetest.c
 * description: test time and date routines
 */
/***********************************************************************
** Includes
***********************************************************************/
/* Used to get the command line option */
#include "plgetopt.h"

#include "prinit.h"
#include "prtime.h"
#include "prprf.h"

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

int failed_already = 0;
PRBool debug_mode = PR_FALSE;

static char* dayOfWeek[] = {"Sun", "Mon", "Tue", "Wed",
                            "Thu", "Fri", "Sat", "???"};
static char* month[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul",
                        "Aug", "Sep", "Oct", "Nov", "Dec", "???"};

static void PrintExplodedTime(const PRExplodedTime* et) {
  PRInt32 totalOffset;
  PRInt32 hourOffset, minOffset;
  const char* sign;

  /* Print day of the week, month, day, hour, minute, and second */
  if (debug_mode)
    printf("%s %s %ld %02ld:%02ld:%02ld ", dayOfWeek[et->tm_wday],
           month[et->tm_month], et->tm_mday, et->tm_hour, et->tm_min,
           et->tm_sec);

  /* Print time zone */
  totalOffset = et->tm_params.tp_gmt_offset + et->tm_params.tp_dst_offset;
  if (totalOffset == 0) {
    if (debug_mode) {
      printf("UTC ");
    }
  } else {
    sign = "+";
    if (totalOffset < 0) {
      totalOffset = -totalOffset;
      sign = "-";
    }
    hourOffset = totalOffset / 3600;
    minOffset = (totalOffset % 3600) / 60;
    if (debug_mode) {
      printf("%s%02ld%02ld ", sign, hourOffset, minOffset);
    }
  }

  /* Print year */
  if (debug_mode) {
    printf("%hd", et->tm_year);
  }
}

static int ExplodedTimeIsEqual(const PRExplodedTime* et1,
                               const PRExplodedTime* et2) {
  if (et1->tm_usec == et2->tm_usec && et1->tm_sec == et2->tm_sec &&
      et1->tm_min == et2->tm_min && et1->tm_hour == et2->tm_hour &&
      et1->tm_mday == et2->tm_mday && et1->tm_month == et2->tm_month &&
      et1->tm_year == et2->tm_year && et1->tm_wday == et2->tm_wday &&
      et1->tm_yday == et2->tm_yday &&
      et1->tm_params.tp_gmt_offset == et2->tm_params.tp_gmt_offset &&
      et1->tm_params.tp_dst_offset == et2->tm_params.tp_dst_offset) {
    return 1;
  } else {
    return 0;
  }
}

static void testParseTimeString(PRTime t) {
  PRExplodedTime et;
  PRTime t2;
  char timeString[128];
  char buf[128];
  PRInt32 totalOffset;
  PRInt32 hourOffset, minOffset;
  const char* sign;
  PRInt64 usec_per_sec;

  /* Truncate the microsecond part of PRTime */
  LL_I2L(usec_per_sec, PR_USEC_PER_SEC);
  LL_DIV(t, t, usec_per_sec);
  LL_MUL(t, t, usec_per_sec);

  PR_ExplodeTime(t, PR_LocalTimeParameters, &et);

  /* Print day of the week, month, day, hour, minute, and second */
  PR_snprintf(timeString, 128, "%s %s %ld %02ld:%02ld:%02ld ",
              dayOfWeek[et.tm_wday], month[et.tm_month], et.tm_mday, et.tm_hour,
              et.tm_min, et.tm_sec);
  /* Print time zone */
  totalOffset = et.tm_params.tp_gmt_offset + et.tm_params.tp_dst_offset;
  if (totalOffset == 0) {
    strcat(timeString, "GMT "); /* I wanted to use "UTC" here, but
                                 * PR_ParseTimeString doesn't
                                 * understand "UTC".  */
  } else {
    sign = "+";
    if (totalOffset < 0) {
      totalOffset = -totalOffset;
      sign = "-";
    }
    hourOffset = totalOffset / 3600;
    minOffset = (totalOffset % 3600) / 60;
    PR_snprintf(buf, 128, "%s%02ld%02ld ", sign, hourOffset, minOffset);
    strcat(timeString, buf);
  }
  /* Print year */
  PR_snprintf(buf, 128, "%hd", et.tm_year);
  strcat(timeString, buf);

  if (PR_ParseTimeString(timeString, PR_FALSE, &t2) == PR_FAILURE) {
    fprintf(stderr, "PR_ParseTimeString() failed\n");
    exit(1);
  }
  if (LL_NE(t, t2)) {
    fprintf(stderr, "PR_ParseTimeString() incorrect\n");
    PR_snprintf(buf, 128, "t is %lld, t2 is %lld, time string is %s\n", t, t2,
                timeString);
    fprintf(stderr, "%s\n", buf);
    exit(1);
  }
}

int main(int argc, char** argv) {
  /* The command line argument: -d is used to determine if the test is being run
  in debug mode. The regress tool requires only one line output:PASS or FAIL.
  All of the printfs associated with this test has been handled with a if
  (debug_mode) test. Usage: test_name -d
  */
  PLOptStatus os;
  PLOptState* opt;

  PR_STDIO_INIT();
  opt = PL_CreateOptState(argc, argv, "d");
  while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) {
    if (PL_OPT_BAD == os) {
      continue;
    }
    switch (opt->option) {
      case 'd': /* debug mode */
        debug_mode = PR_TRUE;
        break;
      default:
        break;
    }
  }
  PL_DestroyOptState(opt);

  /* main test */

  PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);

  /* Testing zero PRTime (the epoch) */
  {
    PRTime t;
    PRExplodedTime et;

    LL_I2L(t, 0);
    if (debug_mode) {
      printf("The NSPR epoch is:\n");
    }
    PR_ExplodeTime(t, PR_LocalTimeParameters, &et);
    PrintExplodedTime(&et);
    if (debug_mode) {
      printf("\n");
    }
    PR_ExplodeTime(t, PR_GMTParameters, &et);
    PrintExplodedTime(&et);
    if (debug_mode) {
      printf("\n\n");
    }
    testParseTimeString(t);
  }

  /*
   *************************************************************
   **
   **  Testing PR_Now(), PR_ExplodeTime, and PR_ImplodeTime
   **  on the current time
   **
   *************************************************************
   */

  {
    PRTime t1, t2;
    PRExplodedTime et;

    if (debug_mode) {
      printf("*********************************************\n");
      printf("**                                         **\n");
      printf("** Testing PR_Now(), PR_ExplodeTime, and   **\n");
      printf("** PR_ImplodeTime on the current time      **\n");
      printf("**                                         **\n");
      printf("*********************************************\n\n");
    }
    t1 = PR_Now();

    /* First try converting to UTC */

    PR_ExplodeTime(t1, PR_GMTParameters, &et);
    if (et.tm_params.tp_gmt_offset || et.tm_params.tp_dst_offset) {
      if (debug_mode) {
        printf("ERROR: UTC has nonzero gmt or dst offset.\n");
      } else {
        failed_already = 1;
      }
      return 1;
    }
    if (debug_mode) {
      printf("Current UTC is ");
    }
    PrintExplodedTime(&et);
    if (debug_mode) {
      printf("\n");
    }

    t2 = PR_ImplodeTime(&et);
    if (LL_NE(t1, t2)) {
      if (debug_mode) {
        printf("ERROR: Explode and implode are NOT inverse.\n");
      } else {
        printf("FAIL\n");
      }
      return 1;
    }

    /* Next, try converting to local (US Pacific) time */

    PR_ExplodeTime(t1, PR_LocalTimeParameters, &et);
    if (debug_mode) {
      printf("Current local time is ");
    }
    PrintExplodedTime(&et);
    if (debug_mode) {
      printf("\n");
    }
    if (debug_mode)
      printf("GMT offset is %ld, DST offset is %ld\n",
             et.tm_params.tp_gmt_offset, et.tm_params.tp_dst_offset);
    t2 = PR_ImplodeTime(&et);
    if (LL_NE(t1, t2)) {
      if (debug_mode) {
        printf("ERROR: Explode and implode are NOT inverse.\n");
      }
      return 1;
    }

    if (debug_mode) {
      printf("Please examine the results\n");
    }
    testParseTimeString(t1);
  }

  /*
   *******************************************
   **
   ** Testing PR_NormalizeTime()
   **
   *******************************************
   */

  /* July 4, 2001 is Wednesday */
  {
    PRExplodedTime et;

    if (debug_mode) {
      printf("\n");
      printf("**********************************\n");
      printf("**                              **\n");
      printf("** Testing PR_NormalizeTime()   **\n");
      printf("**                              **\n");
      printf("**********************************\n\n");
    }
    et.tm_year = 2001;
    et.tm_month = 7 - 1;
    et.tm_mday = 4;
    et.tm_hour = 0;
    et.tm_min = 0;
    et.tm_sec = 0;
    et.tm_usec = 0;
    et.tm_params = PR_GMTParameters(&et);

    PR_NormalizeTime(&et, PR_GMTParameters);

    if (debug_mode) {
      printf("July 4, 2001 is %s.\n", dayOfWeek[et.tm_wday]);
    }
    if (et.tm_wday == 3) {
      if (debug_mode) {
        printf("PASS\n");
      }
    } else {
      if (debug_mode) {
        printf("ERROR: It should be Wednesday\n");
      } else {
        failed_already = 1;
      }
      return 1;
    }
    testParseTimeString(PR_ImplodeTime(&et));

    /* June 12, 1997 23:00 PST == June 13, 1997 00:00 PDT */
    et.tm_year = 1997;
    et.tm_month = 6 - 1;
    et.tm_mday = 12;
    et.tm_hour = 23;
    et.tm_min = 0;
    et.tm_sec = 0;
    et.tm_usec = 0;
    et.tm_params.tp_gmt_offset = -8 * 3600;
    et.tm_params.tp_dst_offset = 0;

    PR_NormalizeTime(&et, PR_USPacificTimeParameters);

    if (debug_mode) {
      printf("Thu Jun 12, 1997 23:00:00 PST is ");
    }
    PrintExplodedTime(&et);
    if (debug_mode) {
      printf(".\n");
    }
    if (et.tm_wday == 5) {
      if (debug_mode) {
        printf("PASS\n");
      }
    } else {
      if (debug_mode) {
        printf("ERROR: It should be Friday\n");
      } else {
        failed_already = 1;
      }
      return 1;
    }
    testParseTimeString(PR_ImplodeTime(&et));

    /* Feb 14, 1997 00:00:00 PDT == Feb 13, 1997 23:00:00 PST */
    et.tm_year = 1997;
    et.tm_month = 2 - 1;
    et.tm_mday = 14;
    et.tm_hour = 0;
    et.tm_min = 0;
    et.tm_sec = 0;
    et.tm_usec = 0;
    et.tm_params.tp_gmt_offset = -8 * 3600;
    et.tm_params.tp_dst_offset = 3600;

    PR_NormalizeTime(&et, PR_USPacificTimeParameters);

    if (debug_mode) {
      printf("Fri Feb 14, 1997 00:00:00 PDT is ");
    }
    PrintExplodedTime(&et);
    if (debug_mode) {
      printf(".\n");
    }
    if (et.tm_wday == 4) {
      if (debug_mode) {
        printf("PASS\n");
      }
    } else {
      if (debug_mode) {
        printf("ERROR: It should be Thursday\n");
      } else {
        failed_already = 1;
      }
      return 1;
    }
    testParseTimeString(PR_ImplodeTime(&et));

    /* What time is Nov. 7, 1996, 18:29:23 PDT? */
    et.tm_year = 1996;
    et.tm_month = 11 - 1;
    et.tm_mday = 7;
    et.tm_hour = 18;
    et.tm_min = 29;
    et.tm_sec = 23;
    et.tm_usec = 0;
    et.tm_params.tp_gmt_offset = -8 * 3600; /* PDT */
    et.tm_params.tp_dst_offset = 3600;

    PR_NormalizeTime(&et, PR_LocalTimeParameters);
    if (debug_mode) {
      printf("Nov 7 18:29:23 PDT 1996 is ");
    }
    PrintExplodedTime(&et);
    if (debug_mode) {
      printf(".\n");
    }
    testParseTimeString(PR_ImplodeTime(&et));

    /* What time is Oct. 7, 1995, 18:29:23 PST? */
    et.tm_year = 1995;
    et.tm_month = 10 - 1;
    et.tm_mday = 7;
    et.tm_hour = 18;
    et.tm_min = 29;
    et.tm_sec = 23;
    et.tm_params.tp_gmt_offset = -8 * 3600; /* PST */
    et.tm_params.tp_dst_offset = 0;

    PR_NormalizeTime(&et, PR_LocalTimeParameters);
    if (debug_mode) {
      printf("Oct 7 18:29:23 PST 1995 is ");
    }
    PrintExplodedTime(&et);
    if (debug_mode) {
      printf(".\n");
    }
    testParseTimeString(PR_ImplodeTime(&et));

    if (debug_mode) {
      printf("Please examine the results\n");
    }
  }

  /*
   **************************************************************
   **
   ** Testing range of years
   **
   **************************************************************
   */

  {
    PRExplodedTime et1, et2;
    PRTime ttt;
    PRTime secs;

    if (debug_mode) {
      printf("\n");
      printf("***************************************\n");
      printf("**                                   **\n");
      printf("**  Testing range of years           **\n");
      printf("**                                   **\n");
      printf("***************************************\n\n");
    }
    /* April 4, 1917 GMT */
    et1.tm_usec = 0;
    et1.tm_sec = 0;
    et1.tm_min = 0;
    et1.tm_hour = 0;
    et1.tm_mday = 4;
    et1.tm_month = 4 - 1;
    et1.tm_year = 1917;
    et1.tm_params = PR_GMTParameters(&et1);
    PR_NormalizeTime(&et1, PR_LocalTimeParameters);
    secs = PR_ImplodeTime(&et1);
    if (LL_GE_ZERO(secs)) {
      if (debug_mode) {
        printf("ERROR: April 4, 1917 GMT returns a nonnegative second count\n");
      }
      failed_already = 1;
      return 1;
    }
    PR_ExplodeTime(secs, PR_LocalTimeParameters, &et2);
    if (!ExplodedTimeIsEqual(&et1, &et2)) {
      if (debug_mode) {
        printf(
            "ERROR: PR_ImplodeTime and PR_ExplodeTime are not inverse for "
            "April 4, 1917 GMT\n");
      }
      failed_already = 1;
      return 1;
    }
    ttt = PR_ImplodeTime(&et1);
    testParseTimeString(ttt);

    if (debug_mode) {
      printf("Test passed for April 4, 1917\n");
    }

    /* July 4, 2050 */
    et1.tm_usec = 0;
    et1.tm_sec = 0;
    et1.tm_min = 0;
    et1.tm_hour = 0;
    et1.tm_mday = 4;
    et1.tm_month = 7 - 1;
    et1.tm_year = 2050;
    et1.tm_params = PR_GMTParameters(&et1);
    PR_NormalizeTime(&et1, PR_LocalTimeParameters);
    secs = PR_ImplodeTime(&et1);
    if (!LL_GE_ZERO(secs)) {
      if (debug_mode) {
        printf("ERROR: July 4, 2050 GMT returns a negative second count\n");
      }
      failed_already = 1;
      return 1;
    }
    PR_ExplodeTime(secs, PR_LocalTimeParameters, &et2);
    if (!ExplodedTimeIsEqual(&et1, &et2)) {
      if (debug_mode) {
        printf(
            "ERROR: PR_ImplodeTime and PR_ExplodeTime are not inverse for July "
            "4, 2050 GMT\n");
      }
      failed_already = 1;
      return 1;
    }
    testParseTimeString(PR_ImplodeTime(&et1));

    if (debug_mode) {
      printf("Test passed for July 4, 2050\n");
    }
  }

  /*
   **************************************************************
   **
   **  Stress test
   *
   **      Go through four years, starting from
   **      00:00:00 PST Jan. 1, 2005, incrementing
   **      every 10 minutes.
   **
   **************************************************************
   */

  {
    PRExplodedTime et, et1, et2;
    PRInt64 usecPer10Min;
    int day, hour, min;
    PRTime usecs;
    int dstInEffect = 0;

    if (debug_mode) {
      printf("\n");
      printf("*******************************************************\n");
      printf("**                                                   **\n");
      printf("**        Stress test  Pacific Time                  **\n");
      printf("**  Starting from midnight Jan. 1, 2005 PST,         **\n");
      printf("**  going through four years in 10-minute increment  **\n");
      printf("**                                                   **\n");
      printf("*******************************************************\n\n");
    }
    LL_I2L(usecPer10Min, 600000000L);

    /* 00:00:00 PST Jan. 1, 2005 */
    et.tm_usec = 0;
    et.tm_sec = 0;
    et.tm_min = 0;
    et.tm_hour = 0;
    et.tm_mday = 1;
    et.tm_month = 0;
    et.tm_year = 2005;
    et.tm_params.tp_gmt_offset = -8 * 3600;
    et.tm_params.tp_dst_offset = 0;
    usecs = PR_ImplodeTime(&et);

    for (day = 0; day < 4 * 365 + 1; day++) {
      for (hour = 0; hour < 24; hour++) {
        for (min = 0; min < 60; min += 10) {
          LL_ADD(usecs, usecs, usecPer10Min);
          PR_ExplodeTime(usecs, PR_USPacificTimeParameters, &et1);

          et2 = et;
          et2.tm_usec += 600000000L;
          PR_NormalizeTime(&et2, PR_USPacificTimeParameters);

          if (!ExplodedTimeIsEqual(&et1, &et2)) {
            printf("ERROR: componentwise comparison failed\n");
            PrintExplodedTime(&et1);
            printf("\n");
            PrintExplodedTime(&et2);
            printf("\n");
            failed_already = 1;
            return 1;
          }

          if (LL_NE(usecs, PR_ImplodeTime(&et1))) {
            printf(
                "ERROR: PR_ExplodeTime and PR_ImplodeTime are not inverse\n");
            PrintExplodedTime(&et1);
            printf("\n");
            failed_already = 1;
            return 1;
          }
          testParseTimeString(usecs);

          if (!dstInEffect && et1.tm_params.tp_dst_offset) {
            dstInEffect = 1;
            if (debug_mode) {
              printf("DST changeover from ");
              PrintExplodedTime(&et);
              printf(" to ");
              PrintExplodedTime(&et1);
              printf(".\n");
            }
          } else if (dstInEffect && !et1.tm_params.tp_dst_offset) {
            dstInEffect = 0;
            if (debug_mode) {
              printf("DST changeover from ");
              PrintExplodedTime(&et);
              printf(" to ");
              PrintExplodedTime(&et1);
              printf(".\n");
            }
          }

          et = et1;
        }
      }
    }
    if (debug_mode) {
      printf("Test passed\n");
    }
  }

  /* Same stress test, but with PR_LocalTimeParameters */

  {
    PRExplodedTime et, et1, et2;
    PRInt64 usecPer10Min;
    int day, hour, min;
    PRTime usecs;
    int dstInEffect = 0;

    if (debug_mode) {
      printf("\n");
      printf("*******************************************************\n");
      printf("**                                                   **\n");
      printf("**         Stress test    Local Time                 **\n");
      printf("**  Starting from midnight Jan. 1, 2005 PST,         **\n");
      printf("**  going through four years in 10-minute increment  **\n");
      printf("**                                                   **\n");
      printf("*******************************************************\n\n");
    }

    LL_I2L(usecPer10Min, 600000000L);

    /* 00:00:00 PST Jan. 1, 2005 */
    et.tm_usec = 0;
    et.tm_sec = 0;
    et.tm_min = 0;
    et.tm_hour = 0;
    et.tm_mday = 1;
    et.tm_month = 0;
    et.tm_year = 2005;
    et.tm_params.tp_gmt_offset = -8 * 3600;
    et.tm_params.tp_dst_offset = 0;
    usecs = PR_ImplodeTime(&et);

    for (day = 0; day < 4 * 365 + 1; day++) {
      for (hour = 0; hour < 24; hour++) {
        for (min = 0; min < 60; min += 10) {
          LL_ADD(usecs, usecs, usecPer10Min);
          PR_ExplodeTime(usecs, PR_LocalTimeParameters, &et1);

          et2 = et;
          et2.tm_usec += 600000000L;
          PR_NormalizeTime(&et2, PR_LocalTimeParameters);

          if (!ExplodedTimeIsEqual(&et1, &et2)) {
            printf("ERROR: componentwise comparison failed\n");
            PrintExplodedTime(&et1);
            printf("\n");
            PrintExplodedTime(&et2);
            printf("\n");
            return 1;
          }

          if (LL_NE(usecs, PR_ImplodeTime(&et1))) {
            printf(
                "ERROR: PR_ExplodeTime and PR_ImplodeTime are not inverse\n");
            PrintExplodedTime(&et1);
            printf("\n");
            failed_already = 1;
            return 1;
          }
          testParseTimeString(usecs);

          if (!dstInEffect && et1.tm_params.tp_dst_offset) {
            dstInEffect = 1;
            if (debug_mode) {
              printf("DST changeover from ");
              PrintExplodedTime(&et);
              printf(" to ");
              PrintExplodedTime(&et1);
              printf(".\n");
            }
          } else if (dstInEffect && !et1.tm_params.tp_dst_offset) {
            dstInEffect = 0;
            if (debug_mode) {
              printf("DST changeover from ");
              PrintExplodedTime(&et);
              printf(" to ");
              PrintExplodedTime(&et1);
              printf(".\n");
            }
          }

          et = et1;
        }
      }
    }
    if (debug_mode) {
      printf("Test passed\n");
    }
  }

  /* Same stress test, but with PR_LocalTimeParameters and going backward */

  {
    PRExplodedTime et, et1, et2;
    PRInt64 usecPer10Min;
    int day, hour, min;
    PRTime usecs;
    int dstInEffect = 0;

    if (debug_mode) {
      printf("\n");
      printf("*******************************************************\n");
      printf("**                                                   **\n");
      printf("**           Stress test    Local Time               **\n");
      printf("**  Starting from midnight Jan. 1, 2009 PST,         **\n");
      printf("**  going back four years in 10-minute increment     **\n");
      printf("**                                                   **\n");
      printf("*******************************************************\n\n");
    }

    LL_I2L(usecPer10Min, 600000000L);

    /* 00:00:00 PST Jan. 1, 2009 */
    et.tm_usec = 0;
    et.tm_sec = 0;
    et.tm_min = 0;
    et.tm_hour = 0;
    et.tm_mday = 1;
    et.tm_month = 0;
    et.tm_year = 2009;
    et.tm_params.tp_gmt_offset = -8 * 3600;
    et.tm_params.tp_dst_offset = 0;
    usecs = PR_ImplodeTime(&et);

    for (day = 0; day < 4 * 365 + 1; day++) {
      for (hour = 0; hour < 24; hour++) {
        for (min = 0; min < 60; min += 10) {
          LL_SUB(usecs, usecs, usecPer10Min);
          PR_ExplodeTime(usecs, PR_LocalTimeParameters, &et1);

          et2 = et;
          et2.tm_usec -= 600000000L;
          PR_NormalizeTime(&et2, PR_LocalTimeParameters);

          if (!ExplodedTimeIsEqual(&et1, &et2)) {
            printf("ERROR: componentwise comparison failed\n");
            PrintExplodedTime(&et1);
            printf("\n");
            PrintExplodedTime(&et2);
            printf("\n");
            return 1;
          }

          if (LL_NE(usecs, PR_ImplodeTime(&et1))) {
            printf(
                "ERROR: PR_ExplodeTime and PR_ImplodeTime are not inverse\n");
            PrintExplodedTime(&et1);
            printf("\n");
            failed_already = 1;
            return 1;
          }
          testParseTimeString(usecs);

          if (!dstInEffect && et1.tm_params.tp_dst_offset) {
            dstInEffect = 1;
            if (debug_mode) {
              printf("DST changeover from ");
              PrintExplodedTime(&et);
              printf(" to ");
              PrintExplodedTime(&et1);
              printf(".\n");
            }
          } else if (dstInEffect && !et1.tm_params.tp_dst_offset) {
            dstInEffect = 0;
            if (debug_mode) {
              printf("DST changeover from ");
              PrintExplodedTime(&et);
              printf(" to ");
              PrintExplodedTime(&et1);
              printf(".\n");
            }
          }

          et = et1;
        }
      }
    }
  }

  if (failed_already) {
    return 1;
  } else {
    return 0;
  }
}
