package ru.yandex.wmconsole.servantlet.top;

import java.util.Collection;
import java.util.Date;
import java.util.LinkedList;
import java.util.Map;

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.wmconsole.data.info.BriefHostInfo;
import ru.yandex.wmconsole.data.info.HostDbHostInfo;
import ru.yandex.wmconsole.data.info.WMCTopInfo;
import ru.yandex.wmconsole.data.info.WMCTopInfoItem;
import ru.yandex.wmconsole.data.wrappers.WMCTopInfoItemWrapper;
import ru.yandex.wmconsole.data.wrappers.WMCTopInfoWrapper;
import ru.yandex.wmconsole.error.ClientException;
import ru.yandex.wmconsole.servantlet.BriefHostInfoHelper;
import ru.yandex.wmconsole.service.HostDbHostInfoService;
import ru.yandex.wmconsole.service.WMCCustomRegionService;
import ru.yandex.wmconsole.service.WMCTopInfoService;
import ru.yandex.wmconsole.util.HostElementWrapper;
import ru.yandex.wmtools.common.data.info.TotalsInfo;
import ru.yandex.wmtools.common.data.wrappers.DateWrapper;
import ru.yandex.wmtools.common.error.InternalException;
import ru.yandex.wmtools.common.servantlet.top.WMToolsQueriesInfoServantlet;
import ru.yandex.wmtools.common.service.RegionsTreeCacheService;
import ru.yandex.wmtools.common.util.XmlConvertableCollectionWrapper;
import ru.yandex.wmtools.common.util.XmlDataWrapper;

/**
 * @author avhaliullin
 */
public abstract class WMCAbstractQueriesInfoServantlet
        extends WMToolsQueriesInfoServantlet<HostDbHostInfo, WMCTopInfo, WMCTopInfoItem, TotalsInfo>
{
    public static class WMCTopInfoCorrespondence extends TopInfoCorrespondence {
        public WMCTopInfoCorrespondence() {
            put(WMCTopInfoItemWrapper.TAG_QUERY, WMCTopInfoService.FIELD_QUERY);
            put(WMCTopInfoItemWrapper.TAG_POSITION, WMCTopInfoService.FIELD_POSITION);
            put(WMCTopInfoItemWrapper.TAG_CLICKS, WMCTopInfoService.FIELD_CLICKS);
            put(WMCTopInfoItemWrapper.TAG_SHOWS, WMCTopInfoService.FIELD_SHOWS);
        }
    }

    private static final WMCTopInfoCorrespondence wmcCorr = new WMCTopInfoCorrespondence();

    private BriefHostInfoHelper hostInfoHelper;
    private RegionsTreeCacheService regionsTreeCacheService;
    protected WMCTopInfoService topInfoService;
    private HostDbHostInfoService hostDbHostInfoService;
    private WMCCustomRegionService customRegionService;


    @Override
    protected HostDbHostInfo getHostInfoType(ServRequest req, ServResponse res, long userId) throws ClientException, InternalException {

        BriefHostInfo briefHostInfo = hostInfoHelper.getHostInfo(req, true, userId, true, true, res, true, true);

        if (briefHostInfo == null) {
            return null;
        }
        return hostDbHostInfoService.getHostDbHostInfo(briefHostInfo.getName());
    }

    @Override
    protected void outputData(
            ServResponse res,
            final HostDbHostInfo hostDbHostInfo,
            final Map<Date, Boolean> dates,
            final Date selectedDate,
            final Integer selectedRegion,
            final Pager pager,
            final WMCTopInfo topInfo) {
        res.addData(new HostElementWrapper(WMCTopInfoWrapper.create(topInfo), hostDbHostInfo.getName()) {
            private static final String TAG_DATES = "dates";
            private static final String TAG_DATE = "date";
            private static final String TAG_SELECTED_DATE = "selected-date";
            private static final String TAG_SELECTED_REGION = "selected-region";
            @Override
            protected void doToXml(StringBuilder result) {
                super.doToXml(result);
                if (pager != null) {
                    pager.toXml(result);
                }
                Collection<XmlDataWrapper> wrappers = new LinkedList<XmlDataWrapper>();
                for (Map.Entry<Date, Boolean> entry : dates.entrySet()) {
                    wrappers.add(new TopDateWrapper(TAG_DATE, entry.getKey(), entry.getValue()));
                }
                new XmlConvertableCollectionWrapper(wrappers, TAG_DATES).toXml(result);
                putDateTag(result, TAG_SELECTED_DATE, selectedDate);
                putIntegerTag(result, TAG_SELECTED_REGION, selectedRegion);
            }
        });
    }

    public static class TopDateWrapper extends DateWrapper {
        private static final String TAG_ENABLED = "enabled";

        private boolean enabled;

        public TopDateWrapper(String tag, Date date, boolean enabled) {
            super(tag, date);
            this.enabled = enabled;
        }

        @Override
        protected void doToXml(StringBuilder result) {
            super.doToXml(result);
            putBooleanTag(result, TAG_ENABLED, enabled);
        }
    }

    @Override
    protected String getFieldShows() {
        return WMCTopInfoService.FIELD_SHOWS;
    }

    @Override
    protected String getFieldClicks() {
        return WMCTopInfoService.FIELD_CLICKS;
    }

    @Override
    public TopInfoCorrespondence getTopInfoCorrespondence() {
        return wmcCorr;
    }

    @Override
    public RegionsTreeCacheService getRegionsTreeCacheService() {
        return regionsTreeCacheService;
    }

    @Override
    protected WMCTopInfoService getTopInfoService() {
        return topInfoService;
    }

    @Override
    protected WMCCustomRegionService getCustomRegionService() {
        return customRegionService;
    }

    @Required
    public void setTopInfoService(WMCTopInfoService topInfoService) {
        this.topInfoService = topInfoService;
    }

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

    @Required
    public void setCustomRegionService(WMCCustomRegionService customRegionService) {
        this.customRegionService = customRegionService;
    }

    @Required
    public void setHostInfoHelper(BriefHostInfoHelper hostInfoHelper) {
        this.hostInfoHelper = hostInfoHelper;
    }

    @Required
    public void setRegionsTreeCacheService(RegionsTreeCacheService regionsTreeCacheService) {
        this.regionsTreeCacheService = regionsTreeCacheService;
    }
}
