package ru.yandex.autotests.direct.web.util.matchers.beans;

import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.hamcrest.StringDescription;

import ru.yandex.autotests.direct.web.util.DirectWebError;
import ru.yandex.autotests.irt.testutils.json.JsonUtils;

/**
 * Class for assertion lists of beans
 * <p/>Here are some examples:
 * <code>
 * withBeans(beanList).assertThat(hasBeans(expectedBeanList));
 * withBeans(beanList).assertThat(everyItem(hasProperty("propertyName")));
 * withBeans(beanList).assertThat(hasItem(hasProperty("propertyName", equalTo(value))));
 * withBeans(beanList).assertThat(hasBean(expectedBean));
 * <code/>
 *
 * @author Roman Kuhta (kuhtich@yandex-team.ru)
 * @see IsBeanCollectionContaining
 */
public class BeanCollectionAssert<T extends Iterable> {
    private T beanList;

    private boolean printMismatchInLine = false;

    private BeanCollectionAssert(T beanList) {
        this.beanList = beanList;
    }

    public static <T extends Iterable> BeanCollectionAssert withBeans(T beanList) {
        return new BeanCollectionAssert<>(beanList);
    }

    /**
     * If called, mismatch of assertion will be printed in a line
     *
     * @return this {@link BeanCollectionAssert}
     */
    public BeanCollectionAssert<T> printInLine() {
        this.printMismatchInLine = true;
        return this;
    }

    public BeanCollectionAssert<T> and(Matcher<T> matcher) {
        return assertThat("", matcher);
    }

    public BeanCollectionAssert<T> assertThat(Matcher<T> matcher) {
        return assertThat("", matcher);
    }

    public BeanCollectionAssert<T> assertThat(String reason, Matcher<T> matcher) {
        if (!matcher.matches(beanList)) {
            Description description = new StringDescription();
            description.appendText(reason)
                    .appendText("\nExpected: ")
                    .appendDescriptionOf(matcher)
                    .appendText("\nBut was: \n")
                    .appendText(JsonUtils.toString(beanList, printMismatchInLine))
                    .appendText("\nMismatch reason:\n");
            matcher.describeMismatch(beanList, description);
            throw new DirectWebError(description.toString());
        }
        return this;
    }
}
