<?php
namespace onespace\tools\widgets\locationPicker;

use onespace\tools\icons\widgets\FontAwesomeIcon6;
use onespace\tools\widgets\locationPicker\LocationPicker;
use yii\bootstrap\Html;
use yii\bootstrap\Modal;
use yii\helpers\ArrayHelper;
use yii\web\JsExpression;
use yii\web\View;

/**
 * Widget that wraps the LocationPicker widget with a useful UI, based on Yii modals
 * 
 * Use startLatitude and startLongitude to initialise the map location. locationSet controls the flag above the buttons
 * 
 * Use any combination of latitudeOutputId, longitudeOutputId, and combinedOutputId to reference external inputs to hand off the result.
 * They will also be monitored for changes in value and the map updated accordingly
 * 
 * It should be safe to use multiple instances on the same page if required
 * @package onespace\tools\widgets\locationPicker
 */
class ModalLocationPicker extends \yii\bootstrap\Widget {

    // starting values
    public $startLatitude;
    public $startLongitude;

    public $locationSet = false;

    public $latitudeOutputId;
    public $longitudeOutputId;
    public $combinedOutputId;

    // override HTML options of various sub components
    public $mapOptions = [];
    public $clientOptions = [];
    public $modalOptions = [];

    // allow overriding text and HTML options of launch button
    public $launchButtonText;
    public $launchButtonOptions = [];
    
    // allow overriding text and HTML options of clear button
    public $clearButtonText;
    public $clearButtonOptions = [];

    public function init() {
        parent::init();

        if ($this->startLatitude == null) {
            $this->startLatitude = -29.8833;
        }
        if ($this->startLongitude == null) {
            $this->startLongitude = 31.05;
        }
    }

    public function run() {
        parent::run();

        $saveLocationJs = '';
        $clearLocationJs = '';
        $listenJs = '';
        if ($this->latitudeOutputId != null) {
            $saveLocationJs .= "$('#{$this->latitudeOutputId}').val($('#{$this->id}_temp_latitude').val())";
            $clearLocationJs .= "$('#{$this->latitudeOutputId}').val(null);";
            $listenJs .= "$('#{$this->latitudeOutputId}').on('input', function() {
                if ($(this).val() == '') {
                    changeLocation_{$this->id}(baseLatitude, baseLongitude);
                } else {
                    changeLocation_{$this->id}($(this).val(), $('#{$this->id}_temp_longitude').val()); 
                }
            });";
        }
        if ($this->longitudeOutputId != null) {
            $saveLocationJs .= "$('#{$this->longitudeOutputId}').val($('#{$this->id}_temp_longitude').val())";
            $clearLocationJs .= "$('#{$this->longitudeOutputId}').val(null);";
            $listenJs .= "$('#{$this->longitudeOutputId}').on('input', function() {
                if ($(this).val() == '') {
                    changeLocation_{$this->id}(baseLatitude, baseLongitude);
                } else {
                    changeLocation_{$this->id}($('#{$this->id}_temp_latitude').val(), $(this).val()); 
                }
            });";
        }
        if ($this->combinedOutputId != null) {
            $saveLocationJs .= "$('#{$this->combinedOutputId}').val($('#{$this->id}_temp_latitude').val() + ', ' + $('#{$this->id}_temp_longitude').val())";
            $clearLocationJs .= "$('#{$this->combinedOutputId}').val(null);";
            $listenJs .= "$('#{$this->combinedOutputId}').on('input', function() {
                if ($(this).val() == '') {
                    changeLocation_{$this->id}(baseLatitude, baseLongitude);
                } else {
                    combined = $(this).val();
                    split = combined.split(',', 2);
                    if (split.length == 2) {
                        changeLocation_{$this->id}(split[0].trim(), split[1].trim()); 
                    } else {
                        changeLocation_{$this->id}(split[0].trim(), 0);
                    }
                }
            });";
        }
        $this->getView()->registerJs(<<< JS
            function launchMapPicker_{$this->id}() {
                $('#{$this->id}-picker-map').locationpicker('autosize');
            }

            function changeLocation_{$this->id}(latitude, longitude) {
                $('#{$this->id}_temp_latitude').val(latitude);
                $('#{$this->id}_temp_longitude').val(longitude);
                $('#{$this->id}-picker-map').locationpicker('location', {latitude: latitude, longitude: longitude});
            }

            function saveLocation_{$this->id}() {
                $('#{$this->id}-location-cleared').hide();
                $('#{$this->id}-location-saved').show();
                {$saveLocationJs}
            }

            function clearLocation_{$this->id}() {
                {$clearLocationJs}
                changeLocation_{$this->id}(baseLatitude, baseLongitude);
                $('#{$this->id}-location-saved').hide();
                $('#{$this->id}-location-cleared').show();
            }
        JS, View::POS_BEGIN);

        $this->getView()->registerJs(<<< JS
            // need something to reference back to when hitting "clear"
            baseLatitude = {$this->startLatitude};
            baseLongitude = {$this->startLongitude};

            // set up auto complete for location search
            searchBar = document.getElementById('{$this->id}-map-address');
            autocomplete = new google.maps.places.Autocomplete(
                searchBar, {
                componentRestrictions: { country: "za" },
                fields: ['place_id', 'geometry', 'name'],
            });

            /**
             * This handles if a user searches by address and chooses one from the drop
             * down menu.
             */
            autocomplete.addListener('place_changed', function () {
                const place = this.getPlace();

                if (!place.geometry) {
                    searchBar.placeholder = 'Search for location or GPS coordinates';
                } else {
                    changeLocation_{$this->id}(place.geometry.location.lat(), place.geometry.location.lng());
                }
            });

            {$listenJs}
        JS, View::POS_READY);

        $this->getView()->registerCss(<<<CSS
            .pac-container {
                z-index: 1051;
            }
        CSS);


        ob_start();
        ob_implicit_flush(false);
        Modal::begin(
            ArrayHelper::merge([
                'header' => 'Select Location',
                'id' => $this->id.'-modal',
                'footer' => Html::tag('div', Html::button('Clear', [
                    'onClick' => 'clearLocation_'.$this->id.'()',
                    'class' => 'btn btn-default',
                    'data-toggle' => 'modal',
                    'data-target' => '#'.$this->id.'-modal',
                ]) . Html::button('Save', [
                    'onClick' => 'saveLocation_'.$this->id.'()',
                    'class' => 'btn btn-primary',
                    'data-toggle' => 'modal',
                    'data-target' => '#'.$this->id.'-modal',
                ])),
            ], $this->modalOptions)
        );
        echo Html::beginTag('div', ['class' => 'input-group']);
        echo Html::textInput('', null, ['id' => $this->id.'-map-address', 'class' => 'form-control']);
        echo Html::tag('span', FontAwesomeIcon6::widget(['identifier' => 'magnifying-glass']), ['class' => 'input-group-addon']);
        echo Html::endTag('div');
        
        // temporary values
        echo Html::hiddenInput($this->id.'_temp_latitude', null, ['id' => $this->id.'_temp_latitude', 'class' => '']);
        echo Html::hiddenInput($this->id.'_temp_longitude', null, ['id' => $this->id.'_temp_longitude', 'class' => '']);
        
        echo LocationPicker::widget([
            'options' => ArrayHelper::merge([
                    'id' => $this->id.'-picker-map',
                    'style' => implode(';', ['width: 100%', 'height: 400px']), // map canvas width and height
                ], $this->mapOptions),
            'clientOptions' => ArrayHelper::merge([
                'location' => [
                    'latitude'  => $this->startLatitude,
                    'longitude' => $this->startLongitude,
                ],
                'radius'    => 0,
                'inputBinding' => [
                    'latitudeInput'     => new JsExpression("$('#{$this->id}_temp_latitude')"),
                    'longitudeInput'    => new JsExpression("$('#{$this->id}_temp_longitude')"),
                ],
                'markerInCenter' => true,
                'enableAutoCorrect' => true,
                'enableReverseGeocode' => false,
                'mapOptions' => [
                    'mapTypeControl' => true,
                ],
            ], $this->clientOptions),
        ]);
        Modal::end();

        echo Html::beginTag('div', ['class' => 'form-group']);
        echo Html::tag('p', FontAwesomeIcon6::widget(['identifier' => 'circle-check']) . ' Location set', ['id' => $this->id.'-location-saved', 'class' => 'text-success', 'style' => (!$this->locationSet ? 'display:none;' : '')]);
        echo Html::tag('p', FontAwesomeIcon6::widget(['identifier' => 'circle-xmark']) . ' No location set', ['id' => $this->id.'-location-cleared', 'class' => '', 'style' => ($this->locationSet ? 'display:none;' : '')]);
        echo Html::button(
            $this->launchButtonText ?: 'Select Location', 
            ArrayHelper::merge([
                'id' => $this->id.'-button-location-select',
                'onClick' => 'launchMapPicker_'.$this->id.'()',
                'class' => 'btn btn-primary',
                'data-toggle' => 'modal',
                'data-target' => '#'.$this->id.'-modal',
            ], $this->launchButtonOptions)
        );
        echo Html::button(
            $this->clearButtonText ?: 'Clear Location', 
            ArrayHelper::merge([
                'id' => $this->id.'-button-location-clear',
                'onClick' => 'clearLocation_'.$this->id.'()',
                'class' => 'btn btn-default',
            ], $this->clearButtonOptions)
        );
        echo Html::endTag('div');


        return ob_get_clean();
    }

}