package org.osmdroid.tileprovider.modules;

import android.content.res.AssetManager;
import android.graphics.drawable.Drawable;

import org.osmdroid.tileprovider.ExpirableBitmapDrawable;
import org.osmdroid.tileprovider.IRegisterReceiver;
import org.osmdroid.tileprovider.MapTile;
import org.osmdroid.tileprovider.MapTileRequestState;
import org.osmdroid.tileprovider.tilesource.BitmapTileSourceBase.LowMemoryException;
import org.osmdroid.tileprovider.tilesource.ITileSource;
import org.osmdroid.tileprovider.tilesource.TileSourceFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.io.InputStream;
import java.util.concurrent.atomic.AtomicReference;

/**
 * Implements a file system cache and provides cached tiles from Assets. This
 * functions as a tile provider by serving cached tiles for the supplied tile
 * source.
 *
 * tiles should be put into apk's assets directory just like following example:
 *
 *     assets/Mapnik/11/1316/806.png
 *
 * @author Marc Kurtz
 * @author Nicolas Gramlich
 * @author Behrooz Shabani (everplays)
 *
 */
public class MapTileAssetsProvider extends MapTileFileStorageProviderBase {

	// ===========================================================
	// Constants
	// ===========================================================

	private static final Logger logger = LoggerFactory.getLogger(MapTileAssetsProvider.class);

	// ===========================================================
	// Fields
	// ===========================================================

	private final long mMaximumCachedFileAge;

	private AssetManager mAssets;

	private final AtomicReference<ITileSource> mTileSource = new AtomicReference<ITileSource>();

	// ===========================================================
	// Constructors
	// ===========================================================

	public MapTileAssetsProvider(final IRegisterReceiver pRegisterReceiver, final AssetManager pAssets) {
		this(pRegisterReceiver, pAssets, TileSourceFactory.DEFAULT_TILE_SOURCE);
	}

	public MapTileAssetsProvider(final IRegisterReceiver pRegisterReceiver,
			final AssetManager pAssets,
			final ITileSource aTileSource) {
		this(pRegisterReceiver, pAssets, aTileSource, DEFAULT_MAXIMUM_CACHED_FILE_AGE);
	}

	public MapTileAssetsProvider(final IRegisterReceiver pRegisterReceiver,
			final AssetManager pAssets,
			final ITileSource pTileSource, final long pMaximumCachedFileAge) {
		this(pRegisterReceiver, pAssets, pTileSource, pMaximumCachedFileAge,
				NUMBER_OF_TILE_FILESYSTEM_THREADS,
				TILE_FILESYSTEM_MAXIMUM_QUEUE_SIZE);
	}

	/**
	 * Provides a file system based cache tile provider. Other providers can register and store data
	 * in the cache.
	 *
	 * @param pRegisterReceiver
	 */
	public MapTileAssetsProvider(final IRegisterReceiver pRegisterReceiver,
			final AssetManager pAssets,
			final ITileSource pTileSource, final long pMaximumCachedFileAge, int pThreadPoolSize,
			int pPendingQueueSize) {
		super(pRegisterReceiver, pThreadPoolSize, pPendingQueueSize);
		setTileSource(pTileSource);

		mAssets = pAssets;
		mMaximumCachedFileAge = pMaximumCachedFileAge;
	}
	// ===========================================================
	// Getter & Setter
	// ===========================================================

	// ===========================================================
	// Methods from SuperClass/Interfaces
	// ===========================================================

	@Override
	public boolean getUsesDataConnection() {
		return false;
	}

	@Override
	protected String getName() {
		return "Assets Cache Provider";
	}

	@Override
	protected String getThreadGroupName() {
		return "assets";
	}

	@Override
	protected Runnable getTileLoader() {
		return new TileLoader(mAssets);
	}

	@Override
	public int getMinimumZoomLevel() {
		ITileSource tileSource = mTileSource.get();
		return tileSource != null ? tileSource.getMinimumZoomLevel() : MINIMUM_ZOOMLEVEL;
	}

	@Override
	public int getMaximumZoomLevel() {
		ITileSource tileSource = mTileSource.get();
		return tileSource != null ? tileSource.getMaximumZoomLevel() : MAXIMUM_ZOOMLEVEL;
	}

	@Override
	public void setTileSource(final ITileSource pTileSource) {
		mTileSource.set(pTileSource);
	}

	// ===========================================================
	// Inner and Anonymous Classes
	// ===========================================================

	protected class TileLoader extends MapTileModuleProviderBase.TileLoader {
		private AssetManager mAssets = null;

		public TileLoader(AssetManager pAssets) {
			mAssets = pAssets;
		}

		@Override
		public Drawable loadTile(final MapTileRequestState pState) throws CantContinueException {
			ITileSource tileSource = mTileSource.get();
			if (tileSource == null) {
				return null;
			}

			final MapTile tile = pState.getMapTile();

			try {
				InputStream is = mAssets.open(tileSource.getTileRelativeFilenameString(tile));
				final Drawable drawable = tileSource.getDrawable(is);
				if (drawable != null) {
					drawable.setState(new int[]{ExpirableBitmapDrawable.EXPIRED});
				}
				return drawable;
			} catch (IOException e) {
			} catch (final LowMemoryException e) {
				throw new CantContinueException(e);
			}

			// If we get here then there is no file in the file cache
			return null;
		}
	}
}

@@ -1565,46 +1565,8 @@
 nal 
-long mMaximumCachedFileAge;%0A%0A%09private 
 Asse
@@ -2075,32 +2075,38 @@
 terReceiver,%0A%09%09%09
+%09%09%09%09%09 
 final AssetManag
@@ -2124,296 +2124,42 @@
 %0A%09%09%09
-final ITileSource aTileSource) %7B%0A%09%09this(pRegisterReceiver, pAssets, aTileSource, DEFAULT_MAXIMUM_CACHED_FILE_AGE);%0A%09%7D%0A%0A%09public MapTileAssetsProvider(final IRegisterReceiver pRegisterReceiver,%0A%09%09%09final AssetManager pAssets,%0A%09%09%09final ITileSource pTileSource, final long pMaximumCachedFileAg
+%09%09%09%09%09 final ITileSource pTileSourc
 e) %7B
@@ -2206,39 +2206,16 @@
 eSource,
- pMaximumCachedFileAge,
 %0A%09%09%09%09NUM
@@ -2295,167 +2295,8 @@
 %09%7D%0A%0A
-%09/**%0A%09 * Provides a file system based cache tile provider. Other providers can register and store data%0A%09 * in the cache.%0A%09 *%0A%09 * @param pRegisterReceiver%0A%09 */%0A
 %09pub
@@ -2363,24 +2363,30 @@
 eceiver,%0A%09%09%09
+%09%09%09%09%09 
 final AssetM
@@ -2400,24 +2400,30 @@
 pAssets,%0A%09%09%09
+%09
+%09%09%09%09 
 final ITileS
@@ -2444,42 +2444,8 @@
 rce,
- final long pMaximumCachedFileAge,
  int
@@ -2465,16 +2465,22 @@
 ize,%0A%09%09%09
+%09%09%09%09%09 
 int pPen
@@ -2616,57 +2616,8 @@
 ts;%0A
-%09%09mMaximumCachedFileAge = pMaximumCachedFileAge;%0A
 %09%7D%0A%09

Remove unused variable