package de.adito.jloadr.repository.jnlp;

import de.adito.jloadr.api.*;
import de.adito.jloadr.common.JLoadrUtil;
import de.adito.jloadr.repository.*;

import javax.annotation.*;
import java.io.IOException;
import java.net.*;
import java.util.*;
import java.util.function.Function;
import java.util.stream.*;

/**
 * @author j.boesl, 05.09.16
 */
public class JnlpResourcePack implements IResourcePack
{
  private URL jnlpUrl;
  private Collection<JnlpUrl> jnlpUrls;
  private Map<IResourceId, IResource> resources;

  protected JnlpResourcePack(URL pJnlpUrl)
  {
    jnlpUrl = pJnlpUrl;
  }

  @Nonnull
  @Override
  public String getId()
  {
    return JLoadrUtil.getHash(jnlpUrl.toExternalForm());
  }

  @Nonnull
  @Override
  public List<IResource> getResources()
  {
    return new ArrayList<>(getResourcesMap().values());
  }

  @Nullable
  @Override
  public IResource getResource(@Nonnull IResourceId pId)
  {
    return getResourcesMap().get(pId);
  }

  synchronized Collection<JnlpUrl> getJnlpUrls()
  {
    if (jnlpUrls == null)
      jnlpUrls = JnlpUrl.load(jnlpUrl);
    return jnlpUrls;
  }

  synchronized Map<IResourceId, IResource> getResourcesMap()
  {
    if (resources == null)
      resources = Stream.concat(
          getJnlpUrls().stream()
              .flatMap(JnlpUrl::streamJarJnlpReferences)
              .map(JnlpURLResource::new)
              .filter(jnlpURLResource -> {
                try {
                  jnlpURLResource.getId();
                  return true;
                }
                catch (Exception pE) {
                  System.err.println(pE.getMessage());
                  return false;
                }
              }),
          Stream.of(_getSplashResource(), new _ConfigResource()))
          .filter(Objects::nonNull)
          .collect(Collectors.toMap(IResource::getId, Function.identity(), (r1, r2) -> r1, LinkedHashMap::new));
    return resources;
  }

  private IResource _getSplashResource()
  {
    return getJnlpUrls().stream()
        .flatMap(jnlpUrl -> jnlpUrl.findChildElementsByPath("information/icon").stream()
            .map(element -> new AbstractMap.SimpleImmutableEntry<>(jnlpUrl, element)))
        .filter(entry -> entry.getValue().getAttribute("kind").equals("splash"))
        .map(entry -> {
          try {
            return new URLResource(new URL(entry.getKey().getCodebase(), entry.getValue().getAttribute("href")))
            {
              @Nonnull
              @Override
              public IResourceId getId()
              {
                return new ResourceId("splash");
              }
            };
          }
          catch (MalformedURLException pE) {
            return null;
          }
        })
        .findAny().orElse(null);
  }


  private class _ConfigResource extends AbstractJLoaderConfigResource
  {
    @Override
    public long getLastModified() throws IOException
    {
      URLConnection urlConnection = jnlpUrl.openConnection();
      return urlConnection.getLastModified();
    }

    @Override
    protected JLoaderConfig createConfig()
    {
      Collection<JnlpUrl> jnlpUrls = getJnlpUrls();

      List<String> vmProperties = jnlpUrls.stream()
          .flatMap(jnlpUrl -> jnlpUrl.findChildElementsByPath("resources/property").stream())
          .map(element -> {
            String name = element.getAttribute("name").replace("jnlp.adito.", "");
            String value = element.getAttribute("value");
            return name.isEmpty() ? null : name + (value.isEmpty() ? "" : "=" + value);
          })
          .filter(Objects::nonNull)
          .collect(Collectors.toList());

      List<String> classpath = getResourcesMap().keySet().stream()
          .map(id -> id.toString().replace(".pack.gz", ""))
          .collect(Collectors.toList());

      String mainClass = jnlpUrls.stream()
          .flatMap(jnlpUrl -> jnlpUrl.findChildElementsByPath("application-desc").stream())
          .map(element -> element.getAttribute("main-class"))
          .filter(str -> str != null && !str.isEmpty())
          .findAny().orElseThrow(() -> new RuntimeException("no main class defined"));

      List<String> arguments = jnlpUrls.stream()
          .flatMap(jnlpUrl -> jnlpUrl.findChildElementsByPath("application-desc/argument").stream())
          .map(element -> element.getTextContent().trim())
          .collect(Collectors.toList());

      JLoaderConfig jLoaderConfig = new JLoaderConfig();
      jLoaderConfig.setVmParameters(vmProperties);
      jLoaderConfig.setClasspath(classpath);
      jLoaderConfig.setMainCls(mainClass);
      jLoaderConfig.setArguments(arguments);

      return jLoaderConfig;
    }
  }


}

@@ -3380,16 +3380,22 @@
 ito.%22, %22
+adito.
 %22);%0A    

Fix 'jnlp.adito.' vm parameters.