/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package CommonFunctions;

import mdot.Main;
import structures.Constants;

/**
 * class CheckFunctions:
 * Contains functions that are commonly called by the applcation.
 * Additional description of function can be found by declaration
 * unless the name gives it away.
 */
public class CheckFunctions {

    public static boolean CheckIfInteger(String tmpString) {
        try {
            int tmpInt = Integer.parseInt(tmpString);
            return true;
        } catch (NumberFormatException num) {
            return false;
        }
    }

    public static boolean CheckIfDouble(String tmpString) {
        try {
            double tmpDouble = Double.parseDouble(tmpString);
            return true;
        } catch (NumberFormatException num) {
            return false;
        }
    }

    public static synchronized double haversineDistance(double lat1, double lon1, double lat2, double lon2) {

        /*
        Haversine formula:
        R = earth’s radius (mean radius = 6,371km)
        Δlat = lat2− lat1
        Δlong = long2− long1
        a = sin²(Δlat/2) + cos(lat1).cos(lat2).sin²(Δlong/2)
        c = 2.atan2(√a, √(1−a))
        d = R.c
         */


        //Convert to radians
        lat1 = Math.toRadians(lat1);
        lon1 = Math.toRadians(lon1);
        lat2 = Math.toRadians(lat2);
        lon2 = Math.toRadians(lon2);
        double dLon = lon2 - lon1;
        double dLat = lat2 - lat1;
        double R = 6371;

        double a = Math.sin(dLat / 2) * Math.sin(dLat / 2)
                + Math.cos(lat1) * Math.cos(lat2)
                * Math.sin(dLon / 2) * Math.sin(dLon / 2);
        double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
        double d = R * c; //distance in kilometers

        d *= 3280.8399; //kilometers to feet

        return d;
    }

    public static double stoppingDistance(double mph) {
        //Braking Distance Formula from:
        //http://www.ehow.com/how_2054775_calculate-braking-distance.html
        //NOTE* This formula is just an AVERAGE. Actual breaking distance can
        //depend on: road conditions, driver age, tire condition, etc.

        double fps = mph * 1.467;
        double decelRate = 20;
        double reactionTime = 2;
        double timeReqToStop = fps / decelRate;
        double brakingdistance = (0.5 * fps * timeReqToStop) + (reactionTime * fps);

        return brakingdistance;
    }

    public static synchronized double bearing(double lat1, double lon1, double lat2, double lon2) {
        //forumula: θ = atan2( sin(Δlong)* cos(lat2), cos(lat1)*sin(lat2) − sin(lat1)*cos(lat2)*cos(Δlong) )
        //found at: http://www.movable-type.co.uk/scripts/latlong.html
        //Δlong = long2 - long1
        //Δlat = lat2 - lat1
        //lon1,lat1 = ME; lon2,lat2 = THEM

        //Convert to radians
        lat1 = Math.toRadians(lat1);
        lon1 = Math.toRadians(lon1);
        lat2 = Math.toRadians(lat2);
        lon2 = Math.toRadians(lon2);
        double dLon = lon2 - lon1;

        double y = Math.sin(dLon) * Math.cos(lat2);
        double x = (Math.cos(lat1) * Math.sin(lat2)) - (Math.sin(lat1) * Math.cos(lat2) * Math.cos(dLon));
        double bearing = (Math.toDegrees(Math.atan2(y, x)) + 360) % 360;

        return bearing;

    }

    private static double deg2rad(double deg) {
        return (deg * Math.PI / 180.0);
    }

    private static double rad2deg(double rad) {
        return (rad * 180.0 / Math.PI);
    }

    //Calculates the MPG for a vehicle using OBD data.
    public static double calculateMPG() {
        double calculatedMPG = 0;
        double MAF = Main.getMe().GetObjectAsDouble("maf");
        double VSS = Main.getMe().GetObjectAsDouble("speed");


        //if there was an error, reset to 0
        if (MAF == -1 || VSS == -1) {
            calculatedMPG = 0;
        } else {
            //14.7 grams of air to 1 gram of gasoline - ideal air/fuel ratio
            //6.17 pounds per gallon - density of gasoline
            //454 grams per pound - conversion
            //3600 seconds per hour conversion
            calculatedMPG = (14.7 * 6.17 * 454 * VSS) / (3600 * MAF);
        }

        return calculatedMPG;
    }

    public static synchronized double findGridLocation(double bearing, String meHeading) {
        //3.Find the location in the grid if ME is heading NORTH
        String gridLocation = null;

        double numberBearing = Math.round(bearing / 45);


        if (numberBearing == 0) {
            gridLocation = Constants.FRONT_CENTER_STRING;
        } else if (numberBearing == 1) {
            gridLocation = Constants.FRONT_RIGHT_STRING;
        } else if (numberBearing == 2) {
            gridLocation = Constants.RIGHT_STRING;
        } else if (numberBearing == 3) {
            gridLocation = Constants.BACK_RIGHT_STRING;
        } else if (numberBearing == 4) {
            gridLocation = Constants.BACK_CENTER_STRING;
        } else if (numberBearing == 5) {
            gridLocation = Constants.BACK_LEFT_STRING;
        } else if (numberBearing == 6) {
            gridLocation = Constants.LEFT_STRING;
        } else if (numberBearing == 7) {
            gridLocation = Constants.FRONT_LEFT_STRING;
        } else if (numberBearing == 8) {
            gridLocation = Constants.FRONT_CENTER_STRING;
        }

        //4. Rotate the grid position according to the direction ME is heading.
        int rotatenum = -1;

        if (meHeading.equals(Constants.GPS_ORIENTATION_NORTH)) {
            rotatenum = 0;
        } else if (meHeading.equals(Constants.GPS_ORIENTATION_NORTHEAST)) {
            rotatenum = 7;
        } else if (meHeading.equals(Constants.GPS_ORIENTATION_EAST)) {
            rotatenum = 6;
        } else if (meHeading.equals(Constants.GPS_ORIENTATION_SOUTHEAST)) {
            rotatenum = 5;
        } else if (meHeading.equals(Constants.GPS_ORIENTATION_SOUTH)) {
            rotatenum = 4;
        } else if (meHeading.equals(Constants.GPS_ORIENTATION_SOUTHWEST)) {
            rotatenum = 3;
        } else if (meHeading.equals(Constants.GPS_ORIENTATION_WEST)) {
            rotatenum = 2;
        } else if (meHeading.equals(Constants.GPS_ORIENTATION_NORTHWEST)) {
            rotatenum = 1;
        }


        double newGridLocation = Double.parseDouble(gridLocation);
        newGridLocation = (newGridLocation + rotatenum) % 8;

        if (newGridLocation == 0) {
            newGridLocation = 8;
        }


        return newGridLocation;

    }
}
