package org.itsnat.itsnatdroidtest.testact.local.intern;
import android.content.Context;
import org.itsnat.itsnatdroidtest.testact.TestActivity;
import org.itsnat.itsnatdroidtest.testact.local.TestSetupLocalLayoutBase;
import org.itsnat.itsnatdroidtest.testact.util.Util;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
/**
* Created by jmarranz on 21/05/2016.
*/
public abstract class AsyncTaskInternResourcesLoader extends android.os.AsyncTask<Void, Void, Object>
{
protected TestActivity act;
public AsyncTaskInternResourcesLoader(TestActivity act)
{
this.act = act;
}
@Override
protected Object doInBackground(Void... params)
{
String urlTestBase = act.getURLTestBase();
String urlDownloadBase = urlTestBase + "/droid/download/";
String urlList = urlDownloadBase + "resources.txt";
try { cleanDownloadedResources(); }
catch (Exception ex) { return ex; }
InputStream input;
try { input = openRemote(urlList); }
catch (Exception ex) { return ex; }
ArrayList<String> resourceLocationList;
try { resourceLocationList = readRemoteResourceLocationList(input); }
catch (Exception ex) { return ex; }
ArrayList<byte[]> resources;
try { resources = downloadResources(resourceLocationList,urlDownloadBase); }
catch (Exception ex) { return ex; }
try { writeResources(resourceLocationList,resources); }
catch (Exception ex) { return ex; }
return null;
}
private InputStream openRemote(String url) throws IOException
{
URL urlObj = new URL(url);
URLConnection urlConnection = urlObj.openConnection();
urlConnection.setConnectTimeout(5000);
urlConnection.setReadTimeout(20000);
urlConnection.setDoInput(true);
return urlConnection.getInputStream();
}
private ArrayList<String> readRemoteResourceLocationList(InputStream input)
{
ArrayList<String> resourceList = new ArrayList<String>(30);
Scanner sc = new Scanner(input,"UTF-8");
while(sc.hasNextLine())
{
String res = sc.nextLine();
String resTrim = res.trim();
if (resTrim.isEmpty()) continue;
if (resTrim.startsWith("#")) continue;
resourceList.add(res);
}
sc.close();
return resourceList;
}
private ArrayList<byte[]> downloadResources(List<String> resourceList, final String urlDownloadBase) throws Exception
{
ArrayList<byte[]> resourceBinList = new ArrayList<byte[]>(resourceList.size());
List<Callable<byte[]>> listCallable = new ArrayList<Callable<byte[]>>(resourceList.size());
for(final String resource : resourceList)
{
Callable<byte[]> callable = new Callable<byte[]>()
{
@Override
public byte[] call() throws Exception
{
String url = urlDownloadBase + resource;
InputStream input = openRemote(url);
return Util.read(input);
}
};
listCallable.add(callable);
}
ExecutorService service = Executors.newCachedThreadPool();
List<Future<byte[]>> listFuture = service.invokeAll(listCallable);
for(Future<byte[]> future : listFuture)
{
byte[] data = future.get(30000, TimeUnit.MILLISECONDS); //http://stackoverflow.com/questions/12305667/how-is-exception-handling-done-in-a-callable
resourceBinList.add(data);
}
return resourceBinList;
}
private void writeResources(ArrayList<String> resourceLocationList,ArrayList<byte[]> resources) throws Exception
{
// http://stackoverflow.com/questions/21326331/how-to-create-nested-folders-and-file-in-context-mode-private
File rootDir = act.getDir(TestSetupLocalLayoutBase.internLocationBase,Context.MODE_PRIVATE); // Crea inicialmente el folder si es necesario añadiendo "app_" ej con "intern" como parámetro /data/data/org.itsnat.itsnatdroidtest/app_intern
// A partir de aquí usar métodos normales pues openFileOutput no admite subdirectorios
int size = resourceLocationList.size();
for(int i = 0; i < size; i++)
{
String location = resourceLocationList.get(i);
byte[] resource = resources.get(i);
int index = location.lastIndexOf('/'); // Esperamos que location apunte a un archivo no a un folder y tenga formato UNIX y que tenga algún subdirectorio
if (index == -1) throw new RuntimeException("Expected some character / in file location format " + location);
String parentLocation = location.substring(0,index);
String locationFileName = location.substring(index + 1);
File internParentDir = new File(rootDir.getAbsolutePath(),parentLocation);
internParentDir.mkdirs();
String absLocation = internParentDir.getAbsolutePath() + "/" + locationFileName;
FileOutputStream outputStream = new FileOutputStream(absLocation);
outputStream.write(resource);
outputStream.close();
}
}
private void cleanDownloadedResources()
{
File dirRoot = act.getDir(TestSetupLocalLayoutBase.internLocationBase,Context.MODE_PRIVATE);
Util.cleanFileTree(dirRoot);
if (dirRoot.listFiles() != null) throw new RuntimeException("Unexpected");
}
@SuppressWarnings("unchecked")
@Override
protected void onPostExecute(Object result)
{
if (result instanceof Exception)
onFinishError((Exception)result);
else
onFinishOk(result);
}
@Override
protected void onPreExecute() {
}
@Override
protected void onProgressUpdate(Void... values) {
}
public abstract void onFinishOk(Object result);
public abstract void onFinishError(Exception ex);
}