package net.hyperic.sigar.win32;

import java.io.IOException;
import java.util.Collections;
import java.util.HashSet;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Set;

import org.apache.log4j.Logger;

/**
 * A simple thread that runs forever monitoring the event log.
 */
public class EventLogThread implements Runnable {

    public static final int DEFAULT_INTERVAL = 60 * 1000;

    private static Logger logger =
        Logger.getLogger(EventLogThread.class.getName());

    private Thread thread = null;
    private static EventLogThread instance = null;
    private boolean shouldDie = false;
    private Set notifiers     = Collections.synchronizedSet(new HashSet());

    private String logName = "Application";
    private long interval  = 10 * 1000; // Default to 10 seconds

    public static synchronized EventLogThread getInstance() {
        if (instance == null) {
            instance = new EventLogThread();
        }

        return instance;
    }

    public void setInterval(long interval) {
        this.interval = interval;
    }

    public void setLogName(String logName) {
        this.logName = logName;
    }
    
    public synchronized void doStart() {
        if (this.thread != null) {
            return;
        }

        this.thread = new Thread(this, "EventLogThread");
        this.thread.setDaemon(true);
        this.thread.start();

        logger.debug(this.thread.getName() + " started");
    }

    public synchronized void doStop() {
        if (this.thread == null) {
            return;
        }
        die();
        this.thread.interrupt();
        logger.debug(this.thread.getName() + " stopped");
        this.thread = null;
    }

    public void add(EventLogNotification notifier) {
        this.notifiers.add(notifier);
    }

    public void remove(EventLogNotification notifier) {
        this.notifiers.remove(notifier);
    }

    private void handleEvents(EventLog log, int curEvent, int lastEvent)
    {
        for (int i = curEvent + 1; i <= lastEvent; i++) {

            EventLogRecord record;

            try {
                record = log.read(i);
            } catch (Win32Exception e) {
                logger.error("Unable to read event id " + i + ": " + e);
                continue;
            }

            synchronized (this.notifiers) {
                for (Iterator it = this.notifiers.iterator(); it.hasNext();)
                {
                    EventLogNotification notification =
                        (EventLogNotification)it.next();
                    if (notification.matches(record))
                        notification.handleNotification(record);
                }
            }
        }
    }

    public void run() {
        
        EventLog log = new EventLog();
        int curEvent;

        try {
            // Open the event log
            log.open(this.logName);

            curEvent = log.getNewestRecord();

            while (!shouldDie) {
                // XXX: Using the waitForChange() method would be a
                //      cleaner way to go, but we cannot interrupt
                //      a native system call.
                int lastEvent = log.getNewestRecord();
                if (lastEvent > curEvent) {
                    handleEvents(log, curEvent, lastEvent);
                }

                curEvent = lastEvent;

                try {
                    Thread.sleep(this.interval);
                } catch (InterruptedException e) {
                }
            }
            
            log.close();

        } catch (Win32Exception e) {
            logger.error("Unable to monitor event log:", e);
        } finally {
            try { log.close(); } 
            catch (Win32Exception e) {}}
    }

    public void die() {
        this.shouldDie = true;
    }

    public static void main(String[] args) {
        HashMap logs = new HashMap();
        if (args.length == 0) {
            args = new String[] {
                "System", "Application", "Security"
            };
        }

        EventLogNotification watcher =
            new EventLogNotification() {
                public boolean matches(EventLogRecord record) {
                    return true;
                }

                public void handleNotification(EventLogRecord record) { 
                    System.out.println(record);
                }
            };

        for (int i=0; i<args.length; i++) {
            String name = args[i];
            EventLogThread eventLogThread = 
                new EventLogThread();

            eventLogThread.setLogName(name);
            eventLogThread.doStart();
            eventLogThread.setInterval(1000);
            eventLogThread.add(watcher);
            logs.put(name, eventLogThread);
        }

        System.out.println("Press any key to stop");
        try {
            System.in.read();
        } catch (IOException e) { }

        for (Iterator it = logs.values().iterator();
             it.hasNext();)
        {
            EventLogThread eventLogThread =
                (EventLogThread)it.next();
            eventLogThread.doStop();
        }
    }
}

@@ -552,38 +552,36 @@
 tic 
-EventLogThread instance = null
+HashMap logs = new HashMap()
 ;%0A  
@@ -862,16 +862,27 @@
 nstance(
+String name
 ) %7B%0A    
@@ -889,111 +889,576 @@
     
-if (instance == null) %7B%0A            instance = new EventLogThread();%0A        %7D%0A%0A        return instance
+EventLogThread instance =%0A            (EventLogThread)logs.get(name);%0A%0A        if (instance == null) %7B%0A            instance = new EventLogThread();%0A            instance.setLogName(name);%0A            logs.put(name, instance);%0A        %7D%0A%0A        return instance;%0A    %7D%0A%0A    public static synchronized void closeInstances() %7B%0A        for (Iterator it = logs.values().iterator();%0A             it.hasNext();)%0A        %7B%0A            EventLogThread eventLogThread =%0A                (EventLogThread)it.next();%0A            eventLogThread.doStop();%0A        %7D%0A        logs.clear()
 ;%0A  
@@ -4348,46 +4348,8 @@
 ) %7B%0A
-        HashMap logs = new HashMap();%0A
     
@@ -4971,36 +4971,32 @@
                 
-new 
 EventLogThread()
@@ -4997,49 +4997,19 @@
 read
-();%0A%0A            eventLogThread.setLogNam
+.getInstanc
 e(na
@@ -5005,32 +5005,33 @@
 Instance(name);%0A
+%0A
             even
@@ -5143,52 +5143,8 @@
 r);%0A
-            logs.put(name, eventLogThread);%0A
     
@@ -5296,224 +5296,40 @@
     
-for (Iterator it = logs.values().iterator();%0A             it.hasNext();)%0A        %7B%0A            EventLogThread eventLogThread =%0A                (EventLogThread)it.next();%0A            eventLogThread.doStop();%0A        %7D
+EventLogThread.closeInstances();
 %0A   

change getInstance to take arg for name of the log