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

int *camisetas;
pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;

void *cliente(void *arg) {
  int s;
  int num = rand() % 10 + 1;
  int numC = *((int *)arg);
  int tipo_cami = rand() % numC;

  // SECCIÓN CRITICA
  s = pthread_mutex_lock(&mtx);
  if (s != 0) {
    printf("Mutex_lock error 1...\n");
    pthread_exit(NULL);
  }

  if (num < camisetas[tipo_cami]) {
    camisetas[tipo_cami] -= num;
    printf("    ||Cliente|| Un cliente ha comprado %d camisetas del tipo %d . "
           "Restantes: %d\n\n",
           num, tipo_cami + 1, camisetas[tipo_cami]);
  } else {
    camisetas[tipo_cami] = 0;
    printf("    ||Cliente|| Un cliente ha comprado todas las existencias del "
           "tipo %d \n\n",
           tipo_cami + 1);
  }

  s = pthread_mutex_unlock(&mtx);
  if (s != 0) {
    printf("Mutex_unlock error 1...\n");
    pthread_exit(NULL);
  }
  // SECCIÓN CRITICA

  pthread_exit(NULL);
}

void *suministrador(void *arg) {
  int s;
  int num = rand() % 10 + 1;
  int numC = (int)(long)arg;
  int tipo_cami = rand() % numC;

  // SECCIÓN CRITICA
  s = pthread_mutex_lock(&mtx);
  if (s != 0) {
    printf("Mutex_lock error 1...\n");
    pthread_exit(NULL);
  }

  camisetas[tipo_cami] += num;
  printf("    ||Suministrador|| Un suministrador ha añadido %d camisetas del "
         "tipo %d . Ahora hay: %d \n\n",
         num, tipo_cami + 1, camisetas[tipo_cami]);

  s = pthread_mutex_unlock(&mtx);
  if (s != 0) {
    printf("Mutex_unlock error 1...\n");
    pthread_exit(NULL);
  }
  // SECCIÓN CRITICA

  pthread_exit(NULL);
}

int main(int argc, char **argv) {
  if (argc < 3) {
    printf("Falta de argumentos \n");
    exit(EXIT_FAILURE);
  }

  long num_threadsC = atoi(argv[1]), num_threadsP = atoi(argv[2]), error;
  pthread_t threadsC[num_threadsC], threadsP[num_threadsP];
  srand(time(NULL));

  camisetas = (int *)malloc(sizeof(int) * atoi(argv[2]));
  for (int i = 0; i < num_threadsP; i++) {
    camisetas[i] = rand() % 100 + 1;
  }

  // CREATES
  for (int t = 0; t < num_threadsC; t++) {
    error = pthread_create(&threadsC[t], NULL, cliente, (void *)&num_threadsP);
    if (error != 0) {
      printf("pthread_create 1 error...\n");
      exit(EXIT_FAILURE);
    }
  }

  for (int t = 0; t < num_threadsP; t++) {
    error = pthread_create(&threadsP[t], NULL, suministrador, (void *)num_threadsP);
    if (error != 0) {
      printf("pthread_create 2 error...\n");
      exit(EXIT_FAILURE);
    }
  }

  // JOINS
  for (int k = 0; k < num_threadsC; k++) {
    error = pthread_join(threadsC[k], NULL);
    if (error != 0) {
      printf("pthread_join 1 error...\n");
      exit(EXIT_FAILURE);
    }
  }
  for (int k = 0; k < num_threadsP; k++) {
    error = pthread_join(threadsP[k], NULL);
    if (error != 0) {
      printf("pthread_join 1 error...\n");
      exit(EXIT_FAILURE);
    }
  }

  printf("PROCESO PADRE, RECUENTO DE CAMISETAS FINAL \n");

  for (int l = 0; l < num_threadsP; l++) {
    printf("-Camiseta del tipo %d. Existencias: %d \n", l + 1, camisetas[l]);
  }
}
