package ru.yandex.autotests.direct.web.util.beanutils;

import ru.yandex.autotests.direct.utils.beans.MongoBeanLoader;
import ru.yandex.autotests.direct.utils.config.DirectTestRunProperties;
import ru.yandex.autotests.direct.web.util.DirectWebError;

/**
 * Implementation of saving and loading beans data into MongoDB
 *
 * @author Roman Kuhta (kuhtich@yandex-team.ru)
 * @see MongoBeanLoader
 */
public class MongoPropertyLoader<T> implements BeanPropertyLoader<T> {
    private MongoBeanLoader<T> mongoBeanLoader;
    private Class<T> beanClass;
    private T bean;

    private void instantiateBean() {
        try {
            this.bean = beanClass.newInstance();
        } catch (Exception e) {
            throw new DirectWebError("Cannot create new instance of bean " + bean.getClass().getName());
        }
    }

    /**
     * Creates new instance of MongoPropertyLoader
     *
     * @param beanClass bean class to be instanced
     */
    public MongoPropertyLoader(Class<T> beanClass) {
        this.beanClass = beanClass;
        this.mongoBeanLoader = new MongoBeanLoader<>(beanClass,
                DirectTestRunProperties.getInstance().getDirectWebMongoTemplatesCollection());
        instantiateBean();
    }

    public T getBean(String templateName) {
        return mongoBeanLoader.getBean(templateName);
    }

    /**
     * Saves BeanWrapper object with child bean into MongoDB
     * If BeanWrapper object with specified name and bean class exists
     * it will be replaced
     *
     * @param bean         bean object with some data
     * @param templateName name of the template to be saved
     */
    @Override
    public void save(T bean, String templateName) {
        mongoBeanLoader.saveBean(bean, templateName);
    }

    /**
     * Fills bean with data from the template for {@link T bean} class with specified templateName
     * If template has null properties they won't be applied to the bean
     *
     * @param templateName name of the template
     * @return returns {@link MongoPropertyLoader} object from with method is called
     */
    @Override
    public MongoPropertyLoader<T> apply(String templateName) {
        NullAwareBeanUtilsBean notNull = new NullAwareBeanUtilsBean();
        notNull.copyProperties(bean, mongoBeanLoader.getBean(templateName));
        return this;
    }

    /**
     * Instantiate {@link MongoPropertyLoader} to {@link T} bean
     *
     * @return returns {@link T} bean filled with data from all applied templates
     */
    @Override
    public T toObject() {
        T result = bean;
        instantiateBean();
        return result;
    }
}
