package com.openfarmanager.android.dialogs;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.graphics.Color;
import android.os.AsyncTask;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import com.openfarmanager.android.App;
import com.openfarmanager.android.R;
import com.openfarmanager.android.core.network.NetworkApi;
import com.openfarmanager.android.filesystem.FileProxy;
import com.openfarmanager.android.filesystem.FileSystemFile;
import com.openfarmanager.android.model.NetworkEnum;
import com.openfarmanager.android.view.ToastNotification;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOCase;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.Serializable;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
/**
* Performs search and shows result.
*
* @author Vlad Namashko.
*/
public class SearchResultDialog extends Dialog {
private FileProxy mSelected;
private ListView mList;
private View mDialogView;
private int mSelectedFilePosition = -1;
private final List<FileProxy> mData = Collections.synchronizedList(new LinkedList<FileProxy>());
private FolderScanner mScanner;
private NetworkScanner mNetworkScanner;
private ProgressBar mProgressBar;
private NetworkEnum mNetworkType;
private SearchActionDialog.SearchActionResult mSearchOptions;
private SearchResultListener mListener;
private String mCurrentDir;
public SearchResultDialog(Context context, NetworkEnum networkType, String currentDir,
SearchActionDialog.SearchActionResult searchOption, SearchResultListener listener) {
super(context);
mNetworkType = networkType;
mCurrentDir = currentDir;
mSearchOptions = searchOption;
mListener = listener;
}
@Override
public void onCreate(Bundle savedInstanceState) {
requestWindowFeature(Window.FEATURE_NO_TITLE);
mDialogView = View.inflate(App.sInstance.getApplicationContext(), R.layout.search_result, null);
setContentView(mDialogView);
mDialogView.findViewById(R.id.cancel).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
dismiss();
}
});
mDialogView.findViewById(R.id.go_to).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (!checkFileSelected()) {
return;
}
mListener.onGotoFile(mSelected);
dismiss();
}
});
mDialogView.findViewById(R.id.new_search).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mListener.onResetSearch();
dismiss();
}
});
mDialogView.findViewById(R.id.view).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (!checkFileSelected()) {
return;
}
mListener.onViewFile(mSelected);
dismiss();
}
});
mDialogView.findViewById(R.id.view).setVisibility(mSearchOptions.isNetworkPanel ? View.GONE : View.VISIBLE);
mProgressBar = (ProgressBar) mDialogView.findViewById(android.R.id.progress);
mList = (ListView) mDialogView.findViewById(android.R.id.list);
mList.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
mSelected = (FileProxy) view.getTag();
}
@Override
public void onNothingSelected(AdapterView<?> adapterView) {
}
});
mList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
mSelected = (FileProxy) view.getTag();
mSelectedFilePosition = i;
((BaseAdapter) mList.getAdapter()).notifyDataSetChanged();
}
});
mList.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
@Override
public boolean onItemLongClick(AdapterView<?> adapterView, View view, int i, long l) {
mSelected = (FileProxy) view.getTag();
if (!checkFileSelected()) {
return true;
}
mListener.onGotoFile(mSelected);
dismiss();
return true;
}
});
mList.setAdapter(new BaseAdapter() {
private List<FileProxy> mData;
@Override
public int getCount() {
return mData == null ? 0 : mData.size();
}
@Override
public Object getItem(int i) {
return mData.get(i);
}
@Override
public long getItemId(int i) {
return i;
}
@Override
public View getView(int i, View view, ViewGroup viewGroup) {
TextView textView;
if (view == null) {
textView = new TextView(getContext());
textView.setTextColor(Color.BLACK);
textView.setEllipsize(TextUtils.TruncateAt.MIDDLE);
textView.setSingleLine();
textView.setTextSize(18);
} else {
textView = (TextView) view;
}
FileProxy f = (FileProxy) getItem(i);
textView.setText(f.getFullPathRaw());
textView.setTag(f);
textView.setBackgroundResource(mSelectedFilePosition == i ? R.color.selected_item : R.color.main_grey);
return textView;
}
@Override
public void notifyDataSetChanged() {
synchronized (SearchResultDialog.this.mData) {
mData = new LinkedList<>(SearchResultDialog.this.mData);
}
super.notifyDataSetChanged();
}
});
setOnDismissListener(new OnDismissListener() {
@Override
public void onDismiss(DialogInterface dialog) {
if (mScanner != null) {
mScanner.cancel(true);
}
}
});
if (mCurrentDir != null) {
if (mNetworkType != null) {
if (mNetworkScanner == null) {
mNetworkScanner = new NetworkScanner(mNetworkType);
mNetworkScanner.execute(mCurrentDir);
}
} else {
if (mScanner == null) {
mScanner = new FolderScanner();
mScanner.execute(new File(mCurrentDir));
}
}
}
}
private boolean checkFileSelected() {
if (mSelected == null) {
ToastNotification.makeText(getContext(), App.sInstance.getString(R.string.error_no_selected_file), Toast.LENGTH_SHORT).show();
return false;
}
return true;
}
private IOCase isCaseSensitive() {
return mSearchOptions.caseSensitive ? IOCase.SENSITIVE : IOCase.INSENSITIVE;
}
/**
* Finds files and folder by Wildcard
*/
private class FolderScanner extends AsyncTask<File, Void, Void> {
@Override
protected void onPreExecute() {
mProgressBar.setVisibility(View.VISIBLE);
}
@Override
protected void onPostExecute(Void aVoid) {
mProgressBar.setVisibility(View.INVISIBLE);
}
@Override
protected Void doInBackground(File... files) {
for (File f : files) {
searchDirectory(f);
}
return null;
}
private void searchDirectory(File mDir) {
if (mDir == null) {
return;
}
File[] files = mDir.listFiles();
if (files == null) {
return;
}
for (File f : files) {
if (isCancelled()) {
return;
}
if (FilenameUtils.wildcardMatch(f.getName(), mSearchOptions.fileMask, isCaseSensitive())) {
if (mSearchOptions.keyword != null && f.isFile()) {
if (searchFile(f)) {
mData.add(new FileSystemFile(f.getAbsolutePath()));
publishProgress();
}
} else {
mData.add(new FileSystemFile(f.getAbsolutePath()));
publishProgress();
}
}
if (isCancelled()) {
return;
}
if (f.isDirectory() && f.canRead()) {
searchDirectory(f);
}
}
}
private boolean searchFile(File f) {
if (!f.canRead()) {
return false;
}
BufferedReader is = null;
try {
String keyword = mSearchOptions.keyword;
Pattern pattern = Pattern.compile(mSearchOptions.wholeWords ? String.format("\\b%s\\b", Pattern.quote(keyword)) : Pattern.quote(keyword),
isCaseSensitive() == IOCase.INSENSITIVE ? Pattern.CASE_INSENSITIVE : 0);
is = new BufferedReader(new FileReader(f));
String line;
while ((line = is.readLine()) != null) {
if (pattern.matcher(line).find()) {
return true;
}
}
} catch (IOException e) {
e.printStackTrace();
} catch (PatternSyntaxException e) {
e.printStackTrace();
} catch (OutOfMemoryError e) {
e.printStackTrace();
} finally {
if (is != null) {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return false;
}
@Override
protected void onProgressUpdate(Void... values) {
((BaseAdapter) mList.getAdapter()).notifyDataSetChanged();
}
}
/**
* Finds files in network storage
*/
private class NetworkScanner extends AsyncTask<String, Void, List<FileProxy>> {
private NetworkEnum mNetworkType;
public NetworkScanner(NetworkEnum networkType) {
mNetworkType = networkType;
}
@Override
protected void onPreExecute() {
mProgressBar.setVisibility(View.VISIBLE);
}
@Override
protected List<FileProxy> doInBackground(String ... path) {
return getNetworkApi().search(path[0], mSearchOptions.fileMask);
}
@Override
protected void onPostExecute(List<FileProxy> searchResult) {
mData.clear();
mData.addAll(searchResult);
((BaseAdapter) mList.getAdapter()).notifyDataSetChanged();
mProgressBar.setVisibility(View.INVISIBLE);
}
private NetworkApi getNetworkApi() {
switch (mNetworkType) {
case Dropbox: default:
return App.sInstance.getDropboxApi();
case SkyDrive:
return App.sInstance.getSkyDriveApi();
case GoogleDrive:
return App.sInstance.getGoogleDriveApi();
case MediaFire:
return App.sInstance.getMediaFireApi();
case WebDav:
return App.sInstance.getWebDavApi();
}
}
}
public interface SearchResultListener extends Serializable {
void onGotoFile(FileProxy file);
void onViewFile(FileProxy file);
void onResetSearch();
}
}