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

#ifdef UNIX

#include <sys/types.h>
#include <sys/wait.h>

struct command * ccForeground = NULL;
#endif

#include "jobs.h"

struct job * joblist;

#ifdef UNIX
int addJobStatus(pid_t pid, const char* command, int state){
#else
int addJobStatus(PROCESS_INFORMATION pid, const char* command, int state){
#endif

  struct job *start = joblist;
  struct job *prev = joblist;
  struct job *tmp;

  int previousjobid = 0;

  while ((start!=NULL)&& (start->jobid == previousjobid+1)){
    prev = start;
    previousjobid = start->jobid;
    start = start->nextjob;

  } 

  //creating 
  tmp = malloc(sizeof(struct job));
  tmp->pid = pid;
  tmp->command = command;
  tmp->jobid = previousjobid+1;
  tmp->status = state; /* running */
  tmp->nextjob = NULL;

  if (prev == NULL){ //the joblist is NULL at the beginning
    joblist = tmp;
  }
  else { //the joblist was not empty
    tmp->nextjob = prev->nextjob;
    prev->nextjob = tmp;
  }

#ifdef UNIX
  printf("[%d] %d\n", previousjobid+1, pid);
#else
  printf("[%d] %d\n", previousjobid+1, pid.dwProcessId);
#endif
  return previousjobid+1;
}

#ifdef UNIX
 int addJob(pid_t pid, const char* command){
   return addJobStatus(pid, command, 0);
 }
 int addStoppedJob(pid_t pid, const char* command){
   return addJobStatus(pid, command, 1);
 }
#else
 int addJob(PROCESS_INFORMATION pid, const char* command){
   return addJobStatus(pid, command, 0);
 }
#endif

int removeJobs(){
  struct job *start = joblist;
  struct job *tmp, *next;
  
  /* find the first job that is not "Exited" or "Done" */
  /* and delete all of them as it goes */
  while((start!=NULL) && (start->status >1 )){
    tmp = start;
    start = start->nextjob;
    free((char *)tmp->command);
    free(tmp);
  }
  
  /* found the first non-deleted node */
  /* it could be NULL */

  joblist = start;
  start = joblist;
  while (start != NULL){
    next = start->nextjob;
    while ((next != NULL) && (next->status > 1)){
      tmp = next;
      next = next->nextjob;
      free((char *)tmp->command);
      free(tmp);
    }
    start->nextjob = next;
    start = next;
  }

  return 0;
}

int printOneJob(struct job *jobs, int opt){
  int status;

#ifdef UNIX
  int pid;
  
  if (opt) {
    pid = 0;
  } else {
    pid = waitpid(jobs->pid, &status, WNOHANG|WUNTRACED);
    if (pid == -1){
      perror("shell: printOneJob");
    }
  }

  if(pid == jobs->pid){

    if (WIFEXITED(status)){
      printf("[%d] ", jobs->jobid);
      printf(" Done  %d       ", WEXITSTATUS(status));
      jobs->status = 3;
      printf("%s\n", jobs->command);
    }else if (WIFSIGNALED(status)){
      printf("[%d]", jobs->jobid);
      printf(" Killed %d      ", WTERMSIG(status));
      jobs->status = 2;
      printf("%s\n", jobs->command);
    }else if (WIFSTOPPED(status)){
      if (jobs->status == 1){ /* it was stopped before */
	/* do nothing*/
      }
      else {
		printf("[%d] ", jobs->jobid);
		printf(" Stopped %d      ", WSTOPSIG(status));
		printf("%s\n", jobs->command);
		jobs->status  = 1;
      }
    }
      return 1;
  }
  else{

    if (opt == 0){
      /* do nothing for printJobStatus because the status didn't change */
    }
    else{
      printf("[%d] ", jobs->jobid);
      if (jobs-> status ==0){
		printf(" Running        ");
      }
      else {
		printf(" Stopped        ");
      }
      printf("%s\n", jobs->command);
    }
  }
#else
   /* windows */
     
  if(GetExitCodeProcess(jobs->pid.hProcess,&status) && (status != STILL_ACTIVE)){
  	printf("[%d]  Exited %d       %s\n", 
		jobs->jobid, status,jobs->command);
	jobs->status = 3;

  }
  else{
    if (opt == 0){
      /* do nothing for printJobStatus because the status didn't change */
    }
    else{
      printf("[%d]  Running          %s\n", jobs->jobid, jobs->command);
	}
  }

#endif

  return 0;  
}

int printJobStatus(){
  struct job *start;
  struct job *next;
  int counter=0;
  //going through the list and print jobs whose status says "exited"
  removeJobs();
  start = joblist;
  while (start){
    next = start->nextjob;
    printOneJob(start, 0);
    start = next;
  }
  //returning number of jobs that changed status
  return counter;
}

int jobs(int argc, char * const argv[]){
  //going through the list and print out their pid, command, elapsed time
  struct job *start;

  removeJobs();
  start = joblist;
  while (start){
    printOneJob(start, 1);
    start = start->nextjob;
  }
  return 0;
}

