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 DataManager {

    private static final String DATABASE_FILE = "data.db";

    private File databaseDir;

    private SQLiteDatabase sqliteDatabase;

    public DataManager(File databaseDir) {
        this.databaseDir = databaseDir;
    }

    public void open() throws DataManagerException {

        try {
            File databaseFile = new File(databaseDir, DATABASE_FILE);

            sqliteDatabase = SQLiteDatabase.openOrCreateDatabase(databaseFile, null);

            if (SQLiteDatabaseHelper.isObjectExists(sqliteDatabase, "table", SQLiteStatic.user_groups_table_name) == false) {
                sqliteDatabase.execSQL(SQLiteStatic.user_groups_sql_create);

                UserGroupEntity userGroupEntity = new UserGroupEntity(null, UserGroupEntity.Type.STAR_GROUP, "StarGroup");

                addUserGroup(userGroupEntity);
            }

            if (SQLiteDatabaseHelper.isObjectExists(sqliteDatabase, "table", SQLiteStatic.user_groups_items_table_name) == false) {
                sqliteDatabase.execSQL(SQLiteStatic.user_groups_items_sql_create);

                sqliteDatabase.execSQL(SQLiteStatic.user_groups_items_sql_index);
            }

            if (SQLiteDatabaseHelper.isObjectExists(sqliteDatabase, "table", SQLiteStatic.queue_events_table_name) == false) {
                sqliteDatabase.execSQL(SQLiteStatic.queue_events_sql_create);
            }

        } catch (SQLException e) {
            throw new DataManagerException(e.toString());
        }
    }

    public void close() {

        if (sqliteDatabase != null) {
            sqliteDatabase.close();
        }
    }

    public synchronized void addUserGroup(UserGroupEntity userGroupEntity) {
        sqliteDatabase.execSQL(SQLiteStatic.user_group_sql_insert,
                new Object[] { userGroupEntity.getType().name(), userGroupEntity.getName() });
    }

    public synchronized void updateUserGroup(UserGroupEntity userGroupEntity) {
        sqliteDatabase.execSQL(SQLiteStatic.user_group_sql_name_update, new Object[] { userGroupEntity.getName(), userGroupEntity.getId() });
    }

    public synchronized void deleteUserGroup(UserGroupEntity userGroupEntity) {

        for (String sql : SQLiteStatic.user_group_sql_delete) {
            sqliteDatabase.execSQL(sql, new Object[] { userGroupEntity.getId() });
        }
    }

    public synchronized List<UserGroupEntity> getAllUserGroupList() {

        Cursor cursor = null;

        try {
            cursor = sqliteDatabase.rawQuery(SQLiteStatic.user_group_sql_select_all, null);

            List<UserGroupEntity> allUserGroupsList = createUserGroupEntityListFromCursor(cursor);

            // sortowanie
            Collections.sort(allUserGroupsList, new Comparator<UserGroupEntity>() {

                @Override
                public int compare(UserGroupEntity o1, UserGroupEntity o2) {

                    UserGroupEntity.Type o1Type = o1.getType();
                    UserGroupEntity.Type o2Type = o2.getType();

                    if (o1Type == UserGroupEntity.Type.STAR_GROUP && o2Type != UserGroupEntity.Type.STAR_GROUP) {
                        return -1;

                    } else if (o1Type != UserGroupEntity.Type.STAR_GROUP && o2Type == UserGroupEntity.Type.STAR_GROUP) {
                        return 1;
                    }

                    return o1.getName().compareTo(o2.getName());
                }
            });

            return allUserGroupsList;

        } finally {
            if (cursor != null) {
                cursor.close();
            }
        }
    }

    private List<UserGroupEntity> createUserGroupEntityListFromCursor(Cursor cursor) {

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

        boolean moveToFirst = cursor.moveToFirst();

        if (moveToFirst == false) {
            return result;
        }

        do {
            Integer id = cursor.getInt(0);
            UserGroupEntity.Type type = UserGroupEntity.Type.valueOf(cursor.getString(1));
            String name = cursor.getString(2);

            result.add(new UserGroupEntity(id, type, name));

        } while (cursor.moveToNext());

        return result;
    }

    public synchronized List<UserGroupEntity> findUserGroupEntity(UserGroupEntity.Type type, String name) {

        List<UserGroupEntity> allUserGroupList = getAllUserGroupList();

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

        for (UserGroupEntity currentUserGroupEntity : allUserGroupList) {

            if (type != null && currentUserGroupEntity.getType() != type) {
                continue;
            }

            if (name != null && currentUserGroupEntity.getName().equals(name) == false) {
                continue;
            }

            result.add(currentUserGroupEntity);
        }

        return result;
    }

    public synchronized UserGroupEntity getStarUserGroup() throws DataManagerException {

        List<UserGroupEntity> allUserGroupList = getAllUserGroupList();

        for (UserGroupEntity currentUserGroupEntity : allUserGroupList) {

            if (currentUserGroupEntity.getType() == UserGroupEntity.Type.STAR_GROUP) {
                return currentUserGroupEntity;
            }
        }

        throw new DataManagerException("No star user group");
    }

    public synchronized List<UserGroupEntity> getUserGroupEntityListForItemId(UserGroupEntity.Type userGroupEntityType, UserGroupItemEntity.Type userGroupItemEntityType, Integer itemId) {

        Cursor cursor = null;

        try {
            cursor = sqliteDatabase.rawQuery(SQLiteStatic.user_group_sql_select_for_item_id, new String[] { userGroupItemEntityType.name(), String.valueOf(itemId), userGroupEntityType.name() });

            return createUserGroupEntityListFromCursor(cursor);

        } finally {
            if (cursor != null) {
                cursor.close();
            }
        }
    }

    public synchronized boolean isItemIdExistsInUserGroup(UserGroupEntity userGroupEntity, UserGroupItemEntity.Type type, Integer itemId) {
        return isExists(SQLiteStatic.user_groups_items_sql_count_group_id_type_item_id, new String[] {
                String.valueOf(userGroupEntity.getId()), type.name(), String.valueOf(itemId) });
    }

    public synchronized void addItemIdToUserGroup(UserGroupEntity userGroupEntity, UserGroupItemEntity.Type type, Integer itemId) {

        boolean alreadyExists = isItemIdExistsInUserGroup(userGroupEntity, type, itemId);

        if (alreadyExists == false) { // add
            sqliteDatabase.execSQL(SQLiteStatic.user_groups_items_sql_insert_group_id_type_item_id, new Object[] { String.valueOf(userGroupEntity.getId()), type.name(), String.valueOf(itemId)  });
        }
    }

    public synchronized void deleteItemIdFromUserGroup(UserGroupEntity userGroupEntity, UserGroupItemEntity.Type type, Integer itemId) {

        boolean alreadyExists = isItemIdExistsInUserGroup(userGroupEntity, type, itemId);

        if (alreadyExists == true) { // delete
            sqliteDatabase.execSQL(SQLiteStatic.user_groups_items_sql_delete_group_id_type_item_id, new Object[] { String.valueOf(userGroupEntity.getId()), type.name(), String.valueOf(itemId)  });
        }
    }

    public synchronized List<UserGroupItemEntity> getUserGroupItemListForUserEntity(UserGroupEntity userGroupEntity) {

        Cursor cursor = null;

        try {
            cursor = sqliteDatabase.rawQuery(SQLiteStatic.user_groups_items_sql_get_list_for_user_group,
                    new String[] { String.valueOf(userGroupEntity.getId()) });

            return createUserGroupItemEntityFromCursor(cursor);

        } finally {
            if (cursor != null) {
                cursor.close();
            }
        }
    }

    private List<UserGroupItemEntity> createUserGroupItemEntityFromCursor(Cursor cursor) {

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

        boolean moveToFirst = cursor.moveToFirst();

        if (moveToFirst == false) {
            return result;
        }

        do {
            Integer id = cursor.getInt(0);
            Integer userGroupId = cursor.getInt(1);
            UserGroupItemEntity.Type type = UserGroupItemEntity.Type.valueOf(cursor.getString(2));
            Integer itemId = cursor.getInt(3);

            result.add(new UserGroupItemEntity(id, userGroupId, type, itemId));

        } while (cursor.moveToNext());

        return result;
    }

    private boolean isExists(String sql, String[] params) {

        Cursor cursor = null;

        try {
            cursor = sqliteDatabase.rawQuery(sql, params);

            cursor.moveToFirst();

            int result = cursor.getInt(0);

            if (result > 0) {
                return true;

            } else {
                return false;
            }

        } finally {
            if (cursor != null) {
                cursor.close();
            }
        }
    }

    public synchronized void addQueueEvent(IQueueEvent queueEvent) {

        ContentValues values = new ContentValues();

        values.put(SQLiteStatic.queue_events_column_userId, queueEvent.getUserId());
        values.put(SQLiteStatic.queue_events_column_operation, queueEvent.getQueryEventOperation().toString());
        values.put(SQLiteStatic.queue_events_column_createDate, queueEvent.getCreateDateAsString());
        values.put(SQLiteStatic.queue_events_column_params, queueEvent.getParamsAsString());

        long id = sqliteDatabase.insert(SQLiteStatic.queue_events_table_name, null, values);

        queueEvent.setId(id);
    }

    public synchronized List<IQueueEvent> getQueueEventList(IQueueEventFactory queueEventFactory) {

        if (sqliteDatabase.isOpen() == false) {
            return new ArrayList<>();
        }

        Cursor cursor = null;

        try {
            cursor = sqliteDatabase.rawQuery(SQLiteStatic.queue_events_sql_select, new String[] { });

            return createQueueEventListFromCursor(queueEventFactory, cursor);

        } finally {
            if (cursor != null) {
                cursor.close();
            }
        }
    }

    private List<IQueueEvent> createQueueEventListFromCursor(IQueueEventFactory queueEventFactory, Cursor cursor) {

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

        boolean moveToFirst = cursor.moveToFirst();

        if (moveToFirst == false) {
            return result;
        }

        do {
            Long id = cursor.getLong(0);
            String userId = cursor.getString(1);
            String operation = cursor.getString(2);
            String createDate = cursor.getString(3);
            String params = cursor.getString(4);

            IQueueEvent queueEvent = queueEventFactory.createQueueEvent(id, userId, operation, createDate, params);

            if (queueEvent != null) {
                result.add(queueEvent);
            }

        } while (cursor.moveToNext());

        return result;
    }

    public synchronized void deleteQueueEvent(IQueueEvent queueEvent) {

        if (sqliteDatabase.isOpen() == false) {
            return;
        }

        sqliteDatabase.execSQL(SQLiteStatic.queue_events_sql_delete_id, new Object[] { queueEvent.getId() });
    }

    private static class SQLiteStatic {

        public static final String user_groups_table_name = "user_groups";

        public static final String user_groups_column_id = "id";
        public static final String user_groups_column_type = "type";
        public static final String user_groups_column_name = "name";

        //

        public static final String user_groups_items_table_name = "user_groups_items";

        public static final String user_groups_items_column_id = "id";
        public static final String user_groups_items_column_user_group_id = "user_group_id";
        public static final String user_groups_items_column_type = "type";
        public static final String user_groups_items_column_item_id = "item_id";

        //

        public static final String queue_events_table_name = "queue_events";

        public static final String queue_events_column_id = "id";
        public static final String queue_events_column_userId = "userId";
        public static final String queue_events_column_operation = "operation";
        public static final String queue_events_column_createDate = "createDate";
        public static final String queue_events_column_params = "params";

        //

        public static final String user_groups_sql_create =
                "create table " + user_groups_table_name + "(" +
                        user_groups_column_id + " integer primary key, " +
                        user_groups_column_type + " varchar(30) not null, " +
                        user_groups_column_name + " varchar(100) not null);";

        //

        public static final String user_groups_items_sql_create =
                "create table " + user_groups_items_table_name + "(" +
                        user_groups_items_column_id + " integer primary key, " +
                        user_groups_items_column_user_group_id + " integer not null, " +
                        user_groups_items_column_type + " varchar(30) not null, " +
                        user_groups_items_column_item_id + " integer not null, " +
                        "foreign key (" + user_groups_items_column_user_group_id + ") references " + user_groups_table_name + "(" + user_groups_column_id + "));";

        public static final String queue_events_sql_create =
                "create table " + queue_events_table_name + "(" +
                        queue_events_column_id + " integer primary key, " +
                        queue_events_column_userId + " varchar(40) not null, " +
                        queue_events_column_operation + " varchar(50) not null, " +
                        queue_events_column_createDate + " text not null, " +
                        queue_events_column_params + " text null);";


        public static final String user_groups_items_sql_index =
                String.format("create index %s_%s_%s_%s_idx on %s(%s,%s,%s)", user_groups_items_table_name,
                        user_groups_items_column_user_group_id, user_groups_items_column_type, user_groups_items_column_item_id, user_groups_items_table_name,
                        user_groups_items_column_user_group_id, user_groups_items_column_type, user_groups_items_column_item_id);

        //

        public static final String user_group_sql_insert =
                "insert into " + user_groups_table_name + "(" +
                        user_groups_column_type + ", " +   user_groups_column_name + ") " +
                        "values (?, ?)";

        public static final String user_group_sql_name_update =
                String.format("update %s set %s = ? where %s = ?", user_groups_table_name, user_groups_column_name, user_groups_items_column_id);

        public static final String[] user_group_sql_delete =
                new String[] {
                        String.format("delete from %s where %s = ?", user_groups_items_table_name, user_groups_items_column_user_group_id),
                        String.format("delete from %s where %s = ?", user_groups_table_name, user_groups_column_id),
                };

        public static final String user_group_sql_select_all =
                "select * from " + user_groups_table_name + ";";

        public static final String user_group_sql_select_for_item_id =
                String.format("select * from %s ug where ug.%s in (select %s from %s ugi where ugi.%s = ? and ugi.%s = ?) and ug.%s = ? order by %s",
                        user_groups_table_name, user_groups_column_id, user_groups_items_column_user_group_id,
                        user_groups_items_table_name, user_groups_items_column_type, user_groups_items_column_item_id, user_groups_column_type,
                        user_groups_column_name);

        //

        public static final String user_groups_items_sql_count_group_id_type_item_id =
            String.format("select count(*) from %s where %s = ? and %s = ? and %s = ?", user_groups_items_table_name,
                    user_groups_items_column_user_group_id, user_groups_items_column_type, user_groups_items_column_item_id);

        public static final String user_groups_items_sql_insert_group_id_type_item_id =
                String.format("insert into %s (%s, %s, %s) values (?, ?, ?)", user_groups_items_table_name,
                        user_groups_items_column_user_group_id, user_groups_items_column_type, user_groups_items_column_item_id);

        public static final String user_groups_items_sql_delete_group_id_type_item_id =
                String.format("delete from %s where %s = ? and %s = ? and %s = ?", user_groups_items_table_name,
                        user_groups_items_column_user_group_id, user_groups_items_column_type, user_groups_items_column_item_id);

        public static final String user_groups_items_sql_get_list_for_user_group =
                String.format("select * from %s where %s = ?", user_groups_items_table_name, user_groups_items_column_user_group_id);

        //

        public static final String queue_events_sql_select =
                String.format("select * from %s order by %s limit 10", queue_events_table_name, queue_events_column_id);

        public static final String queue_events_sql_delete_id =
                String.format("delete from %s where %s = ?", queue_events_table_name, queue_events_column_id);
    }
} public class UserGroupEntity implements Serializable {

    private Integer id;

    private Type type;

    private String name;

    public UserGroupEntity(Integer id, Type type, String name) {
        this.id = id;
        this.type = type;
        this.name = name;
    }

    public Integer getId() {
        return id;
    }

    public Type getType() {
        return type;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public static enum Type {
        STAR_GROUP,

        USER_GROUP;
    }
} public class UserGroupItemEntity implements Serializable {

    private Integer id;

    private Integer userGroupId;

    private Type type;

    private Integer itemId;

    public UserGroupItemEntity(Integer id, Integer userGroupId, Type type, Integer itemId) {
        this.id = id;
        this.userGroupId = userGroupId;
        this.type = type;
        this.itemId = itemId;
    }

    public Integer getId() {
        return id;
    }

    public Integer getUserGroupId() {
        return userGroupId;
    }

    public Type getType() {
        return type;
    }

    public Integer getItemId() {
        return itemId;
    }

    public static enum Type {

        DICTIONARY_ENTRY,

        KANJI_ENTRY;
    }
} public class DataManagerException extends Exception {

    private static final long serialVersionUID = 1L;

    public DataManagerException(String message) {
        super(message);
    }
} 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();
    }
} @SuppressWarnings("deprecation")
public class WordDictionaryTab extends TabActivity {

	private final List<TabHost.TabSpec> tagHostSpecList = new ArrayList<TabHost.TabSpec>();

	private int counter = 1;

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		super.onCreateOptionsMenu(menu);

		menu.add(Menu.NONE, R.id.main_menu_word_dictionary_tab_add_tab, Menu.NONE, R.string.word_dictionary_tab_add_tab);
		menu.add(Menu.NONE, R.id.main_menu_word_dictionary_tab_del_tab, Menu.NONE, R.string.word_dictionary_tab_del_tab);

		MenuShorterHelper.onCreateOptionsMenu(menu);
		
		return true;
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		super.onOptionsItemSelected(item);

		int itemId = item.getItemId();

		if (itemId == R.id.main_menu_word_dictionary_tab_add_tab) { // add tab

			addTab(getTabHost(), false);

			return true;
		} else if (itemId == R.id.main_menu_word_dictionary_tab_del_tab) { // del tab

			delCurrentTab(getTabHost());

			return true;
			
		} else {
			return MenuShorterHelper.onOptionsItemSelected(item, getApplicationContext(), this);
		}
	}

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		JapaneseAndroidLearnHelperApplication.getInstance().setContentViewAndTheme(this, R.layout.word_dictionary_tab);

		TabHost tabHost = getTabHost();

		addTab(tabHost, true);

		tabHost.setCurrentTab(0);
	}

	private void addTab(TabHost tabHost, boolean addFindExtra) {

		// word dictionary
		Intent wordDictionary = new Intent(getApplicationContext(), WordDictionary.class);

		if (addFindExtra == true) {
			wordDictionary.putExtra("findWordRequest", getIntent().getSerializableExtra("findWordRequest"));
		}

		TabSpec wordDictionaryTabSpec = tabHost.newTabSpec("WordDictionaryTabSpec." + counter)
				.setIndicator(getString(R.string.word_dictionary_tab_tab, counter)).setContent(wordDictionary);

		tabHost.addTab(wordDictionaryTabSpec);
		tagHostSpecList.add(wordDictionaryTabSpec);

		tabHost.setCurrentTab(tagHostSpecList.size() - 1);

		counter++;
	}

	private void delCurrentTab(TabHost tabHost) {

		int currentTab = tabHost.getCurrentTab();

		tagHostSpecList.remove(currentTab);

		if (tagHostSpecList.size() == 0) {
			finish();

			return;
		}

		tabHost.clearAllTabs();

		for (TabHost.TabSpec spec : tagHostSpecList) {
			tabHost.addTab(spec);
		}

		if (currentTab >= tagHostSpecList.size()) {
			currentTab = tagHostSpecList.size();
		}

		currentTab = currentTab - 1;

		if (currentTab < 0) {
			currentTab = 0;
		}

		tabHost.setCurrentTab(currentTab);
	}
} 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 interface IScreenItem {
	public void generate(Context context, Resources resources, ViewGroup layout);
	
	public int getY();
	
	public String toString();
} public class Image implements IScreenItem {
	
	private ImageView imageView;
	
	private boolean nullMargins = false;
	
	private Integer layoutWeight;
	
	private Drawable image;
	
	private int level;
	
	private OnClickListener onClickListener;
	
	public Image(Drawable image, int level) {
		this.image = image;
		this.level = level;
	}
	
	public void setNullMargins(boolean nullMargins) {
		this.nullMargins = nullMargins;
	}
		
	public void setLayoutWidth(Integer layoutWeight) {
		this.layoutWeight = layoutWeight;
	}
	
	public void setOnClickListener(OnClickListener onClickListener) {
		this.onClickListener = onClickListener;		
	}

	public void generate(Context context, Resources resources, ViewGroup layout) {
		
		imageView = new ImageView(context);
		
		if (layout instanceof android.widget.TableRow) {
			android.widget.TableRow.LayoutParams layoutParam = new android.widget.TableRow.LayoutParams(android.widget.TableRow.LayoutParams.WRAP_CONTENT, android.widget.TableRow.LayoutParams.WRAP_CONTENT);
			
			if (nullMargins == true) {
				layoutParam.setMargins(0, 0, 0, 0);
			} else {
				layoutParam.setMargins(20 + level * 20, 5, 0, 0);
			}

			if (layoutWeight != null) {
				layoutParam.weight = layoutWeight;
			}
					
			imageView.setLayoutParams(layoutParam);
		} else if (layout instanceof LinearLayout) {
			LinearLayout.LayoutParams layoutParam = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
			
			if (nullMargins == false) {
				layoutParam.setMargins(20 + level * 20, 5, 0, 0);
			}
			
			if (layoutWeight != null) {
				layoutParam.weight = layoutWeight;
			}
			
			imageView.setLayoutParams(layoutParam);
		} else {
			throw new RuntimeException(String.valueOf(layout.getClass()));
		}
		
		imageView.setImageDrawable(image);
		
		imageView.setOnClickListener(onClickListener);

		layout.addView(imageView);
	}
	
	public int getY() {
		
		if (imageView != null) {
			return imageView.getTop();
		}
		
		throw new RuntimeException("imageView is null");
	}

	public void changeImage(Drawable image) {
		this.image = image;

		imageView.setImageDrawable(image);
	}

	@Override
	public String toString() {
		return "";
	}
} public class StringValue implements IScreenItem {
	
	private TextView textView;
	
	private CharSequence value;
	
	private float textSize;
	
	private Integer gravity;
	
	private int level;
	
	private Integer marginLeft = null;
	private Integer marginTop = null;
	private Integer marginRight = null;
	private Integer marginBottom = null;
	
	private Integer layoutWeight;
	
	private OnClickListener onClickListener;
	
	private OnTouchListener onTouchListener;
	
	private Integer textColor;
	
	private Integer defaultTextColor;
	
	private Typeface typeface;
	
	private Integer backgroundColor;

	public StringValue(String value, float textSize, int level) {
		this.value = value;
		this.textSize = textSize;
		this.level = level;
	}

	public StringValue(Spanned value, float textSize, int level) {
		this.value = value;
		this.textSize = textSize;
		this.level = level;
	}
	
	public void setValue(CharSequence value) {
		this.value = value;
		
		if (textView != null) {
			textView.setText(this.value);
		}
	}
	
	public String getValue() {
		return this.value.toString();
	}
	
	public void setGravity(int gravity) {
		this.gravity = gravity;
	}
	
	public void setLayoutWidth(Integer layoutWeight) {
		this.layoutWeight = layoutWeight;
	}
	
	public void setNullMargins(boolean nullMargins) {
		
		if (nullMargins == true) {		
			this.marginLeft = 0;
			this.marginTop = 0;
			this.marginRight = 0;
			this.marginBottom = 0;
			
		} else {
			this.marginLeft = null;
			this.marginTop = null;
			this.marginRight = null;
			this.marginBottom = null;			
		}
	}
	
	public void setTypeface(Typeface typeface) {
		this.typeface = typeface;
	}
	
	public void setBackgroundColor(Integer backgroundColor) {
		this.backgroundColor = backgroundColor;
	}

	public void generate(Context context, Resources resources, ViewGroup layout) {
		textView = new TextView(context);
				
		if (layout instanceof android.widget.TableRow) {
			android.widget.TableRow.LayoutParams layoutParam = new android.widget.TableRow.LayoutParams(android.widget.TableRow.LayoutParams.WRAP_CONTENT, android.widget.TableRow.LayoutParams.WRAP_CONTENT);
			
			if (marginLeft != null || marginTop != null || marginRight != null || marginBottom != null) {
				layoutParam.setMargins(marginLeft != null ? marginLeft : 0, marginTop != null ? marginTop : 0,
						marginRight != null ? marginRight : 0, marginRight != null ? marginRight : 0);
			} else {
				layoutParam.setMargins(20 + level * 20, 5, 0, 0);
			}

			if (layoutWeight != null) {
				layoutParam.weight = layoutWeight;
			}
			
			if (gravity != null) {
				layoutParam.gravity = gravity;
			}
			
			textView.setLayoutParams(layoutParam);
		} else if (layout instanceof LinearLayout) {
			LinearLayout.LayoutParams layoutParam = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
			
			if (marginLeft == null && marginTop == null && marginRight == null && marginBottom == null) {
				layoutParam.setMargins(20 + level * 20, 5, 0, 0);
			}
			
			if (layoutWeight != null) {
				layoutParam.weight = layoutWeight;
			}
			
			textView.setLayoutParams(layoutParam);
		} else {
			throw new RuntimeException(String.valueOf(layout.getClass()));
		}
		
		if (gravity != null) {
			textView.setGravity(gravity);
		}
		
		textView.setTextSize(textSize);
		textView.setText(value);
		
		defaultTextColor = textView.getTextColors().getDefaultColor();
		
		if (textColor != null) {
			textView.setTextColor(textColor.intValue());
		}
		
		if (typeface != null) {
			textView.setTypeface(typeface);
		}
		
		if (backgroundColor != null) {
			textView.setBackgroundColor(backgroundColor);
		}
		
		textView.setOnClickListener(onClickListener);
		textView.setOnTouchListener(onTouchListener);
				
		layout.addView(textView);			
	}
	
	public void setMarginLeft(Integer marginLeft) {
		this.marginLeft = marginLeft;
	}

	public void setMarginTop(Integer marginTop) {
		this.marginTop = marginTop;
	}

	public void setMarginRight(Integer marginRight) {
		this.marginRight = marginRight;
	}

	public void setMarginBottom(Integer marginBottom) {
		this.marginBottom = marginBottom;
	}

	public String toString() {
		if (value != null) {
			return value.toString();
		} else {
			return null;
		}
	}
	
	public int getBottomPositionOnScreen() {
		if (textView == null) {
			throw new RuntimeException("getBottomPositionOnScreen");
		}
		
		int[] location = new int[2];
		
		textView.getLocationOnScreen(location);
		
		return location[1] + textView.getHeight();
	}
	
	public void setOnClickListener(OnClickListener onClickListener) {
		this.onClickListener = onClickListener;		
	}

	public void setOnTouchListener(OnTouchListener onTouchListener) {
		this.onTouchListener = onTouchListener;
	}
	
	public void setText(String text) {
		this.value = text;
		
		if (textView != null) {
			textView.setText(text);
		}
	}
	
	public void setTextColor(Integer textColor) {
		this.textColor = textColor;
		
		if (textView != null) {
			textView.setTextColor(textColor.intValue());
		}
	}
	
	public int getY() {
		
		if (textView != null) {
			return textView.getTop();
		}
		
		throw new RuntimeException("textview is null");
	}

	public Integer getDefaultTextColor() {
		return defaultTextColor;
	}
} public class TableLayout implements IScreenItem {

	public static enum LayoutParam {

		@SuppressWarnings("deprecation")
		FillParent_WrapContent(new android.widget.TableLayout.LayoutParams(
				android.widget.TableLayout.LayoutParams.FILL_PARENT,
				android.widget.TableLayout.LayoutParams.WRAP_CONTENT)),

		WrapContent_WrapContent(new android.widget.TableLayout.LayoutParams(
				android.widget.TableLayout.LayoutParams.WRAP_CONTENT,
				android.widget.TableLayout.LayoutParams.WRAP_CONTENT));

		private android.widget.TableLayout.LayoutParams layoutParam;

		private LayoutParam(LayoutParams layoutParam) {
			this.layoutParam = layoutParam;
		}

		public android.widget.TableLayout.LayoutParams getLayoutParam() {
			return layoutParam;
		}
	}

	private final LayoutParam layoutParam;

	private final Boolean shrinkAllColumns;
	private final Boolean stretchAllColumns;

	private final List<TableRow> tableRows = new ArrayList<TableRow>();

	public TableLayout(LayoutParam layoutParam, Boolean shrinkAllColumns, Boolean stretchAllColumns) {
		this.layoutParam = layoutParam;

		this.shrinkAllColumns = shrinkAllColumns;
		this.stretchAllColumns = stretchAllColumns;
	}

	public void addTableRow(TableRow tableRow) {
		tableRows.add(tableRow);
	}

	@Override
	public void generate(Context context, Resources resources, ViewGroup layout) {

		android.widget.TableLayout tableLayout = new android.widget.TableLayout(context);

		tableLayout.setLayoutParams(layoutParam.getLayoutParam());

		if (shrinkAllColumns != null) {
			tableLayout.setShrinkAllColumns(shrinkAllColumns.booleanValue());
		}

		if (stretchAllColumns != null) {
			tableLayout.setStretchAllColumns(stretchAllColumns.booleanValue());
		}

		for (TableRow currentTableRow : tableRows) {
			currentTableRow.generate(context, resources, tableLayout);
		}

		layout.addView(tableLayout);
	}

	@Override
	public int getY() {

		if (tableRows != null && tableRows.size() > 0) {
			return tableRows.get(0).getY();
		}

		throw new RuntimeException("tableRows is null");
	}

	@Override
	public String toString() {
		StringBuffer sb = new StringBuffer();

		for (TableRow currentTableRow : tableRows) {
			sb.append(currentTableRow.toString()).append("\n");
		}

		return sb.toString();
	}
} public class TableRow implements IScreenItem {
	
	private android.widget.TableRow tableRow = null;
	
	private List<IScreenItem> screenItems = new ArrayList<IScreenItem>();
	
	public void addScreenItem(IScreenItem item) {
		screenItems.add(item);
	}
	
	public int getScreenItemSize() {
		return screenItems.size();
	}

	public void generate(Context context, Resources resources, ViewGroup layout) {
		
		if (screenItems.size() > 0) {
			tableRow = new android.widget.TableRow(context);

			for (IScreenItem currentScreenItem : screenItems) {
				currentScreenItem.generate(context, resources, tableRow);
			}
			
			layout.addView(tableRow);			
		}
	}
	
	public int getY() {
		
		if (tableRow != null) {
			return tableRow.getTop();
		}
		
		throw new RuntimeException("tableRow is null");
	}
	
	public String toString() {
		
		StringBuffer sb = new StringBuffer();
		
		if (screenItems.size() > 0) {
			for (IScreenItem currentScreenItem : screenItems) {
				sb.append(currentScreenItem.toString().replaceAll("\n", " ")).append("; ");
			}
		}
		
		return sb.toString();
	}

	public void setVisibility(int visibility) {
		tableRow.setVisibility(visibility);
	}
} public class TitleItem implements IScreenItem {
	
	private TextView textView;
	
	private String title;
	
	private int level;
	
	private OnClickListener onClickListener;
	
	public TitleItem(String title, int level) {
		this.title = title;
		this.level = level;
	}

	public void generate(Context context, Resources resources, ViewGroup layout) {
		textView = new TextView(context);
		
		textView.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));

		textView.setBackgroundColor(JapaneseAndroidLearnHelperApplication.getInstance().getThemeType().getTitleItemBackgroundColorAsColor());
		textView.setTextSize(16.0f);
		
		StringBuffer titleSb = new StringBuffer();
		
		for (int levelIdx = 0; levelIdx < level; ++levelIdx) {
			titleSb.append("   ");
		}
		titleSb.append(title);
		
		textView.setText(titleSb);	
		
		textView.setOnClickListener(onClickListener);
		
		layout.addView(textView);
	}
	
	public String toString() {
		return " *** " + title;			
	}
	
	public int getTopPositionOnScreen() {
		if (textView == null) {
			throw new RuntimeException("getTopPositionOnScreen");
		}
		
		int[] location = new int[2];
		
		textView.getLocationOnScreen(location);
		
		return location[1];
	}
	
	public int getY() {
		
		if (textView != null) {
			return textView.getTop();
		}
		
		throw new RuntimeException("textview is null");
	}

	public String getTitle() {
		return title;
	}

	public int getLevel() {
		return level;
	}
	
	public void setOnClickListener(OnClickListener onClickListener) {
		this.onClickListener = onClickListener;		
	}
} public class SodActivity extends Activity implements OnClickListener {

	private static final String SAVE_STATE_STROKE_PATHS = "pl.idedyk.android.japaneselearnhelper.sod.SAVE_STATE_STROKE_PATHS";

	private Button drawButton;
	private Button clearButton;
	private Button animateButton;

	private StrokePathInfo strokePathsInfo;

	private StrokeOrderView strokeOrderView;

	private StrokedCharacter character;
	
	private boolean annotateStrokes;
	
	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		super.onCreateOptionsMenu(menu);
		
		MenuShorterHelper.onCreateOptionsMenu(menu);
		
		return true;
	}
	
	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		super.onOptionsItemSelected(item);

		return MenuShorterHelper.onOptionsItemSelected(item, getApplicationContext(), this);
	}

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		
		super.onCreate(savedInstanceState);

		JapaneseAndroidLearnHelperApplication.getInstance().setContentViewAndTheme(this, R.layout.sod);

		JapaneseAndroidLearnHelperApplication.getInstance().logScreen(this, getString(R.string.logs_sod));

		findViews();

		drawButton.setOnClickListener(this);
		clearButton.setOnClickListener(this);
		animateButton.setOnClickListener(this);

		strokePathsInfo = (StrokePathInfo)getIntent().getSerializableExtra("strokePathsInfo");
		
		annotateStrokes = getIntent().getBooleanExtra("annotateStrokes", true);
		
		character = SodStrokeParser.parseWsReply(strokePathsInfo);

		drawSod(character);
	}

	@Override
	protected void onDestroy() {
		super.onDestroy();
	}

	@Override
	protected void onStart() {
		super.onStart();
	}


	@Override
	protected void onResume() {
		super.onResume();

		drawSod(character);
	}

	@Override
	protected void onStop() {
		super.onStop();
	}

	@Override
	protected void onRestoreInstanceState(Bundle savedInstanceState) {
		super.onRestoreInstanceState(savedInstanceState);

		if (savedInstanceState != null) {
			strokePathsInfo = (StrokePathInfo)savedInstanceState.getSerializable(SAVE_STATE_STROKE_PATHS);

			character = SodStrokeParser.parseWsReply(strokePathsInfo);

			if (character != null) {
				strokeOrderView.setAnnotateStrokes(annotateStrokes);
				strokeOrderView.setCharacter(character);
				strokeOrderView.invalidate();
			}
		}
	}

	@Override
	protected void onSaveInstanceState(Bundle outState) {
		super.onSaveInstanceState(outState);

		outState.putSerializable(SAVE_STATE_STROKE_PATHS, strokePathsInfo);
	}

	void drawSod(StrokedCharacter character) {
		this.character = character;

		strokeOrderView.setAnnotateStrokes(annotateStrokes);
		strokeOrderView.setCharacter(character);
		strokeOrderView.invalidate();
	}

	void animate(StrokedCharacter character) {
		this.character = character;

		int animationDelay = 50 + (15 * strokePathsInfo.getStrokePaths().size());
		strokeOrderView.setAnnotateStrokes(annotateStrokes);
		strokeOrderView.setAnimationDelayMillis(animationDelay);
		strokeOrderView.setCharacter(character);
		strokeOrderView.startAnimation();
	}

	private void findViews() {
		drawButton = (Button) findViewById(R.id.sod_draw_button);
		clearButton = (Button) findViewById(R.id.sod_clear_button);
		animateButton = (Button) findViewById(R.id.sod_animate_button);
		strokeOrderView = (StrokeOrderView) findViewById(R.id.sod_draw_view);
	}

	public void onClick(View v) {
		switch (v.getId()) {
		case R.id.sod_draw_button:
			drawSod(character);
			break;
		case R.id.sod_animate_button:
			animate(character);
			break;
		case R.id.sod_clear_button:
			strokeOrderView.clear();
			strokeOrderView.invalidate();
			break;
		default:
			// do nothing
		}
	}
}
 public class StrokePathInfo implements Serializable {
	
	private static final long serialVersionUID = 1L;
	
	private List<KanjivgEntry> strokePaths;

	public List<KanjivgEntry> getStrokePaths() {
		return strokePaths;
	}

	public void setStrokePaths(List<KanjivgEntry> strokePaths) {
		this.strokePaths = strokePaths;
	}	
} public class UserGroupActivity extends Activity {

    private ListView userGroupListView;

    private UserGroupListItemAdapter userGroupListAdapter;

    private List<UserGroupListItem> userGroupList;

    //

    private DictionaryEntry dictionaryEntryToAdd = null;

    private KanjiEntry kanjiEntryToAdd = null;

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        super.onCreateOptionsMenu(menu);

        MenuShorterHelper.onCreateOptionsMenu(menu);

        menu.add(Menu.NONE, R.id.user_group_menu_create_new_group, Menu.NONE, R.string.user_group_menu_create_new_group);

        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        super.onOptionsItemSelected(item);

        int itemId = item.getItemId();

        if (itemId == R.id.user_group_menu_create_new_group) { // tworzenie nowej grupy

            createOrUpdateUserGroup(null);

            return true;

        } else {
            return MenuShorterHelper.onOptionsItemSelected(item, getApplicationContext(), this);
        }
    }

    @Override
    protected void onSaveInstanceState(Bundle bundle) {

        super.onSaveInstanceState(bundle);
    }

    @Override
    protected void onRestoreInstanceState(Bundle bundle) {

        super.onRestoreInstanceState(bundle);
    }

    @Override
    public void onCreate(Bundle bundle) {

        super.onCreate(bundle);

        JapaneseAndroidLearnHelperApplication.getInstance().setContentViewAndTheme(this, R.layout.user_group);

        JapaneseAndroidLearnHelperApplication.getInstance().logScreen(this, getString(R.string.logs_user_group));

        //

        createUserGroupListView();

        //

        loadUserGroups();

        //

        checkItemToAdd();

        //

        // createReportProblemButton();
    }

    @Override
    public void onBackPressed() {

        final Intent mIntent = new Intent();

        setResult(RESULT_OK, mIntent);

        finish();
    }

    private void createUserGroupListView() {

        userGroupListView = (ListView)findViewById(R.id.user_group_list);

        userGroupList = new ArrayList<>();
        userGroupListAdapter = new UserGroupListItemAdapter(this, userGroupList);

        userGroupListView.setAdapter(userGroupListAdapter);

        userGroupListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {

            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {

                final UserGroupListItem userGroupListItem = (UserGroupListItem)userGroupListAdapter.getItem(position);

                UserGroupListItem.ItemType itemType = userGroupListItem.getItemType();

                // tworzenie menu podrecznego
                PopupMenu popupMenu = new PopupMenu(UserGroupActivity.this, view);

                if (dictionaryEntryToAdd != null || kanjiEntryToAdd != null) {
                    popupMenu.getMenu().add(Menu.NONE, R.id.user_group_popup_add_to_this_group, Menu.NONE, R.string.user_group_popup_add_to_this_group);
                }

                popupMenu.getMenu().add(Menu.NONE, R.id.user_group_popup_open_group, Menu.NONE, R.string.user_group_popup_open_group);

                if (itemType == UserGroupListItem.ItemType.USER_GROUP) {
                    popupMenu.getMenu().add(Menu.NONE, R.id.user_group_popup_change_group_name, Menu.NONE, R.string.user_group_popup_change_group_name);
                    popupMenu.getMenu().add(Menu.NONE, R.id.user_group_popup_delete_group, Menu.NONE, R.string.user_group_popup_delete_group);
                }

                //

                popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {

                    @Override
                    public boolean onMenuItemClick(MenuItem item) {

                        int itemId = item.getItemId();

                        if (itemId == R.id.user_group_popup_add_to_this_group) { // dodanie elementu do grupy

                            UserGroupEntity userGroupEntity = userGroupListItem.getUserGroupEntity();

                            addItemIdToUserGroupEntity(userGroupEntity);

                            return true;

                        } else if (itemId == R.id.user_group_popup_open_group) { // otwarcie grupy

                            UserGroupEntity userGroupEntity = userGroupListItem.getUserGroupEntity();

                            Intent intent = new Intent(getApplicationContext(), UserGroupContentsActivity.class);

                            intent.putExtra("userGroupEntity", userGroupEntity);

                            startActivity(intent);

                            return true;

                        } else if (itemId == R.id.user_group_popup_change_group_name) { // zmiana nazwy grupy

                            UserGroupEntity userGroupEntityToUpdate = userGroupListItem.getUserGroupEntity();

                            createOrUpdateUserGroup(userGroupEntityToUpdate);

                            return true;

                        } else if (itemId == R.id.user_group_popup_delete_group) { // usuniecie nazwy grupy

                            UserGroupEntity userGroupEntityToDelete = userGroupListItem.getUserGroupEntity();

                            deleteUserGroup(userGroupEntityToDelete);

                            return true;

                        } else {
                            return false;
                        }
                    }
                });

                //

                popupMenu.show();
            }
        });
    }

    private void loadUserGroups() {

        DictionaryManagerCommon dictionaryManager = JapaneseAndroidLearnHelperApplication.getInstance().getDictionaryManager(this);

        DataManager dataManager = dictionaryManager.getDataManager();

        userGroupList.clear();

        List<UserGroupEntity> allUserGroupsList = dataManager.getAllUserGroupList();

        for (UserGroupEntity currentUserGroupEntity : allUserGroupsList) {
            userGroupList.add(new UserGroupListItem(currentUserGroupEntity, getResources()));
        }

        userGroupListAdapter.notifyDataSetChanged();
    }

    private void createOrUpdateUserGroup(final UserGroupEntity userGroupEntityToUpdate) {

        final EditText groupNameEditText = new EditText(this);

        groupNameEditText.setInputType(InputType.TYPE_CLASS_TEXT);

        if (userGroupEntityToUpdate != null) {
            groupNameEditText.setText(userGroupEntityToUpdate.getName());
        }

        //

        final AlertDialog alertDialog = new AlertDialog.Builder(this).create();

        alertDialog.setTitle(getString(userGroupEntityToUpdate == null ? R.string.user_group_new_group_dialog_title : R.string.user_group_update_group_dialog_title));
        alertDialog.setMessage(getString(userGroupEntityToUpdate == null ? R.string.user_group_new_group_dialog_message : R.string.user_group_update_group_dialog_message));

        alertDialog.setView(groupNameEditText);

        alertDialog.setButton(AlertDialog.BUTTON_POSITIVE, getString(R.string.user_group_ok_button), (DialogInterface.OnClickListener)null);
        alertDialog.setButton(AlertDialog.BUTTON_NEGATIVE, getString(R.string.user_group_cancel_button), (DialogInterface.OnClickListener)null);

        alertDialog.setOnShowListener(new DialogInterface.OnShowListener() {
            @Override
            public void onShow(DialogInterface dialog) {

                Button okButton = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE);

                okButton.setOnClickListener(new View.OnClickListener() {

                    @Override
                    public void onClick(View view) {

                        DictionaryManagerCommon dictionaryManager = JapaneseAndroidLearnHelperApplication.getInstance().getDictionaryManager(UserGroupActivity.this);

                        DataManager dataManager = dictionaryManager.getDataManager();

                        //

                        String newGroupName = groupNameEditText.getText().toString();

                        if (newGroupName == null || newGroupName.length() < 1) {

                            Toast.makeText(UserGroupActivity.this,
                                    getString(R.string.user_group_new_group_name_too_short_error), Toast.LENGTH_SHORT).show();

                            return;
                        }

                        if (newGroupName.length() > 90) {
                            Toast.makeText(UserGroupActivity.this,
                                    getString(R.string.user_group_new_group_name_too_long_error), Toast.LENGTH_SHORT).show();

                            return;
                        }

                        // sprawdzamy, czy grupa o takiej nazwie juz istnieje
                        List<UserGroupEntity> findUserGroupEntityResultList = dataManager.findUserGroupEntity(null, newGroupName);

                        if (findUserGroupEntityResultList != null && findUserGroupEntityResultList.size() > 0) { // grupa o podanej nazwie juz istnieje

                            Toast.makeText(UserGroupActivity.this,
                                    getString(R.string.user_group_new_group_already_exists_error), Toast.LENGTH_SHORT).show();

                            return;
                        }

                        if (userGroupEntityToUpdate == null) { // jesli to nowa grupa, tworzymy ja

                            // nie znaleziono, tworzymy nowa grupe
                            UserGroupEntity newUserGroupEntity = new UserGroupEntity(null, UserGroupEntity.Type.USER_GROUP, newGroupName);

                            dataManager.addUserGroup(newUserGroupEntity);

                        } else { // uaktualnienie nazwy grupy

                            userGroupEntityToUpdate.setName(newGroupName);

                            dataManager.updateUserGroup(userGroupEntityToUpdate);
                        }

                        alertDialog.dismiss();

                        Toast.makeText(UserGroupActivity.this,
                                getString(userGroupEntityToUpdate == null ? R.string.user_group_new_group_created : R.string.user_group_update_group_done), Toast.LENGTH_SHORT).show();

                        // zaladowanie nowe listy grup
                        loadUserGroups();
                    }
                });

                Button cancelButton = alertDialog.getButton(AlertDialog.BUTTON_NEGATIVE);

                cancelButton.setOnClickListener(new View.OnClickListener() {

                    @Override
                    public void onClick(View view) {
                        alertDialog.dismiss();
                    }
                });
            }
        });

        if (isFinishing() == false) {
            alertDialog.show();
        }
    }

    private void checkItemToAdd() {

        Serializable itemToAdd = getIntent().getSerializableExtra("itemToAdd");

        if (itemToAdd != null) {

            TextView itemToAddValueTextView = (TextView)findViewById(R.id.user_group_item_to_add_value);
            TextView itemToAddValueLabelTextView = (TextView)findViewById(R.id.user_group_item_to_add_value_label);
            //View itemToAddTextViewLine1 = (View)findViewById(R.id.user_group_item_to_add_line1);
            View itemToAddTextViewLine2 = (View)findViewById(R.id.user_group_item_to_add_line2);

            //

            CharSequence itemToAddToCharSequence = null;

            if (itemToAdd instanceof DictionaryEntry) {
                dictionaryEntryToAdd = (DictionaryEntry)itemToAdd;

                itemToAddToCharSequence = WordKanjiDictionaryUtils.getWordFullTextWithMark(dictionaryEntryToAdd);

            } else if (itemToAdd instanceof KanjiEntry) {
                kanjiEntryToAdd = (KanjiEntry)itemToAdd;

                String itemToAddToString = WordKanjiDictionaryUtils.getKanjiFullTextWithMark(kanjiEntryToAdd);

                itemToAddToCharSequence = Html.fromHtml(itemToAddToString.replaceAll("\n", "<br/>"));

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

            itemToAddValueTextView.setText(itemToAddToCharSequence);

            itemToAddValueTextView.setVisibility(View.VISIBLE);
            itemToAddValueLabelTextView.setVisibility(View.VISIBLE);
            //itemToAddTextViewLine1.setVisibility(View.VISIBLE);
            itemToAddTextViewLine2.setVisibility(View.VISIBLE);
        }
    }

    public void addItemIdToUserGroupEntity(final UserGroupEntity userGroupEntity) {

        DictionaryManagerCommon dictionaryManager = JapaneseAndroidLearnHelperApplication.getInstance().getDictionaryManager(this);

        final DataManager dataManager = dictionaryManager.getDataManager();

        //

        final Integer itemId;
        final UserGroupItemEntity.Type itemIdUserGroupItemEntityType;

        if (dictionaryEntryToAdd != null) {
            itemId = dictionaryEntryToAdd.getId();
            itemIdUserGroupItemEntityType = UserGroupItemEntity.Type.DICTIONARY_ENTRY;

        } else if (kanjiEntryToAdd != null) {
            itemId = kanjiEntryToAdd.getId();
            itemIdUserGroupItemEntityType = UserGroupItemEntity.Type.KANJI_ENTRY;

        } else {
            throw new RuntimeException("dictionaryEntryToAdd and kanjiEntryToAdd is null");
        }

        boolean itemIdAlreadyExists = dataManager.isItemIdExistsInUserGroup(userGroupEntity, itemIdUserGroupItemEntityType, itemId);

        if (itemIdAlreadyExists == true) {

            Toast.makeText(UserGroupActivity.this,
                    getString(R.string.user_group_item_to_add_user_group_entity_already_exists), Toast.LENGTH_SHORT).show();

            return;
        }

        final AlertDialog alertDialog = new AlertDialog.Builder(this).create();

        alertDialog.setTitle(getString(R.string.user_group_item_to_add_user_group_entity_title));
        alertDialog.setMessage(getString(R.string.user_group_item_to_add_user_group_entity_message,
                userGroupEntity.getType() == UserGroupEntity.Type.USER_GROUP ? userGroupEntity.getName() :
                getString(R.string.user_group_star_group)));

        alertDialog.setButton(AlertDialog.BUTTON_POSITIVE, getString(R.string.user_group_ok_button), new DialogInterface.OnClickListener() {

            @Override
            public void onClick(DialogInterface dialog, int which) {

                // dodanie do grupy
                dataManager.addItemIdToUserGroup(userGroupEntity, itemIdUserGroupItemEntityType, itemId);

                // komunikat
                Toast.makeText(UserGroupActivity.this,
                        getString(R.string.user_group_item_to_add_user_group_entity_toast, userGroupEntity.getType() == UserGroupEntity.Type.USER_GROUP ? userGroupEntity.getName() :
                                getString(R.string.user_group_star_group)), Toast.LENGTH_SHORT).show();

                //

                /*
                dictionaryEntryToAdd = null;
                kanjiEntryToAdd = null;

                //

                TextView itemToAddValueTextView = (TextView) findViewById(R.id.user_group_item_to_add_value);
                TextView itemToAddValueLabelTextView = (TextView) findViewById(R.id.user_group_item_to_add_value_label);
                View itemToAddTextViewLine1 = (View) findViewById(R.id.user_group_item_to_add_line1);
                View itemToAddTextViewLine2 = (View) findViewById(R.id.user_group_item_to_add_line2);

                itemToAddValueTextView.setVisibility(View.GONE);
                itemToAddValueLabelTextView.setVisibility(View.GONE);
                itemToAddTextViewLine1.setVisibility(View.GONE);
                itemToAddTextViewLine2.setVisibility(View.GONE);
                */
            }
        });

        alertDialog.setButton(AlertDialog.BUTTON_NEGATIVE, getString(R.string.user_group_cancel_button), new DialogInterface.OnClickListener() {

            @Override
            public void onClick(DialogInterface dialog, int which) {
                alertDialog.dismiss();

            }
        });

        if (isFinishing() == false) {
            alertDialog.show();
        }
    }

    private void deleteUserGroup(final UserGroupEntity userGroupEntity) {

        DictionaryManagerCommon dictionaryManager = JapaneseAndroidLearnHelperApplication.getInstance().getDictionaryManager(this);

        final DataManager dataManager = dictionaryManager.getDataManager();

        //

        final AlertDialog alertDialog = new AlertDialog.Builder(this).create();

        alertDialog.setTitle(getString(R.string.user_group_delete_user_group_entity_title));
        alertDialog.setMessage(getString(R.string.user_group_delete_user_group_entity_message, userGroupEntity.getName()));

        alertDialog.setButton(AlertDialog.BUTTON_POSITIVE, getString(R.string.user_group_ok_button), new DialogInterface.OnClickListener() {

            @Override
            public void onClick(DialogInterface dialog, int which) {

                // usuniecie grupy
                dataManager.deleteUserGroup(userGroupEntity);

                // komunikat
                Toast.makeText(UserGroupActivity.this,
                        getString(R.string.user_group_delete_user_group_entity_toast, userGroupEntity.getName()), Toast.LENGTH_SHORT).show();

                // zaladowanie nowe listy grup
                loadUserGroups();
            }
        });

        alertDialog.setButton(AlertDialog.BUTTON_NEGATIVE, getString(R.string.user_group_cancel_button), new DialogInterface.OnClickListener() {

            @Override
            public void onClick(DialogInterface dialog, int which) {
                alertDialog.dismiss();

            }
        });

        if (isFinishing() == false) {
            alertDialog.show();
        }
    }

    /*
    private void createReportProblemButton() {

        Button reportProblemButton = (Button)findViewById(R.id.user_group_report_problem_button);

        reportProblemButton.setOnClickListener(new OnClickListener() {

            public void onClick(View view) {

                StringBuffer userGroupListText = new StringBuffer();

                for (int userGroupListAdapterIdx = 0; userGroupListAdapterIdx < userGroupListAdapter.size(); ++userGroupListAdapterIdx) {
                    userGroupListText.append(((UserGroupListItem)userGroupListAdapter.getItem(userGroupListAdapterIdx)).getText().toString()).append("\n--\n");
                }

                String chooseEmailClientTitle = getString(R.string.choose_email_client);

                String mailSubject = getString(R.string.user_group_report_problem_email_subject);

                String mailBody = getString(R.string.user_group_report_problem_email_body, userGroupListText.toString());

                String versionName = "";
                int versionCode = 0;

                try {
                    PackageInfo packageInfo = getPackageManager().getPackageInfo(getPackageName(), 0);

                    versionName = packageInfo.versionName;
                    versionCode = packageInfo.versionCode;

                } catch (PackageManager.NameNotFoundException e) {
                }

                Intent reportProblemIntent = ReportProblem.createReportProblemIntent(mailSubject, mailBody.toString(), versionName, versionCode);

                startActivity(Intent.createChooser(reportProblemIntent, chooseEmailClientTitle));
            }
        });
    }
    */
}
import java.util.ArrayList;
import java.util.List;
import pl.idedyk.android.japaneselearnhelper.JapaneseAndroidLearnHelperApplication;
import pl.idedyk.android.japaneselearnhelper.MenuShorterHelper;
import pl.idedyk.android.japaneselearnhelper.R;
import pl.idedyk.android.japaneselearnhelper.data.DataManager;
import pl.idedyk.android.japaneselearnhelper.data.entity.UserGroupEntity;
import pl.idedyk.android.japaneselearnhelper.data.entity.UserGroupItemEntity;
import pl.idedyk.android.japaneselearnhelper.data.exception.DataManagerException;
import pl.idedyk.android.japaneselearnhelper.dictionary.DictionaryManagerCommon;
import pl.idedyk.android.japaneselearnhelper.dictionaryscreen.WordDictionaryTab;
import pl.idedyk.android.japaneselearnhelper.problem.ReportProblem;
import pl.idedyk.android.japaneselearnhelper.screen.IScreenItem;
import pl.idedyk.android.japaneselearnhelper.screen.Image;
import pl.idedyk.android.japaneselearnhelper.screen.StringValue;
import pl.idedyk.android.japaneselearnhelper.screen.TableLayout;
import pl.idedyk.android.japaneselearnhelper.screen.TableRow;
import pl.idedyk.android.japaneselearnhelper.screen.TitleItem;
import pl.idedyk.android.japaneselearnhelper.sod.SodActivity;
import pl.idedyk.android.japaneselearnhelper.sod.dto.StrokePathInfo;
import pl.idedyk.android.japaneselearnhelper.usergroup.UserGroupActivity;
import pl.idedyk.japanese.dictionary.api.dictionary.dto.FindWordRequest;
import pl.idedyk.japanese.dictionary.api.dictionary.dto.WordPlaceSearch;
import pl.idedyk.japanese.dictionary.api.dto.GroupEnum;
import pl.idedyk.japanese.dictionary.api.dto.KanjiDic2Entry;
import pl.idedyk.japanese.dictionary.api.dto.KanjiEntry;
import pl.idedyk.japanese.dictionary.api.dto.KanjivgEntry;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import android.graphics.Typeface;
import android.os.Bundle;
import android.text.ClipboardManager;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.Toast;
package pl.idedyk.android.japaneselearnhelper.kanji;



@SuppressWarnings("deprecation")
public class KanjiDetails extends Activity {

	private List<IScreenItem> generatedDetails;

	private KanjiEntry kanjiEntry;

	//

	private final static int ADD_ITEM_ID_TO_USER_GROUP_ACTIVITY_REQUEST_CODE = 1;
	
	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		super.onCreateOptionsMenu(menu);

		MenuShorterHelper.onCreateOptionsMenu(menu);

		menu.add(Menu.NONE, R.id.kanji_details_menu_add_item_id_to_user_group, Menu.NONE, R.string.kanji_details_menu_add_item_id_to_user_group);

		return true;
	}
	
	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		super.onOptionsItemSelected(item);

		if (item.getItemId() == R.id.kanji_details_menu_add_item_id_to_user_group) {

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