package ru.yandex.wmconsole.servantlet.sitemaps;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.zip.GZIPInputStream;

import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import ru.yandex.wmtools.common.error.InternalException;
import ru.yandex.wmtools.common.error.InternalProblem;

/**
 * Построитель запроса к валидатору диспетчера
 */
public class SitemapRequestBuilder {
    private static final Logger log = LoggerFactory.getLogger(SitemapRequestBuilder.class);
    private static final String DATA_PARAM = "data=";

    private final ByteArrayOutputStream stream;
    private boolean redirected = false;

    public SitemapRequestBuilder() throws InternalException {
        this.stream = new ByteArrayOutputStream();
        try {
            this.stream.write(DATA_PARAM.getBytes());
        } catch (IOException e) {
            log.error("Unable to write to stream", e);
            throw new InternalException(InternalProblem.INTERNAL_PROBLEM, "can't write constant string to stream");
        }
    }

    public ByteArrayOutputStream getStream() {
        return stream;
    }

    public void setRedirected(boolean redirected) {
        this.redirected = redirected;
    }

    /**
     * Был ли редирект при скачивании sitemap
     */
    public boolean isRedirected() {
        return redirected;
    }

    public static boolean isGzipStream(byte[] bytes) {
        int head = ((int) bytes[0] & 0xff) | ((bytes[1] << 8) & 0xff00);
        return GZIPInputStream.GZIP_MAGIC == head;
    }

    public byte [] getBytesToSend() {
        byte [] actualData = stream.toByteArray();
        // Возможно у пользователя не установлен заголовок Content-Encoding gzip,
        // но сам файл sitemap в gzip-формате. Пытаемся проверить магическую последовательность байт
        if (actualData.length > DATA_PARAM.length() + 2 &&
            isGzipStream(Arrays.copyOfRange(actualData, DATA_PARAM.length(), DATA_PARAM.length() + 2))) {
            try {
                InputStream gzipInputStream = new GZIPInputStream(
                        new ByteArrayInputStream(Arrays.copyOfRange(actualData, DATA_PARAM.length(), actualData.length)));
                ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
                outputStream.write(DATA_PARAM.getBytes());
                IOUtils.copy(gzipInputStream, outputStream);
                return outputStream.toByteArray();
            } catch (IOException e) {
                log.error("Exception while uncompressing gzip file ", e);
                return actualData;
            }
        }
        return actualData;
    }

    public long getSitemapFileSize() {
        return stream.size() - DATA_PARAM.length();
    }
}
