/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.apache.jena.graph.test;

import java.util.Iterator;
import java.util.List;

import org.apache.jena.graph.Graph ;
import org.apache.jena.graph.GraphListener ;
import org.apache.jena.graph.Triple ;

/**
 * These tests are for listeners that add or delete
 * other listeners.
 * It motivates the use of, e.g. CopyOnWriteArrayList
 * for storing listeners.
 */
public class TestRegisterGraphListener extends GraphTestBase {

	private ComeAndGoListener all[];
	private Graph graph;
	
	private static final class SimpleListener extends ComeAndGoListener {
		@Override
		void doSomeDamage() {}
	}

	abstract private static class ComeAndGoListener implements GraphListener {

		// Was I registered when start() was called, and have not been unregistered.
		boolean inPlay = false;
		// currently registered or not.
		boolean registered = false;
		boolean notified = false;
		void registerWith(Graph g) {
			registered= true;
		   g.getEventManager().register(this);	
		}
		void unregisterFrom(Graph g) {
			registered = false;
			inPlay = false;
			g.getEventManager().unregister(this);
		}
		void start() {
			if (registered) inPlay = true;
		}
		void check() {
			if (inPlay && !notified) fail("listener that was in-play was not notified of adding triple.");
		}
		
        @Override
        final public void notifyAddTriple(Graph g, Triple t) {
			notified = true;
			doSomeDamage();
		}
		abstract void doSomeDamage();
		
		@Override
        public void notifyAddArray(Graph g, Triple[] triples) {}
		@Override
        public void notifyAddGraph(Graph g, Graph added) {}
		@Override
        public void notifyAddIterator(Graph g, Iterator<Triple> it) {}
		@Override
        public void notifyAddList(Graph g, List<Triple> triples) {}
		@Override
        public void notifyDeleteArray(Graph g, Triple[] triples) {}
		@Override
        public void notifyDeleteGraph(Graph g, Graph removed) {}
		@Override
        public void notifyDeleteIterator(Graph g, Iterator<Triple> it) {}
		@Override
        public void notifyDeleteList(Graph g, List<Triple> L) {}
		@Override
        public void notifyDeleteTriple(Graph g, Triple t) {}
		@Override
        public void notifyEvent(Graph source, Object value) {}
		
	}
	public TestRegisterGraphListener(String name) {
		super(name);
	}
	
	private void testAddingTriple(int addMe, ComeAndGoListener ...allx) {
		graph = newGraph();
		all = allx;
		for (int i=0;i<addMe;i++) {
			all[i].registerWith(graph); 
		} // 4 is unregistered.
		for (ComeAndGoListener l:all) {
			l.start();
		}
		graph.add(triple("make a change" ));
		for (ComeAndGoListener l:all) {
			l.check();
		}
	}
	
	public void testAddOne() {
		testAddingTriple(2,
				new ComeAndGoListener(){
					@Override
					void doSomeDamage() {
						all[2].registerWith(graph);
					}},
				new SimpleListener(),
				new SimpleListener());
	}
	
	public void testDelete2nd() {
		testAddingTriple(3,
				new ComeAndGoListener(){
					@Override
					void doSomeDamage() {
						all[1].unregisterFrom(graph);
					}},
				new SimpleListener(),
				new SimpleListener());
	}
	public void testDelete1st() {
		testAddingTriple(3,
				new SimpleListener(),
				new ComeAndGoListener(){
					@Override
					void doSomeDamage() {
						all[0].unregisterFrom(graph);
					}},
				new SimpleListener());
	}
	public void testDeleteSelf() {
		testAddingTriple(3,
				new ComeAndGoListener(){
					@Override
					void doSomeDamage() {
						unregisterFrom(graph);
					}},
				new SimpleListener(),
				new SimpleListener());
	}
	public void testDeleteAndAddSelf() {
		testAddingTriple(3,
				new ComeAndGoListener(){
					@Override
					void doSomeDamage() {
						unregisterFrom(graph);
						registerWith(graph);
					}},
				new SimpleListener(),
				new SimpleListener());
	}

}
