package be.iminds.ilabt.jfed.experiment.events;

import java.util.LinkedList;
import java.util.List;

/**
 * User: twalcari
 * Date: 1/11/2016
 * Time: 09:55
 */
public class ExperimentEventHandlerManager {

    private final List<ExperimentEventHandlerRecord<? extends ExperimentEvent>> experimentEventHandlerRecords =
            new LinkedList<>();


    public <T extends ExperimentEvent> void addExperimentEventHandler(
            ExperimentEventType<T> eventType,
            ExperimentEventHandler<T> experimentEventHandler) {

        experimentEventHandlerRecords.add(new ExperimentEventHandlerRecord<>(eventType, experimentEventHandler));
    }


    public void dispatch(ExperimentEvent experimentEvent) {
        for (ExperimentEventHandlerRecord<? extends ExperimentEvent> experimentEventHandlerRecord : experimentEventHandlerRecords) {

            if (isTypeOrSuperTypeOf(experimentEvent.getType(), experimentEventHandlerRecord.getEventType())){
                //noinspection unchecked
                experimentEventHandlerRecord.getExperimentEventHandler().handle(experimentEvent);
            }
        }
    }

    private static boolean isTypeOrSuperTypeOf(ExperimentEventType experimentEventType, ExperimentEventType handlerEventType) {
        do {
            if (experimentEventType == handlerEventType)
                return true;

            experimentEventType = experimentEventType.getSuperType();

        } while (experimentEventType != null);

        return false;


    }

    private static final class ExperimentEventHandlerRecord<T extends ExperimentEvent> {

        private final ExperimentEventType<T> eventType;
        private final ExperimentEventHandler<T> experimentEventHandler;

        public ExperimentEventHandlerRecord(ExperimentEventType<T> eventType, ExperimentEventHandler<T> experimentEventHandler) {
            this.eventType = eventType;
            this.experimentEventHandler = experimentEventHandler;
        }

        public ExperimentEventType<T> getEventType() {
            return eventType;
        }

        public ExperimentEventHandler getExperimentEventHandler() {
            return experimentEventHandler;
        }
    }


}
