package com.algobase.service;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.SystemClock;

import android.provider.Settings;

import android.content.Context;
import android.content.DialogInterface;

import android.util.Log;

import android.view.WindowManager;
import android.widget.Toast;

import android.app.AlertDialog;

//import android.location.Criteria;
//import android.location.LocationProvider;

import android.location.*;

import android.location.Location;
import android.location.LocationManager;
import android.location.provider.ProviderProperties;

import com.algobase.gpx.TrkReader;

import com.algobase.share.dialog.*;
import com.algobase.share.system.*;


public class GpsPlayer {
	
  static void log(String msg) { Log.v("GpsPlayer", msg); }

  //double geoid_correction = 48.0;

  LocationManager location_manager;

  String provider_name = LocationManager.GPS_PROVIDER;

  Context context;
  Handler handler;
  File rootDir;
  File trk_file;
  File play_file;

  boolean skip_breaks = true;
  float speed_factor;
  float gps_acc = 5.0f;
  long max_break;
  int start_dist = 0;

  boolean stopped = false;

  MyThread trk_thread = null;

  void showToast(final String msg) {
     handler.post( new Runnable() {
        public void run() {
            Toast.makeText(context, msg,Toast.LENGTH_LONG).show();
        }
     });
    }

  void copy_file(File source, File target)
  { try {
        FileInputStream in  = new FileInputStream(source);
        FileOutputStream out = new FileOutputStream(target);
        byte[] buffer = new byte[1024];
        int bytes;
        while((bytes = in.read(buffer)) != -1){
          out.write(buffer, 0, bytes);
        }
       in.close();
       out.close();
     }
     catch(IOException e) { log("copy_file: " + e.toString()); }
  }


  public GpsPlayer(Context ctxt) 
  {
    context = ctxt;

    handler = new Handler(Looper.getMainLooper()); 

    rootDir = context.getFilesDir();

    play_file = new File(rootDir,"gps_player.trk");

    if (play_file.exists())
    { showToast("GPS-Player: delete play file.");
      play_file.delete();
     }

    speed_factor = 1;
    max_break = 2000;

    location_manager = 
              (LocationManager)context.getSystemService(Context.LOCATION_SERVICE);

   }

  void setSkipBreaks(boolean b) { 
       skip_breaks = b;
       max_break = b ? 2000 : 0;
  }

  void setSpeed(float f) { speed_factor = f; }
  void setStart(int d) { start_dist = d; }
  void setMaxBreak(long s) { max_break = s; }
  void setAccuracy(float acc) { gps_acc = acc; }


  void sendLocation(double lon, double lat, double alt, float acc, float spd) 
  { 
    long t = System.currentTimeMillis();

    //alt += geoid_correction;

    Location loc = new Location(provider_name);
    loc.setTime(t);
    loc.setLongitude(lon);
    loc.setLatitude(lat);
    loc.setAltitude(alt);
    loc.setAccuracy(acc);
    loc.setSpeed(spd);

    long nanos = SystemClock.elapsedRealtimeNanos();
    loc.setElapsedRealtimeNanos(nanos);

    try {
       location_manager.setTestProviderLocation(provider_name,loc);
    } catch (Exception e) { log(e.toString()); }

   }


  void read_trk(final File file)
  {
    TrkReader trk = new TrkReader(file) {

          long last_time = 0;

          @Override
          public void file_error(String fname, String msg) {
            showToast("Error: " + msg);
          }

          @Override
          public boolean handle_trackpoint(int i, final Location loc, 
                                                  double dist,
                                                  double spd,
                                                  double asc,
                                                  int hrate,
                                                  int power,
                                                  int cad,
                                                  int temp)
          { 

            if (dist < start_dist) return true;
         
            if (stopped) return false;

            long t = loc.getTime();
            double lon = loc.getLongitude();
            double lat = loc.getLatitude();
            double alt = loc.getAltitude();

            float press = 0;

            if (press == 0)
            { double h = loc.getAltitude();
              double p = 1013.25 * Math.pow((1 - 0.0065*h/288.15),5.225);
              press = (float)p;
             }

           if (last_time != 0)
           { long tdiff = (t - last_time) - 10;
             if (max_break > 0 && tdiff > max_break) tdiff = max_break;
             if (tdiff > 0) 
               trk_thread.sleep((int)(0.5f + tdiff/speed_factor));
            }

           sendLocation(lon,lat,alt,gps_acc,(float)spd*speed_factor);

           last_time = t;

           return true;
         }

          @Override
          public void handle_track_end() { 
             stop(); 
          }
     };

    
    trk.read(); 
  }


  @SuppressWarnings("deprecation")
  void start(File file)
  {
    if (play_file.exists())
    {  showToast("GPS-Player is busy.");
       return;
     }

    trk_file = file;
    copy_file(file,play_file);

    showToast("GpsPlayer: " + file.getName() + "  speed: " + speed_factor);

    boolean requiresNetwork = false;
    boolean requiresSatellite = false;
    boolean requiresCell = false;
    boolean hasMonetaryCost = false;

    boolean supportsAltitude = true;
    boolean supportsBearing = false;
    boolean supportsSpeed = true;

    int powerRequirement = 0;
    int accuracy = 0;

    if (Build.VERSION.SDK_INT >= 31)
    { powerRequirement = ProviderProperties.POWER_USAGE_LOW;
      accuracy = ProviderProperties.ACCURACY_FINE;
     }
    else {
     powerRequirement = Criteria.POWER_LOW;
     accuracy = Criteria.ACCURACY_FINE;
    }


    try {
      location_manager.addTestProvider(provider_name,
                                       requiresNetwork,
                                       requiresSatellite,
                                       requiresCell,
                                       hasMonetaryCost,
                                       supportsAltitude,
                                       supportsSpeed,
                                       supportsBearing,
                                       powerRequirement,
                                       accuracy);

      location_manager.setTestProviderEnabled(provider_name,true);


      location_manager.setTestProviderStatus(provider_name,
                                             LocationProvider.AVAILABLE, null,
                                             System.currentTimeMillis());

    } catch (Exception e) { showToast(e.toString()); }

    stopped = false;

    trk_thread = new MyThread() {
      public void run() { read_trk(play_file); }
     };

    trk_thread.start();
  }


  void stop() 
  {
    if (stopped) return;

    if (!play_file.exists())
    {  showToast("GPS-Player not running.");
       return;
     }

    play_file.delete();

    stopped = true;
    trk_file = null;

    try {
       //location_manager.setTestProviderEnabled(provider_name,false);
         location_manager.removeTestProvider(provider_name);
    } catch (Exception e) { log(e.toString()); }

    showToast("GpsPlayer stopped.");

/*
    MyDialogBuilder builder = new MyDialogBuilder(context,"Stop GPS Player");
    builder.setMessage(trk_file.getPath());
    builder.setPositiveButton("ok", new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface d, int which) {
               play_file.delete();
               stopped = true;
               trk_file = null;
               try {
                //location_manager.setTestProviderEnabled(provider_name,false);
                  location_manager.removeTestProvider(provider_name);
               } catch (Exception e) { log(e.toString()); }

               showToast("GpsPlayer stopped.");

            }
    });

     builder.setNegativeButton("cancel");

     AlertDialog dialog = builder.create();

     dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);

     dialog.show();
*/

   }



}
