<?php

require_once __DIR__ . '/../time.php';
require_once __DIR__ . '/../model.php';
require_once __DIR__ . '/../../view/debug.php';
require_once __DIR__ . '/common.php';
require __DIR__ . '/../lib/TransportForLondonAPI.php';
require_once __DIR__ . '/../../locations/locations.php';

class GB_TransportForLondon extends ProviderCommon implements RealTimeProvider
{
    protected static $HOME_REALM = 'gb.gov.atco';
    protected static $HOME_SUB_REALM_UND_STATIONS = 'gb.gov.atco.940GZZLU';
    protected static $HOME_SUB_REALM_BUS_AND_TRAM_STOPS = 'gb.gov.atco.490';

    public static function SourceName()
    {
        return "TfL";
    }

    public static function HomeRealm()
    {
        return self::$HOME_REALM;
    }

    public static function SupportedRealms()
    {
        return [self::$HOME_SUB_REALM_UND_STATIONS, self::$HOME_SUB_REALM_BUS_AND_TRAM_STOPS];
    }

    public static function Capabilities()
    {
        return new InformationProviderCapabilities(CAPABILITY_MAY_PROVIDE_REAL_TIME | CAPABILITY_SHOWS_STOP_OR_PLATFORM_ON_SIMPLE_BOARD);
    }

    protected static $TFL_APP_KEY = '737a890aa4b74350a8405eff7ec2ec48';

    protected function GetTransportForLondonAPIInterfaceImplementation($genericLoc = null)
    {
        return new TransportForLondonAPI(self::$TFL_APP_KEY, TRUE);
    }

    public function ArrivalOrDepartureBoard(string $loc, string $filterLoc, bool $isArrivals, DateTime $at, array $searchOptions = null)
    {
        // FIXME Should these be assertions?
        if (!empty($filterLoc))
            throw new OperationNotSupportedException('TransportForLondonAPI does not support departures with a filter location');
        if ($isArrivals)
            throw new OperationNotSupportedException('TransportForLondonAPI does not support arrivals');    // FIXME although the API call is named "arrivals"!
        /*if ($at && $at != null)
            throw new OperationNotSupportedException('TransportForLondonAPI does not support date/time');*/   // FIXME Check this...

        $TransportForLondonAPI = $this->GetTransportForLondonAPIInterfaceImplementation($loc);

        $providerLoc = Director::provider_id_for($loc);

        $response = $TransportForLondonAPI->Arrivals($providerLoc);
        if ($response !== false) {
            $result = self::normalise_board_response($response, $loc, $searchOptions);

            debugIfTestpilot($response, 'Response');
            debugIfTestpilot($result, 'Normalised response');
        }

        return $result;
    }

    public function ServiceDetails(string $serviceId, string $locOfInterest = null, DateTime $atLocOfInterest = null, array $searchOptions = null)
    {
        throw new OperationNotSupportedException('TransportForLondonAPI does not support service details');
    }

    public function ConnectionsBoard(string $loc, string $serviceId = null, DateTime $scheduledArrival = null, int $arrivalBoardIndex = null, array $searchOptions = null)
    {
        throw new OperationNotSupportedException('TransportForLondonAPI does not support connections board');
    }

    protected static function normalise_board_response($boardResponse, $genericLoc, $searchOptions = null)
    {
        $genericResponse = new ArrDepBoardAtStop(self::Capabilities());

        $services = array();

        $genericResponse->genericId = $genericLoc;

        $services = self::normalise_service_list($boardResponse, $genericLoc);
        $services = sort_board_entries_by_time($services);

        $genericResponse->services = $services;
        // FIXME: Does this always get the name? "940G" vs "9400"?
        $genericResponse->locationName = Locations::GetLocationName($genericLoc);
        if ($boardResponse && count($boardResponse) > 0) {
            $genericResponse->locationName = $boardResponse[0]['stationName'];
        }

        return $genericResponse;
    }

    protected static function normalise_service_list($response, $genericLoc = '')
    {
        $genericServiceList = [];
        if (isset($response) && count($response) > 0) {
            foreach ($response as $service) {
                if (isset($service['destinationName']) && $service['destinationName'] !== $service['stationName']) {
                    // FIXME Works for Underground, removes trains terminating here
                    $genericServiceList[] = self::normalise_service($service, $response, $genericLoc);
                }
            }
        }
        return $genericServiceList;
    }

    private static function normalise_service($vehDeparture, $result, $genericLoc = '')
    {
        $veh = new ServiceAtStop(self::Capabilities());
        $veh->stopIndexOfInterest = 0;
        $veh->previousLocationsKnown = false;
        $veh->subsequentLocationsKnown = false;
        $veh->connectionConfidence = CONNECTION_CONFIDENCE_NONE;
        $veh->serviceMode = $vehDeparture['modeName'];
        $veh->isInService = true;
        $veh->routeDescription = $vehDeparture['lineName'] ?? $vehDeparture['lineId'];

        $veh->destination = new ServiceStartOrEndLocation();
        $veh->destination->name = $vehDeparture['lineName'] . ' to ' . ($vehDeparture['destinationName'] ?? $vehDeparture['towards']);
        if (isset($vehDeparture['destinationNaptanId'])) {
            $veh->destination->providerId = $vehDeparture['destinationNaptanId'];
            $veh->destination->genericId = self::$HOME_REALM . '.' . $vehDeparture['destinationNaptanId'];
        }

        $atStopLoc = new CommercialStopLocation();
        if (isset($vehDeparture['platformName']) && $vehDeparture['platformName'] !== 'null') {
            $atStopLoc->platformOrStop =  ($vehDeparture['modeName'] === 'bus' ? 'Stop ' : '') . $vehDeparture['platformName'];
            $atStopLoc->platformOrStopState = PLATFORM_OR_STOP_REAL_TIME;
        }

        $atStopLoc->departure = new StopMovement();
        $atStopLoc->departure->realTime = DateTime::createFromFormat(DateTime::ISO8601, $vehDeparture['expectedArrival']);
        $atStopLoc->departure->state = REAL_TIME_ONLY;

        $atStopLoc->isCancelled = false;    // Cancellations not supported by NextBuses and TfL
        $atStopLoc->isExtraStop = false;

        $veh->locations[] = $atStopLoc;

        if (isset($vehDeparture['currentLocation']) && $vehDeparture['currentLocation'] !== '') {
            $veh->currentLocationDescription = $vehDeparture['currentLocation'];
        }

        $veh->source = self::SourceName();

        return $veh;
    }
}
