package ru.yandex.wmconsole.servantlet.sitemaps;

import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedList;

import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Required;

import ru.yandex.common.framework.core.ServRequest;
import ru.yandex.common.framework.core.ServResponse;
import ru.yandex.common.framework.pager.Pager;
import ru.yandex.common.util.db.OrderByClause;
import ru.yandex.wmconsole.data.info.BriefHostInfo;
import ru.yandex.wmconsole.data.info.HostDbHostInfo;
import ru.yandex.wmconsole.data.info.MergedSitemapInfo;
import ru.yandex.wmconsole.data.sitemaps.SitemapSourceEnum;
import ru.yandex.wmconsole.data.wrappers.MergedSitemapInfoWrapper;
import ru.yandex.wmconsole.data.wrappers.SitemapInfoWrapper;
import ru.yandex.webmaster.viewer.sitemap.CurrentSitemapService;
import ru.yandex.wmconsole.servantlet.WMCAuthorizedHostOperationServantlet;
import ru.yandex.wmconsole.service.HostDbHostInfoService;
import ru.yandex.wmconsole.util.HostCollectionWrapper;
import ru.yandex.wmtools.common.error.InternalException;
import ru.yandex.wmtools.common.error.UserException;

/**
 * Сервантлет для отображения списка файлов sitemap и sitemapindex
 *
 * @author azakharov
 */
public class CurrentSitemapListServantlet extends WMCAuthorizedHostOperationServantlet {
    private static final String PARAM_SITEMAP = "sitemap";
    private static final String PARAM_SOURCE = "source";
    private static final String PARAM_INDEX = "index";

    private HostDbHostInfoService hostDbHostInfoService;
    private CurrentSitemapService currentSitemapService;

    @Override
    protected void doProcess(ServRequest req, @NotNull ServResponse res, long userId)
            throws UserException, InternalException {
        final Integer sitemapId = getIntParam(req, PARAM_SITEMAP);
        final Integer src = getIntParam(req, PARAM_SOURCE);
        final SitemapSourceEnum source = src != null ? SitemapSourceEnum.R.fromValueOrNull(src) : null;
        final Long indexId = getLongParam(req, PARAM_INDEX);

        BriefHostInfo briefHostInfo = getHostInfoAndVerify(req, userId);
        final HostDbHostInfo hostDbHostInfo = hostDbHostInfoService.getHostDbHostInfo(briefHostInfo.getName());
        if (sitemapId != null && source != null) {
            showSitemapsForSitemapIndex(req, res, briefHostInfo, hostDbHostInfo, sitemapId, source, indexId);
        } else {
            showSitemaps(req, res, briefHostInfo, hostDbHostInfo);
        }
    }

    /**
     *
     * @param req
     * @param res
     * @param briefHostInfo
     * @param hostDbHostInfo
     * @param sitemapId
     * @param source
     * @param indexId идентификатор родительского sitemapindex.
     *                нужен на случай sitemapindex, содержащего другой sitemapindex, cодержимое которого мы смотрим
     * @throws InternalException
     * @throws UserException
     */
    private void showSitemapsForSitemapIndex(final ServRequest req,
                                             @NotNull final ServResponse res,
                                             final BriefHostInfo briefHostInfo,
                                             final HostDbHostInfo hostDbHostInfo,
                                             final long sitemapId,
                                             final SitemapSourceEnum source,
                                             final Long indexId) throws InternalException, UserException {
        Pager pager = createOutputStrategy(req).createPager();

        final Collection<MergedSitemapInfo> sitemapInfos;
        final MergedSitemapInfo rootElement;
        if (SitemapSourceEnum.LATEST == source) {
             rootElement = currentSitemapService.getSitemapInfo(hostDbHostInfo, sitemapId, indexId);
             sitemapInfos = currentSitemapService.getSitemapListChildren(
                     hostDbHostInfo, pager, new OrderByClause(req), sitemapId);
        } else {
            // содержимое смотрим только по последней загруженной версии
            throw new UnsupportedOperationException(
                    "Unsupported source value " + source + ". Only " + SitemapSourceEnum.LATEST + " allowed");
        }

        if (rootElement != null) {
            res.addData(new MergedSitemapInfoWrapper(rootElement, "root-element"));
        }

        final Collection<SitemapInfoWrapper> sitemapWrappers = new LinkedList<SitemapInfoWrapper>();
        for (MergedSitemapInfo info : sitemapInfos) {
            sitemapWrappers.add(new MergedSitemapInfoWrapper(info, false, info.getSource()));
        }

        res.addData(new HostCollectionWrapper(sitemapWrappers, briefHostInfo));
        res.addData(pager);
    }

    private void showSitemaps(final ServRequest req, @NotNull final ServResponse res, final BriefHostInfo briefHostInfo,
                              final HostDbHostInfo hostDbHostInfo) throws InternalException, UserException {
        Pager pager = createOutputStrategy(req).createPager();

        Collection<SitemapInfoWrapper> sitemapWrappers = new ArrayList<SitemapInfoWrapper>();
        for (MergedSitemapInfo info : currentSitemapService.getSitemapUnion(hostDbHostInfo, pager, new OrderByClause(req))) {
            sitemapWrappers.add(new MergedSitemapInfoWrapper(info, false, info.getSource()));
        }

        res.addData(new HostCollectionWrapper(sitemapWrappers, briefHostInfo));
        res.addData(pager);
    }

    @Required
    public void setHostDbHostInfoService(HostDbHostInfoService hostDbHostInfoService) {
        this.hostDbHostInfoService = hostDbHostInfoService;
    }

    @Required
    public void setCurrentSitemapService(CurrentSitemapService currentSitemapService) {
        this.currentSitemapService = currentSitemapService;
    }
}
