/* Implementation of list operations for a linked list of notes */

#include "pitch.h"
#include "noteNode.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

extern pitch scale[NUM_SCALE_NOTES];

/* set list to null */
void
setNull (noteNode** first)
{
  /* deallocate space for any nodes in current melody */
  noteNode* ptr = *first;
  while (ptr != NULL)
    {
      noteNode* oldPtr = ptr;
      ptr = ptr->next;
      free(oldPtr);
    }

  /* set original pointer to NULL */
  *first = NULL;
}

/* find a note of a particular name/octave/duration
   return noteNode (with index of note in the "scale" array within pitch.h)
   or NULL indicating the note could not be made. */
noteNode* makeNote(char name[3], int octave, double duration)
{
  for (int i = 0; i < NUM_SCALE_NOTES ; i++)  /* search notes on the piano */
    {
      if (((strcmp(name, scale[i].name) == 0) 
           || (strcmp(name, scale[i].altName) == 0))
          && (octave == scale[i].octave))
        {  /* note found on piano */
          printf("note found with index %d\n", i);
          noteNode* newNote = malloc(sizeof(noteNode));

          if (newNote==NULL)
            {
              perror("Unable to allocate note node");
              return NULL;
            }
          
          newNote->scaleIndex = i;
          newNote->duration = duration;
          newNote->next = NULL;
          return newNote;
        }
    }
  return NULL; /* note not found in scale */
} /* makeNote */

/* read a note's name, octave, and duration 
   return noteNode (with index of note in the "scale" array within pitch.h)
           or NULL indicating the note was not found.
   input line is cleared when procedure finishes
*/
noteNode*
readNote ()
{
  char name[3]; /* e.g., Af\0' */
  int octave;
  double duration;

  int numTokens;
  
  printf("enter note-name octave duration: ");
  numTokens = scanf("%2s", name);

  if (numTokens != 1)
    {
      printf("Failed to read note-name duration");
      return NULL;
    }
  
  name[0] = toupper(name[0]);  /* letter is capitalized in table */
  name[1] = tolower(name[1]);  /* sharp/flat is in lower case */

  if (name[0] == 'Q')
    {
      while (getchar() != '\n');  /* clear rest of input line */
      return NULL;
    }

  numTokens = scanf("%d", &octave);

  if (numTokens != 1)
    {
      printf("Failed to read octave\n");
      return NULL;
    }

  numTokens = scanf("%lf", &duration);

  if (numTokens != 1)
    {
      printf("Failed to read duration\n");
      return NULL;
    }

  while (getchar() != '\n'); /* clear rest of input line */

  return makeNote(name, octave, duration);
  
} /* readNote */


/* add notes at end of a tune (a melody or musical phrase) */
void
addAtEnd (noteNode** first)
{
  printf("enter note information, concluding with Q for the note-namen\n");
  
  noteNode* newNote = readNote();
  if (newNote == NULL)
    { 
      printf("note addition completed\n");
      return;
    }

  noteNode* ptrToLast;  /* pointer to the last node in the tune */

  if (*first == NULL)  /* list is null, so read and insert first item */
    {
      *first = newNote;
      ptrToLast = *first;
      newNote = readNote();
    }
  else                /* find end of tune in linked list */
    {
      ptrToLast = *first;
      while (ptrToLast->next != NULL)
        {
          ptrToLast = ptrToLast->next;
        }
    }

  while (newNote != NULL)
    {
      /* insert note at end and read next note */
      ptrToLast->next = newNote;
      ptrToLast = newNote;
      newNote = readNote();
    }    
  printf("note addition completed\n");
}

/* print notes in a tune (a melody or musical phrase) in tabular form */
void
printTuneTable (noteNode* first)
{
  noteNode* ptr = first;
  if (ptr == NULL)
    {
      printf("The tune contains no notes\n");
    }
  else
    { 
      printf("  index  name  octave  frequency  duration\n");
      int seqNumber = 1;
      while (ptr != NULL)
        {
          printf("%5d", seqNumber);                    /* print table entry */
          int index = ptr->scaleIndex;
          printf("     %-2s", scale[index].name);
          printf("%7d", scale[index].octave);
          printf("%11d", scale[index].freq);
          printf("%10.2lf", ptr->duration);
          printf("\n");
          
          seqNumber++;                                /* move to next note */
          ptr = ptr->next;
        }
      printf("end of tune\n");
    }
}
