/* options.c --- parsing of command line options
 *
 * This file is gift-ware.  This file is given to you freely
 * as a gift.  You may use, modify, redistribute, and generally hack
 * it about in any way you like, and you do not have to give anyone
 * anything in return.
 *
 * I do not accept any responsibility for any effects, adverse or
 * otherwise, that this code may have on just about anything that
 * you can think of.  Use it at your own risk.
 *
 * Copyright (C) 1999  Michael Bukin
 */

#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <allegro.h>

#include "options.h"

/*
 * Sing song.
 */
static void
sing_help (void)
{
  static char *help =
    "                         Help!\n"
    "              ( J. Lennon, P. McCartney )\n"
    "\n"
    "Help! I need somebody.\n"
    "Help! Not just anybody.\n"
    "Help! You know, I need someone, help!\n"
    "\n"
    "When I was younger, so much younger than today,\n"
    "I never needed anybody's help in any way.\n"
    "But now these days are gone, I'm not so self assured\n"
    "Now I find I've changed my mind, I've opened up the door.\n"
    "\n"
    "Help me if you can, I'm feeling down\n"
    "And I do appreciate you being 'round.\n"
    "Help me, get my feet back on th ground.\n"
    "Won't you please, please, help me?\n"
    "\n"
    "And now my life has changed in, oh, so many ways,\n"
    "My independence seems to vanish in the haze.\n"
    "But ev'ry now and then I feel so insecure.\n"
    "I know that I just need you like I've never done before.\n"
    "\n"
    "Help me if you can, I'm feeling down\n"
    "And I do appreciate you being 'round.\n"
    "Help me, get my feet back on th ground.\n"
    "Won't you please, please, help me?\n"
    "\n"
    "When I was younger, so much younger than today,\n"
    "I never needed anybody's help in any way.\n"
    "But now these days are gone, I'm not so self assured\n"
    "Now I find I've changed my mind, I've opened up the door.\n"
    "\n"
    "Help me if you can, I'm feeling down\n"
    "And I do appreciate you being 'round.\n"
    "Help me, get my feet back on th ground.\n"
    "Won't you please, please, help me?\n"
    "Help me! Help me!";

  printf ("%s\n\n", help);
}

/*
 * Output help on available options.
 */
static void
help (char *prog)
{
  fprintf (stderr, "Usage: %s [OPTIONS]\n"
	   "\n"
	   "  -help            Output Help!\n"
	   "  -help -help      Output more Help!\n"
	   "  -yesterday       Happy birthday, Arron.\n"
	   "  -splunge <STR>   Splunge option.\n"
	   "  -bell            Test PC speaker.\n"
	   "  -29              Solve rather easy task.\n"
	   "  -<NUM>           Count NUM bottles.\n\n",
	   prog);
}

/*
 * Wrong option curses.
 */
static void
wrong_option (char *prog, char *option)
{
  fprintf (stderr, "%s: unrecognized option -- '%s'\n", prog, option);
  help (prog);
}

/*
 * Append src to dst.  Return pointer to terminating '\0' in dst.
 */
static char*
append_string (char *dst, char *src)
{
  strcpy (dst, src);
  return dst + strlen (dst);
}

/*
 * Convert number to text and append string to dst.
 */
static char*
append_number (char *dst, unsigned int num)
{
  static char *tens[10] =
  {
    "zero", "ten", "twenty", "thirty", "fourty",
    "fifty", "sixty", "seventy", "eighty", "ninety"
  };
  static char *nums[20] =
  {
    "zero", "one", "two", "three", "four", "five",
    "six", "seven", "eight", "nine", "ten",
    "eleven", "twelve", "thirteen", "fourteen", "fifteen",
    "sixteen", "seventeen", "eighteen", "nineteen"
  };

  if (num < 20)
    return append_string (dst, nums[num]);
  else
    {
      dst = append_string (dst, tens[num / 10]);
      if ((num % 10) != 0)
	{
	  dst = append_string (dst, " ");
	  dst = append_string (dst, nums[num % 10]);
	}
      return dst;
    }
}

/*
 * Convert number to string.  Return pointer to static string.
 */
static char*
number_to_string (int num)
{
  static char text[1024];
  char *p = text;

  if (num <= 0)
    strcpy (text, "too little");
  else if (num >= 100000)
    strcpy (text, "too much");
  else
    {
      int i = num;

      if (i >= 1000)
	{
	  /* Convert thousands.  */
	  p = append_number (p, i / 1000);
	  p = append_string (p, " thousand");
	  i %= 1000;
	}

      if (i >= 100)
	{
	  /* Convert hundreds.  */
	  if (i != num)
	    p = append_string (p, " ");
	  p = append_number (p, i / 100);
	  p = append_string (p, " hundred");
	  i %= 100;
	}

      if (i != 0)
	{
	  /* Convert the rest.  */
	  if (i != num)
	    p = append_string (p, " and ");
	  p = append_number (p, i);
	}
    }

  return text;
}

/*
 * Count bottles of beer on the wall and pass them around one-by-one.
 */
static void
bottles_of_beer (int num)
{
  int i;

  for (i = num; i > 0; i--)
    {
      char *text = number_to_string (i);

      if (*text)
	*text = toupper (*text);

      printf ("%s %s of beer on the wall\n", text, ((i > 1) ? "bottles" : "bottle"));
      printf ("You take one down, pass it around...\n");
    }

  printf ("No more bottles of beer on the wall.\n\n");
}

/*
 * Sea dog's song.
 */
static void
sea_dogs_song (int num)
{
  int i;

  for (i = num; i > 0; i--)
    {
      char *text = number_to_string (i);

      if (*text)
	*text = toupper (*text);

      printf ("%s %s on the dead man's chest-\n"
	      "Yo-ho-ho, and a bottle of rum!\n", text, ((i > 1) ? "men" : "man"));
    }

  printf ("Drink and the devil had done for the rest-\n"
	  "Yo-ho-ho, and a bottle of rum!\n\n");
}

/*
 * Unknown splunge option.
 */
static void
splunge (char *arg)
{
  printf ("Unrecognized option 'splunge',\n"
	  "My English dictionary is too small.\n");
  if (arg == 0)
    printf ("Absence of argument to option 'splunge' is an error\n\n");
  else
    printf ("Argument '%s' is not an option\n\n", arg);
}

/*
 * Ring bells and blow whistles.
 */
static void
BEL (void)
{
  printf ("\aDing-\aDong (BEL)\n\n");
}

/*
 * Happy birthday, Arron!
 */
static void
sing_happy_birthday (void)
{
  time_t x = time (0);
  struct tm *t = gmtime (&x);

  if ((t->tm_mon != 10) || (t->tm_mday != 25))
    printf ("It's a little late now,\n"
	    "But better late than never:\n\n");

  printf ("Happy birthday to you,\n"
	  "Happy birthday to you,\n"
	  "Happy birthday, dear Arron,\n"
	  "Happy birthday to you.\n\n");
}

/*
 * Calculate Arron's age.
 */
static void
arrons_age (void)
{
  time_t x = time (0);
  struct tm *t = gmtime (&x);
  int age;

  printf ("Task #29:\n"
	  "  If Arron was 29 years old on 1999/11/25 (\"yesterday\"),\n"
	  "  And today is %d/%d/%d, then how old is he now?\n",
	  (int) (t->tm_year + 1900), (int) (t->tm_mon + 1), (int) (t->tm_mday));

  age = t->tm_year - 99 + 29 - (((t->tm_mon < 10) || (t->tm_mday < 25)) ? 1 : 0);
  printf ("Answer:\n"
	  "  Arron is %s%d (%s) years old.\n\n",
	  ((age == 29) ? "still " : ""), age, number_to_string (age));
}

/*
 * Parse command line options.
 */
void
parse_options (int argc, char *argv[])
{
  int i;

  /* Parse command line options (idea stolen from demo game).  */
  for (i = 1; i < argc; i++)
    {
      char *p = argv[i];

      /* Option must start with '-'.  */
      if (*p != '-')
	{
	  wrong_option (argv[0], argv[i]);
	  exit (EXIT_FAILURE);
	}

      /* Option may start with any number of leading '-'.  */
      while (*p == '-')
	p++;

      /* Parse option itself.  */
      if (stricmp (p, "help") == 0)
	{
	  /* Output "Help!".  */
	  static int help_count = 0;

	  switch (help_count++)
	    {
	    case 0:
	      sing_help ();
	      break;
	    case 1:
	      help (argv[0]);
	      break;
	    default:
	      printf ("Sorry, no more help.\n\n");
	      break;
	    }
	}
      else if (stricmp (p, "yesterday") == 0)
	{
	  /* Congratulate Arron Shutt with his birthday (which was "yesterday").  */
	  sing_happy_birthday ();
	}
      else if (stricmp (p, "splunge") == 0)
	{
	  /* Unknown option splunge.  */
	  i++;
	  splunge (((i >= argc) ? 0 : argv[i]));
	}
      else if ((stricmp (p, "bel") == 0)
	       || (stricmp (p, "bell") == 0))
	{
	  /* Ring bells.  */
	  BEL ();
	}
      else
	{
	  /* See if this option is a number.  */
	  static int number_count = 0;
	  int number = 0;

	  while (isdigit (*p))
	    number = number * 10 + *p++ - '0';

	  if (*p != '\0')
	    {
	      /* Unrecognized option (exit with failure).  */
	      wrong_option (argv[0], argv[i]);
	      exit (EXIT_FAILURE);
	    }

	  if (number == 29)
	    arrons_age ();
	  else
	    {
	      if ((number_count++ & 1) == 0)
		bottles_of_beer (number);
	      else
		sea_dogs_song (number);
	    }
	}
    }
}

/*
 * options.c ends here
 */
