package com.ghostsq.commander.adapters;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.util.ArrayList;
import java.util.Date;
import com.ghostsq.commander.Commander;
import com.ghostsq.commander.R;
import com.ghostsq.commander.utils.Utils;
import android.content.Context;
import android.net.Uri;
import android.os.Handler;
import android.text.format.DateFormat;
import android.util.Log;
import android.util.SparseBooleanArray;
public class FindAdapter extends FSAdapter {
public final static String TAG = "FindAdapter";
private Uri uri;
public FindAdapter( Context ctx_ ) {
super( ctx_ );
parentLink = PLS;
}
@Override
public int getType() {
return CA.FIND;
}
@Override
public int setMode( int mask, int mode_ ) {
mode_ &= ~MODE_WIDTH;
return super.setMode( mask, mode_ );
}
@Override
public boolean readSource( Uri uri_, String pass_back_on_done ) {
try {
if( reader != null ) reader.reqStop();
if( uri_ != null )
uri = uri_;
if( uri == null )
return false;
if( uri.getScheme().compareTo( "find" ) == 0 ) {
String path = uri.getPath();
String match = uri.getQueryParameter( "q" );
if( path != null && path.length() > 0 && match != null && match.length() > 0 ) {
notify( Commander.OPERATION_STARTED );
SearchEngine se = new SearchEngine( readerHandler, match, path, pass_back_on_done );
reader = se;
String dirs_s = uri.getQueryParameter( "d" );
String files_s = uri.getQueryParameter( "f" );
boolean dirs = dirs_s != null && "1".equals( dirs_s );
boolean files = files_s != null && "1".equals( files_s );
if( dirs != files )
se.setTypes( files );
String olo_s = uri.getQueryParameter( "o" );
if( olo_s != null && "1".equals( olo_s ) )
se.olo = true;
se.content = uri.getQueryParameter( "c" );
se.larger_than = Utils.parseHumanSize( uri.getQueryParameter( "l" ) );
long st = Utils.parseHumanSize( uri.getQueryParameter( "s" ) );
if( st > 0 )
se.smaller_than = st;
java.text.DateFormat df = DateFormat.getDateFormat( ctx );
try {
se.after_date = df.parse( uri.getQueryParameter( "a" ) );
} catch( Exception e ) {}
try {
se.before_date = df.parse( uri.getQueryParameter( "b" ) );
} catch( Exception e ) {}
commander.startEngine( reader );
return true;
}
}
} catch( Exception e ) {
Log.e( TAG, "FindAdapter.readSource() exception: ", e );
}
Log.e( TAG, "FindAdapter unable to read by the URI '" + ( uri == null ? "null" : uri.toString() ) + "'" );
uri = null;
return false;
}
@Override
public void openItem( int position ) {
if( position == 0 ) { // ..
if( uri != null ) {
commander.Navigate( Uri.parse( uri.getPath() ), null, null );
}
return;
}
super.openItem( position );
}
@Override
public boolean copyItems( SparseBooleanArray cis, CommanderAdapter to, boolean move ) {
return to.receiveItems( bitsToNames( cis ), move ? MODE_MOVE : MODE_COPY );
}
@Override
public boolean createFile( String fileURI ) {
commander.showError( ctx.getString( R.string.not_supported ) );
return false;
}
@Override
public void createFolder( String string ) {
commander.showError( ctx.getString( R.string.not_supported ) );
}
@Override
public Uri getUri() {
return uri;
}
@Override
public String toString() {
return uri != null ? Uri.decode( uri.toString() ) : "";
}
@Override
public boolean receiveItems( String[] fileURIs, int move_mode ) {
notify( ctx.getString( R.string.not_supported ),Commander.OPERATION_FAILED );
return false;
}
@Override
public void setIdentities( String name, String pass ) {
commander.showError( ctx.getString( R.string.not_supported ) );
}
class SearchEngine extends Engine {
private String[] cards;
private String path;
private int depth = 0;
private String pass_back_on_done;
public String match, content;
public boolean olo = false;
public long larger_than, smaller_than;
public Date after_date, before_date;
private boolean dirs = true, files = true;
private ArrayList<File> result;
private int progress = 0;
SearchEngine( Handler h, String match_, String path_, String pass_back_on_done_ ) {
super.setHandler( h );
if( match_.indexOf( '*' ) >= 0 ){
cards = Utils.prepareWildcard( match_ );
match = null;
}
else {
cards = null;
match = match_.toLowerCase();
}
path = path_;
pass_back_on_done = pass_back_on_done_;
larger_than = 0;
smaller_than = Long.MAX_VALUE;
}
final void setTypes( boolean files_only ) {
if( files_only ) {
files = true;
dirs = false;
} else {
files = false;
dirs = true;
}
}
@Override
public void setHandler( Handler h ) {
// has its own handler
}
@Override
public void run() {
try {
Init( null );
result = new ArrayList<File>();
searchInFolder( new File( path ) );
sendProgress( tooLong( 8 ) ? ctx.getString( R.string.search_done ) : null,
Commander.OPERATION_COMPLETED, pass_back_on_done );
} catch( Exception e ) {
sendProgress( e.getMessage(), Commander.OPERATION_FAILED, pass_back_on_done );
}
}
protected final void searchInFolder( File dir ) throws Exception {
try {
String dir_path = dir.getAbsolutePath();
if( dir_path.compareTo( "/sys" ) == 0 ) return;
if( dir_path.compareTo( "/dev" ) == 0 ) return;
if( dir_path.compareTo( "/proc" ) == 0 ) return;
File[] subfiles = dir.listFiles();
if( subfiles == null || subfiles.length == 0 )
return;
double conv = 100./subfiles.length;
for( int i = 0; i < subfiles.length; i++ ) {
sleep( 1 );
if( stop || isInterrupted() )
throw new Exception( ctx.getString( R.string.interrupted ) );
File f = subfiles[i];
int np = (int)(i * conv);
if( np == 0 || np - 1 > progress )
sendProgress( f.getAbsolutePath(), progress = np );
//Log.v( TAG, "Looking at file " + f.getAbsolutePath() );
addIfMatched( f );
if( !olo && f.isDirectory() ) {
if( depth++ > 30 )
throw new Exception( ctx.getString( R.string.too_deep_hierarchy ) );
searchInFolder( f );
depth--;
}
}
} catch( Exception e ) {
Log.e( TAG, "Exception on search: ", e );
}
}
private final void addIfMatched( File f ) {
if( f == null ) return;
try {
boolean dir = f.isDirectory();
if( dir ) {
if( !dirs ) return;
} else {
if( !files ) return;
}
long modified = f.lastModified();
if( after_date != null && modified < after_date.getTime() ) return;
if( before_date != null && modified > before_date.getTime() ) return;
long size = f.length();
if( size < larger_than || size > smaller_than )
return;
if( cards != null && !Utils.match( f.getName(), cards ) )
return;
if( match != null && !f.getName().toLowerCase().contains( match ) )
return;
if( content != null && !dir && !searchInsideFile( f, content ) )
return;
result.add( f );
}
catch( Exception e ) {
Log.e( TAG, f.getName(), e );
}
}
private final boolean searchInsideFile( File f, String s ) {
try {
BufferedReader br = new BufferedReader( new FileReader( f ) );
final int l = s.length();
int ch = 0;
int cnt = 0, p = 0;
double conv = 100./f.length();
while( true ) {
for( int i = 0; i < l; i++ ) {
ch = br.read();
if( ch == -1 )
return false;
if( ch != s.charAt( i ) ) {
if( i > 0 )
br.reset();
break;
}
if( i == 0 )
br.mark( l );
if( i >= l-1 )
return true;
}
int np = (int)(cnt++ * conv);
if( np - 10 > p )
sendProgress( f.getAbsolutePath(), progress, p = np );
sleep( 1 );
}
}
catch( InterruptedException e ) {
}
catch( Exception e ) {
Log.e( TAG, "File: " + f.getName() + ", str=" + s, e );
}
return false;
}
public final FileItem[] getItems( int mode ) {
if( result == null ) return null;
File[] files_ = new File[result.size()];
result.toArray( files_ );
return filesToItems( files_ );
}
}
protected void onReadComplete() {
try {
if( reader instanceof SearchEngine ) {
SearchEngine list_engine = (SearchEngine)reader;
items = list_engine.getItems( mode );
numItems = items != null ? items.length + 1 : 1;
notifyDataSetChanged();
startThumbnailCreation();
}
} catch( Exception e ) {
e.printStackTrace();
}
}
@Override
public Object getItem( int position ) {
try {
Object o = super.getItem( position );
if( o != null ) {
if( o instanceof FileItem ) {
FileItem fi = (FileItem)o;
fi.name = fi.f.getAbsolutePath();
}
return o;
}
} catch( Exception e ) {
Log.e( TAG, "getItem() Exception" );
}
return null;
}
}