<?php
/**
 * The functionality of the module.
 *
 * @package    Nearest Location
 * @author     Max Sternitzke <max.sternitzke@th-luebeck.de>
 */
class Trainingssystem_Plugin_Module_Nearest_Location
{

    public function showFrontend($atts)
    {
        $twig = Trainingssystem_Plugin_Twig::getInstance()->twig;

        $title = "Nahegelegene Orte";
        if (isset($atts['titel'])) { // Allow empty title here!
            $title = $atts['titel'];
        }

        $subject = "Orte";
        if (isset($atts['subject'])) { // Allow empty subject here!
            $subject = $atts['subject'];
        }

        $limit = 3;
        if (isset($atts['limit']) && is_numeric($atts['limit']) && ($atts['limit'] == -1 || $atts['limit'] > 0)) {
            $limit = $atts['limit'];
        } elseif (isset($atts['limit'])) {
            $limit = null;
        }

        $locations = null;
        if (isset($atts['locations']) && $this->validateJsonLocations($atts['locations'])) {
            $locations = $atts['locations'];
        }

        $showlocationsinitially = false;
        if(isset($atts['showlocationsinitially']) && $atts['showlocationsinitially'] == "true") {
            $showlocationsinitially = true;
        }

        $showtooltips = true;
        if(isset($atts['showtooltips']) && $atts['showtooltips'] == "false") {
            $showtooltips = false;
        }

        $myLocationTooltip = "Ihr Standort";
        if(isset($atts['mylocationtooltiptext']) && strlen(trim($atts['mylocationtooltiptext'])) > 0) {
            $myLocationTooltip = $atts['mylocationtooltiptext'];
        }

        $showplzsearch = true;
        if(isset($atts['showplzsearch']) && $atts['showplzsearch'] == "false") {
            $showplzsearch = false;
        }

        if (!is_null($locations) && !is_null($limit)) {
            return $twig->render("nearest-location/nearest-location-overview.html", 
                                    ["title" => $title, 
                                    "subject" => $subject,
                                    "locations_json" => $locations,
                                    "locations" => json_decode($locations, true),
                                    "limit" => $limit, 
                                    "raphael_path" => plugin_dir_url(dirname(__FILE__)) . '../../assets/external/mapael-maps/raphael.min.js',
                                    "mapael_path" => plugin_dir_url(dirname(__FILE__)) . '../../assets/external/mapael-maps/jquery.mapael.min.js',
                                    "map_path" => plugin_dir_url(dirname(__FILE__)) . '../../assets/external/mapael-maps/germany.min.js',
                                    "showlocationsinitially" => $showlocationsinitially,
                                    "showplzsearch" => $showplzsearch,
                                    "showtooltips" => $showtooltips,
                                    "myLocationTooltip" => $myLocationTooltip,
                                ]);
        } else {
            return $twig->render("nearest-location/nearest-location-error.html");
        }
    }

    public function getNearestLocation() 
    {
        $twig = Trainingssystem_Plugin_Twig::getInstance()->twig;
        
        if(isset($_POST['plz']) && strlen(trim($_POST['plz'])) == 5 && isset($_POST['locations']) && isset($_POST['limit']) && is_numeric($_POST['limit']) && isset($_POST['subject']) && isset($_POST['showTooltips'])) {
            $plzarray = $this->getPlzArray(substr($_POST['plz'], 0, 1));

            $locations_valid = $this->validateJsonLocations(stripslashes($_POST['locations']));

            if(isset($plzarray[$_POST['plz']]) && $locations_valid) {

                $limit = $_POST['limit'];
                $subject = $_POST['subject'];
                $showTooltips = $_POST['showTooltips'];
                $locations_decoded = json_decode(stripslashes($_POST['locations']), true);
                $locations = array();

                $i = 0;
                foreach($locations_decoded as $l) {
                    $locations[$i] = array("name" => $l['name'], "description" => $l['description'], "address" => $l['address'], "phone" => $l['phone'], "mail" => $l['mail'], "link" => $l['link'], "lat" => $l['lat'], "long" => $l['long']);
                    if(isset($l['pretitle_text']) && trim($l['pretitle_text']) !== "" && isset($l['pretitle_color']) && trim($l['pretitle_color']) !== "") {
                        $locations[$i]['pretitle_text'] = $l['pretitle_text'];
                        $locations[$i]['pretitle_color'] = $l['pretitle_color'];
                    }
                    $locations[$i]['distance'] = $this->distance($plzarray[$_POST['plz']]['lat'], $plzarray[$_POST['plz']]['long'], $l['lat'], $l['long'], 'K');
                    $i++;
                }
                
                usort($locations, function($a, $b) {
                    return $a['distance'] - $b['distance'];
                });

                echo $twig->render("nearest-location/nearest-location-get.html", ["location" => $plzarray[$_POST['plz']], "limit" => $limit, "subject" => $subject, "locations" => $locations, "showTooltips" => $showTooltips]);
            } elseif(!isset($plzarray[$_POST['plz']])) {
                echo $twig->render("nearest-location/nearest-location-get-plz-not-found.html", ["plz" => $_POST['plz']]);
            } else {
                echo $twig->render("nearest-location/nearest-location-get-error.html");
            }
        } else {
            if(isset($_POST['plz']) && strlen(trim($_POST['plz'])) != 5) {
                echo $twig->render("nearest-location/nearest-location-get-plz-invalid.html");
            } else {
                echo $twig->render("nearest-location/nearest-location-get-error.html");
            }
        }
        wp_die();
    }

    private function getPlzArray($start)
    {

        if (!in_array($start, array("0", "1", "2", "3", "4", "5", "6", "7", "8", "9"))) {
            return array();
        }

        $filename = dirname(__FILE__) . "/plz/" . $start . ".csv";

        $plzarray = array();

        if (($handle = fopen($filename, "r")) !== false) {
            while (($data = fgetcsv($handle, 1000, ",")) !== false) {

                $plzarray[$data[0]]         = array();
                $plzarray[$data[0]]['plz']  = $data[0];
                $plzarray[$data[0]]['city'] = $data[1];
                $plzarray[$data[0]]['long'] = $data[2];
                $plzarray[$data[0]]['lat']  = $data[3];
            }
            fclose($handle);
        }
        return $plzarray;
    }

    /**
     * Checks a configuration json-string.
     * Requires the following format:
     * Array named locations
     *          - Object with fields named as
     *              - name
     *              - description
     *              - link
     *              - GPS long
     *              - GPS lat
     *          - another location Object
     *
     * @return boolean success
     */
    private function validateJsonLocations($string = "")
    {
        if (empty($string)) {
            return false;
        }

        $decoded = json_decode($string, true);

        if (json_last_error() == JSON_ERROR_NONE) {
            if (is_array($decoded)) {
                foreach ($decoded as $l) {
                    if (!isset($l['name']) || !isset($l['description']) || !isset($l['address']) || !isset($l['phone']) || !isset($l['mail']) || !isset($l['link']) || !isset($l['lat']) || !isset($l['long'])) {
                        return false;
                    }
                }
                return true;
            }
        }
        return false;
    }

    /*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
    /*::                                                                         :*/
    /*::  This routine calculates the distance between two points (given the     :*/
    /*::  latitude/longitude of those points). It is being used to calculate     :*/
    /*::  the distance between two locations using GeoDataSource(TM) Products    :*/
    /*::                                                                         :*/
    /*::  Definitions:                                                           :*/
    /*::    South latitudes are negative, east longitudes are positive           :*/
    /*::                                                                         :*/
    /*::  Passed to function:                                                    :*/
    /*::    lat1, lon1 = Latitude and Longitude of point 1 (in decimal degrees)  :*/
    /*::    lat2, lon2 = Latitude and Longitude of point 2 (in decimal degrees)  :*/
    /*::    unit = the unit you desire for results                               :*/
    /*::           where: 'M' is statute miles                                   :*/
    /*::                  'K' is kilometers           (default)                  :*/
    /*::                  'N' is nautical miles                                  :*/
    /*::  Worldwide cities and other features databases with latitude longitude  :*/
    /*::  are available at https://www.geodatasource.com                         :*/
    /*::                                                                         :*/
    /*::  For enquiries, please contact sales@geodatasource.com                  :*/
    /*::                                                                         :*/
    /*::  Official Web site: https://www.geodatasource.com                       :*/
    /*::                                                                         :*/
    /*::         GeoDataSource.com (C) All Rights Reserved 2022                  :*/
    /*::                                                                         :*/
    /*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
    private function distance($lat1, $lon1, $lat2, $lon2, $unit = 'K')
    {
        if (($lat1 == $lat2) && ($lon1 == $lon2)) {
            return 0;
        } else {
            $theta = $lon1 - $lon2;
            $dist  = sin(deg2rad($lat1)) * sin(deg2rad($lat2)) + cos(deg2rad($lat1)) * cos(deg2rad($lat2)) * cos(deg2rad($theta));
            $dist  = acos($dist);
            $dist  = rad2deg($dist);
            $miles = $dist * 60 * 1.1515;
            $unit  = strtoupper($unit);

            if ($unit == "K") {
                return ($miles * 1.609344);
            } else if ($unit == "N") {
                return ($miles * 0.8684);
            } else {
                return $miles;
            }
        }
    }
}
