//   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.usability.rules.patterns;

import java.util.List;

import com.google.common.collect.Lists;

import de.ugoe.cs.autoquest.usability.rules.patterns.visitors.ContainsEventVisitor;
import de.ugoe.cs.autoquest.usability.rules.patterns.visitors.ContainsInteractionPatternVisitor;
import de.ugoe.cs.autoquest.usability.rules.patterns.visitors.EndsWithEventVisitor;
import de.ugoe.cs.autoquest.usability.rules.patterns.visitors.EndsWithInteractionPatternVisitor;
import de.ugoe.cs.autoquest.usability.rules.patterns.visitors.StartsWithEventVisitor;
import de.ugoe.cs.autoquest.usability.rules.patterns.visitors.StartsWithInteractionPatternVisitor;
import de.ugoe.cs.autoquest.usability.taskmodel.filter.types.EventTargetFilter;
import de.ugoe.cs.autoquest.usability.taskmodel.filter.types.EventTypeFilter;
import de.ugoe.cs.autoquest.usability.taskmodel.filter.types.TaskTypeFilter;

/**
 * <p>
 * Helper class, which allows to create {@link InteractionPattern}s.
 * </p>
 * 
 * @author Alexander Deicke
 */
public class InteractionPatternBuilder {

    /**
     * 
     * <p>
     * Starts creation of new interaction pattern.
     * </p>
     * 
     * @return steps to create interaction pattern
     */
    public static SetConcernedTaskModelComponentStep newPattern() {
        return new Steps();
    }

    public static interface SetConcernedTaskModelComponentStep {

        public BuildPatternStep rootTask(TaskTypeFilter concernedNode);

    }

    public static interface BuildPatternStep {

        public StartsWithStep startsWithEvent(EventTypeFilter startsWithEventType);
        
        public StartsWithStep startsWithEvent(EventTypeFilter startsWithEventType, EventTargetFilter eventTarget);

        public StartsWithStep startsWithPattern(InteractionPattern endsWithPattern);

        public ContainsStep containsEvent(EventTypeFilter containsEventType);
        
        public ContainsStep containsEvent(EventTypeFilter containsEventType, EventTargetFilter eventTarget);

        public ContainsStep containsPattern(InteractionPattern containsPattern);

        public EndsWithStep endsWithEvent(EventTypeFilter endsWithEventType);
        
        public EndsWithStep endsWithEvent(EventTypeFilter endsWithEventType, EventTargetFilter eventTarget);

        public EndsWithStep endsWithPattern(InteractionPattern endsPattern);

        public BuildStep patternFinished();

    }

    public static interface StartsWithStep {

        public ContainsStep containsEvent(EventTypeFilter containsEventType);
        
        public ContainsStep containsEvent(EventTypeFilter containsEventType, EventTargetFilter eventTarget);

        public ContainsStep containsPattern(InteractionPattern containsPattern);

        public EndsWithStep endsWithEvent(EventTypeFilter endsWithEventType);
        
        public EndsWithStep endsWithEvent(EventTypeFilter endsWithEventType, EventTargetFilter eventTarget);

        public EndsWithStep endsWithPattern(InteractionPattern endsPattern);

        public BuildStep patternFinished();

    }

    public static interface ContainsStep {

        public EndsWithStep endsWithEvent(EventTypeFilter endsWithEventType);
        
        public EndsWithStep endsWithEvent(EventTypeFilter endsWithEventType, EventTargetFilter eventTarget);

        public EndsWithStep endsWithPattern(InteractionPattern endsPattern);

        public BuildStep patternFinished();
    }

    public static interface EndsWithStep {

        public BuildStep patternFinished();

    }

    public static interface BuildStep {

        public InteractionPattern build();

    }

    private static class Steps implements SetConcernedTaskModelComponentStep, BuildPatternStep,
        StartsWithStep, ContainsStep, EndsWithStep, BuildStep
    {

        private List<InteractionPatternVisitor> visitors = Lists.newArrayList();

        private TaskTypeFilter concernedNode;

        @Override
        public BuildPatternStep rootTask(TaskTypeFilter concernedNode) {
            this.concernedNode = concernedNode;
            return this;
        }

        @Override
        public StartsWithStep startsWithEvent(EventTypeFilter startsWithEventType) {
            this.visitors.add(new StartsWithEventVisitor(startsWithEventType, concernedNode));
            return this;
        }
        
		@Override
		public StartsWithStep startsWithEvent(
				EventTypeFilter startsWithEventType,
				EventTargetFilter startsWithEventTarget) {
            this.visitors.add(new StartsWithEventVisitor(startsWithEventType, startsWithEventTarget, concernedNode));
            return this;
		}

        @Override
        public StartsWithStep startsWithPattern(InteractionPattern startsWithPattern) {
            this.visitors.add(new StartsWithInteractionPatternVisitor(startsWithPattern,
                                                                      concernedNode));
            return this;
        }

        @Override
        public ContainsStep containsEvent(EventTypeFilter containsEventType) {
            this.visitors.add(new ContainsEventVisitor(containsEventType, concernedNode));
            return this;
        }

		@Override
		public ContainsStep containsEvent(EventTypeFilter containsEventType,
				EventTargetFilter containsEventTarget) {
            this.visitors.add(new ContainsEventVisitor(containsEventType, containsEventTarget ,concernedNode));
            return this;
		}
        
        @Override
        public ContainsStep containsPattern(InteractionPattern containsPattern) {
            this.visitors
                .add(new ContainsInteractionPatternVisitor(containsPattern, concernedNode));
            return this;
        }

        @Override
        public EndsWithStep endsWithEvent(EventTypeFilter endsWithEventType) {
            this.visitors.add(new EndsWithEventVisitor(endsWithEventType, concernedNode));
            return this;
        }
        
		@Override
		public EndsWithStep endsWithEvent(EventTypeFilter endsWithEventType,
				EventTargetFilter endsWithEventTarget) {
            this.visitors.add(new EndsWithEventVisitor(endsWithEventType, endsWithEventTarget ,concernedNode));
            return this;
		}

        @Override
        public EndsWithStep endsWithPattern(InteractionPattern endsWithPattern) {
            this.visitors
                .add(new EndsWithInteractionPatternVisitor(endsWithPattern, concernedNode));
            return this;

        }

        @Override
        public BuildStep patternFinished() {
            return this;
        }

        @Override
        public InteractionPattern build() {
            return new InteractionPattern(concernedNode, this.visitors);
        }

    }

}
