package it.reply.orchestrator.service;

import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import javax.annotation.Nonnull;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken;
import org.springframework.stereotype.Service;

import com.google.common.io.ByteStreams;

import alien4cloud.component.repository.exception.CSARVersionAlreadyExistsException;
import alien4cloud.security.model.Role;
import alien4cloud.tosca.ArchiveParser;
import alien4cloud.tosca.ArchiveUploadService;
import alien4cloud.tosca.model.ArchiveRoot;
import alien4cloud.tosca.parser.ParsingException;
import alien4cloud.tosca.parser.ParsingResult;
import alien4cloud.tosca.serializer.VelocityUtil;
import alien4cloud.utils.FileUtil;

@Service
public class ToscaServiceImpl implements ToscaService {

  @Resource
  private ArchiveParser parser;

  @Autowired
  private ArchiveUploadService archiveUploadService;

  @Value("${directories.alien}/${directories.csar_repository}")
  private String alienRepoDir;

  @Value("${tosca.definitions.basepath}")
  private String basePath;
  @Value("${tosca.definitions.normative}")
  private String normativeLocalName;
  @Value("${tosca.definitions.indigo}")
  private String indigoLocalName;

  @PostConstruct
  public void init() throws IOException, CSARVersionAlreadyExistsException, ParsingException {
    if (Files.exists(Paths.get(alienRepoDir))) {
      FileUtil.delete(Paths.get(alienRepoDir));
    }

    setAutentication();

    ClassLoader cl = this.getClass().getClassLoader();

    try (InputStream is = cl.getResourceAsStream(basePath + "/" + normativeLocalName)) {
      Path zipFile = File.createTempFile(normativeLocalName, ".zip").toPath();
      zip(is, zipFile);
      archiveUploadService.upload(zipFile);
    }

    try (InputStream is = cl.getResourceAsStream(basePath + "/" + indigoLocalName)) {
      Path zipFile = File.createTempFile(indigoLocalName, ".zip").toPath();
      zip(is, zipFile);
      archiveUploadService.upload(zipFile);
    }

  }

  public static void zip(@Nonnull InputStream fileStream, @Nonnull Path outputPath)
      throws IOException {
    FileUtil.touch(outputPath);
    try (ZipOutputStream zipOutputStream = new ZipOutputStream(
        new BufferedOutputStream(Files.newOutputStream(outputPath)))) {
      zipOutputStream.putNextEntry(new ZipEntry("definition.yml"));
      ByteStreams.copy(fileStream, zipOutputStream);
      zipOutputStream.closeEntry();
      zipOutputStream.flush();
    }
  }

  @Override
  @Nonnull
  public ArchiveRoot getArchiveRootFromTemplate(@Nonnull String toscaTemplate)
      throws IOException, ParsingException {
    Path zipPath = Files.createTempFile("csar", ".zip");
    try (InputStream is = new ByteArrayInputStream(toscaTemplate.getBytes());) {
      zip(is, zipPath);
    }
    ParsingResult<ArchiveRoot> parsingResult = parser.parse(zipPath);
    ArchiveRoot archiveRoot = parsingResult.getResult();
    // topology.setId(UUID.randomUUID().toString());
    return archiveRoot;
  }

  @Override
  @Nonnull
  public String getTemplateFromTopology(@Nonnull ArchiveRoot archiveRoot) throws IOException {
    Map<String, Object> velocityCtx = new HashMap<>();
    velocityCtx.put("tosca_definitions_version",
        archiveRoot.getArchive().getToscaDefinitionsVersion());
    velocityCtx.put("description", archiveRoot.getArchive().getDescription());
    velocityCtx.put("template_name", archiveRoot.getArchive().getName());
    velocityCtx.put("template_version", archiveRoot.getArchive().getVersion());
    velocityCtx.put("template_author", archiveRoot.getArchive().getTemplateAuthor());
    velocityCtx.put("repositories", archiveRoot.getArchive().getRepositories());
    velocityCtx.put("topology", archiveRoot.getTopology());
    StringWriter writer = new StringWriter();
    VelocityUtil.generate("templates/topology-1_0_0_INDIGO.yml.vm", writer, velocityCtx);
    return writer.toString();
  }

  private static void setAutentication() {
    Authentication auth = new PreAuthenticatedAuthenticationToken(Role.ADMIN.name().toLowerCase(),
        "", AuthorityUtils.createAuthorityList(Role.ADMIN.name()));
    SecurityContextHolder.getContext().setAuthentication(auth);
  }
}

@@ -296,16 +296,41 @@
 .Paths;%0A
+import java.util.Arrays;%0A
 import j
@@ -542,24 +542,109 @@
 .Resource;%0A%0A
+import org.apache.logging.log4j.LogManager;%0Aimport org.apache.logging.log4j.Logger;%0A%0A
 import org.s
@@ -1216,32 +1216,74 @@
 xistsException;%0A
+import alien4cloud.model.components.Csar;%0A
 import alien4clo
@@ -1686,16 +1686,99 @@
 vice %7B%0A%0A
+  private static final Logger LOG = LogManager.getLogger(ToscaServiceImpl.class);%0A%0A
   @Resou
@@ -2687,32 +2687,61 @@
  zipFile);%0A     
+ ParsingResult%3CCsar%3E result =
  archiveUploadSe
@@ -2755,32 +2755,268 @@
 pload(zipFile);%0A
+      if (!result.getContext().getParsingErrors().isEmpty()) %7B%0A        LOG.warn(%22Error parsing definition %7B%7D:%5Cn%7B%7D%22, () -%3E normativeLocalName,%0A            () -%3E Arrays.toString(result.getContext().getParsingErrors().toArray()));%0A      %7D%0A
     %7D%0A%0A    try (
@@ -3193,24 +3193,53 @@
 File);%0A     
+ ParsingResult%3CCsar%3E result =
  archiveUplo
@@ -3261,24 +3261,257 @@
 d(zipFile);%0A
+      if (!result.getContext().getParsingErrors().isEmpty()) %7B%0A        LOG.warn(%22Error parsing definition %7B%7D:%5Cn%7B%7D%22, () -%3E indigoLocalName,%0A            () -%3E Arrays.toString(result.getContext().getParsingErrors().toArray()));%0A      %7D%0A
     %7D%0A%0A  %7D%0A%0A

Improve TOSCA service logging