/*-
 * ~~~~~~licensing~~~~~~
 * core-support-runtime
 * ==========
 * Copyright (C) 2020 - 2025 EmDev LLC
 * ==========
 * You may not use this file except in accordance with the License Terms of the Copyright
 * Holder located at: https://entaxy.ru/eula . All copyrights, all intellectual property
 * rights to the Software and any copies are the property of the Copyright Holder. Unless
 * it is explicitly allowed the Copyright Holder, the User is prohibited from using the
 * Software for commercial purposes to provide services to third parties.
 * 
 * The Copyright Holder hereby declares that the Software is provided on an "AS IS".
 * Under no circumstances does the Copyright Holder guarantee or promise that the
 * Software provided by him will be suitable or not suitable for the specific purposes
 * of the User, that the Software will meet all commercial and personal subjective
 * expectations of the User, that the Software will work properly, without technical
 * errors, quickly and uninterruptedly.
 * 
 * Under no circumstances shall the Copyright Holder or its Affiliates is not liable
 * to the User for any direct or indirect losses of the User, his expenses or actual
 * damage, including, downtime; loss of bussines; lost profit; lost earnings; loss
 * or damage to data, property, etc.
 * ~~~~~~/licensing~~~~~~
 */
package ru.entaxy.platform.core.support.runtime;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectOutputStream;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.io.FileUtils;
import org.apache.cxf.helpers.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class EntaxyResourceURLCachingClassLoader extends EntaxyResourceURLClassLoader {

	private static final Logger log = LoggerFactory.getLogger(EntaxyResourceURLCachingClassLoader.class);
	
	protected final Map<String, File> cacheRootDir = new HashMap<>();
	
	protected final List<URL> urlsToScan = new ArrayList<>();
	
	public EntaxyResourceURLCachingClassLoader(ClassLoader parent) {
		super(parent);
	}

	public void setResourcePath(List<String> resourcePath) {
		this.resourcePath = resourcePath;
		
		for (String s: resourcePath) {
			try {
				URL urlToAdd = processPath(s);

				if (ENTAXY_RESOURCE_PROTOCOL.equalsIgnoreCase(urlToAdd.getProtocol())) {
				
					URL cacheUrl = getCacheUrl(urlToAdd);
					if (cacheUrl != null) {
						
						File cacheRoot = new File(cacheUrl.toURI());
						cacheRoot.mkdirs();
						
						cacheRootDir.put(urlToAdd.toString(), cacheRoot);
						
						urlsToScan.add(urlToAdd);
						addURL(cacheUrl);
					}
				}
				addURL(urlToAdd);
			} catch (MalformedURLException e) {
				log.error("MalformedURLException for [" + s + "]" , e);
			} catch (URISyntaxException e) {
				log.error("URISyntaxException for cache URI for [" + s + "]" , e);
			}
		}

	}
	
	protected URL getCacheUrl(URL originalUrl) {
	
		try {
			URL request = new URL(originalUrl.toString() + "#timestamp");
			String timestamp = IOUtils.readStringFromStream(request.openConnection().getInputStream());
			String cacheUrl = Paths.get(System.getProperty("karaf.home")
					, "data/tmp/class-cache", timestamp).toAbsolutePath().toUri().toURL().toString();
			log.info("\n\t CACHE URL :: " + cacheUrl);
			return new URL(cacheUrl);
		} catch (MalformedURLException e) {
			log.error("Incorrect URL: " + originalUrl.toString(), e);
			return null;
		} catch (IOException e) {
			log.error("Error getting InputStream; URL: " + originalUrl.toString(), e);
			return null;
		}
	}
	
    protected Class<?> findClass(final String name) throws ClassNotFoundException {
            Class<?> result = super.findClass(name);
            
            // TODO run the cde below in separate thread
            
            // find out rhe url where this class was got from
            URL originUrl = null;
            String classAsPath = name.replace('.', '/').concat(".class");
            
            for (URL scan: urlsToScan) {
            	try {
					URL fixedScan = new URL(scan.toString().replaceAll(" ", "%20"));
					URL toCheck = new URL(fixedScan.toURI().resolve(classAsPath)
							.toString().replaceAll("%20", " "));
					log.info("\n\tCHECK URL :: " + toCheck.toString());
					try (InputStream is = toCheck.openConnection().getInputStream() ) {
						
						File rootFolder = cacheRootDir.get(scan.toString());
						File targetFile = Paths.get(rootFolder.getAbsolutePath().toString(), classAsPath).toFile();
						if (!targetFile.exists()) {
							targetFile.getParentFile().mkdirs();
							targetFile.createNewFile();
							try {
								FileUtils.copyInputStreamToFile(is, targetFile);
							} catch (Exception e1) {
								log.error("Error writing file ".concat(targetFile.getAbsolutePath()), e1);
							}
						}
						
					} catch (Exception e) {
						// continue
						log.info("\n\tCHECKED :: " + toCheck.toString());
					}
				} catch (MalformedURLException | URISyntaxException e) {
					log.error("Error combinig urls: " + scan.toString() + " + " + classAsPath, e);
				}
            }
            
            return result;
    }	
}
