/*
 * GreatCircleDistances.java
 *
 * Copyright (c) 2002-2015 Alexei Drummond, Andrew Rambaut and Marc Suchard
 *
 * This file is part of BEAST.
 * See the NOTICE file distributed with this work for additional
 * information regarding copyright ownership and licensing.
 *
 * BEAST is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 *  BEAST is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with BEAST; if not, write to the
 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
 * Boston, MA  02110-1301  USA
 */

package dr.geo;

import dr.evolution.util.Taxa;
import dr.evolution.util.Taxon;
import dr.geo.math.SphericalPolarCoordinates;
import dr.inference.model.Statistic;
import dr.evoxml.TaxaParser;
import dr.evoxml.TaxonParser;
import dr.evoxml.DateParser;
import dr.xml.XMLParseException;
import dr.xml.XMLParser;
import dr.xml.AttributeParser;
import org.xml.sax.SAXException;

import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.io.File;
import java.io.FileReader;

/**
 * @author Alexei Drummond
 */
public class GreatCircleDistances {

    double[][] distances;

    public GreatCircleDistances(Taxa taxa, String attributeName) {

        distances = new double[taxa.getTaxonCount()][taxa.getTaxonCount()];

        for (int i = 0; i < taxa.getTaxonCount(); i++) {

            Taxon taxon = taxa.getTaxon(i);

            String attr = (String)taxon.getAttribute(attributeName);
            String[] loc = attr.split(" ");
            double latitude = Double.parseDouble(loc[0]);
            double longitude = Double.parseDouble(loc[1]);


            SphericalPolarCoordinates coord = new SphericalPolarCoordinates(latitude, longitude);
            //System.out.println(coord);

            for (int j = i+1; j < taxa.getTaxonCount(); j++) {
                Taxon taxon2 = taxa.getTaxon(j);
                attr = (String)taxon2.getAttribute(attributeName);
                String[] loc2 = attr.split(" ");
                latitude = Double.parseDouble(loc2[0]);
                longitude = Double.parseDouble(loc2[1]);

                SphericalPolarCoordinates coord2 = new SphericalPolarCoordinates(latitude, longitude);

                distances[i][j] = distances[j][i] = coord.distance(coord2);
            }
        }
    }

    class DistancesStatistic extends Statistic.Abstract {

        double[] dists = new double[distances.length*distances.length];

        public DistancesStatistic(boolean logTransformed) {

            int k = 0;
            for (double[] distance : distances) {
                for (int j = 0; j < distances.length; j++) {
                    dists[k] = distance[j];
                    if (logTransformed) dists[k] = Math.log(dists[k]);
                    k += 1;
                }
            }
        }

        public int getDimension() {
            return dists.length;
        }

        public double getStatisticValue(int dim) {
            return dists[dim];
        }
    }

    public Statistic getDistanceStatistic(boolean logTransformed) {
        return new DistancesStatistic(logTransformed);
    }

    public static void main(String[] args) throws ParserConfigurationException, IOException, SAXException, XMLParseException {

        XMLParser parser = new XMLParser(true, true);
        parser.addXMLObjectParser(new TaxonParser());
        parser.addXMLObjectParser(new TaxaParser());
        parser.addXMLObjectParser(new AttributeParser());
        parser.addXMLObjectParser(new DateParser());

        parser.parse(new FileReader(new File(args[0])), true);

        Taxa taxa = (Taxa)parser.getRoot().getChild(0);

        System.out.println("Found " + taxa.getTaxonCount() + " taxa");

        GreatCircleDistances distances = new GreatCircleDistances(taxa, "location");

        Statistic statistic = distances.getDistanceStatistic(true);

        for (int i = 0; i < statistic.getDimension(); i++) {
            System.out.println(statistic.getStatisticValue(i));
        }

    }
}
