package at.ac.tuwien.sbc.valesriegler.xvsm.spacehelpers;

import at.ac.tuwien.sbc.valesriegler.common.Util;
import at.ac.tuwien.sbc.valesriegler.xvsm.AbstractXVSMConnector;
import org.mozartspaces.notifications.Notification;
import org.mozartspaces.notifications.NotificationListener;
import org.mozartspaces.notifications.Operation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.Serializable;
import java.util.Date;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

/**
 * 
 * The SpaceListener provides the {@link NotificationListener} interface.
 * <p />
 * In {@link SpaceListener#getEntries()} a method for reading the entities, that are normally expected from the notification,
 * must be supplied. Thus, it's possible in {@link SpaceListener#startHandlingAbsenceOfNotifications()} to start a timer and to
 * execute the actions, which are normally triggered by the notification, with space objects read from {@link SpaceListener#getEntries()}.
 * If {@link SpaceListener#lookAround} is true the timer periodically checks if the corresponding {@link at.ac.tuwien.sbc.valesriegler.xvsm.AbstractXVSMConnector#timeOflastOperation} is old enough (= the agent is idle for some time)
 * and possibly executes the action as a result.
 * 
 * @author Gregor Riegler <gregor DOT riegler AT gmail DOT com>
 *
 */
public abstract class SpaceListener implements NotificationListener {
	private static final Logger log = LoggerFactory
			.getLogger(SpaceListener.class);
	
	protected boolean lookAround = true;
	protected long timeout = 3000;

    protected SpaceAction spaceAction;

    public String name;
    public boolean noNotification;
    @Override
	public void entryOperationFinished(Notification arg0, Operation arg1,
			List<? extends Serializable> entries) {
		synchronized (AbstractXVSMConnector.lockObject) {
			AbstractXVSMConnector.timeOflastOperation.set(new Date().getTime());
			try {
//				log.info("I am running a notification now!");
				spaceAction.inNotification.set(true);
				spaceAction.onEntriesWritten(entries);
			} catch (Exception e) {
//				e.printStackTrace();
			}

		}
	}

	abstract List<? extends Serializable> getEntries() throws Exception;

    public SpaceAction getSpaceAction() {
        return spaceAction;
    }

	public void startHandlingAbsenceOfNotifications() {
		if(!lookAround || Util.runSimulation) return;
		AbstractXVSMConnector.timeOflastOperation.set(new Date().getTime() + 3500);
		
		Timer timer = new Timer();

		timer.schedule(new SpaceTask(), 3000, 3000);
	}
	
	class SpaceTask extends TimerTask {

		@Override
		public void run() {
			if(new Date().getTime()-timeout <= AbstractXVSMConnector.timeOflastOperation.get()) {
				return;
			}
			synchronized(AbstractXVSMConnector.lockObject) {
				try {
					AbstractXVSMConnector.timeOflastOperation.set(new Date().getTime());

					List<? extends Serializable> entries = getEntries();
					if(entries.size() != 0) {
                        log.info("Start '{}' task", name);
						log.info("{} entries in timer", entries.size());
						spaceAction.inNotification.set(false);
						spaceAction.onEntriesWritten(entries);
					}
				} catch (Exception e) {
					log.info(e.getMessage());
				}
				
			}
			
		}
	}
		
}
	
	

