package org.rmatil.sync.core.syncer.file;

import net.engio.mbassy.listener.Handler;
import org.rmatil.sync.core.eventbus.CreateBusEvent;
import org.rmatil.sync.event.aggregator.api.IEventListener;
import org.rmatil.sync.event.aggregator.core.events.IEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

/**
 * A local filesystem event listener which triggers the synchronizing
 * of these events one-by-one using the file syncer.
 * <p>
 * This listener must be invoked in a dedicated thread to ensure
 * that file system events can still be accepted (and blocking for the syncer to complete
 * resulting in lost file system events is avoided)
 * and handled even if the syncer is
 * not able to process them as fast as they occur.
 *
 * @see FileSyncer
 */
public class SyncFileChangeListener implements IEventListener, Runnable {

    protected static final Logger logger = LoggerFactory.getLogger(SyncFileChangeListener.class);

    protected          FileSyncer            fileSyncer;
    protected          BlockingQueue<IEvent> eventQueue;
    protected volatile boolean               isTerminated;

    /**
     * @param fileSyncer The file syncer propagate local file system events to other clients
     */
    public SyncFileChangeListener(FileSyncer fileSyncer) {
        this.fileSyncer = fileSyncer;
        this.eventQueue = new LinkedBlockingQueue<>();
        this.isTerminated = false;
    }

    @Handler
    public void handleBusEvent(CreateBusEvent createBusEvent) {
        logger.debug("Got (" + this.toString() + ") notified from event bus (createBusEvent): " + createBusEvent.getEvent().getEventName() + " for file " + createBusEvent.getEvent().getPath().toString());
        this.eventQueue.add(createBusEvent.getEvent());
    }

    @Override
    public void onChange(List<IEvent> events) {
        this.eventQueue.addAll(events);
    }

    @Override
    public void run() {
        try {
            while (! isTerminated) {
                IEvent headEvent = this.eventQueue.take();

                // an event which has been caused due to handling a conflict
                this.fileSyncer.sync(headEvent);
            }

        } catch (InterruptedException e) {
            logger.info("Got interrupted. Stopping to listen for file change events. FileSyncer will therefore not sync any change until this listener is restarted.");
            this.isTerminated = true;
        } catch (Exception e) {
            logger.error("Error in SyncFileChangeListener Thread. Message: " + e.getMessage(), e);
        }
    }

    public void shutdown() {
        this.isTerminated = true;
        Thread.currentThread().interrupt();
    }

}

@@ -2027,26 +2027,8 @@
 ) %7B%0A
-        try %7B%0A    
     
@@ -2052,24 +2052,42 @@
 rminated) %7B%0A
+            try %7B%0A
             
@@ -2268,27 +2268,33 @@
             
-%7D%0A%0A
+    %0A    
         %7D ca
@@ -2316,32 +2316,36 @@
 dException e) %7B%0A
+    
             logg
@@ -2500,32 +2500,36 @@
 %22);%0A            
+    
 this.isTerminate
@@ -2538,32 +2538,36 @@
 = true;%0A        
+  
+  
 %7D catch (Excepti
@@ -2566,32 +2566,36 @@
 (Exception e) %7B%0A
+    
             logg
@@ -2677,16 +2677,30 @@
 (), e);%0A
+            %7D%0A
         

Fix termination of SyncFileChangeListener if an error occurred