/*
 * Copyright (c) 2016 Open Baton (http://www.openbaton.org)
 *
 * 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.
 *
 */

package org.openbaton.nfvo.core.api;

import org.openbaton.exceptions.AlreadyExistingException;
import org.openbaton.plugin.mgmt.PluginStartup;
import org.openbaton.utils.rabbit.RabbitManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URL;
import java.util.HashSet;
import java.util.Set;

/** Created by rvl on 19.10.16. */
@Service
public class PluginManager implements org.openbaton.nfvo.core.interfaces.PluginManager {

  private final Logger log = LoggerFactory.getLogger(this.getClass());

  @Value("${nfvo.plugin.active.consumers:10}")
  private String numConsumers;

  @Value("${spring.rabbitmq.username:admin}")
  private String username;

  @Value("${spring.rabbitmq.password:openbaton}")
  private String password;

  @Value("${nfvo.rabbit.management.port:15672}")
  private String managementPort;

  @Value("${nfvo.rabbit.brokerIp:localhost}")
  private String brokerIp;

  @Value("${nfvo.plugin.installation-dir:./plugins}")
  private String pluginDir;

  @Value("${nfvo.plugin.wait:true}")
  private boolean waitForPlugin;

  @Value("${nfvo.plugin.install:true}")
  private boolean installPlugin;

  @Value("${spring.config.location:/etc/openbaton/openbaton.properties}")
  private String propFileLocation;

  @Value("${nfvo.plugin.log.path:./plugin-logs}")
  private String pluginLogPath;

  @Value("${nfvo.marketplace.ip:marketplace.openbaton.org}")
  private String marketIp;

  @Value("${nfvo.marketplace.port:8082}")
  private int marketPort;

  @Override
  public void downloadPlugin(String type, String name, String version)
      throws IOException, AlreadyExistingException {

    String id = type + "/" + name + "/" + version;

    for (String pluginId : listInstalledVimDrivers()) {
      if (pluginId.contains(type)) {
        throw new AlreadyExistingException("Plugin of type " + type + " is already installed");
      }
    }
    String url = "http://" + marketIp + ":" + marketPort + "/api/v1/vim-drivers/" + id + "/jar";
    File pluginFolder = new File(pluginDir);
    File[] plugins = pluginFolder.listFiles();
    boolean found = false;
    if (plugins != null) {
      for (File plugin : plugins) {
        if (plugin.getName().toLowerCase().contains(type)) {
          log.info(
              "The plugin "
                  + name
                  + " is already downloaded, but is not started. Starting plugin now.");
          found = true;
          startPlugin(plugin.getPath(), name);
          break;
        }
      }
    }
    if (!found) {
      log.info("Download URL: " + url);
      String path = pluginDir + "/" + name + ".jar";
      URL pluginURL = new URL(url);
      FileOutputStream out = new FileOutputStream(path);
      try {
        BufferedInputStream fileInputStream = new BufferedInputStream(pluginURL.openStream());
        byte[] buf = new byte[8192];
        int bytesread = 0, bytesBuffered = 0;
        while ((bytesread = fileInputStream.read(buf)) > -1) {
          out.write(buf, 0, bytesread);
          bytesBuffered += bytesread;
          if (bytesBuffered > 1024 * 1024) { //flush after 1MB
            bytesBuffered = 0;
            out.flush();
          }
        }
      } finally {
        out.flush();
      }
      startPlugin(path, name);
    }
  }

  @Override
  public void startPlugin(String path, String name) throws IOException {

    PluginStartup.installPlugin(
        name,
        path,
        "localhost",
        "5672",
        Integer.parseInt(numConsumers),
        username,
        password,
        "" + managementPort,
        pluginLogPath,
        waitForPlugin);
  }

  @Override
  public Set<String> listInstalledVimDrivers() throws IOException {
    Set<String> result = new HashSet<>();
    for (String pluginId :
        RabbitManager.getQueues(brokerIp, username, password, Integer.parseInt(managementPort))) {
      if (pluginId.startsWith("vim-driver")) result.add(pluginId);
    }
    return result;
  }
}

@@ -1119,16 +1119,47 @@
 et.URL;%0A
+import java.net.URLConnection;%0A
 import j
@@ -2504,24 +2504,74 @@
 Exception %7B%0A
+    String filename = name.toLowerCase() + %22.jar%22;
 %0A    String 
@@ -2818,105 +2818,8 @@
   %7D%0A
-    String url = %22http://%22 + marketIp + %22:%22 + marketPort + %22/api/v1/vim-drivers/%22 + id + %22/jar%22;%0A
     
@@ -3359,129 +3359,567 @@
     
-log.info(%22Download URL: %22 + url);%0A      String path = pluginDir + %22/%22 + name + %22.jar%22;%0A      URL pluginURL = new URL(url)
+String url = %22http://%22 + marketIp + %22:%22 + marketPort + %22/api/v1/vim-drivers/%22 + id + %22/jar%22;%0A      log.info(%22Download URL: %22 + url);%0A      URL pluginURL = new URL(url);%0A      URLConnection conn = pluginURL.openConnection();%0A      String headerField = conn.getHeaderField(%22Content-Disposition%22);%0A      if (headerField != null && headerField.contains(%22filename=%5C%22%22)) %7B%0A        filename =%0A            headerField.substring(%0A                headerField.indexOf(%22filename=%5C%22%22) + 10, headerField.length() - 1);%0A      %7D%0A      String path = pluginDir + %22/%22 + filename
 ;%0A  
@@ -4055,30 +4055,29 @@
 tStream(
-pluginURL.open
+conn.getInput
 Stream()

save the downloaded plugins with the correct name convention