<?php
/**
 * @author Ulrich Hecht <ulrich.hecht@hecht-software.de>
 * @date 11/11/2016
 */

namespace AppBundle\Util;


use AppBundle\Entity\TravelDeparturePoint;
use Doctrine\Common\Collections\Collection;

class DepartureUtil
{
    /**
     * @param \Doctrine\Common\Collections\Collection|TravelDeparturePoint[] $departures
     * @param \DateTime $startDate
     * @param \DateTime $endDate
     * @param $addEmptyEntries
     *
     * @return array|TravelDeparturePoint[]
     */
    public static function filterDeparturesByPeriod($departures, $startDate, $endDate, $addEmptyEntries)
    {
        $startWeekday = intval($startDate->format('w'));
        $endWeekday = intval($endDate->format('w'));
        return DepartureUtil::filterDeparturesByWeekdays($departures, $startWeekday, $endWeekday, $addEmptyEntries);
    }

    /**
     * @param TravelDeparturePoint[] $departures
     * @param int $startWeekday
     * @param int $endWeekday
     * @param bool $addEmptyEntries
     *
     * @return array|TravelDeparturePoint[]
     */
    public static function filterDeparturesByWeekdays($departures, $startWeekday, $endWeekday, $addEmptyEntries)
    {
        $ret = [];
        foreach ($departures as $departure)
        {
            // #TODO Problems expected here
            if ($departure->getTravelPeriod() != null)
            {
                $ret[] = $departure;
                continue;
            }
            $foundDepartureForStartDate = false;
            $foundDepartureForEndDate = false;
            if (count($departure->getDays()) > 0)
            {
                foreach ($departure->getDays() as $depWeekday)
                {
                    if ($startWeekday == $depWeekday)
                    {
                        $foundDepartureForStartDate = true;
                    }
                    if ($endWeekday == $depWeekday)
                    {
                        $foundDepartureForEndDate = true;
                    }
                    if ($foundDepartureForStartDate && $foundDepartureForEndDate)
                    {
                        $ret[] = $departure;
                        break;
                    }
                }
            }
            if ($addEmptyEntries && !($foundDepartureForStartDate && $foundDepartureForEndDate))
            {
                $entry = new TravelDeparturePoint();
                $entry->setName($departure->getName());
                $entry->setThreeLetter($departure->getThreeLetter());
                $entry->setExtraCharge('');
                $entry->setDays('');
                $entry->setDepartureType('');
                if ($departure->getIsVirtual() !== null)
                {
                    $entry->setIsVirtual($departure->getIsVirtual());
                }
                $ret[] = $entry;
            }
        }
        return $ret;
    }

    /**
     * @param TravelDeparturePoint[] $departures
     * @param TravelDeparturePoint[] $defaultDepartures
     * @param bool $removeIfEmptyExtraCharge
     *
     * @return \AppBundle\Entity\TravelDeparturePoint[]
     */
    public static function mergeDeparturesWithDefaults($departures, $defaultDepartures, $removeIfEmptyExtraCharge)
    {
        $departureKeyByName = [];
        $isRemovedDepartureByName = [];
        foreach ($departures as $departureKey => &$departure)
        {
            if ($removeIfEmptyExtraCharge && $departure->getIsEmpty())
            {
                $isRemovedDepartureByName[$departure->getName()] = true;
                unset($departures[$departureKey]);
            }
            else
            {
                $departure->setIsVirtual(false);
                $departureKeyByName[$departure->getName()] = $departureKey;
            }
        }
        foreach ($defaultDepartures as $defaultDeparture)
        {
            $name = $defaultDeparture->getName();
            if (!isset($departureKeyByName[$name]) && !($removeIfEmptyExtraCharge && (
              isset($isRemovedDepartureByName[$name])) || $defaultDeparture->getIsEmpty()))
            {
                $defaultDeparture->setIsVirtual(true);
                $departures[] = $defaultDeparture;
            }
        }
        if ($departures instanceof Collection)
        {
            $departures = $departures->toArray();
        }
        return DepartureUtil::sortDepartures($departures);
    }

    /**
     * Limit discount for individual arrival to flight price
     *
     * @param TravelDeparturePoint[] $departures
     * @param $flightPrice
     *
     * @return mixed
     */
    public static function limitIndividualArrivalPriceInDepartures($departures, $flightPrice)
    {
        foreach ($departures as $k => $departure)
        {
            if(strtolower($departure->getName()) == 'eigenanreise')
            {
                $departures[$k] = DepartureUtil::limitIndividualArrivalPrice($departure, $flightPrice);
                break;
            }
        }
        return $departures;
    }

    /**
     * Limit discount for individual arrival to flight price
     *
     * @param TravelDeparturePoint $departure
     * @param $flightPrice
     *
     * @return TravelDeparturePoint
     */
    public static function limitIndividualArrivalPrice(TravelDeparturePoint $departure, $flightPrice)
    {
        if(strtolower($departure->getName()) == 'eigenanreise')
        {
            $limit = -$flightPrice;
            if ($departure->getExtraCharge() < $limit)
            {
                $departure->setExtraCharge($limit);
            }
        }
        return $departure;
    }

    /**
     * Compare two departures by their name. However, individual arrival have topmost priority
     *
     * @param TravelDeparturePoint $a
     * @param TravelDeparturePoint $b
     *
     * @return int
     */
    private static function compareDepartureName($a, $b)
    {
        $aName = strtolower($a->getName());
        $bName = strtolower($b->getName());
        if ($aName == 'eigenanreise')
        {
            return $bName == 'eigenanreise' ? 0 : -1;
        }
        elseif ($bName == 'eigenanreise')
        {
            return 1;
        }
        return strcmp($aName, $bName);
    }

    /**
     * @param TravelDeparturePoint[] $departures
     *
     * @return TravelDeparturePoint[]
     */
    public static function sortDepartures($departures)
    {
        usort($departures, ['AppBundle\Util\DepartureUtil', 'compareDepartureName']);
        return $departures;
    }
}