#include "ChordPro.h"

/********************************************************************************/
/* Procedure  : create_input_list                                               */
/* Purpose    : creates a linked list of match structures                       */
/* Inputs     : char *inputted_notes[] - string array of the user note choice   */
/*            : int nm_notes - number of notes that the user has entered        */
/*            : char *main - the initial encoding of the inputted notes         */
/* Outputs    : MATCH_LIST - the head of the created list                       */
/* Notes      : none                                                            */
/********************************************************************************/

MATCH_LIST create_input_list(char *inputted_notes[], int nm_notes, char *main)
{

   MATCH_LIST head = NULL, tail;

   int counter = 0;

   head = malloc(sizeof(MATCH_ELEMENT));

   head->encoding = calloc(13, sizeof(int));
   head->root = calloc(3, sizeof(int));
   head->name = calloc(20, sizeof(char));
   strcpy(head->encoding, main);
   strcpy(head->root, inputted_notes[0]);
   head->match = 0;

   tail = head;

   for (counter = 1; counter < nm_notes; counter++)
   {
      tail->next = malloc(sizeof(MATCH_ELEMENT));
      tail = tail->next;
      tail->encoding = calloc(13, sizeof(int));
      tail->root = calloc(3, sizeof(int));
      tail->name = calloc(20, sizeof(char));
      strcpy(tail->root, inputted_notes[counter]);
      strcpy(tail->encoding, main);
      tail->match = 0;
   }

   tail->next = NULL;
   return head;

}

/********************************************************************************/
/* Procedure  : root_to_index                                                   */
/* Purpose    : finds the global index of a given note in the tonal array       */
/* Inputs     : char *root - the note of which the index is to found            */
/* Outputs    : int - the index of the note                                     */
/* Notes      : uses the global array tonal_board                               */
/********************************************************************************/

int root_to_index(char *root)
{

   extern *tonal_board[];   

   int array_count;

   for (array_count = 0; array_count < 12; array_count++)
   {
      if (!(strcmp(tonal_board[array_count], root)))
      return array_count;
   }

}

/********************************************************************************/
/* Procedure  : reorder_encoding                                                */
/* Purpose    : reorders the encoding so that the root is at the front          */
/* Inputs     : char *encoding - the encoding to be fixed                       */
/*            : int root_index - the position of the root                       */
/* Outputs    : none                                                            */
/* Notes      : none                                                            */ 
/********************************************************************************/

void reorder_encoding(char *encoding, int root_index)
{

   int array_count;
   int enco_count = 0;
   char *temp_encoding = calloc(13, sizeof(char));

   strcpy(temp_encoding, encoding);

   for (array_count = root_index; array_count < 12; array_count++)
   {
      encoding[enco_count] = temp_encoding[array_count];
      enco_count = enco_count + 1;
   }

   for (array_count = 0; array_count < root_index; array_count++)
   {
      encoding[enco_count] = temp_encoding[array_count];
      enco_count = enco_count + 1;
   }

   encoding[0] = '1';

}

/***********************************************************************/
/*                                                                     */
/* Procedure : create_note_array                                       */
/* Purpose   : finds the actual notes selected                         */
/* Inputs    : char *main_enco - the binary encoding                   */
/*           : char *in_notes  - the array to fill                     */
/* Outputs   : none                                                    */
/* Notes     : none                                                    */
/***********************************************************************/

void create_note_array(char *main_enco,char *in_notes[])
{

   extern *tonal_board[];

   int count = 0, current = 0;
   
   for (count = 0; count < 12; ++count)
   {
      if (main_enco[count] == '1')
      {
         in_notes[current] = calloc(strlen(tonal_board[count]) + 1, sizeof(char));
         strcpy(in_notes[current], tonal_board[count]);
         current += 1;
      }
   }

}
 
/***********************************************************************/
/* Procedure : setup_search                                            */
/* Purpose   : create the complete search list                         */
/* Inputs    : char *main_encoding - binary encoding of input          */
/*           : int nm_notes - number of notes inputted                 */
/* Outputs   : MATCH_LIST - the head of the created list               */
/* Notes     :                                                         */
/***********************************************************************/

MATCH_LIST setup_search(char *main_encoding, int num)
{

   char *in_notes[12];
   MATCH_LIST head, current;
   int index;

   create_note_array(main_encoding, in_notes);
   head = create_input_list(in_notes, num, main_encoding);
   current = head;

   while (current != NULL)
   {
      index = root_to_index(current->root);
      current->encoding[index] = 'R';
      reorder_encoding(current->encoding, index);
      current = current->next;
   }

   return head;

}

/***********************************************************************/
/* Procedure : start_search                                            */
/* Purpose   : the actual search of the chords                         */
/* Inputs    : char *main_encoding - binary encoding of input          */
/*           : int nm_notes - number of notes inputted                 */
/* Outputs   : none                                                    */
/* Notes     :                                                         */
/***********************************************************************/

void start_search(char *main_encoding, int nm_notes)
{

   MATCH_LIST head_of_matches = setup_search(main_encoding, nm_notes);
   MATCH_LIST current_match = head_of_matches;
   CHORD_LIST current_chord;
   FOUND_LIST current_found;
   extern CHORD_LIST head_of_chords;
   extern FOUND_LIST head_of_founds;
   int index = 0;
   int nm_ones = 0;   
   int chord_ones = 0;
   head_of_founds = malloc(sizeof(FOUND_ELEMENT));
   current_found = head_of_founds;

   while (current_match != NULL)
   {
      /* printf("Current Encoding = %s.\n", current_match->encoding); */
      current_chord = head_of_chords;
      while (current_chord != NULL)
      {
         /* printf("Current Chord = %s. \n", current_chord->encoding); */
         chord_ones = 0;
         for (index = 0; index < 12; index++)
         {
            if (current_chord->encoding[index] == '1')
                  chord_ones += 1;
            if (current_chord->encoding[index] == current_match->encoding[index])
            {
               if (current_match->encoding[index] == '1')
               {
                  nm_ones += 1;
               }
            }
         }
         if ((nm_ones == (chord_ones)) && (nm_ones != 0) && (nm_ones >= nm_notes))
         {
            current_found->next = add_new_element(current_match->root, current_chord->encoding, current_chord->name, 0); 
            current_found = current_found->next;
         }
         else if ((nm_ones == (chord_ones - 1)) && (nm_ones != 0) && (nm_ones >= nm_notes))
         {
            current_found->next = add_new_element(current_match->root, current_chord->encoding, current_chord->name, 1); 
            current_found = current_found->next;
         }
         else if ((nm_ones == (chord_ones - 2)) && (nm_ones != 0) && (nm_ones >= nm_notes))
         {
            current_found->next = add_new_element(current_match->root, current_chord->encoding, current_chord->name, 2);       
            /* printf("Inter= %s, Notes= %s\n", current_found->chord_notes, current_found->intervals); */
            current_found = current_found->next;
         }
         nm_ones = 0;
         current_chord = current_chord->next;
      }
   current_match = current_match->next;
   }

   current_found->next = NULL;
   current_found = head_of_founds;
   head_of_founds = head_of_founds->next;
   free(current_found);

}

FOUND_LIST add_new_element(char *root, char *encoding, char *name, int accuracy)
{
   
   extern *tonal_board[];
   extern *inter_board[];
   char *space = " \0";
   int root_index, index;
   FOUND_LIST head = malloc(sizeof(FOUND_ELEMENT));
   
   head->full_chord_name = calloc(strlen(root) + strlen(name) + 2, sizeof(char));
   head->chord_notes = calloc(30, sizeof(char));
   head->intervals = calloc(30, sizeof(char));
  
   head->match = accuracy;
   
   root_index = root_to_index(root);
   
   strcpy(head->chord_notes, tonal_board[root_index]);
/*   printf("Root Inter = %s\n", inter_board[0]); */
   strcpy(head->intervals, inter_board[0]); 
   head->chord_notes = strcat(head->chord_notes, space);
   head->intervals = strcat(head->intervals, space); 
   strcpy(head->full_chord_name, root);
   head->full_chord_name = strcat(head->full_chord_name, name);

   for (index = 1; index < 12; ++index)
   {
      if (encoding[index] == '1')
      {
         if ((root_index + index) > 11)
         {
            head->chord_notes = strcat(head->chord_notes, tonal_board[root_index + index - 12]);
            head->chord_notes = strcat(head->chord_notes, space);
         }
         else
         {
            head->chord_notes = strcat(head->chord_notes, tonal_board[root_index + index]);  
            head->chord_notes = strcat(head->chord_notes, space);
         }
         head->intervals = strcat(head->intervals, inter_board[index]);
         head->intervals = strcat(head->intervals, space); 
      }
   }
 /*  printf("Full Notes = %s. Full Name = %s Full Intervals = %s\n", head->chord_notes, name, head->intervals); */

   return head;

}