
package javacodebook.thread.imagedownload;

/**
 * Mit Hilfe dieser Klasse werden Bilder einer Webseite heruntergeladen und in
 * einem vorgegebenen Verzeichnis abgespeichert. 
 * @author Mark Donnermeyer
 */

import javacodebook.regex.html.*;
import java.io.*;
import java.net.URL;
import java.util.Hashtable;

public class DownloadImageVisitor implements LinkVisitor {
    URL  absoluteUrl    = null;
    File downloadFolder = null;
    Hashtable images = new Hashtable();
    
    public DownloadImageVisitor(URL absoluteUrl, File downloadFolder) {
        this.absoluteUrl = absoluteUrl;
        this.downloadFolder = downloadFolder;
    }

    /**
     * Lädt ein Bild von der angegebenen Quelle herunter und speichert es im
     * vorgegebenen Verzeichnis ab. Es wird der Name der Datei, unter dem das
     * Bild zu finden ist, zurückgegeben.
     */
    public String processLink(String tag, String link, boolean href) {
        if (href == true)
            return link;
        
        File file;
        try {
            // Zunächst feststellen, ob dieser Link schon einmal vorgekommen ist.
            // Wenn nicht, dann das entsprechende Bild herunterladen und speichern.
            URL absLink = new URL(absoluteUrl, link);
            if (images.containsKey(absLink))
                file = (File)images.get(absLink);
            else {
                // Evtl. gibt es gleiche Bildnamen unter verschiendenen URL's.
                // Daher muss ein eindeutiger Name gefunden werden.
                // Anschliessend kann das Bild heruntergeladen werden.
                file = getFilename(absLink, downloadFolder);
                images.put(absLink, file);
                ImageDownloader id = new ImageDownloader(absLink, file);
                id.start();
            }
            System.out.println(absLink + " -> " + file);
            return file.toString();
        }
        catch (Exception e) {
            System.err.println("Konnte nicht bearbeitet werden: " + link);
        }
        return link;
    }
    
    /**
     * Es wird ein eindeutiger Dateiname erzeugt. Zuerst wird der Originalname
     * ausprobiert. Wenn das fehlschlägt, dann wird der Name solange durch 
     * Anhängen einer laufenden Nummer verändert, bis er eindeutig ist.
     */
    private File getFilename(URL absLink, File folder) throws IOException {
        String prefix, suffix;
        
        File file = new File(absLink.getPath());
        int dotIndex = file.getName().lastIndexOf('.');
        if (dotIndex > -1) {
            prefix = file.getName().substring(0, dotIndex);
            suffix = file.getName().substring(dotIndex);
        }
        else {
            prefix = file.getName();
            suffix = "";
        }
        
        int index = 0;
        String infix = "";
        while (true) {
            file = new File(folder.toString(), prefix + infix + suffix);
            if (!file.exists())
                break;
            index++;
            infix = "_" + index;
        }
        return file;
    }
}

/**
 * Dieser Thread lädt das Bild von der URL herunter und speichert es unter dem
 * vorgegebenen Namen ab.
 */
class ImageDownloader extends Thread {
    URL image = null;
    File file = null;
    
    public ImageDownloader(URL image, File file) {
        this.image = image;
        this.file = file;
    }
    
    public void run() {
        try {
            FileOutputStream out = new FileOutputStream(file);
            InputStream in = image.openStream();
            
            byte[] buf = new byte[1023];
            int len = -1;
            
            // Das Bild wird ausgelesen und in die Datei geschrieben
            while ((len = in.read(buf)) > -1)
                out.write(buf, 0, len);
            
            in.close();
            out.close();
        }
        catch (Exception e) {
            System.err.println("Fehler beim Download einer Datei: " + e.getMessage());
        }
    }
    
}
