/* 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);

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;
}


/* 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);

  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;
}

/* 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;
}
