package ru.yandex.wmconsole.servantlet.hostlist;

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.collections.CollectionFactory;
import ru.yandex.webmaster.common.host.HostListService;
import ru.yandex.wmconsole.data.HostDataLoadingWrapper;
import ru.yandex.wmconsole.data.HostInfoStatusEnum;
import ru.yandex.wmconsole.data.UpdateStateEnum;
import ru.yandex.wmconsole.data.wrappers.HostInfoWrapper;
import ru.yandex.wmconsole.servantlet.WMCAuthenticationServantlet;
import ru.yandex.webmaster.common.host.HostNodeInfo;
import ru.yandex.wmtools.common.error.InternalException;
import ru.yandex.wmtools.common.error.UserException;
import ru.yandex.wmtools.common.util.XmlConvertableCollectionWrapper;
import ru.yandex.wmtools.common.util.XmlDataWrapper;

import java.net.IDN;
import java.util.List;
import java.util.Set;

/**
 * Site list servantlet
 *
 * User: azakharov
 * Date: 15.01.14
 * Time: 14:39
 */
public class HostListServantlet extends WMCAuthenticationServantlet {

    private HostListService hostListService;

    @Override
    protected void doProcess(ServRequest req, ServResponse res, long userId) throws UserException, InternalException {
        Pager pager = createOutputStrategy(req).createPager();
        List<HostNodeInfo> hostNodes = hostListService.getHostList(userId, pager);

        res.addData(XmlConvertableCollectionWrapper.wrap(hostNodes, HostNodeWrapper.class, "hostlist"));
        res.addData(pager);
    }

    public static class HostNodeWrapper extends XmlDataWrapper<HostNodeInfo> {
        private static final String TAG_NAME = "name";
        private static final String TAG_PUNYCODE_NAME = "punycode-name";
        private static final String TAG_VERIFICATION_STATE = "verification-state";

        private static final String TAG_URLS = "urls";
        private static final String TAG_INDEX_COUNT = "index-count";
        private static final String TAG_TCY = "tcy";
        private static final String TAG_VIRUSED = "virused";
        private static final String TAG_HOST_INFO_STATUS = "host-info-status";
        private static final String TAG_SPIDER_IP = "spider-ip";
        private static final String TAG_LAST_ACCESS = "last-access";
        private static final String TAG_SHOW_INDEX_INFO = "show-index-info";
        private static final String TAG_HOST_INFO_STATUS_DATE = "host-info-status-date";

        private static final String TAG_CHILDREN = "children";

        public HostNodeWrapper(HostNodeInfo data) {
            super(data, "host", "id", Long.toString(data.getHostId()));
        }

        @Override
        protected void doToXml(StringBuilder result) {
            putHostnameTag(result, TAG_NAME, data.getHostName());
            putTag(result, TAG_PUNYCODE_NAME, IDN.toASCII(data.getHostName()));
            if (data.getVerificationState() != null) {
                putTag(result, TAG_VERIFICATION_STATE, data.getVerificationState().toString());

                if (data.getVerificationState().isVerified()) {
                    final Boolean showIndexInfo = needShowIndexInfo(data);
                    if ((UpdateStateEnum.NEW.equals(data.getUpdateState())) || (UpdateStateEnum.FIRST_IN_PROGRESS.equals(data.getUpdateState()))) {
                        putTag(result, HostDataLoadingWrapper.TAG_DATA_LOADING, "");
                        putBooleanTag(result, TAG_SHOW_INDEX_INFO, showIndexInfo);
                        return;
                    }
                    // Если параметр "страниц в поиске" в кэше не нашелся, то он будет загружаться асинхронно
                    // и параметр "загружено" должен загружаться также асинхронно.
                    Long indexCount = data.getIndexCount();
                    if (indexCount == null) {
                        // urlCount и indexCount будут загружены асинхронно
                    } else {
                        long intUrlCount = data.getUrls() == null ? 0 : data.getUrls();
                        if (intUrlCount < indexCount) {
                            // заменяем загружено = в поиске
                            intUrlCount = indexCount;
                        }
                        putLongTag(result, TAG_URLS, intUrlCount);
                        putLongTag(result, TAG_INDEX_COUNT, indexCount);
                    }
                    putBooleanTag(result, TAG_VIRUSED, data.isVirused());
                    putIntegerTag(result, TAG_TCY, data.getTcy());
                    putDateTimeTag(result, TAG_LAST_ACCESS, data.getLastAccess());
                    HostInfoStatusEnum calcHostInfo = data.getCalculatedHostInfoStatus();
                    if (calcHostInfo != null) {
                        if (HostInfoStatusEnum.INTERNAL_ERROR == calcHostInfo) {
                            putTag(result, TAG_HOST_INFO_STATUS, HostInfoStatusEnum.WAITING.getShownName());
                        } else {
                            putTag(result, TAG_HOST_INFO_STATUS, calcHostInfo.getShownName());
                        }
                    }
                    if (HostInfoStatusEnum.ROBOTS_TXT.equals(calcHostInfo) ||
                            HostInfoStatusEnum.WAITING.equals(calcHostInfo) ||
                            HostInfoStatusEnum.FINISHED.equals(calcHostInfo)) {
                        putDateTimeTag(result, TAG_HOST_INFO_STATUS_DATE, data.getHostInfoStatusDate());
                    }
                    if (data.getSpiderIp() != null) {
                        putTag(result, TAG_SPIDER_IP, data.getSpiderIp());
                    }
                    if (showIndexInfo != null) {
                        putBooleanTag(result, TAG_SHOW_INDEX_INFO, showIndexInfo);
                    }
                }
            }

            XmlConvertableCollectionWrapper wrapper =
                    XmlConvertableCollectionWrapper.wrap(data.getChildren(), HostNodeWrapper.class, TAG_CHILDREN);
            wrapper.toXml(result);
        }

        private static Set<HostInfoStatusEnum> STATES_REQUIRE_INDEX_COUNT = CollectionFactory.set(
                HostInfoStatusEnum.ROBOTS_TXT,
                HostInfoStatusEnum.CONNECTION_FAILED,
                HostInfoStatusEnum.DNS_ERROR,
                HostInfoStatusEnum.DISALLOW);

        public static Boolean needShowIndexInfo(HostNodeInfo hostInfo) {
            if (STATES_REQUIRE_INDEX_COUNT.contains(hostInfo.getCalculatedHostInfoStatus()) &&
                    (hostInfo.getIndexCount() == null || hostInfo.getUrls() == null)) {
                return null;
            }

            return HostInfoWrapper.needShowIndexInfo(
                    hostInfo.getVerificationState(),
                    hostInfo.getUpdateState(),
                    hostInfo.getIndexCount(),
                    hostInfo.getUrls(),
                    hostInfo.getCalculatedHostInfoStatus());
        }
    }

    @Required
    public void setHostListService(HostListService hostListService) {
        this.hostListService = hostListService;
    }
}
