package ru.yandex.autotests.directapi.steps;

import java.io.StringReader;
import java.io.StringWriter;
import java.io.Writer;
import java.util.HashMap;
import java.util.Map;

import javax.xml.soap.SOAPMessage;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;

import freemarker.cache.ClassTemplateLoader;
import freemarker.cache.TemplateLoader;
import freemarker.template.Configuration;
import freemarker.template.DefaultObjectWrapper;
import freemarker.template.Template;
import org.apache.axis.MessageContext;
import org.apache.axis.handlers.BasicHandler;
import org.apache.commons.io.output.ByteArrayOutputStream;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import ru.yandex.autotests.directapi.apiclient.HttpMessage;
import ru.yandex.qatools.allure.annotations.Attachment;


/**
 * Created by IntelliJ IDEA.
 * User: mariabye
 * Date: 16.08.11
 * Time: 11:20
 * Axis logger for SOAP request/response
 * Turn on in config-client.wsdd
 */
public class LogHandler extends BasicHandler {
    public static final Log log4j = LogFactory.getLog(LogHandler.class);


    @Override
    public void init() {
        super.init();
    }

    @Override
    public void cleanup() {
        super.cleanup();
    }

    private static HttpMessage message;
    private static HttpMessage originMessage;

    @Override
    public void invoke(MessageContext mc) {
        if (mc.getResponseMessage() == null) {
            originMessage = new HttpMessage();
            originMessage.setRequest(getSOAPMessageAsStringForCurl(mc.getMessage()));
            originMessage.setUrl(mc.getProperty(MessageContext.TRANS_URL).toString());
            message = new HttpMessage();
            message.setUrl(mc.getProperty(MessageContext.TRANS_URL).toString());
            message.setRequest(getSOAPMessageAsString(mc.getMessage()));
        } else {
            message.setResponse(getSOAPMessageAsString(mc.getMessage()));
            message.setStatusCode(mc.getProperty("transport.http.statusCode").toString());
            log4j.trace(message);
            traceHttpMessage(message, originMessage);
        }
    }

    @Attachment(value = "[SOAP/CURL]: Request", type = "text/html")
    public String traceHttpMessage(HttpMessage message, HttpMessage originMessage) {
        Map root = new HashMap();
        root.put("usualFormatString", message.toString());
        root.put("curlString", originMessage.toCurlStringForSoap());
        root.put("buttonName", "SOAP");

        String attachmentHTML;
        try {
            TemplateLoader file = new ClassTemplateLoader(this.getClass(), "/");
            Configuration cfg = new Configuration();
            cfg.setTemplateLoader(file);
            cfg.setObjectWrapper(new DefaultObjectWrapper());
            cfg.setDefaultEncoding("UTF-8");
            Template template = cfg.getTemplate("request2curlTemplate.ftl");
            Writer fileWriter = new StringWriter();
            try {
                template.process(root, fileWriter);
            } finally {
                fileWriter.close();
            }
            attachmentHTML = fileWriter.toString();
        } catch (Exception e) {
            throw new RuntimeException("Error", e);
        }

        return attachmentHTML;
    }


    public static String getSOAPMessageAsString(SOAPMessage soapMessage) {
        try {
            TransformerFactory tff = TransformerFactory.newInstance();
            Transformer tf = tff.newTransformer();

            // Set formatting

            tf.setOutputProperty(OutputKeys.INDENT, "yes");
            tf.setOutputProperty("{http://xml.apache.org/xslt}indent-amount",
                    "2");

            ByteArrayOutputStream streamOut = new ByteArrayOutputStream();
            soapMessage.writeTo(streamOut);
            String response = streamOut.toString();
            streamOut.close();

            StringReader reader = new StringReader(response);
            StringWriter writer = new StringWriter();

            tf.transform(new StreamSource(reader), new StreamResult(writer));

            String strMessage = writer.toString();
            strMessage = strMessage.replaceAll("xmlns:soapenv=\"(.*?)\"", "");
            strMessage = strMessage.replaceAll("xmlns:SOAP-ENV=\"(.*?)\"", "");
            strMessage = strMessage.replaceAll("xmlns:SOAP-ENC=\"(.*?)\"", "");
            strMessage = strMessage.replaceAll("soapenv:encodingStyle=\"(.*?)\"", "");
            strMessage = strMessage.replaceAll("SOAP-ENV:encodingStyle=\"(.*?)\"", "");
            strMessage = strMessage.replaceAll("xmlns:xsi=\"(.*?)\"", "");
            strMessage = strMessage.replaceAll("xmlns:xsd=\"(.*?)\"", "");
            strMessage = strMessage.replaceAll("xmlns:soapenc=\"(.*?)\"", "");
            strMessage = strMessage.replaceAll("soapenv:actor=\"(.*?)\"", "");
            strMessage = strMessage.replaceAll("soapenv:mustUnderstand=\"(.*?)\"", "");
            strMessage = strMessage.replaceAll("xmlns:ns(\\d)=\"(.*?)\"", "");
            strMessage = strMessage.replaceAll("\" +", "\" ");
            strMessage = strMessage.replaceAll(" +>", ">");
            return strMessage;
        } catch (Exception e) {
            System.out.println("Exception in getSOAPMessageAsString "
                    + e.getMessage());
            return null;
        }

    }

    public static String getSOAPMessageAsStringForCurl(SOAPMessage soapMessage) {
        try {
            TransformerFactory tff = TransformerFactory.newInstance();
            Transformer tf = tff.newTransformer();

            // Set formatting

            tf.setOutputProperty(OutputKeys.INDENT, "yes");
            tf.setOutputProperty("{http://xml.apache.org/xslt}indent-amount",
                    "2");

            ByteArrayOutputStream streamOut = new ByteArrayOutputStream();
            soapMessage.writeTo(streamOut);
            String response = streamOut.toString();
            streamOut.close();

            StringReader reader = new StringReader(response);
            StringWriter writer = new StringWriter();

            tf.transform(new StreamSource(reader), new StreamResult(writer));
            return writer.toString();
        } catch (Exception e) {
            System.out.println("Exception in getSOAPMessageAsString "
                    + e.getMessage());
            return null;
        }

    }

}

