public class JapaneseAndroidLearnHelperApplication extends MultiDexApplication {

	public static final ThemeType defaultThemeType = ThemeType.BLACK;
	
	private static JapaneseAndroidLearnHelperApplication singleton;

	public static JapaneseAndroidLearnHelperApplication getInstance() {
		return singleton;
	}
	
	private JapaneseAndroidLearnHelperContext context;
	
	private DictionaryManagerCommon dictionaryManager;
	
	private ConfigManager configManager;
	
	private WordDictionaryMissingWordQueue wordDictionaryMissingWordQueue;

	private QueueEventThread queueEventThread;
	
	private Typeface babelStoneHanSubset = null;
	
	// private Tracker tracker = null;

	@Override
	public void onConfigurationChanged(Configuration newConfig) {
		super.onConfigurationChanged(newConfig);
	}

	@Override
	public void onCreate() {
		super.onCreate();
		
		singleton = this;
	}

	@Override
	public void onLowMemory() {
		super.onLowMemory();
	}

	@Override
	public void onTerminate() {
		super.onTerminate();

		stopQueueThread();

		if (dictionaryManager != null) {
			dictionaryManager.close();
		}
	}
	
	public JapaneseAndroidLearnHelperContext getContext() {
		
		if (context == null) {
			context = new JapaneseAndroidLearnHelperContext();
		}
		
		return context;
	}

	public DictionaryManagerCommon getDictionaryManager(final Activity activity) {
		
		Resources resources = activity.getResources();
		AssetManager assets = activity.getAssets();
				
		if (dictionaryManager == null) {
			
	        int versionCode = 0;
	        
	        try {
	        	PackageInfo packageInfo = getPackageManager().getPackageInfo(getPackageName(), 0);
	        	
	            versionCode = packageInfo.versionCode;

	        } catch (NameNotFoundException e) {        	
	        }
	        
	        ILoadWithProgress loadWithProgress = new ILoadWithProgress() {
				
				@Override
				public void setMaxValue(int maxValue) {
				}
				
				@Override
				public void setError(String errorMessage) {					
					throw new RuntimeException(errorMessage);					
				}
				
				@Override
				public void setDescription(String desc) {
				}
				
				@Override
				public void setCurrentPos(int currentPos) {
				}
			};
						
			dictionaryManager = DictionaryManagerCommon.getDictionaryManager();
			
			dictionaryManager.init(activity, loadWithProgress, resources, assets, getPackageName(), versionCode);
		}
		
		return dictionaryManager;
	}

	public void setDictionaryManager(DictionaryManagerCommon dictionaryManager) {
		this.dictionaryManager = dictionaryManager;
	}

	public DataManager getDataManager() {

		if (dictionaryManager == null) {
			return null;
		}

		return dictionaryManager.getDataManager();
	}

	public ConfigManager getConfigManager(Activity activity) {
		
		if (configManager == null) {
			configManager = new ConfigManager(activity);
		}
		
		return configManager;
	}

	public void setConfigManager(ConfigManager configManager) {
		this.configManager = configManager;
	}
	
	public WordDictionaryMissingWordQueue getWordDictionaryMissingWordQueue(Activity activity) {
		
		if (wordDictionaryMissingWordQueue == null) {
			wordDictionaryMissingWordQueue = new WordDictionaryMissingWordQueue(activity);
		}
		
		return wordDictionaryMissingWordQueue;
	}

	public void setWordDictionaryMissingWordQueue(WordDictionaryMissingWordQueue wordDictionaryMissingWordQueue) {
		this.wordDictionaryMissingWordQueue = wordDictionaryMissingWordQueue;
	}

	public Typeface getBabelStoneHanSubset(AssetManager assetManager) {
		
		if (babelStoneHanSubset != null) {
			return babelStoneHanSubset;
		}
		
		babelStoneHanSubset = Typeface.createFromAsset(getAssets(), "BabelStoneHan-subset.ttf");
		
		return babelStoneHanSubset;
	}

	public void setContentViewAndTheme(Activity activity, int contentViewId) {
		activity.setTheme(getThemeType(activity).styleId);

		DataBindingUtil.setContentView(activity, contentViewId);
	}

	public ThemeType getThemeType() {
		return getThemeType(null);
	}

	private ThemeType getThemeType(Activity activity) {

		if (configManager != null) {
			return configManager.getCommonConfig().getThemeType(defaultThemeType);
		}

		if (activity == null) {
			return defaultThemeType;
		}

		getConfigManager(activity);

		if (configManager != null) {
			return configManager.getCommonConfig().getThemeType(defaultThemeType);
		}

		return defaultThemeType;
	}

	public int getLinkColor() {

		TypedArray typedArray = getTheme().obtainStyledAttributes(
				getThemeType().getStyleId(),
				new int[] { android.R.attr.textColorLink });

		int intColor = typedArray.getColor(0, 0);

		typedArray.recycle();

		return intColor;
	}

	/*
	public Tracker getTracker() {
		
		if (tracker != null) {
			return tracker;
		}
		
		GoogleAnalytics analytics = GoogleAnalytics.getInstance(this);

		tracker = analytics.newTracker(R.xml.app_tracker);

		tracker.enableAdvertisingIdCollection(true);
		
		return tracker;		
	}
	*/

	public void logScreen(Activity activity, String screenName) {

	    /*
		Tracker tracker = getTracker();
		
		tracker.setScreenName(screenName);
		
		tracker.send(new HitBuilders.AppViewBuilder().build());
		*/

		addQueueEvent(activity, new StatLogScreenEvent(getConfigManager(activity).getCommonConfig().getOrGenerateUniqueUserId(), screenName));
	}
	
	public void logEvent(Activity activity, String screenName, String actionName, String label) {

	    /*
		Tracker tracker = getTracker();
		
		tracker.send(new HitBuilders.EventBuilder()
				.setCategory(screenName)
				.setAction(actionName).
				setLabel(label).
				build());
		*/

		addQueueEvent(activity, new StatLogEventEvent(getConfigManager(activity).getCommonConfig().getOrGenerateUniqueUserId(), screenName, actionName, label));
	}

	public synchronized void startQueueThread(Activity activity) {

		if (queueEventThread == null || queueEventThread.isAlive() == false) {

            queueEventThread = new QueueEventThread(activity.getPackageManager(), activity.getPackageName());

            queueEventThread.start();
		}
	}

	public synchronized void stopQueueThread() {

		if (queueEventThread != null && queueEventThread.isAlive() == true) {

            queueEventThread.requestStop();

			try {
                queueEventThread.join(11000);

			} catch (InterruptedException e) {
				// noop
			}
		}
	}

	public synchronized void addQueueEvent(Activity activity, IQueueEvent queueEvent) {

		startQueueThread(activity);

		if (queueEventThread != null) {

			ThemeType themeType = getThemeType(activity);

			queueEventThread.addQueueEvent(activity, themeType, queueEvent);
		}
	}

	public enum ThemeType {

		BLACK(	R.style.JapaneseDictionaryBlackStyle,
				android.R.color.white,
				R.color.title_background_for_black,
				android.R.color.white,
				Color.DKGRAY,
				R.drawable.delete_for_black,
				R.drawable.user_group_list_for_black,
				R.drawable.listening_for_black),

		WHITE(	R.style.JapaneseDictionaryWhiteStyle,
				android.R.color.black,
				R.color.title_background_for_white,
				android.R.color.black,
				Color.WHITE,
				R.drawable.delete_for_white,
				R.drawable.user_group_list_for_white,
				R.drawable.listening_for_white);

		private int styleId;

		private int textColorId;

		private int titleItemBackgroundColorId;

		private int kanjiStrokeColorId;

		private int kanjiSearchRadicalInactiveColorId;

		private int deleteIconId;

		private int userGroupListIconId;

		private int listenIconId;

		private ThemeType(int styleId, int textColorId, int titleItemBackgroundColorId, int kanjiStrokeColorId, int kanjiSearchRadicalInactiveColorId, int deleteIconId, int userGroupListIconId, int listenIconId) {
			this.styleId = styleId;
			this.textColorId = textColorId;
			this.titleItemBackgroundColorId = titleItemBackgroundColorId;
			this.kanjiStrokeColorId = kanjiStrokeColorId;
			this.kanjiSearchRadicalInactiveColorId = kanjiSearchRadicalInactiveColorId;
			this.deleteIconId = deleteIconId;
			this.userGroupListIconId = userGroupListIconId;
			this.listenIconId = listenIconId;
		}

		public int getStyleId() {
			return styleId;
		}

		public int getTextColorId() {
			return textColorId;
		}

		public int getTextColorAsColor() {
			return getInstance().getResources().getColor(textColorId);
		}

		public int getTitleItemBackgroundColorAsColor() {
			return getInstance().getResources().getColor(titleItemBackgroundColorId);
		}

		public Drawable getTitleItemBackgroundColorAsDrawable() {
			ColorDrawable colorDrawable = new ColorDrawable(getTitleItemBackgroundColorAsColor());

			return colorDrawable;
		}

		public int getKanjiStrokeColorAsColor() {
			return getInstance().getResources().getColor(kanjiStrokeColorId);
		}

		public int getKanjiSearchRadicalInactiveColorId() {
			return kanjiSearchRadicalInactiveColorId;
		}

		public int getDeleteIconId() {
			return deleteIconId;
		}

		public int getUserGroupListIconId() {
			return userGroupListIconId;
		}

		public Drawable getUserGroupListIconAsDrawable() {
			return getInstance().getResources().getDrawable(userGroupListIconId);
		}

		public int getListenIconId() {
			return listenIconId;
		}
	}
} public class MenuShorterHelper {

	public static void onCreateOptionsMenu(Menu menu) {
		menu.add(Menu.NONE, R.id.main_menu_kana_text_menu_item, Menu.NONE, R.string.main_menu_kana_text_short);
		menu.add(Menu.NONE, R.id.main_menu_counters_text_menu_item, Menu.NONE, R.string.main_menu_counters_text_short);
		menu.add(Menu.NONE, R.id.main_menu_keigo_table_text_menu_item, Menu.NONE, R.string.main_menu_keigo_table_text_short);
		menu.add(Menu.NONE, R.id.main_menu_transitive_intransitive_pairs_table_text_menu_item, Menu.NONE, R.string.main_menu_transitive_intransitive_pairs_table_text_short);
		menu.add(Menu.NONE, R.id.main_menu_dictionary_text_menu_item, Menu.NONE, R.string.main_menu_dictionary_text);
		menu.add(Menu.NONE, R.id.main_menu_kanji_text_menu_item, Menu.NONE, R.string.main_menu_kanji_text_short);
		// menu.add(Menu.NONE, R.id.main_menu_kanji_recognizer_text_menu_item, Menu.NONE, R.string.main_menu_kanji_recognizer_text_short);
		menu.add(Menu.NONE, R.id.main_menu_show_user_group_menu_item, Menu.NONE, R.string.main_menu_show_user_group_text);
	}
	
	public static boolean onOptionsItemSelected(MenuItem item, Context applicationContext, Activity activity) {
		
		int itemId = item.getItemId();
		
		if (itemId == R.id.main_menu_kana_text_menu_item) { // kana table
			
			Intent intent = new Intent(applicationContext, Kana.class);

			activity.startActivity(intent);
			
			return true;
		} else if (itemId == R.id.main_menu_counters_text_menu_item) { // counter table
			
			Intent intent = new Intent(applicationContext, CountersActivity.class);

			activity.startActivity(intent);
			
			return true;
		} else if (itemId == R.id.main_menu_keigo_table_text_menu_item) { // keigo table
			
			Intent intent = new Intent(applicationContext, KeigoTable.class);

			activity.startActivity(intent);
			
			return true;
		} else if (itemId == R.id.main_menu_transitive_intransitive_pairs_table_text_menu_item) { // transitive intransitive pairs table
			
			Intent intent = new Intent(applicationContext, TransitiveIntransitivePairsTable.class);

			activity.startActivity(intent);
			
		} else if (itemId == R.id.main_menu_dictionary_text_menu_item) { // dictionary
			
			Intent intent = new Intent(applicationContext, WordDictionaryTab.class);

			activity.startActivity(intent);
			
			return true;
		} else if (itemId == R.id.main_menu_kanji_text_menu_item) { // kanji search
			
			Intent intent = new Intent(applicationContext, KanjiSearch.class);

			activity.startActivity(intent);
			
			return true;
		/* } else if (itemId == R.id.main_menu_kanji_recognizer_text_menu_item) { // kanji recognize
			
			Intent intent = new Intent(applicationContext, KanjiRecognizeActivity.class);

			activity.startActivity(intent);	
			
			return true;
		*/
		} else if (itemId == R.id.main_menu_show_user_group_menu_item) { // pokaz grupy uzytkownika

			Intent intent = new Intent(applicationContext, UserGroupActivity.class);

			activity.startActivity(intent);

			return true;
		}

		return false;
	}
} public class AutoCompleteAdapter extends BaseAdapter implements Filterable {

	private Context context;
	
	private List<String> resultList = new ArrayList<String>();
	
	private AutoCompleteSuggestionType autoCompleteSuggestionType;
	
	public AutoCompleteAdapter(Context context, AutoCompleteSuggestionType autoCompleteSuggestionType) {
		this.context = context;
		this.autoCompleteSuggestionType = autoCompleteSuggestionType;
	}
	
    @Override
    public int getCount() {
        return resultList.size();
    }

    @Override
    public String getItem(int index) {
        return resultList.get(index);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }
    
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
    	
        if (convertView == null) {
        	
            LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            
            convertView = inflater.inflate(pl.idedyk.android.japaneselearnhelper.R.layout.word_dictionary_autocomplete_dropdown_item, parent, false);
        }
        
        ((TextView) convertView.findViewById(android.R.id.text1)).setText(getItem(position));
        
        return convertView;
    }
    
    @Override
    public Filter getFilter() {
    	
        Filter filter = new Filter() {
            
        	@Override
            protected FilterResults performFiltering(CharSequence constraint) {
                
        		FilterResults filterResults = new FilterResults();
                
        		if (constraint != null) {
        			
					PackageInfo packageInfo = null;
			        
			        try {
			        	packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
			        	
			        } catch (NameNotFoundException e) {        	
			        }
			        
					
					ServerClient serverClient = new ServerClient();
					
        			// tymczasowo nie wywolujemy serwera
					// List<String> autoComplete = new ArrayList<String>(); //
					
					List<String> autoComplete = serverClient.getAutoComplete(packageInfo, constraint.toString(), autoCompleteSuggestionType);
					
					//
					
                    filterResults.values = autoComplete;
                    filterResults.count = autoComplete.size();
                }
                
        		return filterResults;
            }

            @SuppressWarnings("unchecked")
			@Override
            protected void publishResults(CharSequence constraint, FilterResults results) {
            	
                if (results != null && results.count > 0) {
                    
                	resultList = (List<String>) results.values;
                    
                	notifyDataSetChanged();
                	
                } else {
                	
                    notifyDataSetInvalidated();
                }
            }};
            
        return filter;
    }
} public class DelayAutoCompleteTextView extends AutoCompleteTextView {

    private static final int MESSAGE_TEXT_CHANGED = 100;
    private static final int AUTOCOMPLETE_DELAY = 1;

    private CheckBox useAutocompleteCheckBox;
    
    @SuppressLint("HandlerLeak")
	private final Handler mHandler = new Handler() {
    	
        @Override
        public void handleMessage(Message msg) {
        	
        	MessageObject messageObject = (MessageObject)msg.obj;
        	
            DelayAutoCompleteTextView.super.performFiltering(messageObject.getText(), messageObject.getKeyCode());
        }
    };

    public DelayAutoCompleteTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    protected void performFiltering(CharSequence text, int keyCode) {
    	
    	if (useAutocompleteCheckBox != null && useAutocompleteCheckBox.isChecked() == true) {
    	        
	        mHandler.removeMessages(MESSAGE_TEXT_CHANGED);
	        
	        Message message = mHandler.obtainMessage(MESSAGE_TEXT_CHANGED, new MessageObject(text, keyCode));
	        
	        mHandler.sendMessageDelayed(message, AUTOCOMPLETE_DELAY);
    	}
    }

    @Override
    public void onFilterComplete(int count) {
    	super.onFilterComplete(count);
    }
    
    public void setUseAutocompleteCheckBox(CheckBox useAutocompleteCheckBox) {
    	this.useAutocompleteCheckBox = useAutocompleteCheckBox;
    }
    
    private static class MessageObject {
    	
    	public MessageObject(CharSequence text, int keyCode) {
    		this.text = text;
    		this.keyCode = keyCode;
    	}
    	
    	private CharSequence text;
    	
    	private int keyCode;

		public CharSequence getText() {
			return text;
		}

		public int getKeyCode() {
			return keyCode;
		}
    }
} public class KanjiSearchMeaningConfig {
		
	private final String kanjiSearchMeaningConfigPrefix = "kanjiSearchMeaningConfig_";
		
	private final String eachChangeSearchPostfix = "eachChangeSearch";
		
	private final String useAutocompletePostfix = "useAutocomplete";
		
	private final String useSuggestionPostfix = "useSuggestion";
		
	public Boolean getEachChangeSearch() {
		return preferences.getBoolean(kanjiSearchMeaningConfigPrefix + eachChangeSearchPostfix, false);
	}
		
	public void setEachChangeSearch(boolean eachChangeSearch) {
			
		Editor editor = preferences.edit();
			
		editor.putBoolean(kanjiSearchMeaningConfigPrefix + eachChangeSearchPostfix, eachChangeSearch);
			
		editor.commit();			
	}
		
	public Boolean getUseAutocomplete() {
		return preferences.getBoolean(kanjiSearchMeaningConfigPrefix + useAutocompletePostfix, true);
	}
		
	public void setUseAutocomplete(boolean useAutocomplete) {

		Editor editor = preferences.edit();
			
		editor.putBoolean(kanjiSearchMeaningConfigPrefix + useAutocompletePostfix, useAutocomplete);
			
		editor.commit();			
	}
		
	public Boolean getUseSuggestion() {
		return preferences.getBoolean(kanjiSearchMeaningConfigPrefix + useSuggestionPostfix, true);
	}
		
	public void setUseSuggestion(boolean useSuggestion) {

		Editor editor = preferences.edit();
			
		editor.putBoolean(kanjiSearchMeaningConfigPrefix + useSuggestionPostfix, useSuggestion);
			
		editor.commit();			
	}
} public abstract class DictionaryManagerCommon extends DictionaryManagerAbstract {

    protected static final String KANA_FILE = "kana.csv";

    protected static final String RADICAL_FILE = "radical.csv";

    protected File baseDir;
    protected File databaseDir;

    //

    private WordTestSM2Manager wordTestSM2Manager;

    private DataManager dataManager;

    protected ZinniaManagerCommon zinniaManager;

    //

    private List<RadicalInfo> radicalList = null;

    private KanaHelper kanaHelper;

    protected final KeigoHelper keigoHeper;

    protected DictionaryManagerCommon() {
        keigoHeper = new KeigoHelper();
    }

    public final void init(Activity activity, ILoadWithProgress loadWithProgress, Resources resources, AssetManager assets, String packageName, int versionCode) {

        // init
        loadWithProgress.setDescription(resources.getString(R.string.dictionary_manager_load_init));

        // detect external storage legacy
        boolean externalStorageLegacy = true;

        try {
            Method isExternalStorageLegacyMethod = Environment.class.getMethod("isExternalStorageLegacy");

            externalStorageLegacy = (Boolean)isExternalStorageLegacyMethod.invoke(null);

        } catch (Exception e) {
            externalStorageLegacy = true;

        }

        // check external storage state
        if (checkExternalStorageState(loadWithProgress, resources) == false) {
            return;
        }

        File externalStorageDirectory;

        if (externalStorageLegacy == true) { // stary sposob

            // pobranie glownego katalogu to storage
            File oldStorageDirFile = Environment.getExternalStorageDirectory();
            File oldBaseDir = calculateBaseDir(oldStorageDirFile);

            // pobranie nowej lokalizacji
            File newStorageDirFile = getNewStorageDirFile(activity);
            File newBaseDir = calculateBaseDir(newStorageDirFile);

            if (oldBaseDir.exists() == true) { // jezeli stara lokalizacja istnieje to przenies to w nowe miejsce

                boolean moveStorageResult = moveFile(oldBaseDir, newBaseDir);

                if (moveStorageResult == false) { // operacja nie udala sie

                    loadWithProgress.setError(resources.getString(R.string.dictionary_manager_ioerror));

                    return;
                }
            }

            // ustawienie nowej glownej lokalizacji
            externalStorageDirectory = newStorageDirFile;

        } else { // new way Android 11+
            externalStorageDirectory = getNewStorageDirFile(activity);
        }

        if (externalStorageDirectory == null) {
            loadWithProgress.setError(resources.getString(R.string.dictionary_manager_null_external_storage));

            return;
        }

        // create base dir
        baseDir = calculateBaseDir(externalStorageDirectory);

        if (baseDir.isDirectory() == false) {

            if (baseDir.mkdirs() == false) {
                loadWithProgress.setError(resources.getString(R.string.dictionary_manager_create_directories_error));

                return;
            }
        }

        // create directory dir
        databaseDir = new File(baseDir, "db");

        if (databaseDir.isDirectory() == false) {

            if (databaseDir.mkdirs() == false) {
                loadWithProgress.setError(resources.getString(R.string.dictionary_manager_create_directories_error));

                return;
            }
        }

        // dalsze czynnosci
        init2(activity, loadWithProgress, resources, assets, packageName, versionCode);
    }

    private File calculateBaseDir(File dir) {
        return new File(dir, "JaponskiPomocnik");
    }

    private File getNewStorageDirFile(Activity activity) {

        File newStorageDirFile = activity.getExternalFilesDir(null);

        if (newStorageDirFile == null) { // to chyba nie powinno zadarzyc sie

            newStorageDirFile = new File(Environment.getExternalStorageDirectory(), "/Android/data/" + activity.getPackageName() + "/files");

            newStorageDirFile.mkdirs();

            //

            //newStorageDirFile = activity.getExternalFilesDir(null);
        }

        return newStorageDirFile;
    }

    protected boolean initDataManager(Activity activity, ILoadWithProgress loadWithProgress, Resources resources) {

        // create data manager
        dataManager = new DataManager(databaseDir);

        // open data manager
        try {
            dataManager.open();
        } catch (DataManagerException e) {
            loadWithProgress.setError(resources.getString(R.string.dictionary_manager_ioerror));

            return false;
        }

        // migrate old own group from kanji test
        loadWithProgress.setDescription(resources.getString(R.string.dictionary_manager_migrate_old_own_groups_from_kanji_test));
        loadWithProgress.setCurrentPos(0);

        final ConfigManager.KanjiTestConfig kanjiTestConfig = JapaneseAndroidLearnHelperApplication.getInstance()
                .getConfigManager(activity).getKanjiTestConfig();

        List<String> kanjiTestOldOwnGroupList = kanjiTestConfig.getOwnGroupList();

        if (kanjiTestOldOwnGroupList != null && kanjiTestOldOwnGroupList.size() > 0) {

            for (String kanjiTestOldOwnGroupName : kanjiTestOldOwnGroupList) {

                String kanjiTestOldOwnGroupNameMigrate = kanjiTestOldOwnGroupName + " " + resources.getString(R.string.dictionary_manager_migrate_old_own_groups_from_kanji_test_group_postfix);

                //

                List<UserGroupEntity> userGroupEntityList = dataManager.findUserGroupEntity(UserGroupEntity.Type.USER_GROUP, kanjiTestOldOwnGroupNameMigrate);

                UserGroupEntity userGroupEntity = null;

                if (userGroupEntityList == null || userGroupEntityList.size() == 0) {

                    userGroupEntity = new UserGroupEntity(null, UserGroupEntity.Type.USER_GROUP, kanjiTestOldOwnGroupNameMigrate);

                    dataManager.addUserGroup(userGroupEntity);

                    userGroupEntityList = dataManager.findUserGroupEntity(UserGroupEntity.Type.USER_GROUP, kanjiTestOldOwnGroupNameMigrate);
                }

                userGroupEntity = userGroupEntityList.get(0);

                //

                Set<String> ownGroupKanjiList = kanjiTestConfig.getOwnGroupKanjiList(kanjiTestOldOwnGroupName);

                for (String kanji : ownGroupKanjiList) {

                    KanjiEntry kanjiEntry = null;

                    try {
                        kanjiEntry = findKanji(kanji);

                    } catch (DictionaryException e) {
                        loadWithProgress.setError(resources.getString(R.string.dictionary_manager_generic_ioerror, e.getMessage()));

                        return false;
                    }

                    if (kanjiEntry != null) {

                        boolean isItemIdExists = dataManager.isItemIdExistsInUserGroup(userGroupEntity, UserGroupItemEntity.Type.KANJI_ENTRY, kanjiEntry.getId());

                        if (isItemIdExists == false) {
                            dataManager.addItemIdToUserGroup(userGroupEntity, UserGroupItemEntity.Type.KANJI_ENTRY, kanjiEntry.getId());
                        }
                    }
                }

                kanjiTestConfig.deleteOwnGroup(kanjiTestOldOwnGroupName);
            }
        }

        return true;
    }

    protected boolean initWordTestSM2Manager(Activity activity, ILoadWithProgress loadWithProgress, Resources resources) {

        wordTestSM2Manager = new WordTestSM2Manager(databaseDir);

        // open word test sm2 manager
        try {
            wordTestSM2Manager.open();
        } catch (TestSM2ManagerException e) {
            loadWithProgress.setError(resources.getString(R.string.dictionary_manager_ioerror));

            return false;
        }

        return true;
    }

    protected boolean initKana(Activity activity, ILoadWithProgress loadWithProgress, Resources resources, AssetManager assets) {

        loadWithProgress.setDescription(resources.getString(R.string.dictionary_manager_load_kana));
        loadWithProgress.setCurrentPos(0);

        try {
            InputStream kanaFileInputStream = assets.open(KANA_FILE);
            int kanaFileSize = getWordSize(kanaFileInputStream);
            loadWithProgress.setMaxValue(kanaFileSize);

            kanaFileInputStream = assets.open(KANA_FILE);
            readKanaFile(kanaFileInputStream, loadWithProgress);

        } catch (IOException e) {
            loadWithProgress
                    .setError(resources.getString(R.string.dictionary_manager_generic_ioerror, e.toString()));

            return false;
        }

        return true;
    }

    private void readKanaFile(InputStream kanaFileInputStream, ILoadWithProgress loadWithProgress) throws IOException {

        CsvReader csvReader = new CsvReader(new InputStreamReader(kanaFileInputStream), ',');

        int currentPos = 1;

        Map<String, List<KanjivgEntry>> kanaAndStrokePaths = new HashMap<String, List<KanjivgEntry>>();

        while (csvReader.readRecord()) {

            currentPos++;

            loadWithProgress.setCurrentPos(currentPos);

            //int id = Integer.parseInt(csvReader.get(0));

            String kana = csvReader.get(1);

            String strokePath1String = csvReader.get(2);

            String strokePath2String = csvReader.get(3);

            List<KanjivgEntry> strokePaths = new ArrayList<KanjivgEntry>();

            strokePaths.add(new KanjivgEntry(Utils.parseStringIntoList(strokePath1String /*, false */)));

            if (strokePath2String == null || strokePath2String.equals("") == false) {
                strokePaths.add(new KanjivgEntry(Utils.parseStringIntoList(strokePath2String /*, false */)));
            }

            kanaAndStrokePaths.put(kana, strokePaths);
        }

        kanaHelper = new KanaHelper(kanaAndStrokePaths);

        csvReader.close();
    }

    protected boolean initRadical(Activity activity, ILoadWithProgress loadWithProgress, Resources resources, AssetManager assets) throws DictionaryException {

        loadWithProgress.setDescription(resources.getString(R.string.dictionary_manager_load_radical));
        loadWithProgress.setCurrentPos(0);

        try {
            InputStream radicalInputStream = assets.open(RADICAL_FILE);
            int radicalFileSize = getWordSize(radicalInputStream);
            loadWithProgress.setMaxValue(radicalFileSize);

            radicalInputStream = assets.open(RADICAL_FILE);
            readRadicalEntriesFromCsv(radicalInputStream, loadWithProgress);

        } catch (IOException e) {
            loadWithProgress
                    .setError(resources.getString(R.string.dictionary_manager_generic_ioerror, e.toString()));

            return false;
        }

        return true;
    }

    private void readRadicalEntriesFromCsv(InputStream radicalInputStream, ILoadWithProgress loadWithProgress)
            throws IOException, DictionaryException {

        radicalList = new ArrayList<RadicalInfo>();

        CsvReader csvReader = new CsvReader(new InputStreamReader(radicalInputStream), ',');

        int currentPos = 1;

        while (csvReader.readRecord()) {

            currentPos++;

            loadWithProgress.setCurrentPos(currentPos);

            int id = Integer.parseInt(csvReader.get(0));

            String radical = csvReader.get(1);

            if (radical.equals("") == true) {
                throw new DictionaryException("Empty radical: " + radical);
            }

            String strokeCountString = csvReader.get(2);

            int strokeCount = Integer.parseInt(strokeCountString);

            RadicalInfo entry = new RadicalInfo();

            entry.setId(id);
            entry.setRadical(radical);
            entry.setStrokeCount(strokeCount);

            radicalList.add(entry);
        }

        csvReader.close();
    }

    private boolean checkExternalStorageState(ILoadWithProgress loadWithProgress, Resources resources) {

        String state = Environment.getExternalStorageState();

        if (Environment.MEDIA_MOUNTED.equals(state) == false) {
            loadWithProgress.setError(resources.getString(R.string.dictionary_manager_bad_external_storage_state));

            return false;
        }

        return true;
    }

    private static boolean moveFile(File sourceFile, File destinationFile) {

        if (sourceFile.isFile() == true) {

            // kopiujemy zawartosc
            byte[] buffer = new byte[1024];
            int count;

            FileInputStream sourceFileInputStream = null;
            FileOutputStream destinationFileOutputStream = null;

            try {
                sourceFileInputStream = new FileInputStream(sourceFile);
                destinationFileOutputStream = new FileOutputStream(destinationFile);

                while ((count = sourceFileInputStream.read(buffer)) != -1) {
                    destinationFileOutputStream.write(buffer, 0, count);
                }

            } catch (IOException e) {
                return false;

            } finally {

                if (sourceFileInputStream != null) {

                    try {
                        sourceFileInputStream.close();
                    } catch (IOException e) {
                        //noop
                    }
                }

                if (destinationFileOutputStream != null) {
                    try {
                        destinationFileOutputStream.close();
                    } catch (IOException e) {
                        //noop
                    }
                }

                if (sourceFile.delete() == false) {
                    return false;
                }
            }

        } else if (sourceFile.isDirectory() == true) {

            if (destinationFile.isDirectory() == false) {

                if (destinationFile.mkdir() == false) {
                    return false;
                }
            }

            File[] sourceDirFileList = sourceFile.listFiles();

            for (File currentSourceDirFile : sourceDirFileList) {

                if (moveFile(currentSourceDirFile, new File(destinationFile, currentSourceDirFile.getName())) == false) {
                    return false;
                }
            }

            if (sourceFile.delete() == false) {
                return false;
            }

        } else {
            throw new RuntimeException();
        }

        return true;
    }

    protected int getWordSize(InputStream dictionaryInputStream) throws IOException {

        int size = 0;

        CsvReader csvReader = new CsvReader(new InputStreamReader(dictionaryInputStream), ',');

        while (csvReader.readRecord()) {
            size++;
        }

        dictionaryInputStream.close();

        return size;
    }

    public abstract void init2(Activity activity, ILoadWithProgress loadWithProgress, Resources resources, AssetManager assets, String packageName, int versionCode);

    public abstract void close();

    public DataManager getDataManager() {
        return dataManager;
    }

    public WordTestSM2Manager getWordTestSM2Manager() {
        return wordTestSM2Manager;
    }

    public ZinniaManagerCommon getZinniaManager() {
        return zinniaManager;
    }

    @Override
    public KanaHelper getKanaHelper() {
        return kanaHelper;
    }

    @Override
    public KeigoHelper getKeigoHelper() {
        return keigoHeper;
    }

    @Override
    public List<RadicalInfo> getRadicalList() {
        return radicalList;
    }

    @Override
    protected void finalize() throws Throwable {

        super.finalize();

        dataManager.close();

        wordTestSM2Manager.close();
    }

    public static DictionaryManagerCommon getDictionaryManager() {

        // wersja zdalna
        //return new RemoteDictionaryManager();

        // wersja lokalna
        return new LocalDictionaryManager();
    }
} public static enum ItemType {

	KANJI_ENTRY(R.layout.kanji_entry_simplerow, 0),

	TITLE(R.layout.kanji_entry_simplerow, 0),

	SUGGESTION_VALUE(R.layout.kanji_entry_suggestion_simplerow, 1),

	SHOW_HISTORY_VALUE(R.layout.kanji_entry_show_history_simplerow, 2);
		
	private int layoutResourceId;

	private int viewTypeId;

	// ten sam layoutResourceId musi sie rownac tego samemu viewTypeId !!!
	ItemType(int layoutResourceId, int viewTypeId) {
		this.layoutResourceId = layoutResourceId;
		this.viewTypeId = viewTypeId;
	}

	public int getViewTypeId() {
		return viewTypeId;
	}

	public static int getLayoutResourceId(int itemViewTypeId) {

		ItemType[] values = values();

		for (ItemType itemType : values) {

			if (itemType.getViewTypeId() == itemViewTypeId) {
				return itemType.layoutResourceId;
			}
		}			

		throw new RuntimeException("Unknown itemViewTypeId: " + itemViewTypeId);
	}

} public class ReportProblem {
	
	public static Intent createReportProblemIntent(String mailSubject, String mailBody, String versionName, int versionCode) {
		
		Intent email = new Intent(Intent.ACTION_SEND);
		
		mailBody += "---\nVersion code: " + versionCode + "\nVersion name: " + versionName + "\n";
		
		email.putExtra(Intent.EXTRA_EMAIL, new String[] { "fryderyk.mazurek@gmail.com" } );
		
		email.putExtra(Intent.EXTRA_SUBJECT, mailSubject);
		email.putExtra(Intent.EXTRA_TEXT, mailBody);
		
		email.setType("message/rfc822");
		
		return email;
	}
} public class ServerClient {
	
	//private static final String PREFIX_URL = "http://10.0.2.2:8080"; // dev
	private static final String PREFIX_URL = "https://www.japonski-pomocnik.pl"; // prod

	private static final String SEND_MISSING_WORD_URL = PREFIX_URL + "/android/sendMissingWord";
	private static final String SEARCH_URL = PREFIX_URL + "/android/search";
	private static final String GET_MESSAGE_URL = PREFIX_URL + "/android/getMessage";

	private static final String AUTOCOMPLETE_URL = PREFIX_URL + "/android/autocomplete";
	
	private static final String SPELL_CHECKER_SUGGESTION_URL = PREFIX_URL + "/android/spellCheckerSuggestion";

	private static final String SEND_QUEUE_EVENT_URL = PREFIX_URL + "/android/receiveQueueEvent";

	private static final String REMOTE_DATABASE_CONNECTOR_BASE_URL = PREFIX_URL + "/android/remoteDatabaseConnector/";

	private static final int TIMEOUT = 10000;
	
	public ServerClient() {
				
	}
	
	public boolean sendMissingWord(PackageInfo packageInfo, String word, WordPlaceSearch wordPlaceSearch) {
		
		boolean connected = isConnected();
		
		if (connected == false) {			
			return false;
		}

		HttpURLConnection httpURLConnection = null;
		
		try {
			// przygotuj dane wejsciowe
			Map<String, Object> requestDataMap = new HashMap<String, Object>();

			requestDataMap.put("word", word);
			requestDataMap.put("wordPlaceSearch", wordPlaceSearch.toString());

			httpURLConnection = callRemoteService(packageInfo, SEND_MISSING_WORD_URL, convertMapToJSONObject(requestDataMap).toString());

			// sprawdz odpowiedz
			int statusCode = httpURLConnection.getResponseCode();

			if (statusCode < 200 || statusCode >= 300) {

				Log.e("ServerClient", "Error send missing word: " + httpURLConnection.getResponseCode() + " - " + httpURLConnection.getResponseMessage());

				return false;
			}

			return true;

		} catch (Exception e) {
			Log.e("ServerClient", "Error send missing word: ", e);
			
			return false;

		} finally {

			if (httpURLConnection != null) {
				httpURLConnection.disconnect();
			}
		}
	}
	
	private String createUserAgent(PackageInfo packageInfo) {
		
		StringBuffer sb = new StringBuffer("JapaneseAndroidLearnHelper");
		
		if (packageInfo != null) {			
			sb.append("/" + packageInfo.versionCode + "/" + packageInfo.versionName);
		}
				
		return sb.toString();
	}

	public FindWordResult search(PackageInfo packageInfo, FindWordRequest findWordRequest) {
		
		boolean connected = isConnected();
		
		if (connected == false) {			
			return null;
		}

		HttpURLConnection httpURLConnection = null;

		BufferedReader contentInputStreamReader = null;

		try {
			// przygotuj dane wejsciowe
			Map<String, Object> requestDataMap = createMapFromFindWordRequest(findWordRequest);

			httpURLConnection = callRemoteService(packageInfo, SEARCH_URL, convertMapToJSONObject(requestDataMap).toString());

			// sprawdz odpowiedz
			int statusCode = httpURLConnection.getResponseCode();

			if (statusCode < 200 || statusCode >= 300) {

				Log.e("ServerClient", "Error search: " + httpURLConnection.getResponseCode() + " - " + httpURLConnection.getResponseMessage());
				
				return null;
			}

			// pobierz odpowiedz
			contentInputStreamReader = new BufferedReader(new InputStreamReader(httpURLConnection.getInputStream()));

			StringBuffer jsonResponseSb = new StringBuffer();
			
			while (true) {		
				String readLine = contentInputStreamReader.readLine();
				
				if (readLine == null) {
					break;
				}
				
				jsonResponseSb.append(readLine);			
			}

			if (jsonResponseSb.length() == 0) {
				return null;
			}

			JSONObject responseJSON = new JSONObject(jsonResponseSb.toString());
			
			return createFindWordResultFromJSON(responseJSON);
			
		} catch (Exception e) {
			Log.e("ServerClient", "Error search: ", e);
			
			return null;

		} finally {

			if (contentInputStreamReader != null) {

				try {
					contentInputStreamReader.close();

				} catch (IOException e) {
					// noop
				}
			}

			if (httpURLConnection != null) {
				httpURLConnection.disconnect();
			}
		}
	}

	private boolean isConnected() {
		
		ConnectivityManager cm = (ConnectivityManager)JapaneseAndroidLearnHelperApplication.getInstance().
				getSystemService(Context.CONNECTIVITY_SERVICE);
		
		NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
		
		if (activeNetwork == null) {
			return false;
		}
		
		return activeNetwork.isConnected();		
	}
	
	private static JSONObject convertMapToJSONObject(Map<String, Object> params) throws JSONException {

	    Iterator<Map.Entry<String, Object>> paramsEntrySetIterator = params.entrySet().iterator();

	    JSONObject result = new JSONObject();
	    
	    while (paramsEntrySetIterator.hasNext() == true) { 
	    	
	    	Map.Entry<String, Object> currentPair = (Map.Entry<String, Object>)paramsEntrySetIterator.next();

	        String key = (String)currentPair.getKey();	        
	        Object value = currentPair.getValue();
	        
	        if (value instanceof List<?>) {
	        	
	        	JSONArray jsonArray = new JSONArray();
	        	
	        	List<?> valueList =  (List<?>)value;
	        	
	        	for (Object currentValue : valueList) {					
	        		jsonArray.put(currentValue.toString());	        		
	        	}
	        	
	        	result.put(key, jsonArray);
	        	
	        } else {
	        	result.put(key, value);
	        }	        
	    }
	    
	    return result;
	}
	
	private Map<String, Object> createMapFromFindWordRequest(FindWordRequest findWordRequest) {
				
		Map<String, Object> requestDataMap =  new HashMap<String, Object>();
		
		requestDataMap.put("searchMainDictionary", findWordRequest.searchMainDictionary);
		requestDataMap.put("searchGrammaFormAndExamples", findWordRequest.searchGrammaFormAndExamples);
		requestDataMap.put("searchName", findWordRequest.searchName);
		
		requestDataMap.put("word", findWordRequest.word);
		
		requestDataMap.put("searchKanji", findWordRequest.searchKanji);
		requestDataMap.put("searchKana", findWordRequest.searchKana);
		requestDataMap.put("searchRomaji", findWordRequest.searchRomaji);
		requestDataMap.put("searchTranslate", findWordRequest.searchTranslate);
		requestDataMap.put("searchInfo", findWordRequest.searchInfo);
		requestDataMap.put("searchOnlyCommonWord", findWordRequest.searchOnlyCommonWord);
		
		requestDataMap.put("wordPlaceSearch", findWordRequest.wordPlaceSearch);
		
		requestDataMap.put("dictionaryEntryTypeList", findWordRequest.dictionaryEntryTypeList);
				
		return requestDataMap;
	}
	
	private FindWordResult createFindWordResultFromJSON(JSONObject responseJSON) throws JSONException {
		
		FindWordResult findWordResult = new FindWordResult();
		
		findWordResult.moreElemetsExists = responseJSON.getBoolean("moreElemetsExists");
		findWordResult.foundGrammaAndExamples = responseJSON.getBoolean("foundGrammaAndExamples");
		findWordResult.foundNames = responseJSON.getBoolean("foundNames");
		
		findWordResult.result = new ArrayList<FindWordResult.ResultItem>();
		
		JSONArray resultJsonArray = responseJSON.getJSONArray("result");
		
		for (int resultIdx = 0; resultIdx < resultJsonArray.length(); ++resultIdx) {
			
			JSONObject currentJsonObjectResult = resultJsonArray.getJSONObject(resultIdx);
						
			DictionaryEntry dictionaryEntry = new DictionaryEntry();
			
			// id
			int id = currentJsonObjectResult.getInt("id");
			
			dictionaryEntry.setId(id);
			
			// dictionaryEntryTypeList
			JSONArray dictionaryEntryTypeListJsonArray = currentJsonObjectResult.getJSONArray("dictionaryEntryTypeList");
			
			List<DictionaryEntryType> dictionaryEntryTypeList = new ArrayList<DictionaryEntryType>();
			
			for (int dictionaryEntryTypeListJsonArrayIdx = 0; 
					dictionaryEntryTypeListJsonArrayIdx < dictionaryEntryTypeListJsonArray.length(); ++dictionaryEntryTypeListJsonArrayIdx) {
				
				dictionaryEntryTypeList.add(DictionaryEntryType.getDictionaryEntryType(
						dictionaryEntryTypeListJsonArray.getString(dictionaryEntryTypeListJsonArrayIdx)));
			}
			
			dictionaryEntry.setDictionaryEntryTypeList(dictionaryEntryTypeList);
			
			// attributeList
			AttributeList attributeList = new AttributeList();
			
			if (currentJsonObjectResult.has("attributeList") == true) {
				
				JSONArray attributeListJsonArray = currentJsonObjectResult.getJSONArray("attributeList");
				
				for (int attributeListJsonArrayIdx = 0; attributeListJsonArrayIdx < attributeListJsonArray.length();
						attributeListJsonArrayIdx++) {
					
					JSONObject currentAttributeJsonObject = attributeListJsonArray.getJSONObject(attributeListJsonArrayIdx);
					
					AttributeType attributeType = AttributeType.valueOf(currentAttributeJsonObject.getString("attributeType"));					
					List<String> attributeValueList = convertJSONArrayToListString(currentAttributeJsonObject.getJSONArray("attributeValue"));
					
					attributeList.addAttributeValue(attributeType, attributeValueList);
				}				
			}
			
			dictionaryEntry.setAttributeList(attributeList);
			
			// groups
			JSONArray groupsEnumListJsonArray = currentJsonObjectResult.getJSONArray("groups");
			
			List<GroupEnum> groupsEnumList = new ArrayList<GroupEnum>();
			
			for (int groupsEnumListJsonArrayIdx = 0; 
					groupsEnumListJsonArrayIdx < groupsEnumListJsonArray.length(); ++groupsEnumListJsonArrayIdx) {
				
				groupsEnumList.add(GroupEnum.valueOf(groupsEnumListJsonArray.getString(groupsEnumListJsonArrayIdx)));
			}
			
			dictionaryEntry.setGroups(groupsEnumList);

			// prefixKana
			if (currentJsonObjectResult.has("prefixKana") == true) {
				dictionaryEntry.setPrefixKana(currentJsonObjectResult.getString("prefixKana"));
			}
			
			// kanji
			if (currentJsonObjectResult.has("kanji") == true) {
				dictionaryEntry.setKanji(currentJsonObjectResult.getString("kanji"));
			}
			
			// kanaList
			dictionaryEntry.setKana(currentJsonObjectResult.getString("kana"));
			
			// prefixRomaji
			if (currentJsonObjectResult.has("prefixRomaji") == true) {
				dictionaryEntry.setPrefixRomaji(currentJsonObjectResult.getString("prefixRomaji"));
			}
			
			// romajiList
			dictionaryEntry.setRomaji(currentJsonObjectResult.getString("romaji"));
			
			// translates
			dictionaryEntry.setTranslates(convertJSONArrayToListString(currentJsonObjectResult.getJSONArray("translates")));
			
			// info
			if (currentJsonObjectResult.has("info") == true) {
				dictionaryEntry.setInfo(currentJsonObjectResult.getString("info"));
			}
			
			// name
			dictionaryEntry.setName(currentJsonObjectResult.getBoolean("name"));
						
			findWordResult.result.add(new FindWordResult.ResultItem(dictionaryEntry));
		}
		
		return findWordResult;
	}
	
	private List<String> convertJSONArrayToListString(JSONArray jsonArray) throws JSONException {
		
		List<String> result = new ArrayList<String>();
		
		for (int idx = 0; idx < jsonArray.length(); ++idx) {			
			result.add(jsonArray.getString(idx));			
		}
		
		return result;
	}
	
	public List<String> getAutoComplete(PackageInfo packageInfo, String word, AutoCompleteSuggestionType autoCompleteSuggestionType) {
		
		boolean connected = isConnected();
		
		if (connected == false) {			
			return new ArrayList<>();
		}
		
		if (word == null || word.length() < 2) {
			return new ArrayList<>();
		}

		HttpURLConnection httpURLConnection = null;

		BufferedReader contentInputStreamReader = null;
		
		try {
			// przygotuj dane wejsciowe
			Map<String, Object> requestDataMap = new HashMap<String, Object>();

			requestDataMap.put("word", word);
			requestDataMap.put("type", autoCompleteSuggestionType.getType());

			httpURLConnection = callRemoteService(packageInfo, AUTOCOMPLETE_URL, convertMapToJSONObject(requestDataMap).toString());

			// sprawdz odpowiedz
			int statusCode = httpURLConnection.getResponseCode();

			if (statusCode < 200 || statusCode >= 300) {

				Log.e("ServerClient", "Error send missing word: " + httpURLConnection.getResponseCode() + " - " + httpURLConnection.getResponseMessage());

				return new ArrayList<>();
			}
			
			// pobranie odpowiedzi
			contentInputStreamReader = new BufferedReader(new InputStreamReader(httpURLConnection.getInputStream()));

			StringBuffer jsonResponseSb = new StringBuffer();
			
			while (true) {		
				String readLine = contentInputStreamReader.readLine();
				
				if (readLine == null) {
					break;
				}
				
				jsonResponseSb.append(readLine);			
			}

			if (jsonResponseSb.length() == 0) {
				return null;
			}

			JSONArray responseJSON = new JSONArray(jsonResponseSb.toString());

			List<String> result = new ArrayList<String>();
			
			for (int idx = 0; idx < responseJSON.length(); ++idx) {
				
				JSONObject jsonObject = responseJSON.getJSONObject(idx);
				
				result.add(jsonObject.getString("value"));
			}			
			
			return result;
			
		} catch (Exception e) {
			Log.e("ServerClient", "Error send missing word: ", e);
			
			return null;

		} finally {

			if (contentInputStreamReader != null) {

				try {
					contentInputStreamReader.close();

				} catch (IOException e) {
					// noop
				}
			}

			if (httpURLConnection != null) {
				httpURLConnection.disconnect();
			}
		}
	}
	
	public List<String> getSuggestionList(PackageInfo packageInfo, String word, AutoCompleteSuggestionType autoCompleteSuggestionType) {
		
		boolean connected = isConnected();
		
		if (connected == false) {			
			return null;
		}
		
		if (word == null || word.length() < 2) {
			return null;
		}

		HttpURLConnection httpURLConnection = null;

		BufferedReader contentInputStreamReader = null;
		
		try {
			// przygotuj dane wejsciowe
			Map<String, Object> requestDataMap = new HashMap<String, Object>();

			requestDataMap.put("word", word);
			requestDataMap.put("type", autoCompleteSuggestionType.getType());

			httpURLConnection = callRemoteService(packageInfo, SPELL_CHECKER_SUGGESTION_URL, convertMapToJSONObject(requestDataMap).toString());

			// sprawdz odpowiedz
			int statusCode = httpURLConnection.getResponseCode();

			if (statusCode < 200 || statusCode >= 300) {
				Log.e("ServerClient", "Error send missing word: " + httpURLConnection.getResponseCode() + " - " + httpURLConnection.getResponseMessage());
				
				return null;
			}
			
			// pobranie odpowiedzi
			contentInputStreamReader = new BufferedReader(new InputStreamReader(httpURLConnection.getInputStream()));

			StringBuffer jsonResponseSb = new StringBuffer();
			
			while (true) {		
				String readLine = contentInputStreamReader.readLine();
				
				if (readLine == null) {
					break;
				}
				
				jsonResponseSb.append(readLine);			
			}

			if (jsonResponseSb.length() == 0) {
				return null;
			}

			JSONArray responseJSON = new JSONArray(jsonResponseSb.toString());

			List<String> result = new ArrayList<String>();
			
			for (int idx = 0; idx < responseJSON.length(); ++idx) {
				
				JSONObject jsonObject = responseJSON.getJSONObject(idx);
				
				result.add(jsonObject.getString("value"));
			}			
			
			return result;
			
		} catch (Exception e) {
			Log.e("ServerClient", "Error send missing word: ", e);
			
			return null;

		} finally {

			if (contentInputStreamReader != null) {

				try {
					contentInputStreamReader.close();

				} catch (IOException e) {
					// noop
				}
			}

			if (httpURLConnection != null) {
				httpURLConnection.disconnect();
			}
		}
	}

    public String callRemoteDictionaryConnectorMethod(PackageInfo packageInfo, String methodName, String jsonRequest) throws Exception {

        boolean connected = isConnected();

        if (connected == false) {
            throw new IOException("Not connected");
        }

		HttpURLConnection httpURLConnection = null;

		BufferedReader contentInputStreamReader = null;

        try {
			httpURLConnection = callRemoteService(packageInfo, REMOTE_DATABASE_CONNECTOR_BASE_URL + methodName, jsonRequest);

			// sprawdz odpowiedz
			int statusCode = httpURLConnection.getResponseCode();

			if (statusCode < 200 || statusCode >= 300) {
                Log.e("ServerClient", "Error callRemoteDictionaryConnectorMethod: " + httpURLConnection.getResponseCode() + " - " + httpURLConnection.getResponseMessage());

                throw new IOException(httpURLConnection.getResponseCode() + " - " + httpURLConnection.getResponseMessage());
            }

			// pobranie odpowiedzi
            contentInputStreamReader = new BufferedReader(new InputStreamReader(httpURLConnection.getInputStream()));

            StringBuffer jsonResponseSb = new StringBuffer();

            while (true) {
                String readLine = contentInputStreamReader.readLine();

                if (readLine == null) {
                    break;
                }

                jsonResponseSb.append(readLine);
            }

			if (jsonResponseSb.length() == 0) {
				throw new IOException();
			}

			return jsonResponseSb.toString();

        } catch (Exception e) {
            Log.e("ServerClient", "Error callRemoteDictionaryConnectorMethod: ", e);

            throw e;

		} finally {

			if (contentInputStreamReader != null) {

				try {
					contentInputStreamReader.close();

				} catch (IOException e) {
					// noop
				}
			}

			if (httpURLConnection != null) {
				httpURLConnection.disconnect();
			}
		}
    }

	public static <T> T callInServerThread(Callable<Object> callable, Class<T> resultClass) throws DictionaryException {

		ExecutorService executorService = null;

		try {
			executorService = Executors.newFixedThreadPool(1);

			Future<Object> resultFuture = executorService.submit(callable);

			Object resultObject = null;

			try {
				resultObject = resultFuture.get();

			} catch (Exception e) {
				throw new DictionaryException(e);
			}

			if (resultObject == null) {
				return null;

			} else if (resultObject instanceof DictionaryException) {
				throw (DictionaryException) resultObject;

			} else if (resultObject instanceof Exception) {
				throw new DictionaryException((Exception) resultObject);

			} else if (resultClass.isInstance(resultObject) == true) {
				return (T) resultObject;

			} else {
				throw new RuntimeException("Unknown object: " + resultObject);
			}

		} finally {

			if (executorService != null) {
				executorService.shutdown();
			}
		}
	}

	private HttpURLConnection callRemoteService(PackageInfo packageInfo, String urlString, String requestPostString) throws Exception {

		// url
		URL url = new URL(urlString);

		// tworzymy polaczenie
		HttpURLConnection httpURLConnection = (HttpURLConnection)url.openConnection();

		httpURLConnection.setRequestMethod("POST");

		// parametry do polaczenia
		httpURLConnection.setUseCaches(false);
		httpURLConnection.setAllowUserInteraction(false);
		httpURLConnection.setConnectTimeout(TIMEOUT);
		httpURLConnection.setReadTimeout(TIMEOUT);

		httpURLConnection.setDoInput(true);
		httpURLConnection.setDoOutput(true);

		// ustaw naglowki
		httpURLConnection.setRequestProperty("Accept", "application/json");
		httpURLConnection.setRequestProperty("Content-type", "application/json");
		httpURLConnection.setRequestProperty("User-Agent", createUserAgent(packageInfo));

		httpURLConnection.setRequestProperty("Content-Type", "application/json; utf-8");

		//

		// wywolaj serwer
		httpURLConnection.connect();

		// dane wejsciowe
		BufferedOutputStream bufferedOutputStream = null;

		try {
			bufferedOutputStream = new BufferedOutputStream(httpURLConnection.getOutputStream());

			bufferedOutputStream.write(requestPostString.getBytes("UTF-8"));

			bufferedOutputStream.flush();

		} catch(IOException exception) {
			throw exception;

		} finally {

			if (bufferedOutputStream != null) {

				try {
					bufferedOutputStream.close();

				} catch (IOException e) {
					// noop
				}
			}
		}

		return httpURLConnection;
	}

	public boolean sendQueueEvent(PackageInfo packageInfo, IQueueEvent queueEvent) {

		boolean connected = isConnected();

		if (connected == false) {
			return false;
		}

		HttpURLConnection httpURLConnection = null;

		BufferedReader contentInputStreamReader = null;

		try {
			String jsonRequest = new Gson().toJson(new QueueEventWrapper(queueEvent.getId(), queueEvent.getUserId(), queueEvent.getQueryEventOperation(), queueEvent.getCreateDateAsString(), queueEvent.getParams()));

			httpURLConnection = callRemoteService(packageInfo, SEND_QUEUE_EVENT_URL, jsonRequest);

			// sprawdz odpowiedz
			int statusCode = httpURLConnection.getResponseCode();

			if (statusCode < 200 || statusCode >= 300) {
				Log.e("ServerClient", "Error sendQueueEvent: " + httpURLConnection.getResponseCode() + " - " + httpURLConnection.getResponseMessage());

				return false;
			}

			return true;

		} catch (Exception e) {
			Log.e("ServerClient", "Error sendQueueEvent: ", e);

			return false;

		} finally {

			if (contentInputStreamReader != null) {

				try {
					contentInputStreamReader.close();

				} catch (IOException e) {
					// noop
				}
			}

			if (httpURLConnection != null) {
				httpURLConnection.disconnect();
			}
		}
	}

	public static class GetMessageResult {

		public String message;

		public String timestamp;
	}

	public GetMessageResult getMessage(PackageInfo packageInfo) {

		boolean connected = isConnected();

		if (connected == false) {
			return null;
		}

		HttpURLConnection httpURLConnection = null;

		BufferedReader contentInputStreamReader = null;

		try {
			httpURLConnection = callRemoteService(packageInfo, GET_MESSAGE_URL, new JSONObject().toString());

			// sprawdz odpowiedz
			int statusCode = httpURLConnection.getResponseCode();

			if (statusCode < 200 || statusCode >= 300) {

				Log.e("ServerClient", "Error search: " + httpURLConnection.getResponseCode() + " - " + httpURLConnection.getResponseMessage());

				return null;
			}

			// pobierz odpowiedz
			contentInputStreamReader = new BufferedReader(new InputStreamReader(httpURLConnection.getInputStream()));

			StringBuffer jsonResponseSb = new StringBuffer();

			while (true) {
				String readLine = contentInputStreamReader.readLine();

				if (readLine == null) {
					break;
				}

				jsonResponseSb.append(readLine);
			}

			if (jsonResponseSb.length() == 0) {
				return null;
			}

			JSONObject responseJSON = new JSONObject(jsonResponseSb.toString());

			String message = responseJSON.optString("message");
			String timestamp = responseJSON.optString("timestamp");

			// mamy jakis komunikat
			if (message != null && message.trim().equals("") == false && timestamp != null && timestamp.trim().equals("") == false) {

				GetMessageResult getMessageResult = new GetMessageResult();

				getMessageResult.message = message.trim();
				getMessageResult.timestamp = timestamp.trim();

				return getMessageResult;

			} else {
				return null;
			}

		} catch (Exception e) {
			Log.e("ServerClient", "Error search: ", e);

			return null;

		} finally {

			if (contentInputStreamReader != null) {

				try {
					contentInputStreamReader.close();

				} catch (IOException e) {
					// noop
				}
			}

			if (httpURLConnection != null) {
				httpURLConnection.disconnect();
			}
		}
	}

	public static enum AutoCompleteSuggestionType {
		
		WORD_DICTIONARY("wordDictionaryEntry"),
		
		KANJI_DICTIONARY("kanjiDictionaryEntry");
		
		private String type;
		
		AutoCompleteSuggestionType(String type) {
			this.type = type;
		}

		public String getType() {
			return type;
		}
	}
} public static enum AutoCompleteSuggestionType {
		
	WORD_DICTIONARY("wordDictionaryEntry"),
		
	KANJI_DICTIONARY("kanjiDictionaryEntry");
		
	private String type;
		
	AutoCompleteSuggestionType(String type) {
		this.type = type;
	}

	public String getType() {
		return type;
	}
} public class SearchHistoryHelper {

    private static final int MAX_ELEMENTS = 50;

    private SharedPreferences preferences;

    public SearchHistoryHelper(Activity activity, String searchField) {
        preferences = activity.getSharedPreferences(searchField, Context.MODE_PRIVATE);
    }

    public void addEntry(Entry newEntry) {

        // pobieramy aktualna zawartosc listy
        List<Entry> entryList = getEntryList();

        // szukamy, czy wpis, ktory chcemy dodac juz wystepuje na liscie
        Entry theSameEntryInEntryList = null;

        for (Entry currentEntry: entryList) {

            // mamy taki sam element
            if (currentEntry.text.equals(newEntry.text) == true) {
                theSameEntryInEntryList = currentEntry;

                break;
            }
        }

        // znalezlismy ten sam wpis, uaktualniamy go (w tej chwili to troche bez sensu, ale moze w przyszlosci to zmieni sie
        if (theSameEntryInEntryList != null) {
            theSameEntryInEntryList.text = newEntry.text;

            // usuwamy wpis z tej listy, za chwilke dodamy go na poczatku listy
            entryList.remove(theSameEntryInEntryList);

            entryList.add(0, theSameEntryInEntryList);

        } else {

            // dodajemy wpis na poczatku listy
            entryList.add(0, newEntry);
        }

        if (entryList.size() > MAX_ELEMENTS) { // usuwamy najstarszy wpis
            entryList.remove(entryList.size() - 1);
        }

        // zapisujemy liste
        try {
            saveEntryList(entryList);

        } catch (Exception e) {
            // noop
        }
    }

    public List<Entry> getEntryList() {

        List<Entry> result = new ArrayList<>();

        try {
            // pobranie danych
            JSONObject jsonObject = getJSONObject();

            JSONArray jsonArray = getJSSONArray(jsonObject);

            // utworzenie listy wynikowej
            for (int idx = 0; idx < jsonArray.length(); ++idx) {

                JSONObject jsonArrayEntryObject = jsonArray.getJSONObject(idx);

                String entryText = jsonArrayEntryObject.getString("text");

                result.add(new Entry(entryText));
            }

        } catch (Exception e) {
            // noop
        }

        return result;
    }

    private JSONObject getJSONObject() throws Exception {

        String jsonString = preferences.getString("history", null);

        JSONObject queueJson = null;

        if (jsonString == null) {
            queueJson = new JSONObject();

        } else {
            queueJson = new JSONObject(jsonString);
        }

        return queueJson;
    }

    private JSONArray getJSSONArray(JSONObject jsonObject) throws Exception {

        JSONArray jsonArray = null;

        if (jsonObject.isNull("array") == false) {
            jsonArray = jsonObject.getJSONArray("array");

        } else {
            jsonArray = new JSONArray();
        }

        return jsonArray;
    }

    private void saveEntryList(List<Entry> entryList) throws Exception {

        JSONObject jsonObject = getJSONObject();

        JSONArray jsonArray = new JSONArray();

        for (Entry entry : entryList) {

            JSONObject jsonEntryObject = new JSONObject();

            jsonEntryObject.put("text", entry.getText());

            jsonArray.put(jsonEntryObject);
        }

        jsonObject.put("array", jsonArray);

        // zapisujemy
        SharedPreferences.Editor preferencesEditor = preferences.edit();

        preferencesEditor.putString("history", jsonObject.toString());

        preferencesEditor.commit();
    }

    public static class Entry {

        private String text;

        public Entry(String text) {
            this.text = text;
        }

        public String getText() {
            return text;
        }

        @Override
        public boolean equals(Object o) {

            if (this == o) return true;

            if (o == null || getClass() != o.getClass()) return false;

            Entry entry = (Entry) o;

            return text != null ? text.equals(entry.text) : entry.text == null;
        }

        @Override
        public int hashCode() {
            return text != null ? text.hashCode() : 0;
        }
    }
} public class WordKanjiDictionaryUtils {

    public static String getWordFullTextWithMark(DictionaryEntry dictionaryEntry) {

        String kanji = dictionaryEntry.getKanji();
        String prefixKana = dictionaryEntry.getPrefixKana();
        List<String> kanaList = dictionaryEntry.getKanaList();
        String prefixRomaji = dictionaryEntry.getPrefixRomaji();
        List<String> romajiList = dictionaryEntry.getRomajiList();
        List<String> translates = dictionaryEntry.getTranslates();
        String info = dictionaryEntry.getInfo();

        StringBuffer result = new StringBuffer();

        String tempPrefixKana = prefixKana != null && prefixKana.equals("") == false ? prefixKana : null;
        String tempPrefixRomaji = prefixRomaji != null && prefixRomaji.equals("") == false ? prefixRomaji : null;

        if (dictionaryEntry.isKanjiExists() == true) {

            if (tempPrefixKana != null) {
                result.append("(").append(getStringWithMark(tempPrefixKana, null, false)).append(") ");
            }

            result.append(getStringWithMark(kanji, null, false)).append(" ");
        }

        if (kanaList != null && kanaList.size() > 0) {
            result.append(getStringWithMark(toString(kanaList, tempPrefixKana), null, false)).append(" - ");
        }

        if (romajiList != null && romajiList.size() > 0) {
            result.append(getStringWithMark(toString(romajiList, tempPrefixRomaji), null, false));
        }

        if (translates != null && translates.size() > 0) {
            result.append("\n\n");
            result.append(getStringWithMark(toString(translates, null), null, false));
        }

        if (info != null && info.equals("") == false) {
            result.append(" - ").append(getStringWithMark(info, null, false));
        }

        return result.toString();
    }

    public static String getWordFullTextWithMark(FindWordResult.ResultItem resultItem, String findWord, FindWordRequest findWordRequest) {

        String kanji = resultItem.getKanji();
        String prefixKana = resultItem.getPrefixKana();
        List<String> kanaList = resultItem.getKanaList();
        String prefixRomaji = resultItem.getPrefixRomaji();
        List<String> romajiList = resultItem.getRomajiList();
        List<String> translates = resultItem.getTranslates();
        String info = resultItem.getInfo();

        StringBuffer result = new StringBuffer();

        String tempPrefixKana = prefixKana != null && prefixKana.equals("") == false ? prefixKana : null;
        String tempPrefixRomaji = prefixRomaji != null && prefixRomaji.equals("") == false ? prefixRomaji : null;

        if (resultItem.isKanjiExists() == true) {

            if (tempPrefixKana != null) {
                result.append("(").append(getStringWithMark(tempPrefixKana, findWord, false)).append(") ");
            }

            result.append(getStringWithMark(kanji, findWord, findWordRequest.searchKanji)).append(" ");
        }

        if (kanaList != null && kanaList.size() > 0) {
            result.append(getStringWithMark(toString(kanaList, tempPrefixKana), findWord, findWordRequest.searchKana)).append(" - ");
        }

        if (romajiList != null && romajiList.size() > 0) {
            result.append(getStringWithMark(toString(romajiList, tempPrefixRomaji), findWord, findWordRequest.searchRomaji));
        }

        if (translates != null && translates.size() > 0) {
            result.append("\n\n");
            result.append(getStringWithMark(toString(translates, null), findWord, findWordRequest.searchTranslate));
        }

        if (info != null && info.equals("") == false) {
            result.append(" - ").append(getStringWithMark(info, findWord, findWordRequest.searchInfo));
        }

        return result.toString();
    }

    public static String getKanjiFullTextWithMark(KanjiEntry kanjiEntry) {
        return getKanjiFullTextWithMark(kanjiEntry, null);
    }

    public static String getKanjiFullTextWithMark(KanjiEntry kanjiEntry, String findWord) {

        String kanji = kanjiEntry.getKanji();
        List<String> polishTranslates = kanjiEntry.getPolishTranslates();

        String info = kanjiEntry.getInfo();

        StringBuffer result = new StringBuffer();

        result.append("<big>").append(getStringWithMark(kanji, findWord, true)).append("</big> - ");
        result.append(getStringWithMark(toString(polishTranslates, null), findWord, true));

        if (info != null && info.equals("") == false) {

            result.append("\n");

            result.append(getStringWithMark(info, findWord, true));
        }

        result.append("\n");

        return result.toString();
    }

    public static String getKanjiRadicalTextWithMark(KanjiEntry kanjiEntry) {
        return getKanjiRadicalTextWithMark(kanjiEntry, null);
    }

    public static String getKanjiRadicalTextWithMark(KanjiEntry kanjiEntry, String findWord) {

        KanjiDic2Entry kanjiDic2Entry = kanjiEntry.getKanjiDic2Entry();

        List<String> radicals = null;

        if (kanjiDic2Entry != null) {
            radicals = kanjiDic2Entry.getRadicals();

            if (radicals != null && radicals.size() == 0) {
                radicals = null;
            }
        }

        StringBuffer result = new StringBuffer();

        if (radicals != null) {
            result.append(getStringWithMark(toString(radicals, null), findWord, true));
        }

        return result.toString();
    }


    private static String getStringWithMark(String text, String findWord, boolean mark) {

        if (mark == false) {
            return text;
        }

        if (findWord == null) {
            return text;
        }

        String findWordLowerCase = findWord.toLowerCase(Locale.getDefault());

        StringBuffer texStringBuffer = new StringBuffer(text);
        StringBuffer textLowerCaseStringBuffer = new StringBuffer(text.toLowerCase(Locale.getDefault()));

        int idxStart = 0;

        final String fontBegin = "<font color='red'>";
        final String fontEnd = "</font>";

        while(true) {

            int idx1 = textLowerCaseStringBuffer.indexOf(findWordLowerCase, idxStart);

            if (idx1 == -1) {
                break;
            }

            texStringBuffer.insert(idx1, fontBegin);
            textLowerCaseStringBuffer.insert(idx1, fontBegin);

            texStringBuffer.insert(idx1 + findWordLowerCase.length() + fontBegin.length(), fontEnd);
            textLowerCaseStringBuffer.insert(idx1 + findWordLowerCase.length() + fontBegin.length(), fontEnd);

            idxStart = idx1 + findWordLowerCase.length() + fontBegin.length() + fontEnd.length();
        }

        return texStringBuffer.toString();
    }

    private static String toString(List<String> listString, String prefix) {

        StringBuffer sb = new StringBuffer();

        sb.append("[");

        for (int idx = 0; idx < listString.size(); ++idx) {
            if (prefix != null) {
                sb.append("(").append(prefix).append(") ");
            }

            sb.append(listString.get(idx));

            if (idx != listString.size() - 1) {
                sb.append(", ");
            }
        }

        sb.append("]");

        return sb.toString();
    }
}
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import pl.idedyk.android.japaneselearnhelper.JapaneseAndroidLearnHelperApplication;
import pl.idedyk.android.japaneselearnhelper.MenuShorterHelper;
import pl.idedyk.android.japaneselearnhelper.R;
import pl.idedyk.android.japaneselearnhelper.common.adapter.AutoCompleteAdapter;
import pl.idedyk.android.japaneselearnhelper.common.view.DelayAutoCompleteTextView;
import pl.idedyk.android.japaneselearnhelper.config.ConfigManager.KanjiSearchMeaningConfig;
import pl.idedyk.android.japaneselearnhelper.dictionary.DictionaryManagerCommon;
import pl.idedyk.android.japaneselearnhelper.kanji.KanjiEntryListItem.ItemType;
import pl.idedyk.android.japaneselearnhelper.problem.ReportProblem;
import pl.idedyk.android.japaneselearnhelper.serverclient.ServerClient;
import pl.idedyk.android.japaneselearnhelper.serverclient.ServerClient.AutoCompleteSuggestionType;
import pl.idedyk.android.japaneselearnhelper.utils.SearchHistoryHelper;
import pl.idedyk.android.japaneselearnhelper.utils.WordKanjiDictionaryUtils;
import pl.idedyk.japanese.dictionary.api.dictionary.dto.FindKanjiRequest;
import pl.idedyk.japanese.dictionary.api.dictionary.dto.FindKanjiResult;
import pl.idedyk.japanese.dictionary.api.dictionary.dto.WordPlaceSearch;
import pl.idedyk.japanese.dictionary.api.dto.KanjiDic2Entry;
import pl.idedyk.japanese.dictionary.api.dto.KanjiEntry;
import pl.idedyk.japanese.dictionary.api.exception.DictionaryException;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.graphics.Typeface;
import android.os.AsyncTask;
import android.os.Bundle;
import android.text.Editable;
import android.text.Html;
import android.text.TextWatcher;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.ListView;
import android.widget.RadioButton;
import android.widget.ScrollView;
import android.widget.TextView;
import android.widget.Toast;
		searchOptionsEachChangeCheckBox.setChecked(kanjiSearchMeaningConfig.getEachChangeSearch());
		
		searchOptionsEachChangeCheckBox.setOnClickListener(new OnClickListener() {
			
			public void onClick(View v) {
				
				setSearchButtonVisible();
			}
		});
		
		//
		
		searchOptionsUseAutocompleteCheckBox = (CheckBox)findViewById(R.id.kanji_search_meaning_options_search_use_autocomplete_checkbox);
		
		searchOptionsUseAutocompleteCheckBox.setChecked(kanjiSearchMeaningConfig.getUseAutocomplete());
		
		searchValueEditText.setUseAutocompleteCheckBox(searchOptionsUseAutocompleteCheckBox);
		
		searchOptionsUseAutocompleteCheckBox.setOnClickListener(new OnClickListener() {
			
			public void onClick(View v) {

				kanjiSearchMeaningConfig.setUseAutocomplete(searchOptionsUseAutocompleteCheckBox.isChecked());
				
			}
		});
		
		//
		
		searchOptionsUseSuggestionCheckBox = (CheckBox)findViewById(R.id.kanji_search_meaning_options_search_use_suggestion_checkbox);
		
		searchOptionsUseSuggestionCheckBox.setChecked(kanjiSearchMeaningConfig.getUseSuggestion());
		
		searchOptionsUseSuggestionCheckBox.setOnClickListener(new OnClickListener() {
			
			public void onClick(View v) {

				kanjiSearchMeaningConfig.setUseSuggestion(searchOptionsUseSuggestionCheckBox.isChecked());
				
			}
		});
		
		//
				
		searchOptionsAnyPlaceRadioButton = (RadioButton)findViewById(R.id.kanji_search_meaning_options_search_any_place_radiobutton);
		searchOptionsStartWithPlaceRadioButton = (RadioButton)findViewById(R.id.kanji_search_meaning_options_search_startwith_radiobutton);
		searchOptionsExactPlaceRadioButton = (RadioButton)findViewById(R.id.kanji_search_meaning_options_search_exact_radiobutton);
		
		OnClickListener searchOptionsOnClick = new OnClickListener() {			
			public void onClick(View view) {
				
				if (searchOptionsEachChangeCheckBox.isChecked() == true) {
					performSearch(searchValueEditText.getText().toString());
				}
			}
		};
				
		searchOptionsAnyPlaceRadioButton.setOnClickListener(searchOptionsOnClick);
		searchOptionsStartWithPlaceRadioButton.setOnClickListener(searchOptionsOnClick);
		searchOptionsExactPlaceRadioButton.setOnClickListener(searchOptionsOnClick);
		
		searchValueEditText.addTextChangedListener(new TextWatcher() {
			
			public void onTextChanged(CharSequence s, int start, int before, int count) {
				
				if (searchOptionsEachChangeCheckBox.isChecked() == true) {
					performSearch(s.toString());
				}
			}
			
			public void beforeTextChanged(CharSequence s, int start, int count, int after) {
			}
			
			public void afterTextChanged(Editable s) {				
			}
		});

		searchValueEditText.setOnKeyListener(new View.OnKeyListener() {
			public boolean onKey(View view, int keyCode, KeyEvent keyevent) {

				// nacisniecie entera
				if ((keyevent.getAction() == KeyEvent.ACTION_DOWN) && (keyCode == KeyEvent.KEYCODE_ENTER)) {

					if (searchOptionsEachChangeCheckBox.isChecked() == false) {
						performSearch(searchValueEditText.getText().toString());
					}

					return true;
				}
				return false;
			}
		});

		final Button showHistoryButton = (Button)findViewById(R.id.kanji_search_meaning_show_history_button);

		showHistoryButton.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {

				// pokazywanie histori wyszukiwania

				searchResultList.clear();

				searchResultList.add(KanjiEntryListItem.createKanjiEntryListItemAsTitle(Html.fromHtml("<big><b>" + getString(R.string.kanji_search_meaning_show_history_title) + "</b></big>")));

				SearchHistoryHelper searchHistoryHelper = new SearchHistoryHelper(KanjiSearchMeaning.this, kanjiSearchMeaningSearchHistoryFieldName);

				List<SearchHistoryHelper.Entry> historyEntryList = searchHistoryHelper.getEntryList();

				for (SearchHistoryHelper.Entry entry : historyEntryList) {
					searchResultList.add(KanjiEntryListItem.createKanjiEntryListItemAsHistoryValue(entry.getText(), Html.fromHtml("<big>" + entry.getText() + "</big>")));
				}

				kanjiSearchMeaningElementsNoTextView.setText(getString(R.string.kanji_entry_elements_no, historyEntryList.size()));

				searchResultArrayAdapter.notifyDataSetChanged();
				searchResultListView.setSelection(0);
			}
		});

		searchValueEditText.setAdapter(new AutoCompleteAdapter(this, AutoCompleteSuggestionType.KANJI_DICTIONARY));