package azkaban.test.trigger;

import static org.junit.Assert.*;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.joda.time.DateTime;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import azkaban.trigger.Condition;
import azkaban.trigger.ConditionChecker;
import azkaban.trigger.CheckerTypeLoader;
import azkaban.trigger.Trigger;
import azkaban.trigger.TriggerAction;
import azkaban.trigger.ActionTypeLoader;
import azkaban.trigger.TriggerException;
import azkaban.trigger.TriggerLoader;
import azkaban.trigger.TriggerLoaderException;
import azkaban.trigger.TriggerManager;
import azkaban.trigger.TriggerManagerException;
import azkaban.utils.Props;

public class TriggerManagerTest {
	
	private TriggerLoader triggerLoader;
	
	@Before
	public void setup() throws TriggerException, TriggerManagerException {
		triggerLoader = new MockTriggerLoader();
		
		
	}
	
	@After
	public void tearDown() {
		
	}
	
	@Test
	public void TriggerManagerSimpleTest() throws TriggerManagerException {

		
		Props props = new Props();
		props.put("trigger.scan.interval", 4000);
		TriggerManager triggerManager = new TriggerManager(props, triggerLoader);
		
		triggerManager.registerCheckerType(ThresholdChecker.type, ThresholdChecker.class);
		triggerManager.registerActionType(DummyTriggerAction.type, DummyTriggerAction.class);
		
		ThresholdChecker.setVal(1);
		
		triggerManager.insertTrigger(createDummyTrigger("test1", "triggerLoader", 10), "testUser");
		List<Trigger> triggers = triggerManager.getTriggers();
		assertTrue(triggers.size() == 1);
		Trigger t1 = triggers.get(0);
		t1.setResetOnTrigger(false);
		triggerManager.updateTrigger(t1, "testUser");
		ThresholdChecker checker1 = (ThresholdChecker) t1.getTriggerCondition().getCheckers().values().toArray()[0];
		assertTrue(t1.getSource().equals("triggerLoader"));
		
		Trigger t2 = createDummyTrigger("test2: add new trigger", "addNewTriggerTest", 20);
		triggerManager.insertTrigger(t2, "testUser");
		ThresholdChecker checker2 = (ThresholdChecker) t2.getTriggerCondition().getCheckers().values().toArray()[0];
		
		ThresholdChecker.setVal(15);
		try {
			Thread.sleep(2000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		assertTrue(checker1.isCheckerMet() == false);
		assertTrue(checker2.isCheckerMet() == false);
		assertTrue(checker1.isCheckerReset() == false);
		assertTrue(checker2.isCheckerReset() == false);
		
		try {
			Thread.sleep(2000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		assertTrue(checker1.isCheckerMet() == true);
		assertTrue(checker2.isCheckerMet() == false);
		assertTrue(checker1.isCheckerReset() == false);
		assertTrue(checker2.isCheckerReset() == false);
		
		ThresholdChecker.setVal(25);
		try {
			Thread.sleep(4000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		assertTrue(checker1.isCheckerMet() == true);
		assertTrue(checker1.isCheckerReset() == false);
		assertTrue(checker2.isCheckerReset() == true);
		
		triggers = triggerManager.getTriggers();
		assertTrue(triggers.size() == 1);
		
	}
	
	public class MockTriggerLoader implements TriggerLoader {

		private Map<Integer, Trigger> triggers = new HashMap<Integer, Trigger>();
		private int idIndex = 0;
		
		@Override
		public void addTrigger(Trigger t) throws TriggerLoaderException {
			t.setTriggerId(idIndex++);
			triggers.put(t.getTriggerId(), t);
		}

		@Override
		public void removeTrigger(Trigger s) throws TriggerLoaderException {
			triggers.remove(s.getTriggerId());
			
		}

		@Override
		public void updateTrigger(Trigger t) throws TriggerLoaderException {
			triggers.put(t.getTriggerId(), t);
		}

		@Override
		public List<Trigger> loadTriggers() {
			return new ArrayList<Trigger>(triggers.values());
		}

		@Override
		public Trigger loadTrigger(int triggerId)
				throws TriggerLoaderException {
			// TODO Auto-generated method stub
			return null;
		}

		@Override
		public List<Trigger> getUpdatedTriggers(long lastUpdateTime)
				throws TriggerLoaderException {
			// TODO Auto-generated method stub
			return null;
		}
		
	}
	
	private Trigger createDummyTrigger(String message, String source, int threshold) {
		
		Map<String, ConditionChecker> checkers = new HashMap<String, ConditionChecker>();
		ConditionChecker checker = new ThresholdChecker(ThresholdChecker.type, threshold);
		checkers.put(checker.getId(), checker);
		
		List<TriggerAction> actions = new ArrayList<TriggerAction>();
		TriggerAction act  = new DummyTriggerAction(message);
		actions.add(act);
		
		String expr = checker.getId() + ".eval()";
		
		Condition triggerCond = new Condition(checkers, expr);
		Condition expireCond = new Condition(checkers, expr);
		
		Trigger fakeTrigger = new Trigger(DateTime.now().getMillis(), DateTime.now().getMillis(), "azkaban", source, triggerCond, expireCond, actions);
		fakeTrigger.setResetOnTrigger(true);
		fakeTrigger.setResetOnExpire(true);
		
		return fakeTrigger;
	}

//	public class MockCheckerLoader extends CheckerTypeLoader{
//		
//		@Override
//		public void init(Props props) {
//			checkerToClass.put(ThresholdChecker.type, ThresholdChecker.class);
//		}
//	}
//	
//	public class MockActionLoader extends ActionTypeLoader {
//		@Override
//		public void init(Props props) {
//			actionToClass.put(DummyTriggerAction.type, DummyTriggerAction.class);
//		}
//	}

}
