package com.meteor.cordova.updater;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import android.content.res.AssetManager;
import android.util.Log;
/**
* Like File, but for an Asset.
*
* The asset API is really slow; so we try to cache/avoid lookups.
*/
public class Asset {
private static final String TAG = "meteor.cordova.updater";
final Cache cache;
final String name;
final String path;
static class Cache {
final AssetManager assetManager;
final Map<String, List<Asset>> contents = new HashMap<String, List<Asset>>();
public Cache(AssetManager assetManager) {
this.assetManager = assetManager;
}
public Asset findAsset(String parentPath, String name) {
List<Asset> children = listAssets(parentPath.toString());
for (Asset child : children) {
if (child.name.equals(name)) {
return child;
}
}
return null;
}
public List<Asset> listAssets(String path) {
List<Asset> assets = this.contents.get(path);
if (assets == null) {
String[] assetNames = null;
try {
// This call is slow, so log it
Log.d(TAG, "Doing assetManager list on " + path);
assetNames = assetManager.list(path);
} catch (IOException e) {
Log.w(TAG, "Error listing assets at " + path, e);
}
if (assetNames == null || assetNames.length == 0) {
assets = Collections.emptyList();
} else {
assets = new ArrayList<Asset>(assetNames.length);
for (String assetName : assetNames) {
String childPath = (path.length() != 0) ? (path + "/" + assetName) : assetName;
assets.add(new Asset(this, assetName, childPath));
}
}
this.contents.put(path, assets);
}
return assets;
}
}
/**
* Private constructor for child assets
*
* @param cache
* @param name
* @param path
*/
private Asset(Cache cache, String name, String path) {
this.cache = cache;
this.name = name;
this.path = path;
assert !path.endsWith("/");
}
/**
* Constructor for root asset
*/
public Asset(AssetManager assetManager, String path) {
this.cache = new Cache(assetManager);
this.name = null;
this.path = path;
assert !path.endsWith("/");
}
public boolean hasChildren() {
return !cache.listAssets(this.path).isEmpty();
}
public boolean exists(String path) {
return find(path) != null;
}
public Asset find(String relativePath) {
if (relativePath == null || relativePath.isEmpty()) {
return this;
}
String path = this.path + "/" + relativePath;
String[] pathTokens = path.split("/");
// The last non-empty token is the name
String name = null;
int end = pathTokens.length - 1;
while (end >= 0) {
String pathToken = pathTokens[end];
if (!pathToken.isEmpty()) {
name = pathToken;
break;
}
end--;
}
if (name == null) {
Log.w(TAG, "Asset find on empty path: " + path);
return null;
}
StringBuilder parentPath = new StringBuilder();
for (int i = 0; i < end; i++) {
String pathToken = pathTokens[i];
if (pathToken.length() == 0) {
// Ignore empty bits (either a leading slash, or a double slash)
continue;
}
if (parentPath.length() != 0) {
parentPath.append("/");
}
parentPath.append(pathToken);
}
return cache.findAsset(parentPath.toString(), name);
}
}