// this program will calculate pace, given distance and elapsed time
// this will work equally well for metric and english units.  :-)
//    (whatever units are used for the distance will be the units
//     reflected in the pace)
// compile this with something like "g++ -o pacecalc pacecalc.cc"
//

#include <unistd.h>
#include <stdlib.h>   // for atoi()
#include <getopt.h>   // for getopt_long()
#include <iostream>   // for std::cerr, std::cout, std::endl

static const struct option options[] =
{
    {"time", required_argument, NULL, 1},
    {"dist", required_argument, NULL, 2},
};


void usage(const char* const calledAs) {
  std::cerr << "Usage: " << calledAs
	    << " --time=<time> --dist=<distance>\n";
  std::cerr << "       " << calledAs
  	    << " <time> <distance>\n";
  exit(1);
}


int main(int argc, char* argv[]) {
  char timeStr[10];
  char distStr[25];
  int timeFound = 0;
  int distFound = 0;

  if (argc != 3) {
    usage(argv[0]);
  }

  // parse command line arguments
  int c;
  int optionIndex = 0;
  while ((c = getopt_long(argc, argv, "d:t:+h", options, &optionIndex)) != -1) {
    switch(c) {
    case 1:
    case 't':
      if (strlen(optarg) > 9) {
	std::cerr << optarg << " is not a valid Time" << std::endl;
	usage(argv[0]);
      }
      strcpy(timeStr, optarg);
      timeFound = 1;
      break;
    case 2:
    case 'd':
      if (strlen(optarg) > 24) {
	std::cerr << optarg <<
          " is too long.  Cannot handle more than 24 characters in distance" <<
          std::endl;
	usage(argv[0]);
      }
      strcpy(distStr, optarg);
      distFound = 1;
      break;
    case 'h':
      usage(argv[0]);
    default:
      usage(argv[0]);
    }   // switch(c)
  }   // while()

  if (timeFound != distFound) {
    std::cerr << "Can't mix switches and positional parameters\n\n";
    usage(argv[0]);
  }

  // if there were (only) positional parameters
  if (timeFound == 0 && distFound == 0) {
    int colonOne = 0;
    int colonTwo = 0;

    // see which one(s) contain(s) a colon (':')
    if (strchr(argv[1],':') != NULL)
      colonOne = 1;
    if (strchr(argv[2],':') != NULL)
      colonTwo = 1;

    // exactly one has a colon - use it for timeStr and the other for distStr
    if (colonOne != colonTwo) {
      strcpy(timeStr, argv[colonOne + (colonTwo << 1)]);
      strcpy(distStr, argv[(colonOne << 1) + colonTwo]);
    } else {
      // both have colons!?!
      if (colonOne) {
        std::cerr << "Only one positional parameter is allowed "
                     "to contain a colon (':')\n\n";
        usage(argv[0]);
      // no colon found - assume first parameter is time
      } else {
        strcpy(timeStr, argv[1]);
        strcpy(distStr, argv[2]);
      }
    }
  }

  // convert time parameter to Hours, Minutes and Seconds
  int hours, minutes, seconds;
  if (sscanf(timeStr,"%02d:%02d:%02d", &hours, &minutes, &seconds) != 3) {
    hours = 0;
    if (sscanf(timeStr,"%02d:%02d", &minutes, &seconds) != 2) {
      minutes = 0;
      if (sscanf(timeStr,"%02d", &seconds) != 1) {
        std::cerr << timeStr << " is not a valid Time" << std::endl;
        usage(argv[0]);
      }
    }
  }

  // convert distance parameter (string) into float
  float distance = atof(distStr);
  if (distance <= 0) {
    std::cerr << distStr << " is not valid distance" << std::endl;
    usage(argv[0]);
  }

  // calculate pace in minutes and seconds (per mile/kilometer/cubit/whatever)
  time_t elapsedTime = hours*3600+minutes*60+seconds;
  float pace = elapsedTime / distance;
  int paceMinutes = int(pace/60);
  float paceSeconds = pace - paceMinutes*60;

  // display pace
  if (paceMinutes > 0)
    std::cout << paceMinutes << ":";
  if (paceMinutes > 0 && paceSeconds < 10)
    std::cout << "0";
  std::cout << paceSeconds << std::endl;
}
