gt:         final String[] args2 = arguments.getLeftoverArguments();
context: /*
   * BetterDiscreteTreeToKML.java
   *
   * Copyright (C) 2002-2010 BEAST Development Team
   *
   * 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.app.phylogeography.tools;
  
  
  import java.io.BufferedReader;
  import java.io.BufferedWriter;
  import java.io.FileReader;
  import java.io.FileWriter;
  import java.io.IOException;
  import java.io.PrintStream;
  import java.util.ArrayList;
  import java.util.List;
  import java.util.StringTokenizer;
  
  import dr.app.util.Arguments;
  import jebl.evolution.io.ImportException;
  import jebl.evolution.io.NexusImporter;
  import jebl.evolution.io.TreeImporter;
  import jebl.evolution.trees.RootedTree;
  
  /**
   * @author Philippe Lemey
   * @author Andrew Rambaut
   * @author Marc A. Suchard
   */
  
  public class DiscreteTreeToKML {
  
      public static final String HELP = "help";
      public static final String ANNOTATION = "annotation";
      public static final String COORDINATES = "coordinates";
      public static final String TIMESCALER = "timescaler";
      public static final String MRSD = "mrsd";
      public static final String BWC = "bwc";
      public static final String BWM = "bwm";
      public static final String DIVIDER = "divider";
      public static final String USP = "usp";
      public static final String BW = "bw";
      public static final String BCUSE = "bcuse";
      public static final String BCOLOR = "bcolor";
      public static final String BSTARTCOLOR = "bstartcolor";
      public static final String BENDCOLOR = "bendcolor";
      public static final String ARCHBRANCH = "archbranch";
      public static final String ARCHHEIGHT = "archheight";
      public static final String ALTITUDE = "altitude";
      public static final String TEMP = "temp";
      public static final String CIRCLESEGMENTS = "circlesegments";
      public static final String RADIUS = "radius";
      public static final String AUTORADIUS = "autoradius";
      public static final String CIRCLEOP = "circleop";
      public static final String COORDSFORTAXA = "coordsfortaxa";
      public static final String SLICES = "slices";
      public static final String SLICEBW = "slicebw";
      public static final String SLICEMIDPOINT = "slicemidpoint";
  
  
      public static final String[] use = new String[] {"heights","posteriors"};
      public static final String[] arch = new String[] {"distance","time"};
      public static final String[] falseTrue = new String[] {"false","true"};
      private static final PrintStream progressStream = System.out;
  
      private static final String commandName = "discrete_tree_to_kml";
  
      public static void printUsage(Arguments arguments) {
  
          arguments.printUsage(commandName, "[<inputTree-file-name>] [<output-file-name>]"); //TODO: set this right
          progressStream.println();
          progressStream.println("  Example: " + commandName + " -coordinates coordinates.txt input.tre");
          progressStream.println();
      }
  
      private static int[] countLinesAndTokens(String coordinatesFileString){
          int lineCounter = 0;
          int tokenCounter = 0;
          int[] container = new int[2];
          try{
              BufferedReader reader1 = new BufferedReader(new FileReader(coordinatesFileString));
              String current1 = reader1.readLine();
              while (current1 != null && !reader1.equals("")) {
                  lineCounter++;
                  if (lineCounter == 1) {
                      StringTokenizer tokens = new StringTokenizer(current1);
                      while (tokens.hasMoreTokens()) {
                          tokenCounter++;
                          tokens.nextToken();
                      }
                  }
                  current1 = reader1.readLine();
              }
  
          } catch (IOException e) {
              System.err.println("Error reading " + coordinatesFileString);
              System.exit(1);
          }
          container[0] = lineCounter;
          container[1] = tokenCounter;
          return container;
      }
  
      private static void readLocationsCoordinates(String coordinatesFileString, String[][] locationsAndCoordinates){
              try {
                  BufferedReader reader2 = new BufferedReader(new FileReader(coordinatesFileString));
                  String current2 = reader2.readLine();
                  int counter2 = 0;
                  while (current2 != null && !reader2.equals("")) {
                      StringTokenizer tokens2 = new StringTokenizer(current2);
                      for (int i = 0; i < locationsAndCoordinates[0].length; i++) {
                          locationsAndCoordinates[counter2][i] = tokens2.nextToken();
                          progressStream.print(locationsAndCoordinates[counter2][i]+"\t");
                      }
                      progressStream.print("\r");
                      counter2 ++;
                      current2 = reader2.readLine();
                  }
              } catch (IOException e) {
                  e.printStackTrace();
                  return;
              }
      }
  
      public static double[] parseVariableLengthDoubleArray(String inString) throws Arguments.ArgumentException {
  
          List<Double> returnList = new ArrayList<Double>();
          StringTokenizer st = new StringTokenizer(inString,",");
          while(st.hasMoreTokens()) {
              try {
                  returnList.add(Double.parseDouble(st.nextToken()));
              } catch (NumberFormatException e) {
                  throw new Arguments.ArgumentException();
              }
  
          }
  
          if (returnList.size()>0) {
              double[] doubleArray = new double[returnList.size()];
              for(int i=0; i<doubleArray.length; i++)
                  doubleArray[i] = returnList.get(i);
              return doubleArray;
          }
          return null;
      }
  
      private static RootedTree readTree(String inString) throws Arguments.ArgumentException {
  
          RootedTree tree;
          try {
              TreeImporter importer = new NexusImporter(new FileReader(inString));
              tree = (RootedTree)importer.importNextTree();
          } catch (ImportException e) {
              e.printStackTrace();
              return null;
          } catch (IOException e) {
              e.printStackTrace();
              return null;
          }
          return tree;
      }
  
      public static void main(String[] args) throws Arguments.ArgumentException {
  
          String inputFileName = null;
          String outputFileName = null;
          RootedTree tree = null;
          String[][] locations = null;
  
          String stateAnnotation = "state";
  
          //in case trees are scaled in other time units
          double timeScaler = 1;
  
          double branchWidthConstant = 2.0;   // the width of branches will be stateProbability*branchWidthMultiplier+branchWidthConstant
          double branchWidthMultiplier = 5.0;
  
          double divider = 100; // this is to chop up the branches of the surface tree in 'divider' segments
          boolean useStateProbability = true; // use state probabilities for branch width
          double branchWidth = 10.0; // branch width if posterior probabilities are not used
          boolean usePosterior = false; // use posterior probabilities to color branch
          boolean useHeights = true; // use heights (time) to color branches
          String startBranchColor = "FF00FF"; //red: 0000FF green: 00FF00 magenta: FF00FF white: FFFFFF yellow: 00FFFF cyan: FFFF00
          String endBranchColor = "FFFF00";
          String branchColor = "ffffff"; // branch color if color range based on rates is not used
          boolean arcBranches = true; // branches are arcs with heights proportional to the distance between locations
          boolean arcTimeHeight = false; // the height of the arcs is proportional to the time the branch spans, by default arch-heights are proportional to the distance between locations
          double altitudeFactor = 100; // this is the factor with which to multiply the time of the branch to get the altitude for that branch in the surface Tree
          boolean temporary = false;
  
          double mostRecentDate = 2010;  // required to convert heights to calendar dates
  
          //circles
          int numberOfIntervals = 100;
          //boolean autoRadius = false;
          double radius = 0;
          String circleOpacity = "8F";
  
          //extra coordinates for some taxa
          boolean coordinatesForTaxa = false;
          String[][] taxaCoordinates = null;
  
          //tree slices for google maps, requires treeHeight in exporterString: e.g., exporterString.writeTreeToKML(0.025);
          //TODO: have this outputed to a different file (what happens now)?
          boolean makeTreeSlices = false;
          double[] sliceTimes = null;
          double treeSliceBranchWidth = 3;
          boolean showBranchAtMidPoint = false; // shows complete branch for slice if time is more recent than the branch's midpoint
  
  
          Arguments arguments = new Arguments(
                  new Arguments.Option[]{
                          new Arguments.StringOption(COORDINATES, "coordinate file", "specifies a tab-delimited file with coordinates for the locations"),
                          new Arguments.StringOption(ANNOTATION, "location state annotation string", "specifies the string used for location state annotation [default=state]"),
                          new Arguments.RealOption(TIMESCALER,"specifies the scaling factor by which to rescale time [default=1]"),
                          new Arguments.RealOption(MRSD,"specifies the most recent sampling data in fractional years to rescale time [default=2010]"),
                          new Arguments.RealOption(BWC,"specifies the branch width constant [default=2]"),
                          new Arguments.RealOption(BWM,"specifies the branch width multiplier [default=5]"),
                          new Arguments.StringOption(USP, falseTrue, false,
                                  "use state probabilities for branch width [default = true]"),
                          new Arguments.StringOption(BCUSE, use, false,
                                  "use heights or posterior probabilities for branch colors [default = heights]"),
                          new Arguments.RealOption(BW,"specifies the branch width if posterior probabilities are not used [default=10]"),
                          new Arguments.IntegerOption(DIVIDER,"specifies in how many segments at branch should be chopped up [default=50]"),
                          new Arguments.StringOption(BSTARTCOLOR, "branch start color", "specifies a starting color for the branches [default=FF00FF]"),
                          new Arguments.StringOption(BENDCOLOR, "branch end color", "specifies an end color for the branches [default=FFFF00]"),
                          new Arguments.StringOption(BCOLOR, "branch color", "specifies a branch color if color range based on rates is not used [default=ffffff]"),
                          new Arguments.StringOption(ARCHBRANCH, falseTrue, false,
                                  "use arcs for the branches [default = true], by default arc-heights are proportional to the distance between locations"),
                          new Arguments.StringOption(ARCHHEIGHT, arch, false,
                                  "use time or distance for arch heights [default = no arcs]"),
                          new Arguments.RealOption(ALTITUDE,"specifies the altitudefactor for the branches [default=1000]"),
                          new Arguments.StringOption(TEMP, falseTrue, false,
                                  "display branches only temporary [default=false"),
                          new Arguments.IntegerOption(CIRCLESEGMENTS,"specifies the number of segments to construct circles [default=100]"),
                          new Arguments.IntegerOption(RADIUS,"specifies the radiusfactor for the circles [default='autoradius']"),
                          new Arguments.StringOption(CIRCLEOP, "circle opacity", "sets the opacity of the circles [default=8F]"),
                          new Arguments.Option(HELP, "option to print this message"),
                          new Arguments.StringOption(COORDSFORTAXA, "file with taxa coords", "specifies a file with additional coordinates for particular taxa"),
                          new Arguments.RealOption(SLICEBW,"specifies the branch width for tree slices [default=3]"),
                          new Arguments.StringOption(SLICES,"time","specifies a slice time-list [default=none]"),
                          new Arguments.StringOption(SLICEMIDPOINT, falseTrue, false,
                                  "shows complete branch for sliced tree if time is more recent than the branch's midpoint [default=false"),
                  });
  
          try {
              arguments.parseArguments(args);
          } catch (Arguments.ArgumentException ae) {
              progressStream.println(ae);
              printUsage(arguments);
              System.exit(1);
          }
  
          if (args.length == 0 || arguments.hasOption(HELP)) {
              printUsage(arguments);
              System.exit(0);
          }
  
          try {
  
              String coordinatesFileString = arguments.getStringOption(COORDINATES);
              //System.out.println(coordinatesFileString);
              if (coordinatesFileString != null) {
                  // count lines in locations file and tokens per line
                  int counts[] = countLinesAndTokens(coordinatesFileString);
                  //System.out.println(counts[0]+"\t"+counts[1]);
                  //read in locations
                  locations = new String[counts[0]][counts[1]];
                  readLocationsCoordinates(coordinatesFileString,locations);
              } else {
                  progressStream.println("no coordinates for taxa??");
                  System.exit(1);
              }
  
              if (arguments.hasOption(MRSD)) {
                  mostRecentDate = arguments.getRealOption(MRSD);
              }
  
              if (arguments.hasOption(TIMESCALER)) {
                  timeScaler = arguments.getRealOption(TIMESCALER);
              }
  
              if (arguments.hasOption(DIVIDER)) {
                  divider = arguments.getRealOption(DIVIDER);
              }
  
              if (arguments.hasOption(ALTITUDE)) {
                  altitudeFactor = arguments.getRealOption(ALTITUDE);
              }
  
              String stateAnnotationString = arguments.getStringOption(ANNOTATION);
              if (stateAnnotationString != null){
                  stateAnnotation = stateAnnotationString;
              }
  
              String useStateProbString = arguments.getStringOption(USP);
              if (useStateProbString != null && useStateProbString.compareToIgnoreCase("posteriors") != 0)
                  useStateProbability = false;
  
              String useColorString = arguments.getStringOption(BCUSE);
              if (useColorString != null && useColorString.compareToIgnoreCase("posteriors") == 0) {
                  usePosterior = true;
                  useHeights = false;
              }
              if (useColorString != null && useColorString.compareToIgnoreCase("heights") == 0) {
                  useHeights =  true;
                  usePosterior = false;
              }
  
              if (arguments.hasOption(BWC)) {
                  branchWidthConstant = arguments.getRealOption(BWC);
              }
  
              if (arguments.hasOption(BWM)) {
                  branchWidthMultiplier = arguments.getRealOption(BWM);
              }
  
              if (arguments.hasOption(BW)) {
                  branchWidth = arguments.getRealOption(BW);
              }
  
              String color1String = arguments.getStringOption(BSTARTCOLOR);
              if (color1String != null) {
                  startBranchColor = color1String;
              }
  
              String color2String = arguments.getStringOption(BENDCOLOR);
              if (color2String != null) {
                  endBranchColor = color2String;
              }
  
              String colorString = arguments.getStringOption(BCOLOR);
              if (colorString != null) {
                  branchColor = colorString;
              }
  
              String archString = arguments.getStringOption(ARCHBRANCH);
              if (archString != null && archString.compareToIgnoreCase("false") == 0)
                  arcBranches = false;
  
              String archHeightString = arguments.getStringOption(ARCHHEIGHT);
              if (archHeightString != null && archHeightString.compareToIgnoreCase("time") == 0) {
                  arcTimeHeight = true;
              }
  
              String tempString = arguments.getStringOption(TEMP);
              if (tempString != null && tempString.compareToIgnoreCase("true") == 0)
                  temporary = true;
  
              if (arguments.hasOption(CIRCLESEGMENTS)) {
                  numberOfIntervals = arguments.getIntegerOption(CIRCLESEGMENTS);
              }
  
              if (arguments.hasOption(RADIUS)) {
                  radius = arguments.getIntegerOption(RADIUS);
              }
  
              String circleOpacityString = arguments.getStringOption(CIRCLEOP);
              if (circleOpacityString != null) {
                  circleOpacity = circleOpacityString;
              }
  
              //read in extra taxon locations
              String taxaCoordinatesFileString = arguments.getStringOption(COORDSFORTAXA);
              if (taxaCoordinatesFileString != null) {
                  coordinatesForTaxa = true;
                  progressStream.println("\radditional taxa locations:");
                  // count lines in locations file and tokens per line
                  int[] counts = countLinesAndTokens(taxaCoordinatesFileString);
                  //read in locations
                  taxaCoordinates = new String[counts[0]][counts[1]];
                  readLocationsCoordinates(taxaCoordinatesFileString,taxaCoordinates);
              }
  
              String sliceString = arguments.getStringOption(SLICES);
              if (sliceString != null) {
                  makeTreeSlices = true;
                  sliceTimes = parseVariableLengthDoubleArray(sliceString);
              }
  
              if (arguments.hasOption(SLICEBW)) {
                  treeSliceBranchWidth = arguments.getRealOption(SLICEBW);
              }
  
              String midpointString = arguments.getStringOption(SLICEMIDPOINT);
              if (midpointString != null && midpointString.compareToIgnoreCase("true") == 0)
                  showBranchAtMidPoint = true;
  
          } catch (Arguments.ArgumentException e) {
              progressStream.println(e);
              printUsage(arguments);
              System.exit(-1);
          }
  
  