/**
 * @author Andy Gup
 *
 * Copyright 2016 Esri
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *
 * See the License for the specific language governing permissions and
 * limitations under the License.​
 */
package com.esri.cordova.geolocation.utils;

import com.esri.cordova.geolocation.model.Coordinate;

import java.util.concurrent.ConcurrentLinkedQueue;

public class GeodataHelper {

    private final static int _radiusKM = 6367; // earth's radius km's

    public static double getMean(double[] data){
        double sum = 0.0;
        for(double a : data)
            sum += a;
        return sum/data.length;
    }

    public static double getVariance(double[] data)
    {
        final double mean = getMean(data);
        double temp = 0;
        for(double a :data)
            temp += (mean-a)*(mean-a);
        return temp/data.length;
    }

    public static double getStdDev(double[] data)
    {
        return Math.sqrt(getVariance(data));
    }

    /**
     * Calculate the average geometric center of a Queue that contains cartesian coordinates
     * Reference: http://stackoverflow.com/questions/6671183/calculate-the-center-point-of-multiple-latitude-longitude-coordinate-pairs
     * Reference: http://stackoverflow.com/questions/1185408/converting-from-longitude-latitude-to-cartesian-coordinates
     * Reference: http://en.wikipedia.org/wiki/Spherical_coordinate_system
     * @param queue The location buffer queue
     * @return Returns a Coordinate object
     */
    public static Coordinate getGeographicCenter(final ConcurrentLinkedQueue<Coordinate> queue){
        double x = 0;
        double y = 0;
        double z = 0;
        float accuracy = 0;

        for(final Coordinate coordinate : queue){
            accuracy += coordinate.accuracy;

            // Convert latitude and longitude to radians
            final double latRad = Math.PI * coordinate.latitude / 180;
            final double lonRad = Math.PI * coordinate.longitude / 180;

            // Convert to cartesian coords
            x += _radiusKM * Math.cos(latRad) * Math.cos(lonRad);
            y += _radiusKM * Math.cos(latRad) * Math.sin(lonRad);
            z += _radiusKM * Math.sin(latRad);
        }

        // Get our averages
        final double xAvg = x / queue.size();
        final double yAvg = y / queue.size();
        final double zAvg = z / queue.size();
        final float accuracyAvg = accuracy / queue.size();

        // Convert cartesian back to radians
        final double sphericalLatRads = Math.asin(zAvg / _radiusKM);
        final double sphericalLonRads = Math.atan2(yAvg, xAvg);

        final Coordinate centerPoint = new Coordinate();
        centerPoint.latitude = sphericalLatRads * (180 / Math.PI);
        centerPoint.longitude = sphericalLonRads * (180 / Math.PI);
        centerPoint.accuracy = accuracyAvg;

        return centerPoint;
    }
}