<?php

/**
 * SCSSPHP
 *
 * @copyright 2012-2020 Leaf Corcoran
 *
 * @license http://opensource.org/licenses/MIT MIT
 *
 * @link http://scssphp.github.io/scssphp
 */

namespace ScssPhpRBE\ScssPhp\Util;

/**
 * @internal
 */
final class EquatableUtil
{
    /**
     * @param list<mixed> $list
     */
    public static function listContains(array $list, Equatable $item): bool
    {
        foreach ($list as $listItem) {
            if (!\is_object($listItem)) {
                continue;
            }

            if ($item === $listItem) {
                return true;
            }

            if ($item->equals($listItem)) {
                return true;
            }
        }

        return false;
    }

    /**
     * Checks whether 2 values are equals, using the Equatable semantic to compare objects if possible.
     *
     * When compared values don't implement {@see Equatable}, they are compared
     * using `===`.
     * Values implementing {@see Equatable} are still compared with `===` first to
     * optimize comparisons to the same object, as an object is always expected to
     * be equal to itself.
     *
     * @param mixed $item1
     * @param mixed $item2
     *
     * @return bool
     */
    public static function equals($item1, $item2): bool
    {
        if ($item1 === $item2) {
            return true;
        }

        if ($item1 instanceof Equatable && $item2 instanceof Equatable) {
            return $item1->equals($item2);
        }

        return false;
    }

    /**
     * Checks whether 2 lists are equals, using the Equatable semantic to compare objects if possible.
     *
     * @param list<mixed> $list1
     * @param list<mixed> $list2
     */
    public static function listEquals(array $list1, array $list2): bool
    {
        if (\count($list1) !== \count($list2)) {
            return false;
        }

        foreach ($list1 as $i => $item1) {
            $item2 = $list2[$i];

            if (self::equals($item1, $item2)) {
                continue;
            }

            return false;
        }

        return true;
    }
}
