/* 
 * File:   main.c
 * Author: M650116
 *
 * Created on July 28, 2014, 4:45 PM
 * 
 * Problem statement: 
 *   Calculate the detour distance between two
 * different rides. Given four latitude / longitude
 * pairs, where driver one is traveling from point
 * A to point B and driver two is traveling from 
 * point C to D, write a function (in your language of choice)
 * to calculate the shorter of the detour distances the drivers
 * would need to take to pick up and drop off the other driver
 * 
 */

#include <stdio.h>
#include <stdlib.h>

#include "buddyshare.h"

//#define DEBUG

/*
 * 
 */
int main(int argc, char** argv) {
    
    // Driver one (a, b) and Driver two (c, d)
    latlon a, b, c, d;
    
    // Driver with shorter detour and the distance
    driver_detour more_eff_driver;
    
#ifdef DEBUG
    // Test case... around San Diego
    a.lat = 32.835534;   a.lon = -117.105889;
    b.lat = 32.812102;   b.lon = -117.083455;
    c.lat = 32.820208;   c.lon = -117.128828;
    d.lat = 32.777867;   d.lon = -117.068703;  
#else
    
    // Perform some checks on our input parameters
    if (argc != EXPECTED_NUM_ARGS){
        //Syntax Error
        fprintf(stderr, 
            "'buddyshare': Error - Invalid number of arguments.\n Expected: %i Received: %i\n",
            EXPECTED_NUM_ARGS-1, argc-1);
        return INVALID_ARG_COUNT;
    }
    
    // Check the individual arguments to determine validity
    // Future work...
    
    // Assign values
    getCommandArg(&a, argv[1]);
    getCommandArg(&b, argv[2]);
    getCommandArg(&c, argv[3]);
    getCommandArg(&d, argv[4]);
    
#endif   
    
    // Echo back the parameters the user put in
    printf("a=%f,%f b=%f,%f c=%f,%f d=%f,%f\n",a.lat,a.lon, b.lat, b.lon,
        c.lat, c.lon, d.lat, d.lon);
    
    
    // Call the function determine shortest detour distance for 2 drivers
    more_eff_driver = calculateShorterDetour(a, b, c, d);        
    
    // Output the test case result to the shell
    printf("Detour for driver %u is shorter at %f km (%f miles)\n", 
        more_eff_driver.driver, 
        more_eff_driver.detour_distance,
        more_eff_driver.detour_distance * CONVERT_TO_MI);    
            
    return (EXIT_SUCCESS);
}

// Function to determine shortest detour distance for 2 drivers
driver_detour calculateShorterDetour(latlon a, latlon b, latlon c, latlon d)
{
    
    driver_detour ret_val; // Return value
    
    // the detour distance of driver 1 to pick up and drop off driver 2
    double a_to_b = haversine(&a,&b);
    
    // the detour distance of driver 2 to pick up and drop off driver 1
    double c_to_d = haversine(&c,&d);

    // Intermediate points used to determine detour
    double a_to_c = haversine(&a,&c);
    double d_to_b = haversine(&d,&b);
    
    // Total distance of the whole
    double abcd = a_to_b + c_to_d + a_to_c + d_to_b;
    
    /* 
     * Determine the shorter of the two distances
     * from a bird's eye view using haversine
    */    
    // Detour for driver 2 (c to d) is shorter
    if( abcd - a_to_b > abcd - c_to_d ){        
        ret_val.detour_distance = abcd - c_to_d;
        ret_val.driver = driver_2;
    }
    // Detour for driver 1 (c to d) is shorter
    else if( abcd - a_to_b < abcd - c_to_d ){
        ret_val.detour_distance = abcd - a_to_b;
        ret_val.driver = driver_1;                
    }
    else{ // They are equal
        ret_val.detour_distance = abcd - c_to_d;
        ret_val.driver = driver_all;         
    }   
    
    return (ret_val);
    
}

// Distance equation formula
// Returns units of kilometers
double haversine(latlon * from, latlon * to){
    
    double a; // square of half the chord length between the points    
    double c; // angular distance in radians
    
    // From latitude in radians
    double lat_from = from->lat * CONVERT_TO_RAD;
    
    // From latitude in radians
    double lat_to = to->lat * CONVERT_TO_RAD;
    
    // Change in latitude in radians
    double delta_lat = lat_to - lat_from; 
    
    // Change in longitude in radians
    double delta_lon = (to->lon - from->lon) * CONVERT_TO_RAD;   
        
    // Calculate the "square of half the chord length between the points"
    a = sin(delta_lat / 2);
    a *= a;
    
    // Perform a temp operation to calculate the last sine square
    // statement for a... C is only used as a temp variable here
    c = sin(delta_lon / 2);
    c *= c;
    
    // Put all parts of a together
    a += cos(lat_from) * cos(lat_to) * c;
    
    // Calculate the angular distance in radians
    c = 2 * atan2(sqrt(a), sqrt(1-a));
    
    return (EARTH_MEAN_RADIUS * c);
}

// Get values from argv (command line arguments)
void getCommandArg(latlon * retPoint,char *argv)
{
    // Iterator
    char i;
    char currChar;
    
    retPoint->lat = atof(argv+CHAR_DESC_SIZE);
    retPoint->lon = 0;
    for(i=CHAR_DESC_SIZE; i<MAX_ARGV_CHARS-10; i++){
        currChar = argv[i];
        if ( currChar == COMMA_CHAR_CODE){
            retPoint->lon = atof(argv+i+1);
            break;
        }
    }             
}