package cgeo.geocaching.network;

import cgeo.geocaching.R;
import cgeo.geocaching.Settings;
import cgeo.geocaching.cgBase;
import cgeo.geocaching.connector.ConnectorFactory;
import cgeo.geocaching.files.LocalStorage;

import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpResponse;
import org.apache.http.entity.BufferedHttpEntity;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.net.Uri;
import android.text.Html;
import android.util.Log;
import android.view.Display;
import android.view.WindowManager;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Date;

public class HtmlImage implements Html.ImageGetter {

    private static final String[] BLOCKED = new String[] {
            "gccounter.de",
            "gccounter.com",
            "cachercounter/?",
            "gccounter/imgcount.php",
            "flagcounter.com",
            "compteur-blog.net",
            "counter.digits.com",
            "andyhoppe"
    };
    final private Context context;
    final private String geocode;
    /**
     * on error: return large error image, if <code>true</code>, otherwise empty 1x1 image
     */
    final private boolean returnErrorImage;
    final private int reason;
    final private boolean onlySave;
    final private BitmapFactory.Options bfOptions;
    final private int maxWidth;
    final private int maxHeight;

    public HtmlImage(final Context contextIn, final String geocode, final boolean returnErrorImage, final int reason, final boolean onlySave) {
        this.context = contextIn;
        this.geocode = geocode;
        this.returnErrorImage = returnErrorImage;
        this.reason = reason;
        this.onlySave = onlySave;

        bfOptions = new BitmapFactory.Options();
        bfOptions.inTempStorage = new byte[16 * 1024];

        final Display display = ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
        this.maxWidth = display.getWidth() - 25;
        this.maxHeight = display.getHeight() - 25;
    }

    @Override
    public BitmapDrawable getDrawable(final String url) {
        // Reject empty and counter images URL
        if (StringUtils.isBlank(url) || isCounter(url)) {
            return null;
        }

        Bitmap imagePre = null;

        // Load image from cache
        if (!onlySave) {
            imagePre = loadImageFromStorage(url);
        }

        // Download image and save it to the cache
        if (imagePre == null || onlySave) {
            final String absoluteURL = makeAbsoluteURL(url);
            BufferedHttpEntity bufferedEntity = null;

            if (absoluteURL != null) {
                try {
                    final HttpResponse httpResponse = cgBase.request(absoluteURL, null, false);
                    if (httpResponse != null) {
                        bufferedEntity = new BufferedHttpEntity(httpResponse.getEntity());
                    }
                } catch (Exception e) {
                    Log.e(Settings.tag, "HtmlImage.getDrawable (downloading from web)", e);
                }
            }

            final File file = LocalStorage.getStorageFile(geocode, url, true, true);
            LocalStorage.saveEntityToFile(bufferedEntity, file);
        }

        if (onlySave) {
            return null;
        }

        // now load the newly downloaded image
        if (imagePre == null) {
            imagePre = loadImageFromStorage(url);
        }

        // get image and return
        if (imagePre == null) {
            Log.d(Settings.tag, "HtmlImage.getDrawable: Failed to obtain image");

            if (returnErrorImage) {
                imagePre = BitmapFactory.decodeResource(context.getResources(), R.drawable.image_not_loaded);
            } else {
                imagePre = BitmapFactory.decodeResource(context.getResources(), R.drawable.image_no_placement);
            }
        }

        final int imgWidth = imagePre.getWidth();
        final int imgHeight = imagePre.getHeight();

        int width;
        int height;

        if (imgWidth > maxWidth || imgHeight > maxHeight) {
            final double ratio = Math.min((double) maxHeight / (double) imgHeight, (double) maxWidth / (double) imgWidth);
            width = (int) Math.ceil(imgWidth * ratio);
            height = (int) Math.ceil(imgHeight * ratio);

            try {
                imagePre = Bitmap.createScaledBitmap(imagePre, width, height, true);
            } catch (Exception e) {
                Log.d(Settings.tag, "HtmlImage.getDrawable: Failed to scale image");
                return null;
            }
        } else {
            width = imgWidth;
            height = imgHeight;
        }

        final BitmapDrawable image = new BitmapDrawable(imagePre);
        image.setBounds(new Rect(0, 0, width, height));

        return image;
    }

    private Bitmap loadImageFromStorage(final String url) {
        try {
            final File file = LocalStorage.getStorageFile(geocode, url, true, false);
            final Bitmap image = loadCachedImage(file);
            if (image != null) {
                return image;
            }
            final File fileSec = LocalStorage.getStorageSecFile(geocode, url, true);
            return loadCachedImage(fileSec);
        } catch (Exception e) {
            Log.w(Settings.tag, "HtmlImage.getDrawable (reading cache): " + e.toString());
        }
        return null;
    }

    private final String makeAbsoluteURL(final String url) {
        try {
            // Check if uri is absolute or not, if not attach the connector hostname
            // FIXME: that should also include the scheme
            if (Uri.parse(url).isAbsolute()) {
                return url;
            } else {
                final String host = ConnectorFactory.getConnector(geocode).getHost();
                if (StringUtils.isNotEmpty(host)) {
                    return "http://" + host + url;
                }
            }
        } catch (Exception e) {
            Log.e(Settings.tag, "HtmlImage.makeAbsoluteURL (parse URL)", e);
        }
        return null;
    }

    private Bitmap loadCachedImage(final File file) {
        if (file.exists()) {
            if (reason > 0 || file.lastModified() > (new Date().getTime() - (24 * 60 * 60 * 1000))) {
                setSampleSize(file);
                return BitmapFactory.decodeFile(file.getPath(), bfOptions);
            }
        }
        return null;
    }

    private void setSampleSize(final File file) {
        //Decode image size only
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;

        FileInputStream fis = null;
        try {
            fis = new FileInputStream(file);
            BitmapFactory.decodeStream(fis, null, options);
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }

        int scale = 1;
        if (options.outHeight > maxHeight || options.outWidth > maxWidth) {
            scale = Math.max(options.outHeight / maxHeight, options.outWidth / maxWidth);
        }
        bfOptions.inSampleSize = scale;
    }

    private static boolean isCounter(final String url) {
        for (String entry : BLOCKED) {
            if (StringUtils.containsIgnoreCase(url, entry)) {
                return true;
            }
        }
        return false;
    }
}

@@ -2427,35 +2427,75 @@
         return n
-ull
+ew BitmapDrawable(getTransparent1x1Image())
 ;%0A        %7D%0A%0A   
@@ -4043,90 +4043,31 @@
 e = 
-BitmapFactory.decodeResource(context.getResources(), R.drawable.image_no_placement
+getTransparent1x1Image(
 );%0A 
@@ -5031,32 +5031,185 @@
 n image;%0A    %7D%0A%0A
+    private Bitmap getTransparent1x1Image() %7B%0A        return BitmapFactory.decodeResource(context.getResources(), R.drawable.image_no_placement);%0A    %7D%0A%0A
     private Bitm

use 1x1 transparent image instead of undefined image for counter banners (avoids small blue/violet square in description)