//   Copyright 2012 Georg-August-Universität Göttingen, Germany
//
//   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 de.ugoe.cs.autoquest.plugin.usability2.rules.operator.wrapper;

import static org.fest.assertions.api.Assertions.assertThat;

import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;

import org.junit.Test;

import de.ugoe.cs.autoquest.plugin.html.commands.CMDparseHTML;
import de.ugoe.cs.autoquest.plugin.usability2.rules.operator.Follows;
import de.ugoe.cs.autoquest.plugin.usability2.rules.operator.IFilter;
import de.ugoe.cs.autoquest.plugin.usability2.rules.operator.Label;
import de.ugoe.cs.autoquest.plugin.usability2.rules.operator.filter.EventTypeFilter;
import de.ugoe.cs.autoquest.plugin.usability2.rules.operator.visitors.Contains;
import de.ugoe.cs.autoquest.plugin.usability2.rules.operator.visitors.FindContained;
import de.ugoe.cs.autoquest.plugin.usability2.rules.operator.wrapper.AbstractTaskEntryVisitor;
import de.ugoe.cs.autoquest.plugin.usability2.rules.operator.wrapper.FollowedByUtil;
import de.ugoe.cs.autoquest.plugin.usability2.rules.operator.wrapper.ITaskEntry;
import de.ugoe.cs.autoquest.plugin.usability2.rules.results.IMatch;
import de.ugoe.cs.autoquest.plugin.usability2.rules.results.IResult;
import de.ugoe.cs.autoquest.plugin.usability2.tools.TaskUtilities;
import de.ugoe.cs.autoquest.tasktrees.treeifc.IEventTaskInstance;
import de.ugoe.cs.autoquest.tasktrees.treeifc.ITask;
import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskInstance;
import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskModel;
import de.ugoe.cs.autoquest.usability.testutil.GenerateTaskModelUtil;

/**
 * <p>
 * Test of the FollowedBy Operator
 * </p>
 * 
 * @author Konni Hartmann
 */
public class PreparsingTest {

    private static Class<? extends ITaskInstance> task_instance_class = null;
    
    private static void extractTaskInstanceClass(ITaskInstance instance) {
        Class<? extends ITaskInstance> clazz = instance.getClass();
        
        while (!clazz.getSimpleName().equals("TaskInstance")) {
            Class<?> superclass = clazz.getSuperclass();
            if (ITaskInstance.class.isAssignableFrom(superclass)) {
                clazz = (Class<? extends ITaskInstance>) superclass;
            } else {
                clazz = null;
                break;
            }
        }
        
        if (clazz != null)
            task_instance_class = clazz;
    }
    
    private static int getInstanceID(ITaskInstance instance) {
        try {
            if(task_instance_class == null)
                extractTaskInstanceClass(instance);
            
            Field field = task_instance_class.getDeclaredField("id");
            field.setAccessible(true);
            return field.getInt(instance);
        }
        catch (IllegalArgumentException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        catch (IllegalAccessException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        catch (NoSuchFieldException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        catch (SecurityException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return -1;
    }
    
    static class TestVisitor extends AbstractTaskEntryVisitor {
        int indentionLevel = 0;

        @Override
        public void visitEntry(ITaskEntry value) {
            StringBuilder indent = new StringBuilder((indentionLevel - 1) * 2);
            for (int i = 1; i < indentionLevel; i++)
                indent.append("  ");
//            System.out.printf("%s%s -- R: %s P: %s N: %s\n", indent, value, value.getReference(),
//                              value.getParent(), value.getNext());
            System.out.printf("%s%s -- P: %s N: %s\n", indent, value, value.getParent(), value.getNext());
            
            List<ITaskInstance> filters = value.getAvailableFilters();
            for (ITaskInstance filter : filters) {
                System.out.printf("%s+ (#%s): %s\n", indent, getInstanceID(filter), value.getFilteredInstances(filter));
            }
            System.out.println();
        }

        @Override
        public void visit(ITaskEntry value) {
            indentionLevel++;
            super.visit(value);
            indentionLevel--;
        }
    }
    
    @Test
    public void contains_event_positive() {
        // Given
        String spec_session1 = 
                "UserSession {" + 
                "  Iteration it {" +
                "    Sequence s2 {" +
                "      MouseClick c1 { }" +
                "      Scroll scl { }" +
                "    }" +
                "    Sequence s2 {" +
                "      MouseClick c1 { }" +
                "      Scroll scl { }" +
                "    }" +
                "  }" +  
                "}";

        String spec_session2 = 
                "UserSession {" + 
                "  Iteration it {" + 
                "    Sequence s2 {" +
                "      MouseClick c1 { }" +
                "      Scroll scl { }" +
                "    }" +
                "  }" +  
                "}";

//        ITaskModel taskTree = GenerateTaskModelUtil.getTaskTreeFromFile("logs/log.xml", CMDparseHTML.class);
        ITaskModel taskTree = GenerateTaskModelUtil.getTaskModelFromSpec(spec_session1, spec_session2);
        Collection<ITask> tasks = taskTree.getTasks();
        GenerateInstanceListVisitor gILV = new GenerateInstanceListVisitor();
        
        // When

        for (ITask iTask : TaskUtilities.findRootTasks(tasks)) {
//            ITask iTask = root;
            ITaskEntry followTree = FollowedByUtil.generateFollowList(iTask);
            TestVisitor v = new TestVisitor();
            v.visit(followTree);
            
            for (List<IEventTaskInstance> sequence : followTree.getInstanceSequences()) {
                System.out.println(sequence);
            }
            
            System.out.println();
        }
        
        IFilter f = new Follows(new FindContained(new Label("X", EventTypeFilter.SCROLL)),
                                new Contains(new Label("Y", EventTypeFilter.MOUSE_CLICK))
        );

        IResult result = null;
        
        for (ITask root : TaskUtilities.findRootTasks(tasks)) {
            result = f.match(root);

            if(!result.isPresent())
                continue;

            System.out.println("\n>>RESULTS:");
            System.out.println(result.isPresent());
            for (IMatch m : result) {
                Map<String, ITask> map = m.getLabeledResults();
                System.out.println(">"+map);
            }

            Collection<List<IEventTaskInstance>> sequences = gILV.generateInstanceList(root);
            Collection<List<IEventTaskInstance>> matched = InstanceSequenceFinder.containsSequence(sequences, Arrays.asList(EventTypeFilter.SCROLL, EventTypeFilter.MOUSE_CLICK));
            
            System.out.printf("Found match in %d of %d instances.\n", matched.size(), sequences.size());
        }
      
        // Then
        assertThat(result).isNotNull();
        assertThat(result.isPresent()).isTrue();
    }
}
