package com.algobase.gpx;

import java.lang.reflect.Modifier;
import java.lang.reflect.Field;

import java.io.FileInputStream;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.TimeZone;
import java.util.SimpleTimeZone;

import android.location.Location;

import com.garmin.fit.*;


public class FitReader {

static int TIME_OFFSET =  631065600;

public void handle_track_begin(int i, String name) {}
public void handle_track_end() {}
public void handle_lap(int i) {}
public void handle_trackpoint(int i, Location loc, double dist, int hrate,
                                                                int power) {}

private class Lap {

  int    num_points;
  long   start_time;
  long   end_time;
  double start_lat; 
  double end_lat;
  double start_lon;
  double end_lon;
  long   total_time;
  long   elapsed_time; 
  float  total_dist; 
  float  avg_speed;
  float  max_speed;
  int    avg_hrate;
  int    max_hrate;
  int    avg_cadence;
  int    max_cadence;
  int    avg_power;
  int    max_power;
  int    total_ascent;
  int    total_descent;
  int    calories;
}


   class Listener implements MesgListener, EventMesgListener, 
                                           FileIdMesgListener, 
                                           UserProfileMesgListener, 
                                           DeviceInfoMesgListener, 
                                           RecordMesgListener, 
                                           LapMesgListener, 
                                           SessionMesgListener, 
                                           ActivityMesgListener 
   {
      int    num_points;
      int    num_laps;
      int    num_tracks;

      double semi2deg(int s) { return (180.0*s)/(1L << 31); }

      public void onMesg(Mesg mesg) {}
      public void onMesg(EventMesg mesg) {}

      public void onMesg(FileIdMesg mesg) {
       /*
         String type = mesg.getType().getValue();
         String manufacturer = mesg.getManufacturer();
         String procuct = mesg.getProduct();
         String serial_num = mesg.getSerialNumber();
         String number = mesg.getNumber();
        */
      }

      public void onMesg(UserProfileMesg mesg) 
      {
         if ((mesg.getFriendlyName() != null) ) {
         }
         if (mesg.getGender() != null) 
         { String gender = (mesg.getGender()==Gender.MALE) ? "Male" : "Female";
          }

         if (mesg.getAge() != null) {
         }

         if (mesg.getWeight() != null) {
         }
      }

      private  String garminProductName(final Integer constantValue) 
      {
        final Class<GarminProduct> gcClass = GarminProduct.class;
        for (Field field : gcClass.getDeclaredFields()) 
        { int modifiers = field.getModifiers();
          if (Modifier.isStatic(modifiers) && 
              Modifier.isPublic(modifiers) && 
              Modifier.isFinal(modifiers)) {
            try { if (constantValue.equals(field.get(null)))
                    return field.getName();
                 } catch (IllegalAccessException e) {}
          }
        }
        return null;
      }

      public void onMesg(DeviceInfoMesg mesg)
      {
/*
        final Integer garminProductId = mesg.getGarminProduct();
        if (garminProductId != null && garminProductId.intValue() > 100) {
            String productName = garminProductName(garminProductId);
            if (productName != null) {
            }
        }
*/


         if(mesg.getTimestamp() != null) {
         }

         if (mesg.getBatteryStatus() != null)
         {
            switch(mesg.getBatteryStatus()){
              case BatteryStatus.CRITICAL:
                   break;
              case BatteryStatus.GOOD:
                   break;
              case BatteryStatus.LOW:
                   break;
              case BatteryStatus.NEW:
                   break;
              case BatteryStatus.OK:
                   break;
             }
          }
      }


      public void onMesg(RecordMesg mesg) 
      {
        long t = 0;
        int lat = 0;
        int lon = 0;
        float alt = 0;
        int tmp = 0;
        float dst = 0;
        float hrt = 0;
        float cad = 0;
        float spd = 0;
        float pwr = 0;
        float acc = 0;

        if (mesg.getTimestamp() != null) t = mesg.getTimestamp().getTimestamp();
        t  = 1000*(t + TIME_OFFSET);
        if (mesg.getPositionLat() != null)  lat = mesg.getPositionLat();
        if (mesg.getPositionLong() != null) lon = mesg.getPositionLong();
        if (mesg.getAltitude() != null)     alt = mesg.getAltitude();
        if (mesg.getTemperature() != null)  tmp = mesg.getTemperature();
        if (mesg.getDistance() != null)     dst = mesg.getDistance();
        if (mesg.getHeartRate() != null)    hrt = mesg.getHeartRate();
        if (mesg.getCadence() != null)      cad = mesg.getCadence();
        if (mesg.getSpeed() != null)        spd = mesg.getSpeed();
        if (mesg.getPower() != null)        pwr = mesg.getPower();
        if (mesg.getGpsAccuracy() != null)  acc = mesg.getGpsAccuracy();

        if (lon == 0 || lat == 0) return;

        Location loc = new Location("fit");
        loc.setTime(t);
        loc.setLatitude(semi2deg(lat));
        loc.setLongitude(semi2deg(lon));
        loc.setAltitude(alt);
        loc.setSpeed(spd);

       if (num_points == 0)
       { SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd-HH-mm");
         //f.setTimeZone(new SimpleTimeZone(0,"UTC"));
         f.setTimeZone(TimeZone.getDefault());
         String trk_name = f.format(t);
	 handle_track_begin(num_tracks,trk_name);
        }

        handle_trackpoint(num_points,loc,dst,(int)hrt,(int)pwr);
        num_points++;

       }

      public void onMesg(LapMesg mesg) 
      {
/*
        Lap lap = new Lap();

        if (mesg.getStartTime() != null)
          lap.start_time = mesg.getStartTime().getTimestamp();

        if (mesg.getStartPositionLong() != null)
        { lap.start_lon = semi2deg(mesg.getStartPositionLong());
          if (lap.start_lon > 180) lap.start_lon -= 360;
         }

        if (mesg.getStartPositionLat() != null)
          lap.start_lat = semi2deg(mesg.getStartPositionLat());

        if (mesg.getEndPositionLong() != null)
        { lap.end_lon = semi2deg(mesg.getEndPositionLong());
          if (lap.end_lon > 180) lap.end_lon -= 360;
         }

        if (mesg.getEndPositionLat() != null)
          lap.end_lat = semi2deg(mesg.getEndPositionLat());


        if (mesg.getTimestamp() != null)
          lap.end_time = mesg.getTimestamp().getTimestamp();

        if (mesg.getTotalTimerTime() != null)
          lap.total_time = mesg.getTotalTimerTime().intValue();

        if (mesg.getTotalElapsedTime() != null)
          lap.elapsed_time = mesg.getTotalElapsedTime().intValue();

        if (mesg.getTotalDistance() != null) 
          lap.total_dist =  mesg.getTotalDistance();

        if (mesg.getTotalCalories() != null) 
          lap.calories = mesg.getTotalCalories();


        if (mesg.getAvgHeartRate() != null) 
          lap.avg_hrate = mesg.getAvgHeartRate();

        if (mesg.getMaxHeartRate() != null)
          lap.max_hrate = mesg.getMaxHeartRate();


        if (mesg.getAvgSpeed() != null) 
          lap.avg_speed = mesg.getAvgSpeed();

        if (mesg.getMaxSpeed() != null) 
          lap.max_speed = mesg.getMaxSpeed();


        if (mesg.getAvgCadence() != null) 
          lap.avg_cadence =  mesg.getAvgCadence();

        if (mesg.getMaxCadence() != null)
          lap.max_cadence = mesg.getMaxCadence();


        if (mesg.getAvgPower() != null)
          lap.avg_power = mesg.getAvgPower();

        if (mesg.getMaxPower() != null) 
          lap.max_power = mesg.getMaxPower();


        if (mesg.getTotalAscent() != null)
          lap.total_ascent = mesg.getTotalAscent();

        if (mesg.getTotalDescent() != null)
          lap.total_descent = mesg.getTotalDescent();
*/

         handle_lap(num_laps++);
       }


      public void onMesg(SessionMesg mesg) 
      {
/*
        Lap trk = new Lap();

        int num_laps = 0;
        int first_lap = 0;

        if (mesg.getStartTime() != null)
          trk.start_time = mesg.getStartTime().getTimestamp();

        if (mesg.getStartPositionLong() != null)
        { trk.start_lon = semi2deg(mesg.getStartPositionLong());
          if (trk.start_lon > 180) trk.start_lon -= 360;
         }

        if (mesg.getStartPositionLat() != null)
          trk.start_lat = semi2deg(mesg.getStartPositionLat());

        if (mesg.getTimestamp() != null)
          trk.end_time = mesg.getTimestamp().getTimestamp();

        if (mesg.getTotalTimerTime() != null)
          trk.total_time = mesg.getTotalTimerTime().intValue();

        if (mesg.getTotalElapsedTime() != null)
          trk.elapsed_time = mesg.getTotalElapsedTime().intValue();

        if (mesg.getTotalDistance() != null) 
          trk.total_dist =  mesg.getTotalDistance();

        if (mesg.getTotalCalories() != null) 
          trk.calories = mesg.getTotalCalories();


        if (mesg.getAvgHeartRate() != null) 
          trk.avg_hrate = mesg.getAvgHeartRate();

        if (mesg.getMaxHeartRate() != null)
          trk.max_hrate = mesg.getMaxHeartRate();


        if (mesg.getAvgSpeed() != null) 
          trk.avg_speed = mesg.getAvgSpeed();

        if (mesg.getMaxSpeed() != null) 
          trk.max_speed = mesg.getMaxSpeed();


        if (mesg.getAvgCadence() != null) 
          trk.avg_cadence =  mesg.getAvgCadence();

        if (mesg.getMaxCadence() != null)
          trk.max_cadence = mesg.getMaxCadence();


        if (mesg.getAvgPower() != null)
          trk.avg_power = mesg.getAvgPower();

        if (mesg.getMaxPower() != null) 
          trk.max_power = mesg.getMaxPower();


        if (mesg.getTotalAscent() != null)
          trk.total_ascent = mesg.getTotalAscent();

        if (mesg.getTotalDescent() != null)
          trk.total_descent = mesg.getTotalDescent();

        if (mesg.getNumLaps() != null) 
          num_laps = mesg.getNumLaps();

        if (mesg.getFirstLapIndex() != null) 
          first_lap = mesg.getFirstLapIndex();
*/

        handle_track_end();
        num_tracks++;
      }


      public void onMesg(ActivityMesg mesg) 
      {
         long t = 0; 
         int total_time = 0; 
         int sessions = 0;

         if (mesg.getTimestamp() != null)
           t = mesg.getTimestamp().getTimestamp();

         if (mesg.getTotalTimerTime() != null)
           total_time = mesg.getTotalTimerTime().intValue();

         if (mesg.getNumSessions() != null)
           sessions = mesg.getNumSessions();
       }

   }


   String fname;
   String error_txt = null;

   public FitReader(String fn) { fname = fn; }


   public String get_error() { return error_txt; }


   public void read() 
   {
      FileInputStream in;

/*
      try {
         in = new FileInputStream(fname);
         if (!Decode.checkIntegrity((InputStream) in))
         { error_txt = "FIT file integrity failed.";
           return;
          }
         in.close();
      }
      catch (java.io.IOException e) { error_txt = e.toString(); }
*/

      Decode decode = new Decode();

      //  streams with no header and footer 
      // (stream contains FIT defn and data messages only)
      //decode.skipHeader();        

      // This suppresses exceptions with unexpected eof (also incorrect crc)
      //decode.incompleteStream();  

      Listener listener = new Listener();

      MesgBroadcaster mesgBroadcaster = new MesgBroadcaster(decode);

      mesgBroadcaster.addListener((FileIdMesgListener) listener);
      mesgBroadcaster.addListener((UserProfileMesgListener) listener);
      mesgBroadcaster.addListener((DeviceInfoMesgListener) listener);
      mesgBroadcaster.addListener((RecordMesgListener) listener);
      mesgBroadcaster.addListener((LapMesgListener) listener);
      mesgBroadcaster.addListener((SessionMesgListener) listener);
      mesgBroadcaster.addListener((ActivityMesgListener) listener);

      try {
         in = new FileInputStream(fname);
         mesgBroadcaster.run(in);
         in.close();
       } catch (Exception e) { error_txt = e.toString();  }

      //System.out.println("Decoded FIT file " + fname + ".");
    }

}
