package photato.core.metadata.exif;

import java.util.logging.Logger;
import java.util.logging.Level;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.nio.file.FileSystem;
import java.nio.file.Files;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import org.apache.commons.io.IOUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import photato.helpers.OsHelper;

public class ExifToolDownloader {
    private static final Logger LOGGER = Logger.getLogger( ExifToolDownloader.class.getName() );
    private static final Pattern namePattern = Pattern.compile("http://owl\\.phy\\.queensu\\.ca/~phil/exiftool/exiftool-[0-9]+\\.[0-9]+\\.zip");
    private static final String exifToolRslUrl = "http://owl.phy.queensu.ca/~phil/exiftool/rss.xml";
    private static final String tmpFilename = "exiftool.exe.tmp";
    private static final String targetFilename = "exiftool.exe";
    private static final long maxDelayBeforeRedownload = 30 * 86400 * 1000L;

    public static void run(HttpClient httpClient, FileSystem fileSystem, boolean forceExifToolsDownload) throws IOException {
        if (OsHelper.isWindows()) {
            if (!fileSystem.getPath(targetFilename).toFile().exists()
                    || forceExifToolsDownload
                    || Files.getLastModifiedTime(fileSystem.getPath(targetFilename)).toMillis() + maxDelayBeforeRedownload < System.currentTimeMillis()) {
                LOGGER.log(Level.INFO, "Starting exifTools download");
                downloadExifTools(getExifToolsZipUrl(httpClient), httpClient, fileSystem);
                LOGGER.log(Level.INFO, "End of exifTools download");
            }
        }
    }

    private static String getExifToolsZipUrl(HttpClient httpClient) throws IOException {
        HttpGet request = new HttpGet(exifToolRslUrl);
        HttpResponse response = httpClient.execute(request);
        try (BufferedReader rd = new BufferedReader(new InputStreamReader(response.getEntity().getContent()))) {
            StringBuilder result = new StringBuilder();
            String line;
            while ((line = rd.readLine()) != null) {
                result.append(line);
            }

            Matcher m = namePattern.matcher(result.toString());
            if (m.find()) {
                return m.group(0);
            } else {
                throw new IOException("Cannot find the exiftool url in the provided rss");
            }
        }
    }

    private static void downloadExifTools(String exifToolsUrl, HttpClient httpClient, FileSystem fileSystem) throws IOException {
        HttpGet request = new HttpGet(exifToolsUrl);
        HttpResponse response = httpClient.execute(request);
        HttpEntity entity = response.getEntity();
        if (entity != null) {
            // Download the zip file
            File tmpFile = fileSystem.getPath(tmpFilename).toFile();
            tmpFile.delete(); // Delete the tmp file in case it already exists
            try (InputStream inputStream = entity.getContent();
                    OutputStream outputStream = new FileOutputStream(tmpFile)) {
                IOUtils.copy(inputStream, outputStream);
            }

            // Unzip
            try (ZipInputStream zis = new ZipInputStream(new FileInputStream(tmpFile))) {
                ZipEntry ze = zis.getNextEntry();

                if (ze != null) {
                    File newFile = fileSystem.getPath(targetFilename).toFile();
                    newFile.delete(); // Delete in case it already exists

                    byte[] buffer = new byte[4096];
                    try (FileOutputStream fos = new FileOutputStream(newFile)) {
                        int len;
                        while ((len = zis.read(buffer)) > 0) {
                            fos.write(buffer, 0, len);
                        }
                    }
                }
            }

            // Delete .zipFile
            tmpFile.delete();
        }
    }

}