/* Program to demonstrate formatted text file I/O */

#include <stdio.h>
#include <stdlib.h>
#include <string.h> /* for strerror */
#include <errno.h>  /* for errno */

#define BUF_LEN 256
#define STATE_LEN 22

#define DATA_FORMAT_ERROR 2

/* Read 5 lines (in 3 different ways for illustration)
 *
 * Preconditions:
 *   stream is a valid file stream pointer
 *   None of the first five lines exceeds BUF_LEN length
 * Postconditions:
 *   Five lines (five newline characters) have been read from stream
 *   Returns zero upon success, non-zero otherwise (with errno set)
 */
int
readHeader (FILE* stream);

/* Read, process, and print individual lines (years read two different ways)
 *
 * Preconditions:
 *   stream is a valid file stream pointer
 *   1979 <= year <= 1997
 * Postconditions:
 *   stream pointer has been advanced (due to reading)
 *   Prints state and median income for the given year on separate lines
 *   Returns zero upon success, non-zero otherwise (with errno set)
 */
int
printYear (FILE* stream, int year);

/* Main program */
int
main (int argc, char * argv[] )
{
  const char * DATA_FILE = "state-income.txt";
  
  if (argc != 2)                                              /* Check usage  */
  {
    fprintf (stderr, "Usage: %s year\n", argv[0]);
    return EXIT_FAILURE;
  }
  
  int year = atoi (argv[1]);                   /* Read and validate parameter */

  if (year>1997 || year<1979)
  {
    fprintf (stderr, "%s: parameter year must in [1979,1997]\n", argv[0]);
    return EXIT_FAILURE;
  }

  FILE* inFile = fopen (DATA_FILE, "r");         /* Attempt to open data file */

  if (inFile==NULL)
  {
    fprintf (stderr, "%s: Cannot open %s: %s\n",
             argv[0], DATA_FILE, strerror(errno));
    return EXIT_FAILURE;
  }

  if (readHeader (inFile))           /* Read the header and check for success */
  {
    fprintf (stderr, "%s: Unable to read header from %s: %s\n",
             argv[0], DATA_FILE, strerror (errno));
    return EXIT_FAILURE;
  }

  if (printYear (inFile, year))          /* Read and process individual lines */
  {
    fprintf (stderr, "%s: Error processing year %d: %s\n",
             argv[0], year, strerror (errno));
    return EXIT_FAILURE;
  }

  if (fclose (inFile))
  {
    fprintf (stderr, "%s: Error closing file: %s\n",
             argv[0], strerror (errno));
    return EXIT_FAILURE;
  }

  return EXIT_SUCCESS;
} // main


/* Read 5 lines (in 3 different ways for illustration)
 *
 * Preconditions:
 *   stream is a valid file stream pointer
 *   None of the first five lines exceeds BUF_LEN length
 * Postconditions:
 *   Five lines (five newline characters) have been read from stream
 *   Returns zero upon success, non-zero otherwise (with errno set)
 *   Premature EOF is not detected
 */
int
readHeader (FILE * stream)
{
  /* Read one line into statically allocated memory 
     using fgets (and check for success ) */
  char line[BUF_LEN];
  fgets (line, BUF_LEN, stream);

  if (ferror (stream)) return 1;

  /* Read another line into dynamically allocated memory (with check for 
     success) using fgets (and check for success ) */
  char * anotherline = malloc (sizeof(char) * BUF_LEN);

  if (anotherline==NULL) return 1;
  
  fgets (anotherline, BUF_LEN, stream);

  free (anotherline);
  
  if (ferror (stream)) return 1;

  /* Read the last lines character-by-character (with checks for success) */
  int i;
  for (i = 0; i < 3; i++)
    while (fgetc(stream) != '\n')
      ;

  if (ferror(stream)) return 1;

  return 0;
} // readHeader


/* Read, process, and print individual lines (years read two different ways) */
int
printYear(FILE* stream, int year)
{
  char stateString[STATE_LEN];
  
  printf("Statistics for %d\n", year);
  while (fgets(stateString, STATE_LEN, stream))
  {
    printf("%s",stateString);
    
    /* skip initial columns--note: fgetc for illustration; could use fscanf */
    for (int y = 0; y < 1997-year; y++)
    {
      int c;
      for (c = 0; c < 6; c++) /* Each column is six characters */
        fgetc(stream);
    }
      
    /* read and print median for given year */
    int median;
    int parsed = fscanf(stream, "%d", &median);
    
    if (parsed==EOF || parsed==0) /* Unexpected data format */
      break;
    
    printf("%d\n", median);
    
    /* ignore rest of line */
    while (fgetc(stream) != '\n')
      ;
  }

  if (ferror(stream)) return 1;

  return 0;
} // printYear
