package com.epam.jenkins.deployment.sphere.plugin.metadata.persistence.dao;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Enumeration;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import javax.sql.DataSource;

import org.flywaydb.core.Flyway;
import lombok.NonNull;
import lombok.extern.java.Log;

import com.google.common.io.ByteStreams;

@Log
public class DatabaseMigrator {

    private static final Character CLASSPATH_DELIMITER = '/';
    private static final String JAR_FILE_NAME = "classes.jar";
    private static final String MIGRATION_SOURCE_PATH = "db/migration";
    private static final String MIGRATION_DIST_PATH = File.separator + ".." + File.separator + "classes" + File.separator + MIGRATION_SOURCE_PATH;
    private static final String DB_VERSION_TABLE = "SCHEMA_VERSION";

    public void migrate(@NonNull DataSource dataSource) {
        log.info("Db migration started");
        Flyway flyway = new Flyway();
        flyway.setLocations(prepareMigrationLocation());
        flyway.setBaselineOnMigrate(true);
        flyway.setTable(DB_VERSION_TABLE);
        flyway.setDataSource(dataSource);
        flyway.setClassLoader(this.getClass().getClassLoader());
        flyway.migrate();
        log.info("Db migration successfully done");
    }

    private String prepareMigrationLocation() {
        String migrationSourcePath;
        try {
            JarFile jarFile = getClassJarFile(DatabaseMigrator.class);
            String jarLocation = jarFile.getName().replace(JAR_FILE_NAME, "");
            copyMigrationToClassPath(jarFile, MIGRATION_SOURCE_PATH, jarLocation + MIGRATION_DIST_PATH);
            migrationSourcePath = "filesystem:" + jarLocation + MIGRATION_DIST_PATH;
        } catch (IOException e) {
            log.warning("Loading migration files error: " + e.getMessage());
            migrationSourcePath = "classpath:" + MIGRATION_SOURCE_PATH;
        }
        return migrationSourcePath;
    }

    private JarFile getClassJarFile(Class<?> clazz) throws IOException {
        String path = CLASSPATH_DELIMITER + clazz.getName().replace('.', CLASSPATH_DELIMITER) + ".class";
        String url = clazz.getResource(path).toString();
        int bangIndex = url.indexOf("!");
        if (bangIndex == -1) {
            throw new IOException("Jar file not found");
        }
        String jarUriPrefix = "jar:file:";
        return new JarFile(url.substring(jarUriPrefix.length() + 1, url.indexOf("!")));
    }

    private void copyMigrationToClassPath(JarFile jarFile, String jarDirectory, String destinationDirectory) throws IOException {
        for (Enumeration<JarEntry> entries = jarFile.entries(); entries.hasMoreElements(); ) {
            JarEntry entry = entries.nextElement();
            if (isMigrationEntry(entry, jarDirectory)) {
                String destinationFileName = destinationDirectory + File.separator + entry.getName().substring(jarDirectory.length());
                File destinationFile = new File(destinationFileName);
                File parentFile = destinationFile.getParentFile();
                if (parentFile != null) {
                    parentFile.mkdirs();
                }
                copyMigrationResources(jarFile, entry, destinationFile);
            }
        }
    }

    private void copyMigrationResources(final JarFile jarFile, final JarEntry entry, final File destinationFile) throws IOException {
        try (InputStream in = jarFile.getInputStream(entry);
             OutputStream out = new FileOutputStream(destinationFile)) {
            ByteStreams.copy(in, out);
        }
    }

    private boolean isMigrationEntry(JarEntry entry, String jarDirectory) {
        return entry.getName().startsWith(jarDirectory + CLASSPATH_DELIMITER) && !entry.isDirectory();
    }

}
@@ -1078,22 +1078,22 @@
 cations(
-p
 re
-par
+solv
 eMigrati
@@ -1086,32 +1086,41 @@
 resolveMigration
+Resources
 Location());%0A   
@@ -1417,14 +1417,14 @@
 ing 
-p
 re
-par
+solv
 eMig
@@ -1429,16 +1429,25 @@
 igration
+Resources
 Location
@@ -1470,89 +1470,99 @@
 ing 
-migrationSourcePath;%0A        try %7B%0A            JarFile jarFile = getClassJarFile(
+sourcePath = %22classpath:%22 + MIGRATION_SOURCE_PATH;%0A        try %7B%0A            Class clazz = 
 Data
@@ -1579,17 +1579,16 @@
 or.class
-)
 ;%0A      
@@ -1604,257 +1604,301 @@
 ing 
-jarLocation = jarFile.getName().replace(JAR_FILE_NAME, %22%22);%0A            copyMigrationToClassPath(jarFile, MIGRATION_SOURCE_PATH, jarLocation + MIGRATION_DIST_PATH);%0A            migrationSourcePath = %22filesystem:%22 + jarLocation + MIGRATION_DIST_PATH;
+path = CLASSPATH_DELIMITER + clazz.getName().replace('.', CLASSPATH_DELIMITER) + %22.class%22;%0A            String url = clazz.getResource(path).toString();%0A            if (url.contains(%22!%22)) %7B%0A                sourcePath = resolveMigrationResourceLocationFromJarFile(sourcePath, url);%0A            %7D
 %0A   
@@ -2009,80 +2009,8 @@
 ));%0A
-            migrationSourcePath = %22classpath:%22 + MIGRATION_SOURCE_PATH;%0A
     
@@ -2034,18 +2034,9 @@
 urn 
-migrationS
+s
 ourc
@@ -2065,255 +2065,238 @@
 ate 
-JarFile getClassJarFile(Class%3C?%3E clazz) throws IOException %7B%0A        String path = CLASSPATH_DELIMITER + clazz.getName().replace('.', CLASSPATH_DELIMITER) + %22.class%22;%0A        String url = clazz.getResource(path).toString();%0A        int bangIndex =
+String resolveMigrationResourceLocationFromJarFile(String sourcePath, final String url) throws IOException %7B%0A        String jarUriPrefix = %22jar:file:%22;%0A        JarFile jarFile = new JarFile(url.substring(jarUriPrefix.length() + 1,
  url
@@ -2308,16 +2308,18 @@
 xOf(%22!%22)
+))
 ;%0A      
@@ -2324,227 +2324,273 @@
     
-if (bangIndex == -1) %7B%0A            throw new IOException(%22Jar file not found%22);%0A        %7D%0A        String jarUriPrefix = %22jar:file:%22;%0A        return new JarFile(url.substring(jarUriPrefix.length() + 1, url.indexOf(%22!%22)))
+String jarLocation = jarFile.getName().replace(JAR_FILE_NAME, %22%22);%0A        copyMigrationToClassPath(jarFile, MIGRATION_SOURCE_PATH, jarLocation + MIGRATION_DIST_PATH);%0A        sourcePath = %22filesystem:%22 + jarLocation + MIGRATION_DIST_PATH;%0A        return sourcePath
 ;%0A  
@@ -3338,17 +3338,16 @@
 Resource
-s
 (jarFile
@@ -3442,17 +3442,16 @@
 Resource
-s
 (final J

Fix one more critical SonarQube issue