#include <stdio.h>
#include <stdlib.h>
#include "lists.h"

struct Interval
{
   float start;
   float finish;
   float value;
};

struct Intervals
{
   struct Interval * items;
   int number;
};

struct WIS_result
{
   float best_value;
   list best_set;
};

struct Intervals read_intervals(char * filename)
{
   struct Intervals result;
   result.number = 0;
   result.items = 0;

   FILE * handle = fopen(filename, "rb");
   if (handle == 0)
   {
      printf("cannot open %s\n", filename);
      return result;
   }

   fscanf(handle, "%d", &(result.number));
   result.items = malloc(sizeof(struct Interval) * (1 + result.number));
//   printf("number = %d\n", result.number);

   result.items[0].start = 0;
   result.items[0].finish = 0;
   result.items[0].value = 0;
   int counter;
   for (counter = 1; counter <= result.number; counter++)
   {
      float start, finish, value; 
      fscanf(handle, "%f %f %f", & start, & finish, & value);
      result.items[counter].start = start;
      result.items[counter].finish = finish;
      result.items[counter].value = value;
//      printf("%3d: start = %5.1f,   finish = %5.1f,   value = %5.1f\n", counter, start, finish, value);
      if (finish < result.items[counter-1].finish)
      {
         printf("error, intervals are not sorted\n");
         exit(1);
      }
   }

   return result;
}


int * compute_last_complete(struct Intervals intervals)
{
   int * last_complete = malloc(sizeof(int) * (1+intervals.number));
   last_complete[0] = 0;
   int counter, second_counter;
   for (counter = 1; counter <= intervals.number; counter++)
   {
      float start = intervals.items[counter].start;
      second_counter = counter - 1;
      while(1)
      {
         float finish = intervals.items[second_counter].finish;
         if (finish <= start)
         {
            last_complete[counter] = second_counter;
//            printf(" last_complete[%d] = %d\n", counter, second_counter);
            break;
         }
         second_counter--;
      }
   }
   return last_complete;
}
   
   
struct WIS_result wis(struct Intervals intervals)
{
   int * last_complete = compute_last_complete(intervals);
   int * last_used = malloc(sizeof(int) * (1+intervals.number));
   float * solutions = malloc(sizeof(float) * (1+ intervals.number));
   solutions[0] = 0;
   last_used[0] = 0;
   int counter;
   for (counter = 1; counter <= intervals.number; counter++)
   {
      float solution_without = solutions[counter - 1];
      float value = intervals.items[counter].value;
      float solution_with = solutions[last_complete[counter]] + value;
      
      if (solution_with > solution_without) 
      {
         solutions[counter] = solution_with;
         last_used[counter] = counter;
      }
      else
      {
         solutions[counter] = solution_without;
         last_used[counter] = last_used[counter-1];
      }
//      printf("counter %4d: solution_without = %6.1f, solution_with = %6.1f, best = %6.1f\n",
//            counter, solution_without, solution_with, solutions[counter]);
   }

   // begin backtracking
   list best_set = newList();
   counter = last_used[intervals.number];
   while(counter != 0)
   {
      struct Interval * interval = malloc(sizeof(struct Interval));
      *interval = intervals.items[counter];
      insertAtBeginning(best_set, newLink(interval));
      counter = last_used[last_complete[counter]];
   }
     
   struct WIS_result result;
   result.best_value = solutions[intervals.number];
   result.best_set = best_set;
   free(solutions);
   free(last_complete);
   free(last_used);
   
   return result;
}

void print_interval_list(list intervals)
{
   link current;
   for (current = listFirst(intervals); current != NULL; current = linkNext(current))
   {
      struct Interval * interval = (struct Interval *) linkItem(current);
      float start = interval->start;
      float finish = interval->finish;
      float value = interval->value;

      printf("start = %5.1f,   finish = %5.1f,   value = %5.1f\n", start, finish, value);
   }
}


int main()
{
   struct Intervals intervals = read_intervals("wis1.txt");
 
   struct WIS_result result = wis(intervals);
   printf("    best_value = %6.2f\n", result.best_value);
   print_interval_list(result.best_set);

   free(intervals.items);
   destroyList(result.best_set);
   
   return 0; 
}