<?php

$profile  = getenv("SAVVY_PROFILE");
if ($profile) {
  require("../../core/backend.${profile}.php");
} else {
  require('../../core/backend.php');
}

require '../config.php';
require 'functions.php';

$worker= new GearmanWorker();
$worker->addServers($gearmanServers);
$worker->addFunction('process_tl_batch', 'processTrackLocationBatch');

$isStoreDebugTrack = file_exists($tracklocation_dir."debug") && is_dir($tracklocation_dir."debug");
$batchSize = 1000;

while (1)
{
	$worker->work();
	if ($worker->returnCode() != GEARMAN_SUCCESS) break;
}

function processTrackLocationBatch($job) {

  global $tracklocation_dir, $pgconn, $pgconn_gps, $isStoreDebugTrack, $batchSize;

	echo "[".date("Y-m-d H:i:s")."] Process 'Track Location Batch' job starting\n";
	$workload = $job->workload();
  $data = json_decode($workload, true);
	$tlSession = $data['sessionId'];
	$loc = $data['loc'];
	$deviceToken = $data['deviceToken'];

	//	$pattern = '/^(tl_(\d)*_'.$tlSession.'_(\w|\d|\.)*\.json.lock)$/';
	$pattern = '/^(tl_'.$tlSession.'\.csv)$/';

	$files = preg_grep($pattern, scandir($tracklocation_dir));
	if (!$files) {
//    $q = "UPDATE tracking_data_job SET locked = FALSE, updated=now() WHERE session='{$tlSession}'";
//    $r = pg_query($pgconn, $q);
    echo "[".date("Y-m-d H:i:s")."] 'Track Location Batch' job complete\n";
    return false;
  }

	$sortedFiles = [];
	foreach ($files as $file) {
		$sortedFiles[$file] = filemtime($tracklocation_dir.$file);
	}

	asort($sortedFiles);
	$files = array_keys($sortedFiles);

	$rows = [];
	foreach ( $files as $file) {
		if($isStoreDebugTrack) {
			copy($tracklocation_dir . $file, $tracklocation_dir."debug/".$file);
			echo "[".date("Y-m-d H:i:s")."] Debug track stored : ".$tracklocation_dir."debug/".$file."\n";
		}

    $fh = fopen($tracklocation_dir . $file, 'r');
    $rowId = 1;
    $cntr=0;
    while (($line = fgetcsv($fh, 10000, ",")) !== FALSE) {
      if($rowId == 1){ $rowId++; continue; }   // continue is used for skip row 1
      $row = arrayToTrack($line);
      if (isset($row)) {
        array_push($rows, $row);
        $cntr++;
        if ($cntr >= $batchSize) {
          processBatch($rows, $tlSession, $deviceToken, $loc);
          $rows = [];
          $cntr=0;
        }
      }
    }
    fclose($fh);
	}
	if (count($rows) > 0) {
    processBatch($rows, $tlSession, $deviceToken, $loc);
  }

  foreach ( $files as $file) {
    if ( ! unlink( $tracklocation_dir . $file ) ) {
      $newFileName = str_ireplace( ".csv", ".csv.done", $file );
      rename( $tracklocation_dir . $file, $tracklocation_dir . $newFileName );
      echo( "$tracklocation_dir.$newFileName cannot be deleted, it was renamed to $tracklocation_dir.$newFileName" );
    }
  }

  $pattern = '/^(tl_(\d)*_'.$tlSession.'_(\w|\d|\.)*\.json.lock)$/';
  $files = preg_grep($pattern, scandir($tracklocation_dir));
  foreach ( $files as $file) {
    if ( ! unlink( $tracklocation_dir . $file ) ) {
      $newFileName = str_ireplace( ".lock", ".done", $file );
      rename( $tracklocation_dir . $file, $tracklocation_dir . $newFileName );
      echo( "$tracklocation_dir.$newFileName cannot be deleted, it was renamed to $tracklocation_dir.$newFileName" );
    }
  }


	$q = "UPDATE tracking_data_job SET locked = FALSE, updated=now() WHERE session='{$tlSession}'";
	$r = pg_query($pgconn, $q);
	echo "[".date("Y-m-d H:i:s")."] 'Track Location Batch' job complete\n";
}

function processBatch(&$rows, $tlSession, $deviceToken, $loc) {

  usort($rows, function($a1, $a2) {
    $v1 = strtotime($a1['traked_date']);
    $v2 = strtotime($a2['traked_date']);
    return $v1 - $v2;
  });

  list ($pass, $device, $session) = checkRequestHeaders(
    'tracklocation',
    ['member_id' => $rows[0]['member_id']],
    [
      "x-session-id" => $tlSession,
      "x-devicetoken" => $deviceToken
    ],
    ['tracklocation' => 1]
  );

  $rows[0]["duration"] = 0;
  $rows[0]["distance"] = 0;
  $rows[0]["loc"] = $loc;
  $rows[0]["previous_id"] = "NULL";

  $device_id  = (isset($device) && array_key_exists("id",$device) && $device["id"]>0) ? $device["id"] : "NULL";
  $rows[0]["device_id"] = $device_id;
  $rows[0] = populateFromPrevious($rows[0]);

  $row = save_tracked($rows[0]);
  $count = count($rows);

  for ($i = 1; $i < $count; $i++) {
    if($rows[$i-1]['member_id'] != $rows[$i-1]['member_id']) {
      list ($pass, $device, $session) = checkRequestHeaders(
        'tracklocation',
        ['member_id' => $rows[$i]['member_id']],
        [
          "x-session-id" => $tlSession,
          "x-devicetoken" => $deviceToken
        ],
        ['tracklocation' => 1]
      );
      $rows[$i]["device_id"] = (isset($device) && array_key_exists("id",$device) && $device["id"]>0) ? $device["id"] : "NULL";
    } else {
      $rows[$i]["device_id"] = $rows[$i-1]["device_id"];
    }

    $rows[$i]["previous_id"] = "NULL";
    $rows[$i]["duration"] = 0;
    $rows[$i]["distance"] = 0;
    $rows[$i]["loc"] = $loc;

    if(!isset($row) || !array_key_exists("id",$row)) {
      $rows[$i] = populateFromPrevious($rows[$i]);
    } else  {
      $date1=strtotime($rows[$i-1]["traked_date"]);
      $date2=strtotime($rows[$i]["traked_date"]);
      $diff = $date2 - $date1;
      $duration = $diff * 1000;

      if ($rows[$i]["traked_group"] === $rows[$i-1]["traked_group"] ) {
        $rows[$i]["previous_id"] = $row["id"];
        $rows[$i]["duration"] = (int)($duration < 2147483647 ? $duration : 2147483647);
        $rows[$i]["distance"] = (int)(distance_between_two_gps_coordinates($rows[$i-1]["lat"],$rows[$i-1]["lng"],$rows[$i]["lat"],$rows[$i]["lng"]) * 1000);
      }
    }
    $row = save_tracked($rows[$i]);
  }
}

function arrayToTrack($row) {
  $track = null;
  $row = array_filter($row, function($value) { return !is_null($value) && $value !== ''; });

  if ( count( $row ) === 9 && intval( $row[2] ) > 0 && validateDate($row[0])) {
    $track                 = [];
    $track["traked_date"]  = $row[0];
    $track["traked_group"] = $row[1];
    $track["member_id"]    = $row[2];
    $track["lat"]          = floatval( $row[3] );
    $track["lng"]          = floatval( $row[4] );
    $track["speed"]        = floatval( $row[5] ) < 0 ? 0 : floatval( $row[5] );
    $track["timestamp"]    = $row[6];
    $track["point_count"]  = $row[7];
    $track["sync_saved"]   = $row[8];
  }
 return $track;
}


function distance_between_two_gps_coordinates($lat1, $lon1, $lat2, $lon2) {
	return acos(sin(deg2rad($lat1)) * sin(deg2rad($lat2)) + cos(deg2rad($lat1)) * cos(deg2rad($lat2)) * cos(deg2rad($lon2 - $lon1))) * 6371;
}

function validateDate($date, $format = 'Y-m-d H:i:s'){
  $d = DateTime::createFromFormat($format, $date);
  return $d && $d->format($format) === $date;
}

function populateFromPrevious($row) {

	global $pgconn_gps;

	$device_id = $row["device_id"];
	$ttimeStr = "to_timestamp('".$row["traked_date"]."', 'YYYY-MM-DD HH24:MI:SS')";

	$q = "SELECT id , lat, lng, ttime, traked_group ";
	$q.= "FROM members_tracking ";
	$q.= "WHERE member_id=".$row['member_id']." AND ttime < ".$ttimeStr." AND ";
	$q.= ($device_id == "NULL" ? "device_id IS NULL" : "device_id=${device_id}");
	$q.= " ORDER BY ttime DESC LIMIT 1";
	$r = pg_query($pgconn_gps, $q);

	$row["previous_id"] = "NULL";
	$row["duration"] = 0;
	$row["distance"] = 0;
	if ($r && pg_num_rows($r) && $f=pg_fetch_assoc($r)) {
		$date1=strtotime($f["ttime"]);
		$date2=strtotime($row["traked_date"]);
		$diff = $date2 - $date1;
		$duration = $diff * 1000;
		if ($row["traked_group"] === $f["traked_group"] ) {
			$row["previous_id"] = $f["id"];
			$row["duration"] = (int)($duration < 2147483647 ? $duration : 2147483647);
			$row["distance"] = (int)(distance_between_two_gps_coordinates($f["lat"],$f["lng"],$row["lat"],$row["lng"]) * 1000);
		}
	}
	return $row;
}

function save_tracked($in) {
	global $pgconn_gps;

	$ttimeStr = "to_timestamp('".$in["traked_date"]."', 'YYYY-MM-DD HH24:MI:SS')";

	$result = [];

	if ($in["member_id"]>0 && $in["lng"]!="" && $in["lat"]!="") {
		$q     = "INSERT INTO members_tracking (member_id, traked_group, speed, lat, lng, gps, ttime, loc, created, device_id, distance, duration, previous_id) ";
		$q     .= " VALUES(";
		$q     .= $in["member_id"] . ", ";
		$q     .= "'".$in["traked_group"] . "', ";
		$q     .= $in["speed"] . ", ";
		$q     .= $in["lat"] . ", ";
		$q     .= $in["lng"] . ", ";
		$q     .= "ST_SetSRID(ST_MakePoint(" . $in["lng"] . "," . $in["lat"] . "),4326)::geography". ", ";
		$q     .= $ttimeStr . ", ";
		$q     .= "'".$in["loc"] . "', ";
		$q     .= "now(), ";
		$q     .= $in["device_id"]. ", ";
		$q     .= $in["distance"] . ", ";
		$q     .= $in["duration"] . ", ";
		$q     .= ($in["previous_id"] ? $in["previous_id"]: "NULL");
		$q     .= ") RETURNING *";
		$r = pg_query( $pgconn_gps, $q );
		if ($r && pg_num_rows($r) && $f=pg_fetch_assoc($r)) {
			$result = $f;
		} else {
			error_log(pg_last_error($pgconn_gps));
		}
	}

	return $result;
}

