package eu.dnetlib.efg1914.various.servlet;

import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.StringReader;
import java.io.StringWriter;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;

import eu.dnetlib.efg1914.various.locales.MyLocale;
import eu.dnetlib.efg1914.various.utils.SetLocalesVariables;
import org.apache.commons.io.IOUtils;
import org.apache.log4j.Logger;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.runtime.RuntimeConstants;
import org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader;
import org.springframework.context.ApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

import eu.dnetlib.efg1914.authoring.components.dao.ConfigurationDAO;
import eu.dnetlib.efg1914.authoring.components.dao.FrameDAO;
import eu.dnetlib.efg1914.authoring.components.dao.ItemDAO;
import eu.dnetlib.efg1914.authoring.components.dao.ThemeDAO;
import eu.dnetlib.efg1914.authoring.components.dao.TopicDAO;
import eu.dnetlib.efg1914.various.managers.PageCreator;
import eu.dnetlib.efg1914.various.managers.components.ThemePage;

@SuppressWarnings("serial")
public class ThemeServlet extends HttpServlet {

    private ApplicationContext context = null;
    private Transformer transformer = null;

    private ThemeDAO themeDao = null;
    private TopicDAO topicDao = null;
    private FrameDAO frameDao = null;
    private ItemDAO itemDao = null;

    private String sourcePath = null;

    private ConfigurationDAO configurationDao = null;
    private String configurationName = null;

    // The String containing the name of the file that contains the code for
    // statistics
    private String trackingFileName = null;
    private String trackingFileContent = null;
    private InputStream is = null;
    private String locale = null;
    private String locale2 = null;
    private String showLanguages = null;

    private static Logger logger = Logger.getLogger(ThemeServlet.class);

    public void init(ServletConfig config) throws ServletException {
        super.init(config);
        context = WebApplicationContextUtils.getWebApplicationContext(getServletContext());
        setSourcePath((String) context.getBean("gridfsPath"));

        setItemDao((ItemDAO) context.getBean("itemDao"));
        setFrameDao((FrameDAO) context.getBean("frameDao"));
        setTopicDao((TopicDAO) context.getBean("topicDao"));
        setThemeDao((ThemeDAO) context.getBean("themeDao"));
        setTrackingFileName((String) context.getBean("trackingFileName"));

        setConfigurationDao((ConfigurationDAO) context.getBean("configurationDao"));
        setConfigurationName((String) context.getBean("configurationName"));
        setLocale((String) context.getBean("locale"));
        setLocale2((String) context.getBean("locale2"));

        is = this.getClass().getClassLoader().getResourceAsStream(trackingFileName);

        try {
            if (is != null) {
                trackingFileContent = IOUtils.toString(is);
                is.close();
            } else {
                trackingFileContent = "";
            }

        } catch (IOException e) {
            logger.warn("Could not load tracking file.", e);

        }
        setShowLanguages((String) context.getBean("showLanguages"));
        if (!(showLanguages.equals("true") || showLanguages.equals("false"))) {
            showLanguages = "false";
        }

    }

    @Override
    public void doGet(HttpServletRequest request, HttpServletResponse response) {
        PrintWriter writer = null;
        String id = request.getParameter("id");

        VelocityEngine ve = new VelocityEngine();
        ve.setProperty(RuntimeConstants.RESOURCE_LOADER, "classpath");
        ve.setProperty("classpath.resource.loader.class", ClasspathResourceLoader.class.getName());
        VelocityContext context = null;
        String lan = (String) request.getSession().getAttribute("language");
        if (lan == null || lan.isEmpty()) {
            request.getSession().setAttribute("language", locale);
            lan = (String) request.getSession().getAttribute("language");
        }
        if (id == null) {
            // TODO serve home page
            // throw new UnsupportedOperationException("Undefined action.");


        }

        try {
            ThemePage themePage = PageCreator.createThemePage(configurationDao, configurationName, id, themeDao, topicDao, frameDao, itemDao);

            if (!themePage.getTheme().isPublished()) {
                // TODO
            }

            response.setCharacterEncoding("UTF-8");
            writer = response.getWriter();

            // Create xsl transformer
            transformer = TransformerFactory.newInstance().newTemplates(new StreamSource(this.getClass().getClassLoader().getResourceAsStream("/eu/dnetlib/efg1914/various/servlet/theme.xsl"))).newTransformer();
            transformer.setParameter("currentId", id);
            transformer.setParameter("sourcePath", sourcePath);
            transformer.setParameter("trackingCode", trackingFileContent);

            logger.debug("SOURCE PATH " + sourcePath + "    " + transformer.getParameter("sourcePath"));

            String queryString = request.getQueryString();
            if (queryString == null) {
                transformer.setParameter("requestUrl", request.getRequestURL());
            } else {
                transformer.setParameter("requestUrl", request.getRequestURL().append('?').append(queryString).toString());
            }

            // Calculate menu
            Template t = ve.getTemplate("/eu/dnetlib/efg1914/various/servlet/menu.vm");
            StringWriter menuWriter = new StringWriter();
            context = new VelocityContext();
            context.put("current", "-1");
            context.put("sourcePath", sourcePath);
            context.put("collection", themePage.getCollection());
            context.put("currentId", id);
            try {
                MyLocale myLocale = new MyLocale(lan);

                transformer.setParameter("viewMore", myLocale.getValue("theme.viewMore"));
                transformer.setParameter("tooltip", myLocale.getValue("theme.tooltip"));
            } catch (IOException e) {
                e.printStackTrace();
            }
            SetLocalesVariables.setContextVariables(context, lan, locale, locale2, showLanguages);

            t.merge(context, menuWriter);

            // add menu in transformer
            transformer.setParameter("menu", menuWriter.toString());

            // load screen warning page
            StringWriter warningWriter = new StringWriter();
            IOUtils.copy(this.getClass().getClassLoader().getResourceAsStream("/eu/dnetlib/efg1914/various/servlet/screenSizeWarning.html"), warningWriter);

            // add screen warning in transformer
            transformer.setParameter("screenSizeWarning", warningWriter.toString());

            JAXBContext jaxbcontext = JAXBContext.newInstance(ThemePage.class);
            Marshaller marshaller = jaxbcontext.createMarshaller();
            marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");

            StringWriter stringWriter = new StringWriter();
            marshaller.marshal(themePage, stringWriter);

            transformer.transform(new StreamSource(new StringReader(stringWriter.toString().replaceAll("&#", "&amp;#"))), new StreamResult(writer));

            logger.debug("THEME xml" + stringWriter.toString());

        } catch (Exception e) {
            logger.error("Unable to load theme page for theme " + id, e);
            try {
                response.sendRedirect(request.getRequestURL().substring(0, request.getRequestURL().length() - request.getServletPath().length()) + "/welcome");
            } catch (IOException ioe) {
                logger.error("Unable to load main page ", ioe);
            }
        }
    }

    public String getLocale2() {
        return locale2;
    }

    public void setLocale2(String locale2) {
        this.locale2 = locale2;
    }

    public String getShowLanguages() {
        return showLanguages;
    }

    public void setShowLanguages(String showLanguages) {
        this.showLanguages = showLanguages;
    }

    public String getLocale() {
        return locale;
    }

    public void setLocale(String locale) {
        this.locale = locale;
    }

    public ThemeDAO getThemeDao() {
        return themeDao;
    }

    public void setThemeDao(ThemeDAO themeDao) {
        this.themeDao = themeDao;
    }

    public TopicDAO getTopicDao() {
        return topicDao;
    }

    public void setTopicDao(TopicDAO topicDao) {
        this.topicDao = topicDao;
    }

    public FrameDAO getFrameDao() {
        return frameDao;
    }

    public void setFrameDao(FrameDAO frameDao) {
        this.frameDao = frameDao;
    }

    public ItemDAO getItemDao() {
        return itemDao;
    }

    public void setItemDao(ItemDAO itemDao) {
        this.itemDao = itemDao;
    }

    public String getSourcePath() {
        return sourcePath;
    }

    public void setSourcePath(String sourcePath) {
        this.sourcePath = sourcePath;
    }

    public ConfigurationDAO getConfigurationDao() {
        return configurationDao;
    }

    public void setConfigurationDao(ConfigurationDAO configurationDao) {
        this.configurationDao = configurationDao;
    }

    public String getConfigurationName() {
        return configurationName;
    }

    public void setConfigurationName(String configurationName) {
        this.configurationName = configurationName;
    }

    public String getTrackingFileName() {
        return trackingFileName;
    }

    public void setTrackingFileName(String trackingFileName) {
        this.trackingFileName = trackingFileName;
    }

}
