#include "kernel/types.h"
#include "user/user.h"

#define WORK 100000000000
#define MAXTIME 200
#define TIMESLICE 10

/*

This testcase checks whether virtual runtime is updated correctly or not.
The policy-testcase will not be checked if you fail this testcase.

*/

int
test()
{
  // Fork ten processes
  int id;
  for (id = 0; id < 10 && !fork(); id++)
    ;

  int numTickChanges = 0, currUpTime = 0, prevUpTime = 0, currRunTime = 0;

  int baseUpTime = uptime();
  int baseRunTime = read_runtime();

  int errorRunTimes[MAXTIME], errorUpTimes[MAXTIME];
  int errorNo = 0;
  int schedulerInvoked = 0;

  while (1) {
    currRunTime = read_runtime();
    currUpTime = uptime();

    if (currUpTime != prevUpTime && currUpTime - baseUpTime < MAXTIME) {
      if (currUpTime == prevUpTime + 1) {
        numTickChanges++;
      } else {
        if ((currRunTime - baseRunTime - numTickChanges) > 1 ||
            (currRunTime - baseRunTime - numTickChanges) < -1) {
          errorRunTimes[errorNo] = currRunTime - baseRunTime;
          errorUpTimes[errorNo] = numTickChanges;
          errorNo++;
        }

        schedulerInvoked++;
        if (schedulerInvoked == 2) {
          prevUpTime = currUpTime;
          break;
        }
      }

      prevUpTime = currUpTime;
    }

    if (currUpTime - baseUpTime > MAXTIME)
      break;
  }

  int status;
  wait(&status);

  for (int i = 0; i < errorNo; i++) {
    printf("[PROCESS ID %d] %d. Virtual Runtime: %d, Actual execution time as "
           "calculated by uptime: %d\n",
           id, i + 1, errorRunTimes[i], errorUpTimes[i]);
  }

  if (errorNo > 10) {
    printf(".\n.\n.\n\n");
  }

  if (id == 0) {
    if (status == 2 || schedulerInvoked < 2)
      return 2;
    else
      return errorNo || status;
  }

  if (errorNo)
    exit(1);
  if (schedulerInvoked < 2)
    exit(2);
  exit(0);
}

int
main()
{
  printf("================================\n");
  printf("----RUNNING TESTCASE-VRUNTIME---\n");
  printf("================================\n");

  int result = test();
  if (result == 0) {
    printf("===========================\n");
    printf("------TESTCASE PASSED------\n");
    printf("===========================\n");
  } else if (result == 1) {
    printf("===========================\n");
    printf("------TESTCASE FAILED------\n");
    printf("Virtual Runtimes do not match\n");
    printf("===========================\n");
  } else {
    printf("===========================\n");
    printf("------TESTCASE FAILED------\n");
    printf("Process not scheduled out\n");
    printf("===========================\n");
  }
}
