/* This program uses code from "Algorithms in C, Third Edition,"
 *               by Robert Sedgewick, Addison-Wesley, 1998.
 */

#include <stdio.h>
#include <stdlib.h>

#include "lists.h"
#include "stacks.h"
#include "tokens.h"


list infixToPostfix(list infix_tokens)
{
   list result = newList();
   Stack op_stack = newStack();
   
   while (!(listEmpty(infix_tokens)))
   {
      link current = deleteAtBeginning(infix_tokens);
      Token T = linkItem(current);
      free(current);
      
      if (tokenIsLeftParen(T))
      {
         free(T);
      }
      else if (tokenIsRightParen(T))
      {
         Token op = pop(op_stack);
         insertAtEnd(result, newLink(op));
      }
      else if (tokenIsOperator(T))
      {
         push(op_stack, T);
      }
      else if (tokenIsInt(T))
      {
         insertAtEnd(result, newLink(T));
      }
   }
   
   destroyStack(op_stack);
   return result;
}

int applyOperation(char operator, int number1, int number2)
{
   int result;

   if (operator == '+')
   {
      result = number1 + number2;
   }
   else if (operator == '-')
   {
      result = number1 - number2;
   }
   else if (operator == '*')
   {
      result = number1 * number2;
   }
   else if (operator == '/')
   {
      result = number1 / number2;
   }
   
   return result;
}

int evaluatePostfix(list tokens)
{
   Stack stack = newStack();
   
   while (!(listEmpty(tokens)))
   {
      link current = deleteAtBeginning(tokens);
      Token T = linkItem(current);
      free(current);
      
      if (tokenIsInt(T))
      {
         int * number = malloc(sizeof(int));
         *number = tokenInt(T);
         push(stack, number);
      }
      else if (tokenIsOperator(T))
      {
         char operator = tokenOperator(T);
         int * operand2 = pop(stack);
         int * operand1 = pop(stack);
         int * outcome = malloc(sizeof(int));
         *outcome = applyOperation(operator, *operand1, *operand2);
         push(stack, outcome);
         free(operand1);
         free(operand2);
      }
      free(T);
   }

   int * final_outcome = pop(stack);
   int result = *final_outcome;
   free(final_outcome);
   destroyStack(stack);
   
   return result;
}

int main(int argc, char ** argv)
{
   char * input_file = argv[1];
   
   input_file = "in2.txt";
   
   FILE * handle = fopen(input_file, "rb");
   while(1)
   {
      char * line = 0;
      int allocated = 0;
      int items = getline(&line, &allocated, handle);
      if (items == -1)
      {
         break;
      }
      
      printf("--------------------------------\n");
      printf("processing: %s\n", line);
      list infix_tokens = tokenize(line);
      if (listEmpty(infix_tokens))
      {
         free(line);
         free(infix_tokens);
         continue;
      }
      printf("infix tokens:");
      printTokenList(infix_tokens);
      
      list postfix_tokens = infixToPostfix(infix_tokens);
      printf("\npostfix tokens:");
      printTokenList(postfix_tokens);
      
      int result = evaluatePostfix(postfix_tokens);
      printf("\nresult: %d\n", result);
      
      destroyList(infix_tokens);
      destroyList(postfix_tokens);
      free(line);
   }
   
   fclose(handle);
   
   int * a;
   char * b = (char *) a;
   
   return 0;
}
