package ru.yandex.wmconsole.servantlet.support;

import javax.xml.bind.JAXBException;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

import org.springframework.beans.factory.annotation.Required;

import ru.yandex.common.framework.core.ServRequest;
import ru.yandex.common.framework.core.ServResponse;
import ru.yandex.webmaster.common.urltree.YandexSearchShard;
import ru.yandex.wmconsole.data.HostRobotDbInfo;
import ru.yandex.wmconsole.data.info.BriefHostInfo;
import ru.yandex.wmconsole.data.info.HostDbHostInfo;
import ru.yandex.wmconsole.servantlet.WMCAuthenticationServantlet;
import ru.yandex.wmconsole.service.HostDbHostInfoService;
import ru.yandex.wmconsole.service.LinksCacheService;
import ru.yandex.wmconsole.service.dao.TblRobotdbInfoDao;
import ru.yandex.wmconsole.service.dao.TblUrlTreesDao;
import ru.yandex.wmconsole.util.XmlUtil;
import ru.yandex.wmtools.common.error.InternalException;
import ru.yandex.wmtools.common.error.InternalProblem;
import ru.yandex.wmtools.common.error.UserException;
import ru.yandex.wmtools.common.error.UserProblem;

/**
 * User: azakharov
 * Date: 31.05.13
 * Time: 17:35
 */
public class TreeDatViewerServantlet extends WMCAuthenticationServantlet {
    private static final String PARAM_HOST = "host";

    private HostDbHostInfoService hostDbHostInfoService;
    private TblRobotdbInfoDao tblRobotdbInfoDao;
    private LinksCacheService linksCacheService;
    private TblUrlTreesDao tblUrlTreesDao;

    @Override
    protected void doProcess(ServRequest req, ServResponse res, long userId) throws UserException, InternalException {
        final BriefHostInfo hostInfo = getHostInfoService().getBriefHostInfoByIdOrName(
                getRequiredStringParam(req, PARAM_HOST));
        if (hostInfo == null) {
            throw new UserException(UserProblem.HOST_NOT_FOUND_IN_DATABASE, "Host not found in db");
        }
        final HostDbHostInfo hostDbHostInfo = hostDbHostInfoService.getHostDbHostInfo(hostInfo.getName());
        HostRobotDbInfo robotDbInfo = tblRobotdbInfoDao.getRobotDbInfo(hostDbHostInfo);
        final Integer preciseIndexCount = robotDbInfo.getIndexCount();
        final YandexSearchShard searchShard = tblUrlTreesDao.getOptimumShardId(hostDbHostInfo);
        final Long xmlIndexCountCount = linksCacheService.checkCacheAndGetIndexCount(hostDbHostInfo, searchShard);
        final IndexingEntitySource pagesInIndexSource =
                preciseIndexCount != null ? IndexingEntitySource.TREE_DAT : IndexingEntitySource.XML_SEARCH;
        final Integer preciseLinksCount = robotDbInfo.getLinksCount();
        final Long xmlLinksCount = linksCacheService.checkCacheAndGetLinksCount(hostDbHostInfo, searchShard);
        final IndexingEntitySource linksCountSource =
                preciseLinksCount != null ? IndexingEntitySource.TREE_DAT : IndexingEntitySource.XML_SEARCH;
        try {
            res.addData(
                    XmlUtil.xmlConvertable(
                            new TreeDatWrapper(
                                    pagesInIndexSource,
                                    preciseIndexCount,
                                    xmlIndexCountCount,
                                    linksCountSource,
                                    preciseLinksCount,
                                    xmlLinksCount)));
        } catch (JAXBException e) {
            throw new InternalException(InternalProblem.JAXB_MARSHALLING_ERROR, "", e);
        }
    }

    public static enum IndexingEntitySource {
        TREE_DAT,
        XML_SEARCH
    }

    @XmlRootElement(name = "host-data-source-info")
    public static class TreeDatWrapper {
        IndexingEntitySource pagesInIndexSource;
        Integer treeDatPagesInIndex;
        Long xmlsearchPagesInIndex;

        IndexingEntitySource linksCountSource;
        Integer treeDatLinksCount;
        Long xmlsearchLinksCount;

        // for JAXB
        public TreeDatWrapper() {
        }

        public TreeDatWrapper(IndexingEntitySource pagesInIndexSource,
                              Integer treeDatPagesInIndex,
                              Long xmlsearchPagesInIndex,
                              IndexingEntitySource linksCountSource,
                              Integer treeDatLinksCount,
                              Long xmlsearchLinksCount) {
            this.pagesInIndexSource = pagesInIndexSource;
            this.treeDatPagesInIndex = treeDatPagesInIndex;
            this.xmlsearchPagesInIndex = xmlsearchPagesInIndex;
            this.linksCountSource = linksCountSource;
            this.treeDatLinksCount = treeDatLinksCount;
            this.xmlsearchLinksCount = xmlsearchLinksCount;
        }

        @XmlElement(name = "index-count-source")
        public IndexingEntitySource getPagesInIndexSource() {
            return pagesInIndexSource;
        }

        public void setPagesInIndexSource(IndexingEntitySource pagesInIndexSource) {
            this.pagesInIndexSource = pagesInIndexSource;
        }

        @XmlElement(name = "precise-pages-in-index")
        public Integer getTreeDatPagesInIndex() {
            return treeDatPagesInIndex;
        }

        public void setTreeDatPagesInIndex(Integer treeDatPagesInIndex) {
            this.treeDatPagesInIndex = treeDatPagesInIndex;
        }

        @XmlElement(name = "xml-pages-in-index")
        public Long getXmlsearchPagesInIndex() {
            return xmlsearchPagesInIndex;
        }

        public void setXmlsearchPagesInIndex(Long xmlsearchPagesInIndex) {
            this.xmlsearchPagesInIndex = xmlsearchPagesInIndex;
        }

        @XmlElement(name = "links-count-source")
        public IndexingEntitySource getLinksCountSource() {
            return linksCountSource;
        }

        public void setLinksCountSource(IndexingEntitySource linksCountSource) {
            this.linksCountSource = linksCountSource;
        }

        @XmlElement(name = "precise-links-count")
        public Integer getTreeDatLinksCount() {
            return treeDatLinksCount;
        }

        public void setTreeDatLinksCount(Integer treeDatLinksCount) {
            this.treeDatLinksCount = treeDatLinksCount;
        }

        @XmlElement(name = "xml-links-count")
        public Long getXmlsearchLinksCount() {
            return xmlsearchLinksCount;
        }

        public void setXmlsearchLinksCount(Long xmlsearchLinksCount) {
            this.xmlsearchLinksCount = xmlsearchLinksCount;
        }
    }

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

    @Required
    public void setTblRobotdbInfoDao(TblRobotdbInfoDao tblRobotdbInfoDao) {
        this.tblRobotdbInfoDao = tblRobotdbInfoDao;
    }

    @Required
    public void setLinksCacheService(LinksCacheService linksCacheService) {
        this.linksCacheService = linksCacheService;
    }

    @Required
    public void setTblUrlTreesDao(TblUrlTreesDao tblUrlTreesDao) {
        this.tblUrlTreesDao = tblUrlTreesDao;
    }
}
