#include <malloc.h>
#include <math.h>
#include "map.h" // See this file for documentation of functions here

Map_t * Load_Map(FILE * Input_Stream_Ptr)
{
  if (NULL == Input_Stream_Ptr)
    {
      return NULL;
    }

  Map_t * Return_Ptr = malloc(sizeof(Map_t));

  if (NULL == Return_Ptr)
    {
      return NULL;
    }

  /* This could use bulletproofing, but we're assuming correct inputs for now
   */

  // Get the node/edge counts
  fscanf(Input_Stream_Ptr, "%lu %lu\n",
	 &(Return_Ptr->Num_Nodes),
	 &(Return_Ptr->Num_Edges) );

  // Allocate the node array
  Return_Ptr->Node_List_Ptr =
    malloc( Return_Ptr->Num_Nodes * sizeof(Node_t) );

  if (NULL == Return_Ptr->Node_List_Ptr)
    {
      free(Return_Ptr);
      return NULL;
    }

  // Allocate the edge array
  Return_Ptr->Edge_List_Ptr =
    malloc( Return_Ptr->Num_Edges * sizeof(Edge_t) );
  
  if (NULL == Return_Ptr->Edge_List_Ptr)
    {
      free(Return_Ptr->Node_List_Ptr);
      free(Return_Ptr);
      return NULL;
    }

  // Read in the node data
  Index_t i;
  for (i=0; i < Return_Ptr->Num_Nodes; i++)
    {
      /* Temporary variables to hold the coordinates
	 We read them in as doubles, and then we can let the compiler do the
	 casting for us */
      double Temp_X, Temp_Y;
      // The "number" field is discarded currently
      fscanf(Input_Stream_Ptr, "%*d %lf %lf\n",
	     &Temp_X, &Temp_Y);

      Return_Ptr->Node_List_Ptr[i].X = Temp_X;
      Return_Ptr->Node_List_Ptr[i].Y = Temp_Y;
    }

  // Read in the edge data

  for (i=0; i < Return_Ptr->Num_Edges; i++)
    {
      // Read in the current edge
      Index_t From, To;
      fscanf(Input_Stream_Ptr, "%lu %lu\n", &From, &To );
      
      // This is such a mess
      Return_Ptr->Edge_List_Ptr[i].Distance = 
	sqrt( 
	     ( Return_Ptr->Node_List_Ptr[To].X -
	       Return_Ptr->Node_List_Ptr[From].X ) *
	     ( Return_Ptr->Node_List_Ptr[To].X -
	       Return_Ptr->Node_List_Ptr[From].X )
	     +
	     ( Return_Ptr->Node_List_Ptr[To].Y -
	       Return_Ptr->Node_List_Ptr[From].Y ) *
	     ( Return_Ptr->Node_List_Ptr[To].Y -
	       Return_Ptr->Node_List_Ptr[From].Y )
	     );
	     
      Return_Ptr->Edge_List_Ptr[i].From = From;
      Return_Ptr->Edge_List_Ptr[i].To = To;
    }

  return Return_Ptr;
}

void Delete_Map(Map_t * Target_Ptr)
{
  if (NULL == Target_Ptr) return;
  if (NULL != Target_Ptr->Node_List_Ptr)
    free(Target_Ptr->Node_List_Ptr);
  if (NULL != Target_Ptr->Edge_List_Ptr)
    free(Target_Ptr->Edge_List_Ptr);
  free(Target_Ptr);
}


//Grabs query file data
Query_t* Load_Query(FILE* Input_Stream_Ptr)
{
  if (NULL == Input_Stream_Ptr)
    {
      return NULL;
    }

  Query_t * Return_Ptr = malloc(sizeof(Query_t));

  if (NULL == Return_Ptr)
    {
      return NULL;
    }


  // Get the query count
  fscanf(Input_Stream_Ptr, "%lu\n",
	 &(Return_Ptr->Num_Paths) );

  // Allocate the path array
  Return_Ptr->Path_List_Ptr =
    malloc( Return_Ptr->Num_Paths * sizeof(Edge_t) );

  if (NULL == Return_Ptr->Path_List_Ptr)
    {
      free(Return_Ptr);
      return NULL;
    }

  // Read in the query data
  Index_t i;
  for (i=0; i < Return_Ptr->Num_Paths; i++)
    {
      // For safety, read into GIGANTIC int types, then cast appropriately
      // GOTCHA: This will break on billions of nodes...
      unsigned long int Temp_From, Temp_To;

      fscanf(Input_Stream_Ptr, "%lu %lu\n",
	     &Temp_From, &Temp_To);

      Return_Ptr->Path_List_Ptr[i].From = Temp_From;
      Return_Ptr->Path_List_Ptr[i].To = Temp_To;
    }
  return Return_Ptr;
}

void Delete_Query(Query_t * Target_Ptr)
{
  if (Target_Ptr != NULL)
    {
      if (NULL != Target_Ptr->Path_List_Ptr)
	{
	  free(Target_Ptr->Path_List_Ptr);
	}
      free(Target_Ptr);
    }
}

