/* Copyright (c) 2011 Peter Troshin
 *  
 *  JAva Bioinformatics Analysis Web Services (JABAWS) @version: 2.0     
 * 
 *  This library is free software; you can redistribute it and/or modify it under the terms of the
 *  Apache License version 2 as published by the Apache Software Foundation
 * 
 *  This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
 *  even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the Apache 
 *  License for more details.
 * 
 *  A copy of the license is in apache_license.txt. It is also available here:
 * @see: http://www.apache.org/licenses/LICENSE-2.0.txt
 * 
 * Any republication or derived work distributed in source code form
 * must include this copyright and license notice.
 */
package compbio.stat.servlet;

import java.io.IOException;
import java.io.PrintWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.sql.SQLException;
import java.util.Date;
import java.util.Map;
import java.util.Calendar;
import java.text.SimpleDateFormat;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import compbio.engine.conf.PropertyHelperManager;
import compbio.stat.collector.StatDB;
import compbio.stat.servlet.util.*;
import compbio.util.PropertyHelper;
import compbio.util.Util;

import org.apache.log4j.Logger;

public class AnnualStat extends HttpServlet {

    private static final Logger log = Logger.getLogger(AnnualStat.class);

    private static PropertyHelper ph = PropertyHelperManager.getPropertyHelper();

    private final Scheduler scheduler = new Scheduler();

    private static int getIntProperty(String propValue) {
        int value = 0;
        if (!Util.isEmpty(propValue)) {
            propValue = propValue.trim();
            value = Integer.parseInt(propValue);
        }
        return value;
    }

    static int refreshUsageStatsFrequency() {
        return getIntProperty(ph.getProperty("local.usage.stats.refresh.frequency"));
    }

    @Override
    public void init() {
        // startup the scheduler with current time
        int hour = Calendar.getInstance().get(Calendar.HOUR_OF_DAY);
        int min = Calendar.getInstance().get(Calendar.MINUTE);
        int sec = Calendar.getInstance().get(Calendar.SECOND);
        // refresh sleep time (in between requests) - minutes
        final int refresh_freq = refreshUsageStatsFrequency();

        scheduler.schedule(new SchedulerTask() {
            public void run() {
                refreshCache();
            }

            private void refreshCache() {
                hitEndpointForRefresh();
                log.info("Refreshing the In Memory Cache...");
                log.info(String.format("Refreshing again in %d minutes", refresh_freq));
            }
        }, new RefreshIterator(hour, min, sec, refresh_freq));
    }

    public void clearContextCache() {
        // try remove the current values from the context
        try {
            this.getServletConfig().getServletContext().removeAttribute("usageStatsResults");
            this.getServletConfig().getServletContext().removeAttribute("usageStatsTimestamp");
            this.getServletConfig().getServletContext().removeAttribute("usageStatsStart");
            this.getServletConfig().getServletContext().removeAttribute("usageStatsEnd");
            log.info("In Memory Cache Cleared!");
        } catch (Exception e) {
            log.warn("In Memory Cache Not Cleared. Perhaps not available yet!");
        }
    }

    private void hitEndpointForRefresh() {
        String endpointURL;
        endpointURL = (String) this.getServletConfig().getServletContext().getAttribute("usageStatsURL");
        if (endpointURL != null){
            try {
                URL url = new URL(endpointURL);
                System.out.println(endpointURL);
                HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                connection.setRequestProperty("User-Agent", "JABAWS Usage Stats Refreshing the Context Cache");
                int status = connection.getResponseCode();
                log.info(String.format("Hitting %s with an internal user-agent! status code: %s",
                        endpointURL, status));
            } catch (IOException e) {
                log.warn("Something wrong when hitting " + endpointURL);
                log.warn(e);
            }
        }
    }

    public Map<Date, Totals> checkMonthlyTotals(HttpServletResponse resp) throws ServletException, IOException {

        try {
            System.out.println("Updating the Usage Stats In Memory Cache...");
            StatDB db = new StatDB();
            Date earliestRec = db.getEarliestRecord();
            if (earliestRec == null) {
                PrintWriter writer = resp.getWriter();
                writer.println("No statistics found in the database. Please allow "
                        + "at least one hour after a server start for the statistics "
                        + "collector to collect the data. ");
                writer.close();
                return null;
            }
            return StatCollection.getStats(earliestRec);
        } catch (SQLException e) {
            e.printStackTrace();
            throw new ServletException(e);
        }
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {

        Map<Date, Totals> monthlyTotals;
        String timeStamp = new String();
        long startTime;
        long endTime;
        String refresh_freq;

        // save the main caller URL in the context
        String url = new String();
        url = req.getRequestURL().toString();
        System.out.println("UR: " + url);
        this.getServletConfig().getServletContext().setAttribute("usageStatsURL", url);

        // check user-agent: this is a trick to get the cache refreshed periodically
        String useragent = new String();
        useragent = req.getHeader("user-agent");
        // check if there are values available in the context
        if (this.getServletConfig().getServletContext().getAttribute("usageStatsResults") == null ||
                useragent.equals("JABAWS Usage Stats Refreshing the Context Cache")) {

            // get stats from db
            startTime = System.nanoTime();
            monthlyTotals = checkMonthlyTotals(resp);
            endTime = System.nanoTime();
            if (monthlyTotals != null) {
                // try clear the previous values if any
                clearContextCache();
                // add the current values to the context
                this.getServletConfig().getServletContext().setAttribute("usageStatsResults", monthlyTotals);
                timeStamp = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss").format(
                        Calendar.getInstance().getTime());
                this.getServletConfig().getServletContext().setAttribute("usageStatsTimestamp", timeStamp);
                this.getServletConfig().getServletContext().setAttribute("usageStatsStart", startTime);
                this.getServletConfig().getServletContext().setAttribute("usageStatsEnd", endTime);
                refresh_freq = String.valueOf(refreshUsageStatsFrequency());
                this.getServletConfig().getServletContext().setAttribute("usageStatsRefreshFreq", refresh_freq);
            } else {
                return;
            }

        } else {
            // get last results available
            monthlyTotals = (Map<Date, Totals>) this.getServletConfig().getServletContext().getAttribute("usageStatsResults");
            timeStamp = (String) this.getServletConfig().getServletContext().getAttribute("usageStatsTimestamp");
            startTime = (Long) this.getServletConfig().getServletContext().getAttribute("usageStatsStart");
            endTime = (Long) this.getServletConfig().getServletContext().getAttribute("usageStatsEnd");
            refresh_freq = (String) this.getServletConfig().getServletContext().getAttribute("usageStatsRefreshFreq");
        }

        req.setAttribute("stat", monthlyTotals);
        req.setAttribute("total", Totals.sumOfTotals(monthlyTotals));
        req.setAttribute("timeexec", (endTime - startTime) / 1000000000);
        req.setAttribute("timestamp", timeStamp);
        req.setAttribute("refreshfreq", refresh_freq);
        RequestDispatcher dispatcher = req.getRequestDispatcher("statpages/MonthlySummary.jsp");
        req.setAttribute("isAdmin", isAdmin(req));
        dispatcher.forward(req, resp);

    }

    static boolean isAdmin(final HttpServletRequest request) {
        return request.isUserInRole("admin");
    }

}
