package com.skillsoft.skillport.jbehave.selenium;

import static java.util.Arrays.asList;
import static org.jbehave.core.reporters.Format.CONSOLE;
import static org.jbehave.core.reporters.Format.HTML;
import static org.jbehave.core.reporters.Format.TXT;
import static org.jbehave.core.reporters.Format.XML;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.jbehave.core.Embeddable;
import org.jbehave.core.configuration.Configuration;
import org.jbehave.core.embedder.Embedder;
import org.jbehave.core.io.CodeLocations;
import org.jbehave.core.io.LoadFromClasspath;
import org.jbehave.core.io.StoryFinder;
import org.jbehave.core.junit.JUnitStories;
import org.jbehave.core.reporters.StoryReporterBuilder;
import org.jbehave.core.steps.InjectableStepsFactory;
import org.jbehave.core.steps.InstanceStepsFactory;
import org.jbehave.core.steps.SilentStepMonitor;
import org.jbehave.web.selenium.PerStorySeleniumSteps;
import org.jbehave.web.selenium.SeleniumConfiguration;
import org.jbehave.web.selenium.SeleniumContext;
import org.jbehave.web.selenium.SeleniumScreenshotOnFailure;
import org.jbehave.web.selenium.SeleniumStepMonitor;
import org.jbehave.web.selenium.SeleniumSteps;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Component;

import com.skillsoft.skillport.jbehave.selenium.steps.SkillPortSteps;
import com.skillsoft.skillport.jbehave.util.PropertiesLoader;
import com.thoughtworks.selenium.DefaultSelenium;
import com.thoughtworks.selenium.Selenium;
import com.thoughtworks.selenium.condition.ConditionRunner;

@Component
public class SkillPortStories extends JUnitStories {

	public static final String APPLICATION_PROPERTIES = "application.properties";
	public static final String STORY_LOCATION = CodeLocations
			.codeLocationFromClass(SkillPortStories.class).getFile()
			+ "/com/skillsoft/skillport/jbehave/selenium/stories";
	private Selenium selenium = new DefaultSelenium("localhost", 4444,
			PropertiesLoader
					.getPropertyValue(APPLICATION_PROPERTIES, "browser"),
			PropertiesLoader
					.getPropertyValue(APPLICATION_PROPERTIES, "baseurl"));
	private ConditionRunner conditionRunner = SeleniumConfiguration
			.defaultConditionRunner(selenium);
	private SeleniumSteps lifecycleSteps = new PerStorySeleniumSteps(selenium);
	private SeleniumContext seleniumContext = new SeleniumContext();
	@Autowired
	private List<SkillPortSteps> skillPortStepList;

	public SkillPortStories() {
		Embedder embedder = configuredEmbedder();
		embedder.embedderControls().useStoryTimeoutInSecs(600);
	}

	@Override
	public Configuration configuration() {
		Class<? extends Embeddable> embeddableClass = this.getClass();
		return new SeleniumConfiguration()
				.useSelenium(selenium)
				.useSeleniumContext(seleniumContext)
				.useStepMonitor(
						new SeleniumStepMonitor(selenium, seleniumContext,
								new SilentStepMonitor()))
				.useStoryLoader(new LoadFromClasspath(embeddableClass))
				.useStoryReporterBuilder(
						new StoryReporterBuilder()
								.withCodeLocation(
										CodeLocations
												.codeLocationFromClass(embeddableClass))
								.withDefaultFormats()
								.withFormats(CONSOLE, TXT, HTML, XML)
								.withFailureTrace(true)
								.withFailureTraceCompression(false));
	}

	public List<SkillPortSteps> getSkillPortStepList() {
		return skillPortStepList;
	}

	@SuppressWarnings({ "rawtypes", "unchecked" })
	public List<Object> getSkillPortStepObjects() {
		makeThisaSpringBeanIfNot();
		List skillPortSteps = new ArrayList();
		populateAllSkillPortStepObjects(skillPortSteps);
		Collections.sort(skillPortSteps);
		skillPortSteps.add(lifecycleSteps);
		skillPortSteps.add(new SeleniumScreenshotOnFailure(selenium));
		return skillPortSteps;
	}

	private void makeThisaSpringBeanIfNot() {
		if (skillPortStepList == null) {
			ClassPathXmlApplicationContext appContext = new ClassPathXmlApplicationContext(
					new String[] { "applicationContext.xml" });
			SkillPortStories storiesBean = appContext
					.getBean(SkillPortStories.class);
			setSkillPortStepList(storiesBean.getSkillPortStepList());

		}

	}

	private void populateAllSkillPortStepObjects(List<Object> skillPortSteps) {
		for (SkillPortSteps steps : skillPortStepList) {
			steps.init(selenium, conditionRunner);
			skillPortSteps.add(steps);
		}
	}

	public void setSkillPortStepList(List<SkillPortSteps> skillPortStepList) {
		this.skillPortStepList = skillPortStepList;
	}

	@Override
	public InjectableStepsFactory stepsFactory() {
		return new InstanceStepsFactory(configuration(),
				getSkillPortStepObjects());
	}

	@Override
	protected List<String> storyPaths() {
		List<String> storyPathList = new ArrayList<String>();
		storyPathList.addAll(new StoryFinder().findPaths(CodeLocations
				.codeLocationFromClass(this.getClass()).getFile(),
				asList("**/*.story"), null));
		return storyPathList;
	}

}
