content: /*
   * Licensed to the Apache Software Foundation (ASF) under one or more
   * contributor license agreements.  See the NOTICE file distributed with
   * this work for additional information regarding copyright ownership.
   * The ASF licenses this file to You 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.apache.camel.quarkus.component.fop.it;
  
  import java.io.IOException;
  import java.io.InputStream;
  import java.io.StringWriter;
  import java.io.Writer;
  import java.nio.file.Files;
  import java.nio.file.Path;
  import java.nio.file.Paths;
  import java.util.function.Function;
  import java.util.stream.Stream;
  
  import io.quarkus.test.junit.QuarkusTest;
  import io.restassured.RestAssured;
  import io.restassured.http.ContentType;
  import io.restassured.response.ExtractableResponse;
  import io.restassured.specification.RequestSpecification;
  import io.smallrye.common.os.OS;
  import org.apache.pdfbox.Loader;
  import org.apache.pdfbox.io.RandomAccessReadBuffer;
  import org.apache.pdfbox.pdmodel.PDDocument;
  import org.apache.pdfbox.text.PDFTextStripper;
  import org.junit.jupiter.api.Assumptions;
  import org.junit.jupiter.api.BeforeAll;
  import org.junit.jupiter.api.BeforeEach;
  import org.junit.jupiter.api.Test;
  
  import static org.junit.jupiter.api.Assertions.assertEquals;
  
  @QuarkusTest
  class FopTest {
  
      public static final String MSG = "hello";
      private static Path tmpDir;
  
      @BeforeAll
      static void copyResources() throws IOException {
          /*
           * Local files are not available when this test is run in Quarkus Platform.
           * ppalaga was not able to find a way to make FOP load the font declared in mycfg.xml from the classpath
           * As a workaround, the resources are simply copied from the class loader to target/tmp directory
           * before the test starts
           */
          tmpDir = Paths.get("target/tmp");
          Files.createDirectories(tmpDir);
          final ClassLoader cl = FopTest.class.getClassLoader();
          Stream.of("Freedom-10eM.ttf", "mycfg.xml")
                  .forEach(resource -> {
                      final Path target = tmpDir.resolve(resource);
                      if (!Files.exists(target)) {
                          try (InputStream in = cl.getResourceAsStream(resource)) {
                              Files.copy(in, target);
                          } catch (IOException e) {
                              throw new RuntimeException("Could not read resource " + resource, e);
                          }
                      }
                  });
      }
  
      @BeforeEach
      public void beforeEach() {
          // Disable tests on GitHub Actions Windows runners. Font cache building is too slow and restoring saved caches is too unreliable
          Assumptions.assumeFalse(OS.current().equals(OS.WINDOWS) && "true".equals(System.getenv("CI")));
      }
  
      @Test
      public void convertToPdf() throws IOException {
          convertToPdf(msg -> decorateTextWithXSLFO(msg, null), null);
      }
  
      @Test
      public void convertToPdfWithCustomFont() throws IOException {
          convertToPdf(msg -> decorateTextWithXSLFO(msg, "Freedom"),
                  tmpDir.resolve("mycfg.xml").toAbsolutePath().toUri().toString());
      }
  
      private void convertToPdf(Function<String, String> msgCreator, String userConfigFile) throws IOException {
          RequestSpecification requestSpecification = RestAssured.given()
                  .contentType(ContentType.XML);
          if (userConfigFile != null) {
              requestSpecification.queryParam("userConfigURL", userConfigFile);
          }
          ExtractableResponse response = requestSpecification
                  .body(msgCreator.apply(MSG))
                  .post("/fop/post") //
                  .then()
                  .statusCode(201)
                  .extract();
  
          PDDocument document = getDocumentFrom(response.asInputStream());
          String content = extractTextFrom(document);
          assertEquals(MSG, content);
      }
  
      public static String decorateTextWithXSLFO(String text, String font) {
          String foBlock = font == null ? "      <fo:block>" + text + "</fo:block>\n"
                  : "      <fo:block font-family=\"" + font + "\">" + text + "</fo:block>\n";
          return "<fo:root xmlns:fo=\"http://www.w3.org/1999/XSL/Format\">\n"
                  + "  <fo:layout-master-set>\n"
                  + "    <fo:simple-page-master master-name=\"only\">\n"
                  + "      <fo:region-body region-name=\"xsl-region-body\" margin=\"0.7in\"  padding=\"0\" />\n"
                  + "      <fo:region-before region-name=\"xsl-region-before\" extent=\"0.7in\" />\n"
                  + "        <fo:region-after region-name=\"xsl-region-after\" extent=\"0.7in\" />\n"
                  + "      </fo:simple-page-master>\n"
                  + "    </fo:layout-master-set>\n"
                  + "    <fo:page-sequence master-reference=\"only\">\n"
                  + "      <fo:flow flow-name=\"xsl-region-body\">\n"
                  + foBlock
                  + "    </fo:flow>\n"
                  + "  </fo:page-sequence>\n"
                  + "</fo:root>";
      }
  
      private PDDocument getDocumentFrom(InputStream inputStream) throws IOException {
          return Loader.loadPDF(new RandomAccessReadBuffer(inputStream));
      }
  
      private String extractTextFrom(PDDocument document) throws IOException {
          Writer output = new StringWriter();
          PDFTextStripper stripper = new PDFTextStripper();
          stripper.writeText(document, output);
          return output.toString().trim();
      }
  }
  