<?php

namespace OSM\Element;

use OSM\Element\Element;
use OSM\Element\Member\Way;
use OSM\Point;

class Relation extends Element {

    public function getOuterWays(): array {
        return array_filter($this->members, function ($member) {
            return (
                ($member instanceof \OSM\Element\Member\Way)
                and ($member->role === 'outer')
            );
        });
    }

    public function getOuterWaysStartingWith(Point $point, ?Way $exclude = null): array {
        return array_filter($this->members, function ($member) use ($point, $exclude) {
            return (
                ($member instanceof \OSM\Element\Member\Way)
                and ($member->role === 'outer')
                and ($point->isSame($member->getFirstPoint()))
                and (
                    is_null($exclude)
                    or !$member->isSame($exclude)
                )
            );
        });
    }

    public function getOuterWaysStopingWith(Point $point, ?Way $exclude = null): array {
        return array_filter($this->members, function ($member) use ($point, $exclude) {
            return (
                ($member instanceof \OSM\Element\Member\Way)
                and ($member->role === 'outer')
                and ($point->isSame($member->getLastPoint()))
                and (
                    is_null($exclude)
                    or !$member->isSame($exclude)
                )
            );
        });
    }

    public function getOrderedOuterWays(): array {
        $orderedWays = [];
        $ways = $this->getOuterWays();

        $currentWay = reset($ways);
        $veryFirstPoint = $currentWay->getFirstPoint();
        $isDone = false;
        while (!$isDone) {
            $orderedWays[] = $currentWay; 
            $nextWays = $this->getOuterWaysStartingWith($currentWay->getLastPoint(), $currentWay);
            assert(count($nextWays) <= 1);
            if (count($nextWays) === 1) {
                $nextWay = reset($nextWays);
                if ($veryFirstPoint->isSame($nextWay->getFirstPoint())) {
                    break;
                }
                $currentWay = $nextWay;
                continue;
            } else {
                $nextWays =  $this->getOuterWaysStopingWith($currentWay->getLastPoint(), $currentWay);
                assert(count($nextWays) <= 1);
                if (count($nextWays) === 1) {
                    $nextWay = reset($nextWays);
                    $nextWay->reversePoints();
                    if ($veryFirstPoint->isSame($nextWay->getFirstPoint())) {
                        break;
                    }
                    $currentWay = $nextWay;
                    continue;
                } else {
                    $isDone = true;
                }
            }
        }

        return $orderedWays;
    }

}