/*
 * $Id: DocExpiredNotification.java,v 1.40 2008/04/17 10:01:00 marbobo Exp $
 * 
 * Copyright (c) Siemens AG 2008 
 *           (c) Universität Paderborn 2008 
 * Licensed under EUPL 1.1. 
 *
 * $Log: DocExpiredNotification.java,v $
 * Revision 1.40  2008/04/17 10:01:00  marbobo
 * + Velocity-Templates angepasst
 *
 * Revision 1.39  2008/02/12 09:34:01  korowa
 * Eine Möglichkeit für den Benutzer hinzugefügt die Emailsart auszuwählen(HTML oder Plaintext)
 *
 * Revision 1.38  2007/08/08 12:14:39  marbobo
 * + License-Funktionalität komplett umgeschrieben
 * + Bugfix bzgl. Beschreibungsfelder von Entitäten
 * + Bugfix mailing
 *
 * Revision 1.37  2006/10/09 12:19:25  marbobo
 * + Beim erhöhen der Zugriffsanzahl wird nicht mehr saveDocument aufgerufen
 *
 * Revision 1.36  2006/10/04 03:15:15  marbobo
 * + Vollständige Unterstützung für Templates implementiert
 * + Alles von Virtoweb auf ProCoBa umgestellt
 *
 * Revision 1.35  2006/07/17 13:04:03  lawern
 * Neuer typografiegewichteter Index und k-NN-Klassifikation aus meiner Diss.
 *
 * Revision 1.34  2006/07/12 12:21:51  marbobo
 * + Bugfix
 *
 * Revision 1.33  2005/12/15 15:28:51  marbobo
 * + Benutzername und Passwort für Mailserver implementiert
 *
 * Revision 1.32  2005/09/13 09:51:44  jonyp
 * cleaning the code
 *
 * Revision 1.31  2005/09/13 08:40:37  jonyp
 * added DBExceptions due to chance of method getDocumentId in VKCDocument
 *
 * Revision 1.30  2005/07/28 19:57:25  marbobo
 * + Template-Pfade angepasst
 *
 * Revision 1.29  2005/04/12 12:56:05  korowa
 * Neuer path für Velocity Engine gesetzt, Head.txt enthält jetzt die gemeinsame Eigenschaften
 * (header,css-Teil und importiertes Bild)die früher in jeder Mail- HTML-Datei  standen.
 *
 * Revision 1.28  2005/02/15 18:44:52  marbobo
 * + Unicode-Konforme E-Mails
 *
 * Revision 1.27  2005/02/10 14:45:06  marbobo
 * + Unicode-Anzeige bei Emails
 *
 * Revision 1.26  2005/02/08 15:48:48  jonyp
 * + try catch in main while-loop of run-method to force thread to run forever
 *
 * Revision 1.25  2005/01/28 15:32:19  jonyp
 * added some code to prevent dockeywords/docdescription to be null in hashmap for velocity
 *
 * Revision 1.24  2004/12/16 14:13:35  marbobo
 * + Weitere Umstellungen und Optimierungen bzgl. PreparedStatements
 *
 * Revision 1.23  2004/12/09 12:40:05  lawern
 * vergessene PreparedStatements geschlossen
 *
 * Revision 1.22  2004/12/07 21:37:04  marbobo
 * + Statement auf PreparedStatement umgestellt
 *
 * Revision 1.21  2004/11/24 13:01:15  lawern
 * Global "conn.setAutoCommit( false );" enfernt, weil überflüssig.
 *
 * Revision 1.20  2004/11/24 09:25:57  lawern
 * Hibernate ist VKC-Geschichte!
 *
 * Revision 1.19  2004/11/18 19:38:23  marbobo
 * + changed order of close-stmt to resultset/connect/session  in finally-blocks
 *
 * Revision 1.18  2004/11/10 15:02:48  koppy
 * Projektweite Überarbeitung von Error-Logs, Stacktraces,..
 *
 * Revision 1.17  2004/11/09 14:35:35  marbobo
 * + Umstellung von authorId auf publisherId
 * + Hinzufügen von AuthorName für Dokumente
 * + Nötwendige Änderungen betreffend AuthorName und PublisherId
 *
 * Revision 1.16  2004/10/21 14:45:25  marbobo
 * + CURRENT_TIME ersetzt mit java-Anweisung
 *
 * Revision 1.15  2004/09/20 10:23:54  koppy
 * Mailgenerierung überarbeitet
 *
 * Revision 1.14  2004/08/20 12:47:25  koppy
 * Mini Anpassung
 *
 * Revision 1.13  2004/07/20 08:28:18  jonyp
 * added copyright info + cvs log
 *
 * Revision 1.12  2004/06/27 17:21:28  marbobo
 * + Quellcode maintenance
 *
 * Revision 1.11  2004/06/22 13:20:19  lawern
 * Classify auf das Interface Classifier umgestellt.
 *
 * Revision 1.10  2004/06/20 21:41:40  marbobo
 * - Unnötige flush-Anweisungen entfernt
 * + Bugfixes
 *
 * Revision 1.8  2004/03/23 15:36:10  bigmac
 * getExpiredDocuments() und setDocExpired() aus VKCDocumentSerializer hierher verschoben
 *
 * Revision 1.6  2004/03/11 20:17:14  bigmac
 * Anpassungen an VKCUserSerializer
 *
 * Revision 1.5  2004/03/09 18:40:34  bigmac
 * Anpassungen an VKCSysParameterSerializer
 *
 * Revision 1.2  2004/03/02 23:05:42  bigmac
 * Anpassungen an VKCDocumentSerializer und VKCCategorySerializer
 *
 */
package vkc.messenger.mail;

import java.sql.Connection;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Timestamp;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Set;
import java.util.Vector;

import vkc.db.entities.VKCDocument;
import vkc.db.entities.VKCCategory;
import vkc.db.entities.VKCUser;
import vkc.db.helper.DBHelper;
import vkc.db.serializer.VKCCategorySerializer;
import vkc.db.serializer.VKCDocumentSerializer;
import vkc.db.serializer.VKCKeywordSerializer;
import vkc.db.serializer.VKCUserSerializer;
import vkc.exception.DBException;
import vkc.misc.VKCLogManager;
import vkc.search.Search;
import vkc.util.ServletUtils;
import vkc.util.StringUtils;
import vkc.util.VKCStringUtils;
import vkc.view.WebShare;
import vkc.view.bean.ResourceInfo;

/**
 * Klasse fuer die Benachrichtigung von ablaufenden Dokumenten
 * 
 * @author teng
 * 
 */
public class DocExpiredNotification extends NotificationMail {
    private String mailingTime;

    /**
     * 
     * @param mailingTime
     *            Time for checking expired documents and send notification
     *            mail. Format:"00:00:00"
     */
    public DocExpiredNotification(String time) {
        super();

        mailingTime = time;
    }

    public void run() {
        try {
            if (!init()) {
                VKCLogManager.errorLog(this, "1", "Init DocExpiredNotification failed...");

                return;
            }

            while (true) {

                try {

                    while (!isEnabled()) {
                        try {
                            sleep(5000);
                        } catch (InterruptedException iex) {
                            break;
                        }
                    }

                    if (debug) {
                        VKCLogManager.infoLog(this, "DocExpiredNotification checking expired documents...");
                    }

                    HashMap hm = getDoc();

                    if (hm != null) {
                        sendMail(hm);
                    }

                    try {
                        sleep(getSleepTime(mailingTime));
                    } catch (InterruptedException iex) {
                        break;
                    }

                } catch (Exception ex) {
                    VKCLogManager.errorLog(this, "1", "DocExpiredNotification thread caught exception -> continue execution", ex);
                    continue;
                }
            }
        } catch (Exception ex) {
            VKCLogManager.errorLog(this, "1", "run failed: " + ex.getMessage(), ex);
        }
    }

    /**
     * Gibt HashMap mit Key:publisherId als VKCUser, Value:Vector mit
     * VKCDocument zurueck.
     * 
     * @param notificationType
     * @return
     */
    private HashMap getDoc() {
        HashMap map = null;

        try {
            Collection c;
            c = getExpiredDocuments();

            if (c != null && !c.isEmpty()) {
                Iterator it = c.iterator();
                map = new HashMap();
                VKCDocument doc;
                Vector v;
                Integer publisherId;

                while (it.hasNext()) {
                    doc = (VKCDocument) it.next();
                    publisherId = doc.getPublisherId();

                    if (map.containsKey(publisherId)) {
                        ((Vector) map.get(publisherId)).add(doc);
                    } else {
                        v = new Vector();
                        v.add(doc);
                        map.put(publisherId, v);
                    }
                }
            }
        } catch (DBException dbex) {
        }

        return map;
    }

    /**
     * Setzt den Status der abgelaufenen Dokumente in der DB als abgelaufen und
     * gibt alle abgelaufenen Dokumente zurueck
     * 
     * @return alle abgelaufenen Dokumente
     * 
     * @throws DBException
     */
    private final static Collection getExpiredDocuments() throws DBException {
        String query = "SELECT documentId FROM Documents WHERE expires is not null AND flag <> " + VKCDocument.FLAG_EXPIRED + " AND flag <> " + VKCDocument.FLAG_DELETED + " AND expires < ?";
        Object[] params = {new Timestamp(System.currentTimeMillis())};
        Collection c = VKCDocumentSerializer.getDocumentsByQuery(query, params);

        if (c != null) {
            Iterator it = c.iterator();
            VKCDocument doc;

            while (it.hasNext()) {
                doc = (VKCDocument) it.next();
                setDocExpired(doc.getDocumentId());
            }
        }

        return c;
    }

    /**
     * Setzen das Status eines Dokument als abgelaufen
     * 
     * @param docId
     * 
     * @throws DBException
     */
    private static final void setDocExpired(Integer docId) throws DBException {
        Connection conn = null;
        PreparedStatement pStmt1 = null;
        PreparedStatement pStmt2 = null;
        ResultSet rs = null;

        try {
            conn = WebShare.database.getConnection();

            pStmt1 = conn.prepareStatement("UPDATE Documents SET flag = " + VKCDocument.FLAG_EXPIRED + " WHERE documentId = ?");
            pStmt1.setInt(1, docId.intValue());
            pStmt1.execute();

            // Abgelaufenes Dokument aus dem Suchindex entfernen
            Search.removeDocument(docId, true);

            // Classify-Index aktualisieren
            pStmt2 = conn.prepareStatement("SELECT categoryId FROM categoryDocuments WHERE documentId = ?");
            pStmt2.setInt(1, docId.intValue());
            rs = pStmt2.executeQuery();

            if (rs.next()) {
                VKCCategory category = VKCCategorySerializer.retrieveCategory(new Integer(rs.getInt("categoryId")), conn);
                WebShare.classifier.updateCategory(category);

                // veränderte Category-Keywords abspeichern
                VKCKeywordSerializer.saveKeywords(conn, category.getKeywords(), "CategoryKeywords", "categoryId", category.getCategoryId());
            }

            conn.commit();
        } catch (Exception e) {
            DBHelper.rollBack(conn);
            throw new DBException(e);
        } finally {
            DBHelper.close(rs);
            DBHelper.close(pStmt1);
            DBHelper.close(pStmt2);
            DBHelper.close(conn);
        }
    }

    /**
     * Berechnen wie lange dieser Thread schlafen soll
     * 
     * @param mailingTime
     * @return
     */
    private long getSleepTime(String mailingTime) {
        // Berechnen den Zeitpunkt fuer Mailing
        mailingTime += ".000";
        String currentDate = new Timestamp(System.currentTimeMillis()).toString().substring(0, 10);
        // Datum von heute
        Timestamp time = Timestamp.valueOf(currentDate + " " + mailingTime);
        long st = time.getTime() - System.currentTimeMillis();

        if (st < 1000) {
            return time.getTime() + 24L * 60L * 60L * 1000L - System.currentTimeMillis();
            // one day later
        }

        return st;
    }

    /**
     * 
     * @param authorDocs
     *            contains Key:Integer publisherId, Value:Vector with
     *            <code>VKCDocument</code>s
     * @return
     */
    private int sendMail(HashMap authorDocs) {
        int sendedMailCount = 0;

        VKCUser publisher = null;

        String subject;
        VKCUser user = null;
        String docTitle = "";
        String dateString;
        String authorName;
        String publisherEmail;

        String asciiText = "";
        String docDescription = null;
        String docKeywords = null;
        String docName = null;
        String categoryName = null;
        String categoryURL = null;
        Integer catId;
        Vector docInfos = null;

        HashMap map = authorDocs;
        Set keys = map.keySet();

        for (Iterator mapit = keys.iterator(); mapit.hasNext();) {
            // -------------- for one user --------------
            Integer userID = (Integer) mapit.next();

            try {
                user = VKCUserSerializer.retrieveUser(userID);
            } catch (DBException dbex) {
                continue;
            }

            recepient = VKCStringUtils.decodeXmlEntities(user.getEmail());
            language = user.getLanguage();

            subject = WebShare.resources.getMessage(language.getLocale(), "vkc.messenger.docsExpiredSubject");

            if (docInfos == null) {
                docInfos = new Vector();
            } else {
                docInfos.removeAllElements();
            }

            Vector v = (Vector) map.get(userID);
            // ----------- alle Dokumente fuer diesen User ------------------

            for (Iterator it = v.iterator(); it.hasNext();) {
                VKCDocument doc = (VKCDocument) it.next();

                catId = doc.getCategoryId();
                docTitle = doc.getTitle();

                if (docTitle != null && docTitle.length() > 0) {
                    subject += (" <" + VKCStringUtils.decodeXmlEntities(docTitle) + ">");
                }

                docDescription = doc.getDescription();
                docKeywords = doc.getKeywordsAsString();
                docName = doc.getName();

                try {
                    if (catId != null) {
                        categoryURL = vkc_rootURL + catURL + catId.intValue();
                        VKCCategory cat = VKCCategorySerializer.retrieveCategory(catId);

                        // create category name displayed
                        categoryName = cat.getName();
                        // inclusive all parent categories
                        Integer parent = cat.getParentCategoryId();

                        while (parent != null) {
                            cat = VKCCategorySerializer.retrieveCategory(parent);
                            categoryName = cat.getName() + "/" + categoryName;
                            parent = cat.getParentCategoryId();
                        }
                    } else {
                        continue;
                    }
                } catch (DBException dbex) {
                    if (debug) {
                        VKCLogManager.infoLog(this, "" + dbex);
                    }

                    continue;
                }

                dateString = doc.getPublished().toString();
                
                try {
                    publisher = VKCUserSerializer.retrieveUser(doc.getPublisherId());
                    authorName = doc.getAuthorName();

                    if (publisher.getShowEmail()) {
                        publisherEmail = publisher.getEmail();
                    } else {
                        publisherEmail = null;
                    }
                } catch (DBException dbex) {
                    VKCLogManager.errorLog(this, "", "VKCDocPublishMail.sendMail():", dbex);

                    continue;
                }

                createTemplateParser();

                if (plainTemplateParser != null || htmlTemplateParser != null) {
                    valueMap = new HashMap();

                    valueMap.put("docname", VKCStringUtils.filterUnicodeChars(docName));
                    valueMap.put("doctitle", VKCStringUtils.filterUnicodeChars(docTitle));
                    valueMap.put("date", dateString);
                    valueMap.put("authorname", VKCStringUtils.filterUnicodeChars(authorName));
                    valueMap.put("publishername", VKCStringUtils.filterUnicodeChars(publisher.getLastnameLabel()));
                    valueMap.put("categoryurl", categoryURL);
                    valueMap.put("categoryname", VKCStringUtils.filterUnicodeChars(categoryName));

                    if (!StringUtils.isEmpty(docKeywords)) {
                        valueMap.put("dockeywords", VKCStringUtils.filterUnicodeChars(docKeywords));
                    } else {
                        valueMap.put("dockeywords", "");
                    }

                    if (!StringUtils.isEmpty(docDescription)) {
                        valueMap.put("docdescription", VKCStringUtils.filterUnicodeChars(docDescription));
                    } else {
                        valueMap.put("docdescription", "");
                    }

                    if (publisherEmail != null) {
                        valueMap.put("email", publisherEmail);
                    }

                    docInfos.add(valueMap);
                }
            }// all documents ready

            // --------- data in the email body for this user is ready
            // -----------
            HashMap context = new HashMap();
            context.put("language", language.getShortName());
            context.put("adminEmail", senderAddr);
            context.put("docInfos", docInfos);
            context.put("fullname", VKCStringUtils.filterUnicodeChars(user.getFirstname() + " " + user.getLastname()));
            context.put("resources", new ResourceInfo(WebShare.resources, language.getLocale()));
            context.put("vkcstringutils", new VKCStringUtils());
            context.put("template", user.getTemplate().getName());

            if (plainTemplateParser != null) {
                plainTemplateParser.setContextData(context);
                String asciiPath = "templates/${template.name}/velocitytemplates/mail/doc_expired_notification.plain";
                asciiText = plainTemplateParser.createString(ServletUtils.replacePathVars(asciiPath, user));
            }

            String htmlText = null;

            if (htmlTemplateParser != null) {
                htmlTemplateParser.setContextData(context);
                String htmlPath = "templates/${template.name}/velocitytemplates/mail/doc_expired_notification.html";
                htmlText = htmlTemplateParser.createString(ServletUtils.replacePathVars(htmlPath, user));
            }

            try {
                if (debug) {
                    VKCLogManager.infoLog(this, "sending SMTPMail " + sendedMailCount + "...");
                }

                mailUtils.setUser(user);
                mailUtils.sendSMTPMailWithVKCLogo(senderAddr, recepient, subject, asciiText, htmlText, null, null, smtpServer, smtpUsername, smtpPassword);
                if(user.isEnableHtmlNotification()){
                    mailUtils.sendSMTPMailWithVKCLogo(senderAddr, recepient, subject, asciiText, htmlText, null, null, smtpServer, smtpUsername, smtpPassword);
                }else {
                    mailUtils.sendSMTPMail(senderAddr, recepient, subject, asciiText, null, null, null, smtpServer, smtpUsername, smtpPassword);
                }

                sendedMailCount++;
            } catch (Exception iex) {
                VKCLogManager.infoLog(this, "" + iex);
            }

            asciiText = null;
            plainTemplateParser = null;
            htmlTemplateParser = null;
            docInfos.removeAllElements();
        }

        return sendedMailCount;
    }
}