package com.cocoahero.android.gmaps.addons.mapbox;

import java.io.Closeable;
import java.io.File;

import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;

import com.google.android.gms.maps.model.Tile;
import com.google.android.gms.maps.model.TileProvider;

public class MapBoxOfflineTileProvider implements TileProvider, Closeable {

    // ------------------------------------------------------------------------
    // Instance Variables
    // ------------------------------------------------------------------------

    private int mMinimumZoom = Integer.MIN_VALUE;
    private int mMaximumZoom = Integer.MAX_VALUE;
    private SQLiteDatabase mDatabase;

    // ------------------------------------------------------------------------
    // Constructors
    // ------------------------------------------------------------------------

    public MapBoxOfflineTileProvider(File file) {
        int flags = SQLiteDatabase.OPEN_READONLY | SQLiteDatabase.NO_LOCALIZED_COLLATORS;
        this.mDatabase = SQLiteDatabase.openDatabase(file.getAbsolutePath(), null, flags);
        this.calculateZoomConstraints();
    }

    // ------------------------------------------------------------------------
    // TileProvider Interface
    // ------------------------------------------------------------------------

    @Override
    public Tile getTile(int x, int y, int z) {
        Tile tile = NO_TILE;
        if (this.isZoomLevelAvailable(z) && this.isDatabaseAvailable()) {
            int row = (int) (Math.pow(2, z) - y);
            String[] projection = { "tile_data" };
            String predicate = "tile_row = ? AND tile_column = ? AND zoom_level = ?";
            String[] values = { String.valueOf(row), String.valueOf(x), String.valueOf(z) };
            Cursor c = this.mDatabase.query("tiles", projection, predicate, values, null, null, null);
            if (c != null) {
                c.moveToFirst();
                if (!c.isAfterLast()) {
                    tile = new Tile(256, 256, c.getBlob(0));
                }
                c.close();
            }
        }
        return tile;
    }

    // ------------------------------------------------------------------------
    // Closeable Interface
    // ------------------------------------------------------------------------

    @Override
    public void close() {
        if (this.mDatabase != null) {
            this.mDatabase.close();
            this.mDatabase = null;
        }
    }

    // ------------------------------------------------------------------------
    // Public Methods
    // ------------------------------------------------------------------------

    public int getMinimumZoom() {
        return this.mMinimumZoom;
    }

    public int getMaximumZoom() {
        return this.mMaximumZoom;
    }
    
    public boolean isZoomLevelAvailable(int zoom) {
        return (zoom >= this.mMinimumZoom) && (zoom <= this.mMaximumZoom);
    }

    // ------------------------------------------------------------------------
    // Private Methods
    // ------------------------------------------------------------------------

    private void calculateZoomConstraints() {
        if (this.isDatabaseAvailable()) {
            String[] projection = { "min(zoom_level)", "max(zoom_level)" };
            Cursor c = this.mDatabase.query("tiles", projection, null, null, null, null, null);
            c.moveToFirst();
            if (!c.isAfterLast()) {
                this.mMinimumZoom = c.getInt(0);
                this.mMaximumZoom = c.getInt(1);
            }
            c.close();
        }
    }

    private boolean isDatabaseAvailable() {
        return (this.mDatabase != null) && (this.mDatabase.isOpen());
    }

}

@@ -906,24 +906,131 @@
 ile file) %7B%0A
+        this(file.getAbsolutePath());%0A    %7D%0A    %0A    public MapBoxOfflineTileProvider(String pathToFile) %7B%0A
         int 
@@ -1160,38 +1160,26 @@
 atabase(
-file.getAbsolutePath()
+pathToFile
 , null, 
@@ -2412,32 +2412,328 @@
 --------------%0A%0A
+    /**%0A     * Closes the provider, cleaning up any background resources.%0A     * %0A     * %3Cp%3E%0A     * You must call %7B@link #close()%7D when you are finished using an instance of%0A     * this provider. Failing to do so may leak resources, such as the backing%0A     * SQLiteDatabase.%0A     * %3C/p%3E%0A     */%0A
     @Override%0A  
@@ -3073,78 +3073,488 @@
     
-public int getMinimumZoom() %7B%0A        return this.mMinimumZoom;%0A    %7D%0A
+/**%0A     * The minimum zoom level supported by this provider.%0A     * %0A     * @return the minimum zoom level supported or %7B@link Integer.MIN_VALUE%7D if%0A     *         it could not be determined.%0A     */%0A    public int getMinimumZoom() %7B%0A        return this.mMinimumZoom;%0A    %7D%0A%0A    /**%0A     * The maximum zoom level supported by this provider.%0A     * %0A     * @return the maximum zoom level supported or %7B@link Integer.MAX_VALUE%7D if%0A     *         it could not be determined.%0A     */
 %0A   
@@ -3616,36 +3616,280 @@
 imumZoom;%0A    %7D%0A
+%0A
     
+/**%0A     * Determines if the requested zoom level is supported by this provider.%0A     * %0A     * @param zoom The requested zoom level.%0A     * @return %7B@code true%7D if the requested zoom level is supported by this%0A     *         provider.%0A     */
 %0A    public bool

Add some documentation