/*
 * $Id: UserDocMailsPopulator.java,v 1.5 2007/08/08 12:14:39 marbobo Exp $
 *
 * Copyright (c) Siemens AG 2008 
 *           (c) Universität Paderborn 2008 
 * Licensed under EUPL 1.1. 
 * 
 * Created on 16.08.2004
 *
 * $Log: UserDocMailsPopulator.java,v $
 * Revision 1.5  2007/08/08 12:14:39  marbobo
 * + License-Funktionalität komplett umgeschrieben
 * + Bugfix bzgl. Beschreibungsfelder von Entitäten
 * + Bugfix mailing
 *
 * Revision 1.4  2006/06/13 02:13:34  marbobo
 * + Unterstützung für Rollback-Operationen implementiert (korrigiert) - bzgl. Benachrichtigung
 *
 * Revision 1.3  2005/09/13 00:20:11  marbobo
 * + Unterstützung für Rollback-Operationen implementiert
 *
 * Revision 1.2  2004/11/10 15:02:48  koppy
 * Projektweite Überarbeitung von Error-Logs, Stacktraces,..
 *
 * Revision 1.1  2004/08/20 12:50:49  koppy
 * Klasse zur Überprüfung/zum Hinzufügen neuer UserDocMails:
 * Diese werden zunächst gepuffert und in einem
 * konfigurierbaren Zeitabstand(Email->Benachrichtigungscheck)
 * abgearbeitet...
 *
 */
package vkc.messenger.mail;

import java.util.Vector;

import vkc.db.entities.VKCDocument;
import vkc.db.serializer.VKCSysParameterSerializer;
import vkc.exception.DBException;
import vkc.misc.VKCLogManager;
import vkc.view.WebShare;

/**
 * This thread runs in the background
 * and is responsible for populating user doc mails
 * on new published documents.
 * @author Andreas Koop
 */
public class UserDocMailsPopulator extends Thread{
    private static final UserDocMailsPopulator instance = new UserDocMailsPopulator();
    
    /**
     * List of documents(of type VKCDocument)
     * to be populated
     */
    private Vector outstandingDocuments = new Vector();
    private Vector prepareOutstandingDocuments = new Vector();
    
    private UserDocMailsPopulator() {
        this.setPriority(Thread.MIN_PRIORITY);
        this.setDaemon(true);
    }
    
    public static UserDocMailsPopulator getInstance() {
        return instance;
    }
    
    
    /**
     * Kurze Anmerkung: Die Implementierung wäre besser
     * mit Hilfe der Klassen Timer, TimerTask.
     * Da sich die Periode jedoch ändern kann,
     * ist diese bescheidene Implementierung
     * (mit den zahlreichen Millis) gewählt worden. 
     * 
     * @see java.lang.Runnable#run()
     */
    public void run() {
        // Am Anfang eine kleine Verzögerung...
        try {
            Thread.sleep(1000 * 60 * 2);
        } catch (InterruptedException e1) {
            Thread.currentThread().interrupt();

            return;    
        }
        
        long startTime = 0;
        long periodMillis = 0;
        long remainingMillis = 0;
        
        while (true) {
            try {
                startTime = System.currentTimeMillis();
                periodMillis = 1000L * 60L * VKCSysParameterSerializer.retrieveIntValue("MAIL", "NotificationCheckPeriod", 10);
                
                if (outstandingDocuments.isEmpty()) {
                    try {
                        Thread.sleep(periodMillis);
                    } catch (InterruptedException e2) {
                        Thread.currentThread().interrupt();
                        
                        return;
                    }
                    
                    continue;
                }
                
                int userDocMailCount = 0;
                
                while (!outstandingDocuments.isEmpty()) {
                    VKCDocument doc = (VKCDocument)outstandingDocuments.remove(0);
                    
                    userDocMailCount += MailManager.getMailManager().populateUserDocMails(doc);
                    
                }
               
                if (userDocMailCount > 0) {
    				WebShare.docPublishMail.wakeUp();
                }
            } catch (DBException e) {
                VKCLogManager.errorLog(this, "", e.getMessage(), e);
            }
            
            remainingMillis = periodMillis - (System.currentTimeMillis() - startTime); 

            if (remainingMillis <= 0) {
            	continue;
            }
            
            try {
                Thread.sleep(remainingMillis);
            } catch (InterruptedException e2) {
                Thread.currentThread().interrupt();
            
                return;
            }
        }
    }
    
    /**
     * Neues Dokument hinzufügen
     * @param document
     */
    public void addForPopulation(VKCDocument document) {
        outstandingDocuments.add(document);
    }
    
    public void prepareForPopulation(VKCDocument document) {
    	prepareOutstandingDocuments.add(document);
    }
    
    public void removePreparedForPopulation(VKCDocument document) {
    	prepareOutstandingDocuments.remove(document);
    }
    
    public void completeOutstandingDocument(VKCDocument document) {
		int index = prepareOutstandingDocuments.indexOf(document);
		
		if (index != -1) {
			VKCDocument doc = (VKCDocument)prepareOutstandingDocuments.remove(index);
			outstandingDocuments.add(doc);
		}
    }
}