/**
 * Copyright 2010 OpenEngSB Division, Vienna University of Technology
 *
 * Licensed 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.openengsb.core.workflow;

import static org.hamcrest.CoreMatchers.nullValue;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;

import java.io.File;
import java.util.HashMap;
import java.util.Map;

import junit.framework.Assert;

import org.apache.commons.io.FileUtils;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mockito;
import org.openengsb.core.common.Domain;
import org.openengsb.core.common.Event;
import org.openengsb.core.common.context.ContextCurrentService;
import org.openengsb.core.common.util.AliveState;
import org.openengsb.core.workflow.internal.WorkflowServiceImpl;
import org.openengsb.core.workflow.internal.dirsource.DirectoryRuleSource;
import org.openengsb.core.workflow.model.RuleBaseElementId;
import org.openengsb.core.workflow.model.RuleBaseElementType;

public class WorkflowServiceTest {

    public interface LogDomain extends Domain {
        void log(String string);
    }

    public class LogDomainMock implements LogDomain {
        private StringBuffer log = new StringBuffer();

        @Override
        public void log(String string) {
            log.append(string);
        }

        @Override
        public AliveState getAliveState() {
            return AliveState.OFFLINE;
        }
    }

    private WorkflowServiceImpl service;
    private RuleManager manager;
    private RuleListener listener;
    private DummyExampleDomain logService;

    @Before
    public void setUp() throws Exception {
        service = new WorkflowServiceImpl();
        setupRulemanager();
        service.setRulemanager(manager);
        service.setCurrentContextService(Mockito.mock(ContextCurrentService.class));
        setupDomains();
        listener = new RuleListener();
        service.registerRuleListener(listener);
    }

    private void setupRulemanager() throws RuleBaseException {
        manager = new DirectoryRuleSource("data/rulebase");
        ((DirectoryRuleSource) manager).init();
        manager.add(new RuleBaseElementId(RuleBaseElementType.Rule, "logtest"),
            "when\n Event ( contextId == \"test-context\")\n then \n example.doSomething(\"42\");");
    }

    private void setupDomains() {
        Map<String, Domain> domains = createDomainMocks();
        service.setDomainServices(domains);
    }

    private Map<String, Domain> createDomainMocks() {
        Map<String, Domain> domains = new HashMap<String, Domain>();
        logService = Mockito.mock(DummyExampleDomain.class);
        domains.put("example", logService);
        DummyNotificationDomain notification = Mockito.mock(DummyNotificationDomain.class);
        domains.put("notification", notification);
        return domains;
    }

    @After
    public void tearDown() throws Exception {
        File ruleDir = new File("data");
        while (ruleDir.exists()) {
            FileUtils.deleteQuietly(ruleDir);
        }
    }

    @Test
    public void testProcessEvent() throws Exception {
        Event event = new Event();
        service.processEvent(event);
    }

    @Test
    public void testProcessEventTriggersHelloWorld() throws Exception {
        Event event = new Event();
        service.processEvent(event);
        Assert.assertTrue(listener.haveRulesFired("hello1"));
    }

    @Test
    public void testUseLog() throws Exception {
        Event event = new Event("test-context");
        service.processEvent(event);
        Assert.assertTrue(listener.haveRulesFired("logtest"));
    }

    @Test
    public void testUseLogContent() throws Exception {
        Event event = new Event("test-context");
        service.processEvent(event);
        Mockito.verify(logService, Mockito.times(2)).doSomething(Mockito.anyString());
    }

    @Test
    public void addInvalidRule_shouldNotModifyRulebase() throws Exception {
        try {
            manager.add(new RuleBaseElementId(RuleBaseElementType.Rule, "hello"), "this*is_invalid");
            fail("expected Exception");
        } catch (RuleBaseException e) {
            // expected
        }
        Event event = new Event("test-context");
        service.processEvent(event);
        Mockito.verify(logService, Mockito.times(2)).doSomething(Mockito.anyString());
    }

    @Test
    public void invalidMofidyRule_shouldNotModifyRulebase() throws Exception {
        try {
            manager.update(new RuleBaseElementId(RuleBaseElementType.Rule, "hello1"), "this*is_invalid");
            fail("expected Exception");
        } catch (RuleBaseException e) {
            assertThat(e.getCause(), nullValue());
        }
        Event event = new Event("test-context");
        service.processEvent(event);
        Mockito.verify(logService, Mockito.times(2)).doSomething(Mockito.anyString());
    }
}

@@ -670,140 +670,8 @@
 w;%0A%0A
-import static org.hamcrest.CoreMatchers.nullValue;%0Aimport static org.junit.Assert.assertThat;%0Aimport static org.junit.Assert.fail;%0A%0A
 impo
@@ -687,16 +687,16 @@
 o.File;%0A
+
 import j
@@ -1366,16 +1366,192 @@
 tType;%0A%0A
+import static org.mockito.Mockito.verify;%0A%0Aimport static org.hamcrest.CoreMatchers.nullValue;%0A%0Aimport static org.junit.Assert.assertThat;%0Aimport static org.junit.Assert.fail;%0A%0A
 public c
@@ -2147,16 +2147,66 @@
 Service;
+%0A    private DummyNotificationDomain notification;
 %0A%0A    @B
@@ -3314,32 +3314,8 @@
     
-DummyNotificationDomain 
 noti
@@ -4150,32 +4150,32 @@
 ssEvent(event);%0A
-
         Assert.a
@@ -4220,32 +4220,416 @@
 test%22));%0A    %7D%0A%0A
+    @Test%0A    public void testUpdateRule() throws Exception %7B%0A        manager.update(new RuleBaseElementId(RuleBaseElementType.Rule, %22hello1%22),%0A            %22when%5Cn Event ( contextId == %5C%22test-context%5C%22)%5Cn then %5Cn example.doSomething(%5C%2221%5C%22);%22);%0A        Event event = new Event(%22test-context%22);%0A        service.processEvent(event);%0A        verify(logService).doSomething(%2221%22);%0A    %7D%0A%0A
     @Test%0A    pu

add additional test for rule-update