/*
 * #%L
 * wcm.io
 * %%
 * Copyright (C) 2017 wcm.io
 * %%
 * 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.
 * #L%
 */
package io.wcm.qa.galenium.imagecomparison;

import static io.wcm.qa.galenium.configuration.GaleniumConfiguration.getActualImagesDirectory;
import static io.wcm.qa.galenium.configuration.GaleniumConfiguration.getExpectedImagesDirectory;
import static io.wcm.qa.galenium.reporting.GaleniumReportUtil.getLogger;
import static io.wcm.qa.galenium.util.FileHandlingUtil.constructRelativePath;

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.imageio.ImageIO;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.galenframework.specs.Spec;
import com.galenframework.validation.CombinedValidationListener;
import com.galenframework.validation.ImageComparison;
import com.galenframework.validation.PageValidation;
import com.galenframework.validation.ValidationError;
import com.galenframework.validation.ValidationResult;

import io.wcm.qa.galenium.configuration.GaleniumConfiguration;
import io.wcm.qa.galenium.exceptions.GaleniumException;
import io.wcm.qa.galenium.util.FileHandlingUtil;


/**
 * {@link CombinedValidationListener} to handle storing of sampled image files in ZIP file.
 */
public class ImageComparisonValidationListener extends CombinedValidationListener {

  private static final BufferedImage DUMMY_IMAGE = new BufferedImage(20, 20, BufferedImage.TYPE_3BYTE_BGR);

  // Logger
  private static final Logger log = LoggerFactory.getLogger(ImageComparisonValidationListener.class);

  private static final String REGEX_IMAGE_FILENAME = ".*image file ([^,]*\\.png).*";

  @Override
  public void onSpecError(PageValidation pageValidation, String objectName, Spec spec, ValidationResult result) {
    super.onSpecError(pageValidation, objectName, spec, result);
    trace("spec error triggered: " + objectName);
    if (GaleniumConfiguration.isSaveSampledImages()) {
      String text = spec.toText();
      if (StringUtils.contains(text, "image file ")) {
        trace("saving sample: " + objectName);
        logSpec(spec);
        Matcher matcher = getImagePathExtractionRegEx().matcher(text);
        if (matcher.matches() && matcher.groupCount() >= 1) {
          String imagePath = matcher.group(1);

          debug("image: " + imagePath);
          try {
            File actualImage = getActualImage(result);
            File imageFile = getImageFile(imagePath);
            trace("begin copying image '" + imageFile + "' -> '" + actualImage + "'");
            FileUtils.copyFile(actualImage, imageFile);
            trace("done copying image '" + imageFile + "' -> '" + actualImage + "'");
          }
          catch (GaleniumException | IOException ex) {
            String msg = "could not write image: " + imagePath;
            log.error(msg, ex);
            getLogger().error(msg, ex);
          }
        }
        else {
          String msg = "could not extract image name from: " + text;
          log.warn(msg);
          getLogger().warn(msg);
        }
      }
      else {
        trace("not saving sample. " + objectName);
      }
    }
    else {
      trace("not an image comparison spec");
    }
  }

  private void debug(String msg) {
    getLogger().debug(msg);
  }

  private void trace(String msg) {
    getLogger().trace(msg);
  }

  protected File getActualImage(ValidationResult result) {

    ValidationError error = result.getError();
    String msg;
    if (error != null) {
      ImageComparison imageComparison = error.getImageComparison();
      if (imageComparison != null) {
        File actualImage = imageComparison.getSampleFilteredImage();
        if (actualImage != null) {
          return actualImage;
        }
        else {
          msg = "could not find sampled image in image comparison.";
        }
      }
      else {
        msg = "could not find image comparison in validation error.";
      }
    }
    else {
      msg = "could not find error in validation result.";
    }

    try {
      File imageFile = File.createTempFile("dummy_image", "png");
      trace("begin writing image '" + imageFile);
      ImageIO.write(DUMMY_IMAGE, "png", imageFile);
      trace("done writing image '" + imageFile);
      return imageFile;
    }
    catch (IOException ex) {
      throw new GaleniumException(msg, ex);
    }
  }

  protected File getImageFile(String imagePath) {
    String sampledImagesRootPath = getActualImagesDirectory();
    String path;
    if (StringUtils.isNotBlank(sampledImagesRootPath)) {
      File rootDirectory = new File(getExpectedImagesDirectory());
      String relativeImagePath = constructRelativePath(rootDirectory, new File(imagePath));
      path = sampledImagesRootPath + File.separator + relativeImagePath;
    }
    else {
      path = imagePath;
    }
    File imageFile = new File(path);
    FileHandlingUtil.ensureParent(imageFile);
    return imageFile;
  }

  protected Pattern getImagePathExtractionRegEx() {
    return Pattern.compile(REGEX_IMAGE_FILENAME);
  }

  protected void logSpec(Spec spec) {
    debug("checking for image file: " + spec.toText() + " (with regex: " + REGEX_IMAGE_FILENAME + ")");
  }

}

@@ -1165,39 +1165,8 @@
 n;%0A%0A
-import javax.imageio.ImageIO;%0A%0A
 impo
@@ -2995,34 +2995,29 @@
        File 
-actualImag
+sourc
 e = getActua
@@ -3048,33 +3048,137 @@
     
+if (source == null) %7B%0A              source = new 
 File
- 
+(
 image
-File = getImage
+Path);%0A            %7D%0A            File target = getNewSampleImageTarget
 File
@@ -3230,32 +3230,29 @@
  image '%22 + 
-imageFil
+sourc
 e + %22' -%3E '%22
@@ -3250,35 +3250,30 @@
  %22' -%3E '%22 + 
-actualIma
+tar
 ge
+t
  + %22'%22);%0A   
@@ -3304,30 +3304,22 @@
 ile(
-actualImage, imageFile
+source, target
 );%0A 
@@ -3360,24 +3360,21 @@
 ge '%22 + 
-imageFil
+sourc
 e + %22' -
@@ -3380,27 +3380,22 @@
 -%3E '%22 + 
-actualIma
+tar
 ge
+t
  + %22'%22);
@@ -4360,22 +4360,24 @@
 ison.get
-Sample
+Original
 Filtered
@@ -4738,344 +4738,54 @@
   %7D%0A
-%0A
     
-try %7B%0A      File imageFile = File.createTempFile(%22dummy_image%22, %22png%22);%0A      trace(%22begin writing image '%22 + imageFile);%0A      ImageIO.write(DUMMY_IMAGE, %22png%22, imageFile);%0A      trace(%22done writing image '%22 + imageFile);%0A      return imageFile;%0A    %7D%0A    catch (IOException ex) %7B%0A      throw new GaleniumException(msg, ex);%0A    %7D
+getLogger().debug(msg);%0A%0A    return null;%0A
 %0A  %7D
@@ -4806,21 +4806,36 @@
 File get
-Image
+NewSampleImageTarget
 File(Str

clean up naming and logic