public class AfterVideoStart {

    private final VideoType videoType;
    private final VideoMetaData videoMetaData;

    public AfterVideoStart(VideoType videoType, VideoMetaData videoMetaData) {
        this.videoType = videoType;
        this.videoMetaData = videoMetaData;
    }

    public VideoType getVideoType() {
        return videoType;
    }

    public VideoMetaData getVideoMetaData() {
        return videoMetaData;
    }

} public class AfterVideoStop {

    private final VideoType videoType;
    private final VideoMetaData videoMetaData;

    public AfterVideoStop(VideoType videoType, VideoMetaData videoMetaData) {
        this.videoType = videoType;
        this.videoMetaData = videoMetaData;
    }

    public VideoType getVideoType() {
        return videoType;
    }

    public VideoMetaData getVideoMetaData() {
        return videoMetaData;
    }

} public class BeforeVideoStart {

    private final VideoType videoType;

    private final VideoMetaData videoMetaData;

    public BeforeVideoStart(VideoType videoType, VideoMetaData videoMetaData) {
        this.videoType = videoType;
        this.videoMetaData = videoMetaData;
    }

    public VideoType getVideoType() {
        return videoType;
    }

    public VideoMetaData getVideoMetaData() {
        return videoMetaData;
    }

} public class BeforeVideoStop {

    private final VideoType videoType;
    private final VideoMetaData videoMetaData;

    public BeforeVideoStop(VideoType videoType, VideoMetaData videoMetaData) {
        this.videoType = videoType;
        this.videoMetaData = videoMetaData;
    }

    public VideoType getVideoType() {
        return videoType;
    }

    public VideoMetaData getVideoMetaData() {
        return videoMetaData;
    }
} public class StartRecordClassVideo {

    private final VideoMetaData videoMetaData;
    private final VideoType videoType;

    public StartRecordClassVideo(VideoType videoType, VideoMetaData videoMetaData) {
        this.videoMetaData = videoMetaData;
        this.videoType = videoType;
    }

    public VideoMetaData getVideoMetaData() {
        return videoMetaData;
    }

    public VideoType getVideoType() {
        return videoType;
    }
} public class StartRecordSuiteVideo {

    private final VideoType videoType;
    private final VideoMetaData videoMetaData;

    public StartRecordSuiteVideo(VideoType videoType, VideoMetaData videoMetaData) {
        this.videoType = videoType;
        this.videoMetaData = videoMetaData;
    }

    public VideoType getVideoType() {
        return videoType;
    }

    public VideoMetaData getVideoMetaData() {
        return videoMetaData;
    }

} public class StartRecordVideo {

    private final VideoType videoType;
    private final VideoMetaData videoMetaData;

    public StartRecordVideo(VideoType videoType, VideoMetaData videoMetaData) {
        this.videoType = videoType;
        this.videoMetaData = videoMetaData;
    }

    public VideoType getVideoType() {
        return videoType;
    }

    public VideoMetaData getVideoMetaData() {
        return videoMetaData;
    }

} public class StopRecordClassVideo {
    private final VideoType videoType;
    private final VideoMetaData videoMetaData;

    public StopRecordClassVideo(VideoType videoType, VideoMetaData videoMetaData) {
        this.videoMetaData = videoMetaData;
        this.videoType = videoType;
    }

    public VideoMetaData getVideoMetaData() {
        return videoMetaData;
    }

    public VideoType getVideoType() {
        return videoType;
    }
} public class StopRecordSuiteVideo {

    private final VideoType videoType;
    private final VideoMetaData videoMetaData;

    public StopRecordSuiteVideo(VideoType videoType, VideoMetaData videoMetaData) {
        this.videoMetaData = videoMetaData;
        this.videoType = videoType;
    }

    public VideoMetaData getVideoMetaData() {
        return videoMetaData;
    }

    public VideoType getVideoType() {
        return videoType;
    }

} public class StopRecordVideo {

    private final VideoMetaData videoMetaData;
    private final VideoType videoType;

    public StopRecordVideo(VideoType videoType, VideoMetaData videoMetaData) {
        this.videoMetaData = videoMetaData;
        this.videoType = videoType;
    }

    public VideoMetaData getVideoMetaData() {
        return videoMetaData;
    }

    public VideoType getVideoType() {
        return videoType;
    }
} public class DefaultVideoStrategy implements VideoStrategy {

    private VideoConfiguration configuration;

    @Override
    public void setConfiguration(VideoConfiguration configuration) {
        Validate.notNull(configuration, "Video configuration can not be a null object!");
        this.configuration = configuration;
    }

    @Override
    public boolean isTakingAction(Event event, TestResult result) {
        if (event instanceof AfterTestLifecycleEvent && !(event instanceof After)) {
            switch (result.getStatus()) {
                case FAILED:
                    return configuration.getTakeOnlyOnFail();
                case PASSED:
                    return configuration.getStartBeforeTest() || configuration.getTakeOnlyOnFail();
                case SKIPPED:
                default:
                    return false;
            }
        }
        return false;
    }

    @Override
    public boolean isTakingAction(Event event) {
        if (event instanceof BeforeSuite
                || event instanceof AfterSuite) {
            return configuration.getStartBeforeSuite();
        } else if (event instanceof BeforeClass
                || event instanceof AfterClass) {
            return configuration.getStartBeforeClass();
        } else if (event instanceof Before) {
            return configuration.getStartBeforeTest()
                || configuration.getTakeOnlyOnFail();
        }

        return false;
    }

    @Override
    public int precedence() {
        return 0;
    }
} public class VideoLifecycleObserver {

    @Inject
    private Instance<TestResult> testResult;

    @Inject
    private Instance<VideoStrategy> strategy;

    @Inject
    private Instance<Recorder> recorder;

    @Inject
    private Event<BeforeVideoStart> beforeVideoStart;

    @Inject
    private Event<AfterVideoStart> afterVideoStart;

    @Inject
    private Event<BeforeVideoStop> beforeVideoStop;

    @Inject
    private Event<AfterVideoStop> afterVideoStop;

    @Inject
    private Event<StartRecordVideo> startRecordVideo;

    @Inject
    private Event<StopRecordVideo> stopRecordVideo;

    @Inject
    private Event<StartRecordClassVideo> startRecordClassVideo;

    @Inject
    private Event<StopRecordClassVideo> stopRecordClassVideo;

    @Inject
    private Event<StartRecordSuiteVideo> startRecordSuiteVideo;

    @Inject
    private Event<StopRecordSuiteVideo> stopRecordSuiteVideo;

    public void beforeSuite(@Observes BeforeSuite event) {
        if (strategy.get().isTakingAction(event)) {
            VideoMetaData suiteMetaData = getMetaData();
            VideoType videoType = getVideoType();

            beforeVideoStart.fire(new BeforeVideoStart(videoType, suiteMetaData));

            startRecordSuiteVideo.fire(new StartRecordSuiteVideo(videoType, suiteMetaData));

            afterVideoStart.fire(new AfterVideoStart(videoType, suiteMetaData));
        }
    }

    public void beforeClass(@Observes BeforeClass event) {
        if (strategy.get().isTakingAction(event)) {
            VideoMetaData classMetaData = getClassMetaData(event);
            VideoType videoType = getVideoType();

            beforeVideoStart.fire(new BeforeVideoStart(videoType, classMetaData));

            startRecordClassVideo.fire(new StartRecordClassVideo(videoType, classMetaData));

            afterVideoStart.fire(new AfterVideoStart(videoType, classMetaData));
        }
    }

    public void beforeTest(@Observes Before event) {
        if (strategy.get().isTakingAction(event)) {
            VideoMetaData testMetaData = getMetaData(event);
            VideoType videoType = getVideoType();

            beforeVideoStart.fire(new BeforeVideoStart(videoType, testMetaData));

            startRecordVideo.fire(new StartRecordVideo(videoType, testMetaData));

            afterVideoStart.fire(new AfterVideoStart(videoType, testMetaData));
        }
    }

    public void afterTest(@Observes AfterTestLifecycleEvent event) {
        if (strategy.get().isTakingAction(event, testResult.get())) {
            VideoMetaData metaData = getMetaData(event);
            metaData.setTestResult(testResult.get());
            VideoType videoType = getVideoType();

            beforeVideoStop.fire(new BeforeVideoStop(videoType, metaData));

            stopRecordVideo.fire(new StopRecordVideo(videoType, metaData));

            afterVideoStop.fire(new AfterVideoStop(videoType, metaData));
        }
    }

    public void afterClass(@Observes AfterClass event) {
        if (strategy.get().isTakingAction(event)) {
            VideoMetaData metaData = getClassMetaData(event);
            VideoType videoType = getVideoType();

            beforeVideoStop.fire(new BeforeVideoStop(videoType, metaData));

            stopRecordClassVideo.fire(new StopRecordClassVideo(videoType, metaData));

            afterVideoStop.fire(new AfterVideoStop(videoType, metaData));
        }
    }

    public void afterSuite(@Observes AfterSuite event) {
        if (strategy.get().isTakingAction(event)) {
            VideoMetaData metaData = getMetaData();
            VideoType videoType = getVideoType();

            beforeVideoStop.fire(new BeforeVideoStop(videoType, metaData));

            stopRecordSuiteVideo.fire(new StopRecordSuiteVideo(videoType, metaData));

            afterVideoStop.fire(new AfterVideoStop(videoType, metaData));
        }
    }

    private VideoMetaData getMetaData() {
        VideoMetaData metaData = new VideoMetaData();
        metaData.setTimeStamp(System.currentTimeMillis());
        return metaData;
    }

    private VideoMetaData getMetaData(TestLifecycleEvent event) {
        VideoMetaData metaData = getMetaData();
        metaData.setTestClass(event.getTestClass());
        metaData.setTestMethod(event.getTestMethod());
        return metaData;
    }

    private VideoMetaData getClassMetaData(ClassLifecycleEvent event) {
        VideoMetaData metaData = getMetaData();
        metaData.setTestClass(event.getTestClass());
        return metaData;
    }

    private VideoType getVideoType() {
        return recorder.get().getVideoType();
    }
} public class VideoRecorderExtensionInitializer {

    @Inject
    @ApplicationScoped
    private InstanceProducer<VideoStrategy> strategy;

    @Inject
    @ApplicationScoped
    private InstanceProducer<VideoRecorderEnvironmentCleaner> cleaner;

    @Inject
    private Instance<ServiceLoader> serviceLoader;

    @Inject
    private Event<VideoExtensionConfigured> extensionConfiguredEvent;

    public void afterReportingExtensionConfigured(@Observes ReportingExtensionConfigured event) {

        VideoStrategy strategy = new SkippingVideoStrategy();

        VideoRecorderEnvironmentCleaner cleaner = serviceLoader.get().onlyOne(VideoRecorderEnvironmentCleaner.class,
            DefaultVideoRecorderEnvironmentCleaner.class);

        this.strategy.set(strategy);
        this.cleaner.set(cleaner);

        extensionConfiguredEvent.fire(new VideoExtensionConfigured());
    }
} public class VideoTaker {

    @Inject
    private Instance<Recorder> recorder;

    @Inject
    private Instance<VideoConfiguration> configuration;

    @Inject
    private Event<PropertyReportEvent> propertyReportEvent;

    @Inject
    private Instance<TakenResourceRegister> resourceRegister;

    private final DefaultFileNameBuilder nb = new DefaultFileNameBuilder();

    // starts

    public void onStartSuiteRecording(@Observes StartRecordSuiteVideo event) {
        File videoTarget = new File("suite", configuration.get().getVideoName());
        recorder.get().startRecording(videoTarget, event.getVideoType());
    }

    public void onStartClassRecording(@Observes StartRecordClassVideo event) {
        File videoTarget = new File("class", configuration.get().getVideoName());
        recorder.get().startRecording(videoTarget, event.getVideoType());
    }

    public void onStartRecording(@Observes StartRecordVideo event) {

        VideoMetaData metaData = event.getVideoMetaData();
        metaData.setResourceType(event.getVideoType());
        String fileName = nb
            .withMetaData(metaData)
            .build();

        File videoTarget = new File(event.getVideoMetaData().getTestClassName(), fileName);
        recorder.get().startRecording(videoTarget, event.getVideoType());
    }

    // stops

    public void onStopSuiteRecording(@Observes StopRecordSuiteVideo event) {
        Video video = recorder.get().stopRecording();
        resourceRegister.get().addTaken(video);
        video.setResourceMetaData(event.getVideoMetaData());

        resourceRegister.get().addReported(video);
        propertyReportEvent.fire(new PropertyReportEvent(getVideoEntry(video)));
    }

    public void onStopClassRecording(@Observes StopRecordClassVideo event) {
        Video video = recorder.get().stopRecording();
        video.setResourceMetaData(event.getVideoMetaData());
        resourceRegister.get().addReported(video);

        propertyReportEvent.fire(new PropertyReportEvent(getVideoEntry(video)));
    }

    public void onStopRecording(@Observes StopRecordVideo event) throws IOException {
        Video video = recorder.get().stopRecording();

        TestResult testResult = event.getVideoMetaData().getTestResult();

        if (testResult != null) {
            Status status = testResult.getStatus();
            appendStatus(video, status);

            resourceRegister.get().addReported(video);

            if ((status.equals(Status.PASSED) && !configuration.get().getTakeOnlyOnFail())
                || (status.equals(Status.FAILED) && configuration.get().getTakeOnlyOnFail())) {
                propertyReportEvent.fire(new PropertyReportEvent(getVideoEntry(video)));
            }
        } else {
            resourceRegister.get().addTaken(video);
        }
    }

    private PropertyEntry getVideoEntry(Video video) {
        VideoEntry videoEntry = new VideoEntry();
        videoEntry.setPath(video.getResource().getAbsolutePath());
        videoEntry.setType(video.getResourceType().toString());
        videoEntry.setSize(Long.toString(video.getResource().length()));
        videoEntry.setHeight(video.getHeight());
        videoEntry.setWidth(video.getWidth());
        videoEntry.setMessage(video.getMessage());
        return videoEntry;
    }

    private void appendStatus(Video video, Status status) {
        File record = video.getResource();

        String fileNameWithExtension = record.getName();

        String newFileName;

        int lastIndexOfDot = fileNameWithExtension.lastIndexOf(".");

        StringBuilder sb = new StringBuilder();

        if (lastIndexOfDot == -1) {
            sb.append(fileNameWithExtension).append("_").append(status.toString().toLowerCase());
        } else {
            String extension = fileNameWithExtension.substring(lastIndexOfDot + 1);
            sb.append(fileNameWithExtension.substring(0, lastIndexOfDot))
                .append("_")
                .append(status.toString().toLowerCase())
                .append(".")
                .append(extension);
        }

        newFileName = sb.toString();

        File moved = new File(record.getParentFile(), newFileName);

        record.renameTo(moved);
        video.setResource(moved);
    }

} public class ReporterConfiguration extends Configuration<ReporterConfiguration> {

    private static final Logger LOGGER = Logger.getLogger(ReporterConfiguration.class.getName());

    public static final String DEFAULT_TYPE = "xml";

    public static final String DEFAULT_LANGUAGE = "en";

    public static final String DEFAULT_MAX_IMAGE_WIDTH = "500";

    public static final String DEFAULT_ASCIIDOC_STANDARD_COMPLIANT = "false";

    // in percents

    public static final String DEFAULT_IMAGE_WIDTH = "100";

    public static final String DEFAULT_IMAGE_HEIGHT = "100";

    public static final String DEFAULT_TITLE = "Arquillian test run report";

    private String report = DEFAULT_TYPE;

    private String file = getFileDefaultFileName();

    private static final String ROOT_DIR = "target";

    private static final String TEMPLATE = "template.xsl";

    private final String reportAfterEvery = ReportFrequency.CLASS.toString();

    private static final String LANGUAGE = "en";

    private static final String MAX_IMAGE_WIDTH = DEFAULT_MAX_IMAGE_WIDTH;

    private static final String IMAGE_WIDTH = DEFAULT_IMAGE_WIDTH;

    private static final String IMAGE_HEIGHT = DEFAULT_IMAGE_HEIGHT;

    private static final String TITLE = DEFAULT_TITLE;

    private static final String ASCIIDOC_STANDARD_COMPLIANT = DEFAULT_ASCIIDOC_STANDARD_COMPLIANT;

    private static final String ASCII_DOC_ATTRIBUTES_FILE = "";

    public String getAsciiDocAttributesFile() {
        return getProperty("asciiDocAttributesFile", ASCII_DOC_ATTRIBUTES_FILE);
    }

    /**
     *
     * @return true if we want generated asciidoc document be compliant with standard format. False otherwise and output will be an AsciiDoc document to be rendered by Asciidoctor.
     */
    public boolean isAsciiDocCompliant() {
        return Boolean.parseBoolean(getProperty("asciidocStandardCompliant", ASCIIDOC_STANDARD_COMPLIANT).toLowerCase());
    }

    /**
     *
     * @return type of report we want to get, it defaults to "xml"
     */
    public String getReport() {
        return getProperty("report", report).toLowerCase();
    }

    /**
     *
     * @return file where to export a report
     */
    public File getFile() {
        return new File(getRootDir(), getProperty("file", file));
    }

    /**
     *
     * @return root directory which prepends {@link #getFile()}
     */
    public File getRootDir() {
        return new File(getProperty("rootDir", ROOT_DIR));
    }

    /**
     * XSL template for transforming XML to HTML when using HTML report type, defaults to "template.xsl". When this file is not
     * found, default system XSL template is used.
     *
     * @return xsl template file
     */
    public File getTemplate() {
        return new File(getProperty("template", TEMPLATE));
    }

    public String getReportAfterEvery() {
        return getProperty("reportAfterEvery", reportAfterEvery).toLowerCase();
    }

    /**
     * Language to use for resulting report. Defaults to "en" as English.
     *
     * @return language
     */
    public String getLanguage() {
        return getProperty("language", LANGUAGE).toLowerCase();
    }

    /**
     * Gets width for displayed images. When some image has its width lower than this number, it will be displayed as a link
     * instead as an image directly displayed on a resulting HTML page.
     *
     * @return maximum width of an image to be displayed
     */
    public String getMaxImageWidth() {
        return getProperty("maxImageWidth", MAX_IMAGE_WIDTH);
    }

    /**
     *
     * @return the width of all images in percents. If this number is smaller then 100, the width of all images will be resized
     *         from presentation point of view.
     */
    public String getImageWidth() {
        return getProperty("imageWidth", IMAGE_WIDTH);
    }

    /**
     *
     * @return the height of all images in percets. If this number is smaller then 100, the height of all images will be resized
     *         from presentation point of view.
     */
    public String getImageHeight() {
        return getProperty("imageHeight", IMAGE_HEIGHT);
    }

    public String getTitle() {
        return getProperty("title", TITLE);
    }

    private static String getFileDefaultFileName() {
        return new StringBuilder()
            .append("arquillian_report")
            .append(".")
            .append(DEFAULT_TYPE)
            .toString();
    }

    @Override
    public void validate() throws ReporterConfigurationException {
        if (report.isEmpty()) {
            LOGGER.info("Report type can not be empty string! Choosing default type \"xml\"");
            report = DEFAULT_TYPE;
        }

        if (getTitle() == null || getTitle().isEmpty()) {
            setProperty("title", DEFAULT_TITLE);
        }

        try {
            int width = Integer.parseInt(getMaxImageWidth());
            if (width <= 0) {
                setProperty("maxImageWidth", DEFAULT_MAX_IMAGE_WIDTH);
            }
        } catch (NumberFormatException ex) {
            setProperty("maxImageWidth", DEFAULT_MAX_IMAGE_WIDTH);
        }

        try {
            int width = Integer.parseInt(getImageWidth());
            if (width <= 0 || width > 100) {
                setProperty("imageWidth", DEFAULT_IMAGE_WIDTH);
            }
        } catch (NumberFormatException ex) {
            setProperty("imageWidth", DEFAULT_IMAGE_WIDTH);
        }

        try {
            int height = Integer.parseInt(getImageHeight());
            if (height <= 0 || height > 100) {
                setProperty("imageHeight", DEFAULT_IMAGE_HEIGHT);
            }
        } catch (NumberFormatException ex) {
            setProperty("imageHeight", DEFAULT_IMAGE_HEIGHT);
        }

        try {
            ReportFrequency.valueOf(ReportFrequency.class, getReportAfterEvery().toUpperCase());
        } catch (IllegalArgumentException ex) {
            throw new ReporterConfigurationException(
                "Report frequency you specified in arquillian.xml is not valid. "
                        + "The configured frequency is: " + getReportAfterEvery().toUpperCase() + ". "
                        + "The supported frequencies are: " + ReportFrequency.getAll(), ex);
        }

        // we check language only for html output
        if (getProperty("report", report).startsWith("htm")) {
            LanguageResolver languageResolver = new LanguageResolver();

            List<String> supportedLanguages = languageResolver.getSupportedLanguages();

            if (!languageResolver.isLanguageSupported(getLanguage())) {
                LOGGER.log(Level.INFO, "Language you set ({0}) for HTML report is not supported. It will default to "
                    + "\"{1}\". When you are executing this from IDE, put reporter api jar to build path among external "
                    + "jars in order to scan it.",
                    new Object[] { getLanguage(), DEFAULT_LANGUAGE, supportedLanguages });
                setProperty("language", DEFAULT_LANGUAGE);
            }
        }

        try {
            if (!getRootDir().exists()) {
                boolean created = getRootDir().mkdirs();
                if (!created) {
                    throw new ReporterConfigurationException("Unable to create root directory " + getRootDir().getAbsolutePath());
                }
            } else {
                if (!getRootDir().isDirectory()) {
                    throw new ReporterConfigurationException("Root directory you specified is not a directory - "
                        + getRootDir().getAbsolutePath());
                }
                if (!getRootDir().canWrite()) {
                    throw new ReporterConfigurationException(
                        "You can not write to '" + getRootDir().getAbsolutePath() + "'.");
                }
            }
        } catch (SecurityException ex) {
            throw new ReporterConfigurationException(
                "You are not permitted to operate on specified resource: " + getRootDir().getAbsolutePath() + "'.", ex);
        }

        setFileName(getProperty("report", report));
    }

    public void setFileName(String reportType) {
        String fileProperty = getProperty("file", file);
        setProperty("report", reportType);
        String reportProperty = getProperty("report", reportType);

        if (!fileProperty.endsWith(reportProperty)) {
            StringBuilder sb = new StringBuilder();
            if (fileProperty.contains(".")) {
                sb.append(fileProperty.substring(0, fileProperty.lastIndexOf(".")));
            } else {
                sb.append(fileProperty);
            }
            sb.append(".");
            sb.append(reportProperty);
            file = sb.toString();
            setProperty("file", file);
        }
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append(String.format("%-40s %s%n", "report", getReport()));
        sb.append(String.format("%-40s %s%n", "rootDir", getRootDir().getPath()));
        sb.append(String.format("%-40s %s%n", "file", getFile().getPath()));
        sb.append(String.format("%-40s %s%n", "template", getTemplate().getPath()));
        sb.append(String.format("%-40s %s%n", "reportAfterEvery", getReportAfterEvery()));
        sb.append(String.format("%-40s %s%n", "language", getLanguage()));
        sb.append(String.format("%-40s %s%n", "maxImageWidth", getMaxImageWidth()));
        sb.append(String.format("%-40s %s%%%n", "imageWidth", getImageWidth()));
        sb.append(String.format("%-40s %s%%%n", "imageHeight", getImageHeight()));
        return sb.toString();
    }

} public class PropertyReportEvent {

    private final PropertyEntry propertyEntry;

    /**
     *
     * @param propertyEntry property entry to hook into reporting tree from your extension
     * @throws IllegalArgumentException if {@code propertyEntry} is a null object
     */
    public PropertyReportEvent(PropertyEntry propertyEntry) {
        Validate.notNull(propertyEntry, "property entry can not be a null object");
        this.propertyEntry = propertyEntry;
    }

    public PropertyEntry getPropertyEntry() {
        return propertyEntry;
    }
}
import java.io.File;
import java.util.List;
import org.arquillian.extension.recorder.video.event.AfterVideoStart;
import org.arquillian.extension.recorder.video.event.AfterVideoStop;
import org.arquillian.extension.recorder.video.event.BeforeVideoStart;
import org.arquillian.extension.recorder.video.event.BeforeVideoStop;
import org.arquillian.extension.recorder.video.event.StartRecordClassVideo;
import org.arquillian.extension.recorder.video.event.StartRecordSuiteVideo;
import org.arquillian.extension.recorder.video.event.StartRecordVideo;
import org.arquillian.extension.recorder.video.event.StopRecordClassVideo;
import org.arquillian.extension.recorder.video.event.StopRecordSuiteVideo;
import org.arquillian.extension.recorder.video.event.StopRecordVideo;
import org.arquillian.extension.recorder.video.event.VideoExtensionConfigured;
import org.arquillian.extension.recorder.video.impl.DefaultVideoRecorderEnvironmentCleaner;
import org.arquillian.extension.recorder.video.impl.DefaultVideoStrategy;
import org.arquillian.extension.recorder.video.impl.VideoLifecycleObserver;
import org.arquillian.extension.recorder.video.impl.VideoRecorderExtensionInitializer;
import org.arquillian.extension.recorder.video.impl.VideoTaker;
import org.arquillian.recorder.reporter.ReporterConfiguration;
import org.arquillian.recorder.reporter.event.PropertyReportEvent;
import org.arquillian.recorder.reporter.impl.TakenResourceRegister;
import org.jboss.arquillian.core.api.Injector;
import org.jboss.arquillian.core.api.Instance;
import org.jboss.arquillian.core.api.annotation.ApplicationScoped;
import org.jboss.arquillian.core.api.annotation.Inject;
import org.jboss.arquillian.core.spi.ServiceLoader;
import org.jboss.arquillian.junit.event.AfterRules;
import org.jboss.arquillian.test.spi.LifecycleMethodExecutor;
import org.jboss.arquillian.test.spi.TestResult;
import org.jboss.arquillian.test.spi.annotation.TestScoped;
import org.jboss.arquillian.test.spi.event.suite.After;
import org.jboss.arquillian.test.spi.event.suite.AfterClass;
import org.jboss.arquillian.test.spi.event.suite.AfterSuite;
import org.jboss.arquillian.test.spi.event.suite.Before;
import org.jboss.arquillian.test.spi.event.suite.BeforeClass;
import org.jboss.arquillian.test.spi.event.suite.BeforeSuite;
import org.jboss.arquillian.test.test.AbstractTestTestBase;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.runners.MockitoJUnitRunner;
/*
 * JBoss, Home of Professional Open Source
 * Copyright 2014, Red Hat, Inc. and/or its affiliates, and individual
 * contributors by the @authors tag. See the copyright.txt in the
 * distribution for a full listing of individual contributors.
 *
 * 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.arquillian.extension.recorder.video;



/**
 * @author <a href="mailto:smikloso@redhat.com">Stefan Miklosovic</a>
 *
 */
@RunWith(MockitoJUnitRunner.class)
public class RecorderLifecycleObserverTestCase extends AbstractTestTestBase {

    @Mock
    private ServiceLoader serviceLoader;

    @Mock
    private VideoConfiguration configuration = new VideoConfiguration(new ReporterConfiguration());

    @Mock
    private Recorder recorder;

    @Mock
    private VideoRecorderEnvironmentCleaner cleaner = new DefaultVideoRecorderEnvironmentCleaner();

    @Mock
    private Video video = new FakeVideo();

    private File videoFile;

    private VideoStrategy strategy = new DefaultVideoStrategy();

    private TakenResourceRegister takenResourceRegister = new TakenResourceRegister();

    @Inject
    private Instance<Injector> injector;

    @Override
    public void addExtensions(List<Class<?>> extensions) {
        extensions.add(VideoLifecycleObserver.class);
        extensions.add(VideoRecorderExtensionInitializer.class);
        extensions.add(VideoTaker.class);
    }

    @org.junit.Before
    public void setup() throws Exception {
        bind(ApplicationScoped.class, ServiceLoader.class, serviceLoader);
        bind(ApplicationScoped.class, VideoConfiguration.class, configuration);
        bind(ApplicationScoped.class, Recorder.class, recorder);
        bind(ApplicationScoped.class, TakenResourceRegister.class, takenResourceRegister);

        strategy.setConfiguration(configuration);
        bind(ApplicationScoped.class, VideoStrategy.class, strategy);

        Mockito.when(recorder.getVideoType()).thenReturn(VideoType.MP4);

        Mockito.doNothing().when(cleaner).clean(configuration);

        Mockito.when(serviceLoader.onlyOne(VideoRecorderEnvironmentCleaner.class, DefaultVideoRecorderEnvironmentCleaner.class))
            .thenReturn(cleaner);

//        Mockito.when(serviceLoader.onlyOne(VideoStrategy.class, DefaultVideoStrategy.class))
//            .thenReturn(strategy);

        videoFile = File.createTempFile("fakeVideo", recorder.getVideoType().toString().toLowerCase());

        Mockito.when(configuration.getVideoName()).thenReturn("record");

        Mockito.when(video.getResource()).thenReturn(videoFile);
        Mockito.when(video.getResourceType()).thenReturn(VideoType.MP4);
        Mockito.when(video.getWidth()).thenReturn(100);
        Mockito.when(video.getHeight()).thenReturn(100);

        Mockito.when(recorder.stopRecording()).thenReturn(video);
    }

    @org.junit.After
    public void teardown() {
        if (videoFile != null && videoFile.exists()) {
            if (!videoFile.delete()) {
                throw new IllegalStateException("Unable to delete temporary file: " + videoFile.getAbsolutePath());
            }
        }
    }

    @Test
    public void defaultConfigurationTest() throws Exception {

        // by default, no videos are taken at all

        fire(new VideoExtensionConfigured());

        fire(new BeforeSuite());
        fire(new BeforeClass(DummyTestCase.class));
        fire(new Before(DummyTestCase.class, DummyTestCase.class.getMethod("test")));

        bind(TestScoped.class, TestResult.class, TestResult.passed());

        fire(new AfterRules(DummyTestCase.class, DummyTestCase.class.getMethod("test"), LifecycleMethodExecutor.NO_OP));
        fire(new AfterClass(DummyTestCase.class));
        fire(new AfterSuite());

        assertEventFired(BeforeVideoStart.class, 0);
        assertEventFired(StartRecordVideo.class, 0);