package com.algobase.gpx;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.text.ParsePosition;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
import java.util.SimpleTimeZone;

import android.util.Log;
import com.algobase.stracks.sTracksRoot;



public class GpxWriter {

    File gpx_file;
    BufferedWriter file_writer;

    String creator;
    SimpleDateFormat df;

    long startTime;
    int numPoints;


private String format(String pattern, Object... args)
{ return String.format(Locale.US,pattern,args); }


private void log(String msg) { Log.v("sTracksLog",msg); }


public GpxWriter()
{ gpx_file = null;
  file_writer = null;
  creator = "sTracks with barometer";
  df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
  df.setTimeZone(new SimpleTimeZone(0, "UTC"));
  startTime = 0;
  numPoints = 0;
 }

public GpxWriter(File file)
{ gpx_file = file;
  creator = "sTracks with barometer";
  df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
  df.setTimeZone(new SimpleTimeZone(0, "UTC"));
  startTime = 0;
  numPoints = 0;
  try {
    file_writer = new BufferedWriter(new FileWriter(file));
  } catch (IOException e) { e.printStackTrace(); }
    
}


public void write_header()
{
  try {
    file_writer.write("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\" ?>");

  file_writer.newLine();

  file_writer.write("<gpx xmlns=\"http://www.topografix.com/GPX/1/1\" xmlns:gpxx=\"http://www.garmin.com/xmlschemas/GpxExtensions/v3\" xmlns:gpxtpx=\"http://www.garmin.com/xmlschemas/TrackPointExtension/v1\" ");
  file_writer.write("creator =\"" + creator + "\" ");
  file_writer.write("version=\"1.1\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd http://www.garmin.com/xmlschemas/GpxExtensions/v3 http://www.garmin.com/xmlschemas/GpxExtensionsv3.xsd http://www.garmin.com/xmlschemas/TrackPointExtension/v1 http://www.garmin.com/xmlschemas/TrackPointExtensionv1.xsd\" >");
  file_writer.newLine();
  file_writer.flush();
  } catch (IOException e) { e.printStackTrace(); }
}


public void add_waypoint(double lon, double lat, double alt, 
                         long t, String name)
{
  Date d = new Date(t);
  String time_str = df.format(d);

  try {
    file_writer.write(format("<wpt lat=\"%9.6f\" lon=\"%9.6f\">",lat,lon));
    file_writer.newLine();
    file_writer.write(format("<ele>%.2f</ele>",alt));
    file_writer.newLine();
    file_writer.write("<time>" + time_str + "</time>");
    file_writer.newLine();
    file_writer.write("<name>" + name + "</name>");
    file_writer.newLine();
/*
    file_writer.write("<desc>" + desc + "</desc>");
    file_writer.newLine();
    file_writer.write("<sym>" + sym + "</sym>");
    file_writer.newLine();
    file_writer.write("<type>" + sym + "</type>");
    file_writer.newLine();
*/
    file_writer.write("</wpt>");
    file_writer.newLine();
    file_writer.flush();
  } catch (IOException e) { e.printStackTrace(); }
}
  

public void begin_track(String trk_name)
{  
  // trk_name  yyyy-mm-dd-hh-mm

  if (trk_name.startsWith("20") && trk_name.length() >= 16)
  { String str = trk_name.substring(0,10) + "T" + 
                 trk_name.substring(11,13) + ":" +
                 trk_name.substring(14,16) + "Z";

    SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm'Z'");
    df.setTimeZone(TimeZone.getDefault());
    Date date = df.parse(str,new ParsePosition(0));
    if (date != null)
      startTime = date.getTime();
   }
   else
      startTime = new Date().getTime();

   write_header();

   try {
     file_writer.newLine();
     file_writer.write("<trk><name>" + trk_name + "</name>");
     file_writer.newLine();
     file_writer.flush();
   } catch (IOException e) { e.printStackTrace(); }
}


public void begin_lap()
{  
   try {
     file_writer.write("<trkseg>");
     file_writer.newLine();
     file_writer.flush();
   } catch (IOException e) { e.printStackTrace(); }
}



public void add_point(long t, double lon, double lat, double alt, double speed,
                                                                  int hrate,
                                                                  int power)
{ 
  if (numPoints == 0 && startTime > 0 && startTime < t) t = startTime;

  numPoints++;

  Date date = new Date(t);

  try {
   file_writer.write(format("<trkpt lat=\"%9.6f\" lon=\"%9.6f\">\n",lat,lon));
   file_writer.write(format("  <ele>%.2f</ele>\n",alt));
   file_writer.write(format("  <time>%s</time>\n", df.format(date)));
   file_writer.write(format("  <speed>%.2f</speed>\n",speed));

   if (hrate > 0) file_writer.write(format("  <hrate>%d</hrate>\n",hrate));
   if (power > 0) file_writer.write(format("  <power>%d</power>\n",power));

   file_writer.write("  <extensions>\n");
   file_writer.write(format("    <heartrate>%d</heartrate>\n",hrate));
   file_writer.write(format("    <power>%d</power>\n",power));
   file_writer.write("  </extensions>\n");

   file_writer.write("</trkpt>\n");
   file_writer.newLine();
   file_writer.flush();
  } catch (IOException e) { e.printStackTrace(); }
}


public void finish_lap()
{ 
  try {
    file_writer.write("</trkseg>");
    file_writer.newLine();
  } catch (IOException e) { e.printStackTrace(); }
} 


public void finish_track()
{ 
  try {
    file_writer.write("</trk>");
    file_writer.newLine();
    file_writer.write("</gpx>");
    file_writer.newLine();
    file_writer.close();
  } catch (IOException e) { e.printStackTrace(); }
} 


public void add_description(File file,
                            int num_points,
                            int num_laps,
                            long begin_time, long end_time, 
                            long total_time, long break_time,
                            int  total_dist, int  total_ascent, 
                            double avg_speed, double max_speed)

{ if (!file.exists()) return;
  File tmp = new File(file.getParent(),"t.gpx");
  copy_add_description(file,tmp,num_points,num_laps,begin_time,end_time,
                       total_time, break_time,total_dist,total_ascent,
                       avg_speed,max_speed);
  file.delete();
  tmp.renameTo(file);
}


public void add_description(File file, String description)
{ if (!file.exists()) return;
  File tmp = new File(file.getParent(),"t.gpx");
  copy_add_description(file,tmp,description);
  file.delete();
  tmp.renameTo(file);
}


public void copy_add_description(File infile, File outfile,
                                 int num_points,
                                 int num_laps,
                                 long begin_time, long end_time, 
                                 long total_time, long break_time,
                                 int  total_dist, int  total_ascent, 
                                 double avg_speed, double max_speed)
{ 
     //SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
     //df.setTimeZone(new SimpleTimeZone(0, "UTC"));

     String description = "";
     description += format("version=%d;\n",sTracksRoot.GPX_VERSION);
     description += format("start=%s;\n",df.format(begin_time));
     description += format("end=%s;\n",  df.format(end_time));
     description += format("time=%d;\n", total_time/1000);
     description += format("breaks=%d;\n", total_time/1000);
     description += format("dist=%d;\n", total_dist);
     description += format("ascent=%d;\n", total_ascent);
     description += format("avgspeed=%.1f;\n", avg_speed);
     description += format("maxspeed=%.1f;\n", max_speed);
     description += format("points=%d;\n",  num_points);
     description += format("laps=%d;\n",  num_laps);

     copy_add_description(infile,outfile,description);
  }


public void copy_add_description(File infile, File outfile, String d)
{ 
     log("copy_add_description");

     byte[] buffer = new byte[2048];

     String description = "<desc>\n" + d + "</desc>\n\n";

     log(description);

     try {
        FileInputStream in = new FileInputStream(infile);
        FileOutputStream out = new FileOutputStream(outfile);

        int n = in.read(buffer);

        String txt = new String(buffer);

        int p = txt.indexOf("<trkseg>");

        if (p == -1)
          out.write(buffer,0,n);
        else
        { 
      
          // remove old <desc>...</desc> if present between <trk> and p
          int desc_start = -1;
          int desc_end = -1;

          int trk_p = txt.lastIndexOf("<trk>",p);

          if (trk_p != -1)
          { desc_start = txt.indexOf("<desc>",trk_p);
            if (desc_start > p) desc_start = -1;
            if (desc_start != -1) 
            { desc_end = txt.indexOf("</desc>",desc_start);
              int q = txt.lastIndexOf("</name>",desc_start);
              if (q != -1) desc_start = q + 7;
             }
           }

          if (desc_start == -1 || desc_end == -1)
           { //out.write(buffer,0,p);
             out.write(txt.substring(0,p).getBytes());
           }
          else
          { out.write(txt.substring(0,desc_start).getBytes());
            out.write(txt.substring(desc_end+7,p).getBytes());
           }
            
          out.write(description.getBytes());

          out.write(txt.substring(p).getBytes());
        }

        while ((n = in.read(buffer)) != -1) out.write(buffer, 0, n);

        in.close();
        out.close();
      } catch(IOException e) { log("Exception: " + e.toString()); }
  }

};


