class DbSearchDataStore implements SearchDataStore {

    @Override
    public Observable<List<MediaItemEntity>> search( String searchString ) {
        Log.d( TAG, "search : enter" );

        String search = "*" + searchString + "*";
        search = search.replaceAll( " ", "*" );

        final String query = search;
        Log.d( TAG, "search : query=" + query );

        return Observable.create( new Observable.OnSubscribe<List<MediaItemEntity>>() {

            @Override
            public void call( Subscriber<? super List<MediaItemEntity>> subscriber ) {
                Log.d( TAG, "search.call : enter" );

                Cursor cursor;

                SQLiteQueryBuilder builder = new SQLiteQueryBuilder();

                try {

                    List<MediaItemEntity> mediaItems = new ArrayList<>();

                    builder.setTables( MediaItemEntity.TABLE_NAME );

                    String selection = MediaItemEntity.SQL_SELECT_MATCH;
                    String[] selectionArgs = new String[] { query };

                    MediaItemEntity mediaItem;
                    cursor = builder.query( db, null, selection, selectionArgs, null, null, MediaItemEntity.FIELD_START_DATE + " DESC, " + MediaItemEntity.FIELD_TITLE );
                    while( cursor.moveToNext() ) {

                        mediaItem = MediaItemEntity.create(
                            cursor.getInt( cursor.getColumnIndex( MediaItemEntity.FIELD_ID ) ),
                            Media.valueOf( cursor.getString( cursor.getColumnIndex( MediaItemEntity.FIELD_MEDIA ) ) ),
                            cursor.getString( cursor.getColumnIndex( MediaItemEntity.FIELD_TITLE ) ),
                            cursor.getString( cursor.getColumnIndex( MediaItemEntity.FIELD_SUBTITLE ) ),
                            cursor.getString( cursor.getColumnIndex( MediaItemEntity.FIELD_DESCRIPTION ) ),
                            new DateTime( cursor.getLong( cursor.getColumnIndex( MediaItemEntity.FIELD_START_DATE ) ) ),
                            cursor.getInt( cursor.getColumnIndex( MediaItemEntity.FIELD_PROGRAM_FLAGS ) ),
                            cursor.getInt( cursor.getColumnIndex( MediaItemEntity.FIELD_SEASON ) ),
                            cursor.getInt( cursor.getColumnIndex( MediaItemEntity.FIELD_EPISODE ) ),
                            cursor.getString( cursor.getColumnIndex( MediaItemEntity.FIELD_STUDIO ) ),
                            cursor.getString( cursor.getColumnIndex( MediaItemEntity.FIELD_CAST_MEMBERS ) ),
                            cursor.getString( cursor.getColumnIndex( MediaItemEntity.FIELD_CHARACTERS ) ),
                            cursor.getString( cursor.getColumnIndex( MediaItemEntity.FIELD_URL ) ),
                            cursor.getString( cursor.getColumnIndex( MediaItemEntity.FIELD_FANART_URL ) ),
                            cursor.getString( cursor.getColumnIndex( MediaItemEntity.FIELD_COVERART_URL ) ),
                            cursor.getString( cursor.getColumnIndex( MediaItemEntity.FIELD_BANNER_URL ) ),
                            cursor.getString( cursor.getColumnIndex( MediaItemEntity.FIELD_PREVIEW_URL ) ),
                            cursor.getString( cursor.getColumnIndex( MediaItemEntity.FIELD_CONTENT_TYPE ) ),
                            cursor.getLong( cursor.getColumnIndex( MediaItemEntity.FIELD_DURATION ) ),
                            cursor.getInt( cursor.getColumnIndex( MediaItemEntity.FIELD_LIVE_STREAM_PERCENT_COMPLETE ) ),
                            ( cursor.getInt( cursor.getColumnIndex( MediaItemEntity.FIELD_RECORDING ) ) != 0 ),
                            cursor.getInt( cursor.getColumnIndex( MediaItemEntity.FIELD_LIVE_STREAM_ID ) ),
                            ( cursor.getInt( cursor.getColumnIndex( MediaItemEntity.FIELD_WATCHED_STATUS ) ) != 0 ),
                            cursor.getString( cursor.getColumnIndex( MediaItemEntity.FIELD_UPDATE_SAVED_BOOKMARK_URL ) ),
                            cursor.getLong( cursor.getColumnIndex( MediaItemEntity.FIELD_BOOKMARK ) ),
                            cursor.getString( cursor.getColumnIndex( MediaItemEntity.FIELD_INETREF ) ),
                            cursor.getString( cursor.getColumnIndex( MediaItemEntity.FIELD_CERTIFICATION ) ),
                            cursor.getInt( cursor.getColumnIndex( MediaItemEntity.FIELD_PARENTAL_LEVEL ) ),
                            cursor.getString( cursor.getColumnIndex( MediaItemEntity.FIELD_RECORDING_GROUP ) ),
                            Collections.emptyList()
                        );

//                        Log.d( TAG, "search.call : searchResultEntity=" + searchResultEntity.toString() );
                        mediaItems.add( mediaItem );

                    }
                    cursor.close();

                    subscriber.onNext( mediaItems );
                    subscriber.onCompleted();

                } catch( Exception e ) {
                    Log.e( TAG, "search.call : error", e );

                    subscriber.onError( new DatabaseException( e.getCause() ) );

                }

                Log.d( TAG, "search.call : exit" );
            }

        });

    }

    public  DbSearchDataStore( final SQLiteDatabase db );

}