#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <sys/time.h>

/**
 * Helper function to report timing information.
 */
void output_time_difference(char* name, struct timeval* start,
                            struct timeval* end) {
  long secs_used = (end->tv_sec - start->tv_sec);
  long usecs_used = (end->tv_usec - start->tv_usec);
  double secs = secs_used + (double)usecs_used / 1000000;
  printf("%s took %f seconds\n", name, secs);
}

int target;
int num_threads;

void* find_factors(void* arg) {
  int start = *((int*)arg);
  for (int i = start; i <= target; i = i + num_threads) {
    if (target % i == 0) {
      printf("%d is a factor\n", i);
    }
  }
  return NULL;
}

/**
 *  Find all nontrivial factors of a given number, using concurrency.
 */
int main(int argc, char** argv) {
  if (argc != 3) {
      printf("Usage: %s target num_threads\n", argv[0]);
      return -1;
  }
  target = atoi(argv[1]);
  num_threads = atoi(argv[2]);
  
  struct timeval startTime, endTime;
  gettimeofday(&startTime, NULL);
  
  pthread_t* threads = malloc(num_threads * sizeof(pthread_t));
  int* starts = malloc(num_threads * sizeof(int));

  for (int i = 0; i < num_threads; i++) {
    starts[i] = i + 1; // Thread 0 starts with 1, 1 starts with 2, etc.
    pthread_create(&threads[i], NULL, find_factors, &starts[i]);
  }

  for (int i = 0; i < num_threads; i++) 
    pthread_join(threads[i], NULL);
    
  free(starts);
  free(threads);

  gettimeofday(&endTime, NULL);
  printf("All done!\n");
  
  output_time_difference("factor", &startTime, &endTime); // report timing
  return 0;
}