/*
 * 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;
        }
    }
/*
    //Calculate the distance between two latitude and longitude locations
    //Returns values in KILOMETERS.
    public static double distance(double lat1, double lon1, double lat2, double lon2) {
        double theta = lon1 - lon2;
        double dist = Math.sin(deg2rad(lat1)) * Math.sin(deg2rad(lat2)) + Math.cos(deg2rad(lat1)) * Math.cos(deg2rad(lat2)) * Math.cos(deg2rad(theta));
        dist = Math.acos(dist);
        dist = rad2deg(dist);
        dist = dist * 60 * 1.1515;

        return (dist);
    }
 *
 *  //Calculate the distance between two latitude and longitude locations
    //Returns value in FEET.
    public static double distancefeet(double lat1, double lon1, double lat2, double lon2) {
        double theta = lon1 - lon2;
        double dist = Math.sin(deg2rad(lat1)) * Math.sin(deg2rad(lat2)) + Math.cos(deg2rad(lat1)) * Math.cos(deg2rad(lat2)) * Math.cos(deg2rad(theta));
        dist = Math.acos(dist);
        dist = rad2deg(dist);
        dist = dist * 60 * 1.1515;
        dist = dist * 5280;

        return (dist);
    }

*/
    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
        //long1,lat1 = ME; long2,lat2 = THEM
        //var y = Math.sin(dLon) * Math.cos(lat2);
        //var x = Math.cos(lat1)*Math.sin(lat2) - Math.sin(lat1)*Math.cos(lat2)*Math.cos(dLon);
        //var brng = Math.atan2(y, x).toDeg();

        //var y = Math.sin(dLon) * Math.cos(lat2);
        //var x = Math.cos(lat1)*Math.sin(lat2) -        Math.sin(lat1)*Math.cos(lat2)*Math.cos(dLon);
        //var brng = Math.atan2(y, x).toDeg();

       
        //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;

        //java.lang.System.out.println(bearing + "...............");

        return bearing;

    }

    /*
    public static GPSLocation GetNewlocationForDist(GPSLocation gps) {
        double lat1 = deg2rad(gps.getLat());
        double lon1 = deg2rad(gps.getLon());
        String heading1 = gps.getHeading();
        double feet = Main.feetDistance;
        double d = feet * 0.0003048;
        double R = 6378.1370;

        double lat2 = 0.0;
        double lon2 = 0.0;
        double brng = 0.0;

        if (heading1.equals(Constants.GPS_ORIENTATION_NORTH)) {
            brng = 0;
        } else if (heading1.equals(Constants.GPS_ORIENTATION_SOUTH)) {
            brng = Math.PI;
        } else if (heading1.equals(Constants.GPS_ORIENTATION_WEST)) {
            brng = 3 * Math.PI / 2.0;
        } else if (heading1.equals(Constants.GPS_ORIENTATION_EAST)) {
            brng = Math.PI / 2.0;
        } else if (heading1.equals(Constants.GPS_ORIENTATION_NORTHEAST)) {
            brng = Math.PI / 4.0;
        } else if (heading1.equals(Constants.GPS_ORIENTATION_SOUTHWEST)) {
            brng = 5 * Math.PI / 4.0;
        } else if (heading1.equals(Constants.GPS_ORIENTATION_NORTHWEST)) {
            brng = 7 * Math.PI / 4.0;
        } else if (heading1.equals(Constants.GPS_ORIENTATION_SOUTHEAST)) {
            brng = 3 * Math.PI / 4.0;
        }

        lat2 = Math.asin(Math.sin(lat1) * Math.cos(d / R) +
                Math.cos(lat1) * Math.sin(d / R) * Math.cos(brng));

        lon2 = lon1 + Math.atan2(Math.sin(brng) * Math.sin(d / R) * Math.cos(lat1),
                Math.cos(d / R) - Math.sin(lat1) * Math.sin(lat2));

        gps.setLat(rad2deg(lat2));
        gps.setLon(rad2deg(lon2));


        return gps;
    }
*/
    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;

    }
    
}
