package ru.yandex.webmaster3.validator.xml;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;

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

import ru.yandex.webmaster3.core.WebmasterException;
import ru.yandex.webmaster3.core.http.Action;
import ru.yandex.webmaster3.core.http.ReadAction;
import ru.yandex.webmaster3.core.http.WebmasterErrorResponse;
import ru.yandex.webmaster3.core.metrics.Category;
import ru.yandex.webmaster3.core.validator.XmlValidatorSourceType;
import ru.yandex.webmaster3.validator.common.wsw.model.WswErrorDescription;

/**
 * @author leonidrom
 */
@ReadAction
@Category("validator")
public class ValidateXmlAction extends Action<ValidateXmlRequest, ValidateXmlResponse>  {
    private XmlParser xmlParser;
    private ValidationSourceResolver validationSourceResolver;

    @Override
    public ValidateXmlResponse process(ValidateXmlRequest request) throws WebmasterException {
        boolean userProxy = request.getUserId().isPresent();
        InputStream xmlStream;
        XmlValidatorSourceType xmlType = request.getXmlType();
        if (xmlType == XmlValidatorSourceType.RESOURCE || xmlType == XmlValidatorSourceType.FILE) {
            try {
                xmlStream = request.getXmlFile().getInputStream();
            } catch (IOException e) {
                throw new WebmasterException("Unable to read xml file from request",
                        new WebmasterErrorResponse.IllegalParameterValueResponse(getClass(), "xmlFile", null), e);
            }
        } else {
            try {
                xmlStream = validationSourceResolver.getSourceInputStreams(request.getXml(), xmlType, userProxy)[0];
            } catch (WebmasterException exp) {
                if (exp.getError().getClass().equals(WebmasterErrorResponse.SitaErrorResponse.class)) {
                    WebmasterErrorResponse.SitaErrorResponse error = (WebmasterErrorResponse.SitaErrorResponse) exp.getError();
                    return new ValidateXmlResponse.XmlDownloadingErrorResponse(error.getHttpCode());
                }
                throw exp;
            }
        }

        XmlValidatorSourceType xsdType = request.getXsdType();
        InputStream[] xsdStreams;
        if (xsdType == XmlValidatorSourceType.FILE) {
            InputStream xsdStream;
            try {
                xsdStream = request.getXsdFile().getInputStream();
            } catch (IOException e) {
                throw new WebmasterException("Unable to read xml file from request",
                        new WebmasterErrorResponse.IllegalParameterValueResponse(getClass(), "xmlFile", null), e);
            }

            xsdStreams = new InputStream[]{xsdStream};
        } else {
            try {
                xsdStreams = validationSourceResolver.getSourceInputStreams(request.getXsd(), xsdType, userProxy);
            } catch (WebmasterException exp) {
                if (exp.getError().getClass().equals(WebmasterErrorResponse.SitaErrorResponse.class)) {
                    WebmasterErrorResponse.SitaErrorResponse error = (WebmasterErrorResponse.SitaErrorResponse) exp.getError();
                    return new ValidateXmlResponse.XsdDownloadingErrorResponse(error.getHttpCode());
                }
                throw exp;
            }
        }

        var errors = new ArrayList<>(xmlParser.validate(xmlStream, xsdStreams));
        var wswErrorDescription = new WswErrorDescription(errors);
        var sb = new StringBuilder();
        switch (request.getOutputFormat()) {
            case XML:
                wswErrorDescription.toXml(sb);
                break;
            case JSON:
                wswErrorDescription.toJson(sb);
                break;
        }

        return new ValidateXmlResponse.NormalResponse(sb.toString());
    }

    @Required
    public void setXmlParser(XmlParser xmlParser) {
        this.xmlParser = xmlParser;
    }

    @Required
    public void setValidationSourceResolver(ValidationSourceResolver validationSourceResolver) {
        this.validationSourceResolver = validationSourceResolver;
    }
}
