package com.amaze.filemanager.fragments;
import android.content.Context;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.util.Log;
import com.amaze.filemanager.filesystem.BaseFile;
import com.amaze.filemanager.filesystem.HFile;
import com.amaze.filemanager.utils.OpenMode;
import java.util.ArrayList;
import java.util.regex.Pattern;
/**
* Created by vishal on 26/2/16.
*/
public class SearchAsyncHelper extends Fragment {
private HelperCallbacks mCallbacks;
private String mPath, mInput;
public SearchTask mSearchTask;
private OpenMode mOpenMode;
private boolean mRootMode, isRegexEnabled, isMatchesEnabled;
public static final String KEY_PATH = "path";
public static final String KEY_INPUT = "input";
public static final String KEY_OPEN_MODE = "open_mode";
public static final String KEY_ROOT_MODE = "root_mode";
public static final String KEY_REGEX = "regex";
public static final String KEY_REGEX_MATCHES = "matches";
// interface for activity to communicate with asynctask
public interface HelperCallbacks {
void onPreExecute(String query);
void onPostExecute(String query);
void onProgressUpdate(BaseFile val,String query);
void onCancelled();
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
// hold instance of activity as there is a change in device configuration
mCallbacks = (HelperCallbacks) context;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
mPath = getArguments().getString(KEY_PATH);
mInput = getArguments().getString(KEY_INPUT);
mOpenMode = OpenMode.getOpenMode(getArguments().getInt(KEY_OPEN_MODE));
mRootMode = getArguments().getBoolean(KEY_ROOT_MODE);
isRegexEnabled = getArguments().getBoolean(KEY_REGEX);
isMatchesEnabled = getArguments().getBoolean(KEY_REGEX_MATCHES);
mSearchTask = new SearchTask();
mSearchTask.execute(mPath);
}
@Override
public void onDetach() {
super.onDetach();
// to avoid activity instance leak while changing activity configurations
mCallbacks = null;
}
public class SearchTask extends AsyncTask<String, BaseFile, Void> {
@Override
protected void onPreExecute() {
/*
* Note that we need to check if the callbacks are null in each
* method in case they are invoked after the Activity's and
* Fragment's onDestroy() method have been called.
*/
if (mCallbacks!=null) {
mCallbacks.onPreExecute(mInput);
}
}
// mCallbacks not checked for null because of possibility of
// race conditions b/w worker thread main thread
@Override
protected Void doInBackground(String... params) {
String path = params[0];
HFile file=new HFile(mOpenMode, path);
file.generateMode(getActivity());
if(file.isSmb())return null;
// level 1
// if regex or not
if (!isRegexEnabled) search(file, mInput);
else {
// compile the regular expression in the input
Pattern pattern = Pattern.compile(bashRegexToJava(mInput));
// level 2
if (!isMatchesEnabled) searchRegExFind(file, pattern);
else searchRegExMatch(file, pattern);
}
return null;
}
@Override
public void onPostExecute(Void c){
if (mCallbacks!=null) {
mCallbacks.onPostExecute(mInput);
}
}
@Override
protected void onCancelled() {
if (mCallbacks!=null) mCallbacks.onCancelled();
}
@Override
public void onProgressUpdate(BaseFile... val) {
if (!isCancelled() && mCallbacks!=null) {
mCallbacks.onProgressUpdate(val[0],mInput);
}
}
/**
* Recursively search for occurrences of a given text in file names and publish the result
* @param file the current path
* @param query the searched text
*/
private void search(HFile file, String query) {
if (file.isDirectory()) {
ArrayList<BaseFile> f = file.listFiles(mRootMode);
// do you have permission to read this directory?
if (!isCancelled())
for (BaseFile x : f) {
if (!isCancelled()) {
if (x.isDirectory()) {
if (x.getName().toLowerCase()
.contains(query.toLowerCase())) {
publishProgress(x);
}
if (!isCancelled()) search(x, query);
} else {
if (x.getName().toLowerCase()
.contains(query.toLowerCase())) {
publishProgress(x);
}
}
} else return;
}
} else {
Log.d("SearchAsyncHelper", file.getPath() + "Permission Denied");
}
}
/**
* Recursively find a java regex pattern {@link Pattern} in the file names and publish the result
* @param file the current file
* @param pattern the compiled java regex
*/
private void searchRegExFind(HFile file, Pattern pattern) {
if (file.isDirectory()) {
ArrayList<BaseFile> f = file.listFiles(mRootMode);
if (!isCancelled()) {
for (BaseFile x : f) {
if (!isCancelled()) {
if (x.isDirectory()) {
if (pattern.matcher(x.getName()).find()) publishProgress(x);
if (!isCancelled()) searchRegExFind(x, pattern);
} else {
if (pattern.matcher(x.getName()).find()) {
publishProgress(x);
}
}
} else return;
}
}
} else {
Log.d("SearchAsyncHelper", file.getPath() + "Permission Denied");
}
}
/**
* Recursively match a java regex pattern {@link Pattern} with the file names and publish the result
* @param file the current file
* @param pattern the compiled java regex
*/
private void searchRegExMatch(HFile file, Pattern pattern) {
if (file.isDirectory()) {
ArrayList<BaseFile> f = file.listFiles(mRootMode);
if (!isCancelled())
for (BaseFile x : f) {
if (!isCancelled()) {
if (x.isDirectory()) {
if (pattern.matcher(x.getName()).matches()) publishProgress(x);
if (!isCancelled()) searchRegExMatch(x, pattern);
} else {
if (pattern.matcher(x.getName()).matches()) {
publishProgress(x);
}
}
} else return;
}
} else {
Log.d("SearchAsyncHelper", file.getPath() + "Permission Denied");
}
}
/**
* method converts bash style regular expression to java. See {@link Pattern}
* @param originalString
* @return converted string
*/
private String bashRegexToJava(String originalString) {
StringBuilder stringBuilder = new StringBuilder();
for(int i=0; i<originalString.length(); i++) {
switch (originalString.charAt(i) + "") {
case "*":
stringBuilder.append("\\w*");
break;
case "?":
stringBuilder.append("\\w");
break;
default:
stringBuilder.append(originalString.charAt(i));
break;
}
}
Log.d(getClass().getSimpleName(), stringBuilder.toString());
return stringBuilder.toString();
}
}
}