import java.io.File;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Paths;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import me.xdrop.fuzzywuzzy.FuzzySearch;
import org.hamcrest.Matchers;
import org.junit.Assert;
import org.junit.Test;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.zeroturnaround.exec.ProcessExecutor;

public class Edition070_Audio_Verification extends Edition069_Audio_Capture {

    private File getReferenceAudio() throws URISyntaxException {
        URL refImgUrl = getClass().getClassLoader().getResource("Edition070_Reference.wav");
        return Paths.get(refImgUrl.toURI()).toFile();
    }

    @Test
    @Override
    public void testAudioCapture() throws Exception {
        WebDriverWait wait = new WebDriverWait(driver, 10);

        // navigate to band homepage
        driver.get("http://www.splendourhyaline.com");

        // click the amazon store icon for the first album
        WebElement store = wait.until(ExpectedConditions.presenceOfElementLocated(
            By.cssSelector("img[src='/img/store-amazon.png']")
        ));
        driver.executeScript("window.scrollBy(0, 100);");
        store.click();

        // start playing a sample of the first track
        WebElement play = wait.until(ExpectedConditions.presenceOfElementLocated(
            By.xpath("//div[@data-track-number='1']//div[@data-action='dm-playable']")
        ));

        driver.executeScript("window.scrollBy(0, 150);");

        // start the song sample
        play.click();

        // start an ffmpeg audio capture of system audio. Replace with a path and device id
        // appropriate for your system (list devices with `ffmpeg -f avfoundation -list_devices true -i ""`
        File audioCapture = new File("/Users/jlipps/Desktop/capture.wav");
        captureForDuration(audioCapture, 10000);

        // now we calculate the fingerprint of the freshly-captured audio...
        AudioFingerprint fp1 = AudioFingerprint.calcFP(audioCapture);

        // as well as the fingerprint of our baseline audio...
        AudioFingerprint fp2 = AudioFingerprint.calcFP(getReferenceAudio());

        // and compare the two
        double comparison = fp1.compare(fp2);

        // finally, we assert that the comparison is sufficiently strong
        Assert.assertThat(comparison, Matchers.greaterThanOrEqualTo(70.0));
    }
}

class AudioFingerprint {

    private static String FPCALC = "/Users/jlipps/Desktop/chromaprint/fpcalc";

    private String fingerprint;

    AudioFingerprint(String fingerprint) {
        this.fingerprint = fingerprint;
    }

    public String getFingerprint() { return fingerprint; }

    public double compare(AudioFingerprint other) {
        return FuzzySearch.partialRatio(this.getFingerprint(), other.getFingerprint());
    }

    public static AudioFingerprint calcFP(File wavFile) throws Exception {
        String output = new ProcessExecutor()
            .command(FPCALC, "-raw", wavFile.getAbsolutePath())
            .readOutput(true).execute()
            .outputUTF8();

        Pattern fpPattern = Pattern.compile("^FINGERPRINT=(.+)$", Pattern.MULTILINE);
        Matcher fpMatcher = fpPattern.matcher(output);

        String fingerprint = null;

        if (fpMatcher.find()) {
            fingerprint = fpMatcher.group(1);
        }

        if (fingerprint == null) {
            throw new Exception("Could not get fingerprint via Chromaprint fpcalc");
        }

        return new AudioFingerprint(fingerprint);
    }
}