package com.door43.translationstudio.core; import android.content.Context; import android.database.sqlite.SQLiteDatabase; import android.support.annotation.Nullable; import com.door43.tools.reporting.Logger; import com.door43.util.Security; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Locale; /** * Created by joel on 8/26/2015. * TODO: we might make this static in the library as well */ public class Indexer { private final IndexerSQLiteHelper mDatabaseHelper; private final Context mContext; private SQLiteDatabase mDatabase; private final String mId; /** * Creates a new instance of the index * @param name the name of the index */ public Indexer(Context context, String name, IndexerSQLiteHelper helper) { mId = name; mDatabaseHelper = helper; mDatabase = mDatabaseHelper.getWritableDatabase(); mContext = context; } /** * Closes the index database */ public synchronized void close() { mDatabaseHelper.close(); } /** * Returns the version of the indexer * @return */ public int getVersion() { // TODO: return the version of the index. We can get this info from the database. return 0; } /** * Destroys the entire index */ public synchronized void delete() { close(); mDatabaseHelper.deleteDatabase(mContext); } /** * Rebuilds the index database */ public synchronized void rebuild() { mDatabase = mDatabaseHelper.getWritableDatabase(); } /** * Call to start a transaction */ public void beginTransaction() { mDatabase.beginTransactionNonExclusive(); } /** * Call to close the transaction * @param sucess */ public void endTransaction(boolean sucess) { if(sucess) { mDatabase.setTransactionSuccessful(); } mDatabase.endTransaction(); } /** * Removes a project from the index * @param projectSlug */ public synchronized void deleteProject (String projectSlug) { mDatabaseHelper.deleteProject(mDatabase, projectSlug); } /** * Removes a source language from the index * @param projectSlug * @param sourceLanguageSlug */ public synchronized void deleteSourceLanguage (String projectSlug, String sourceLanguageSlug) { mDatabaseHelper.deleteSourceLanguage(mDatabase, sourceLanguageSlug, projectSlug); } /** * Removes a resource from the index * @param sourceTranslation */ private synchronized void deleteResource (SourceTranslation sourceTranslation) { mDatabaseHelper.deleteResource(mDatabase, sourceTranslation.resourceSlug, sourceTranslation.sourceLanguageSlug, sourceTranslation.projectSlug); } /** * Removes a resource from the index * @param resourceId */ public synchronized void deleteResource(long resourceId) { mDatabaseHelper.deleteResource(mDatabase, resourceId); } /** * Saves a resource to the index * @param resource */ public void saveResource(Resource resource, long sourceLanguageId) { mDatabaseHelper.addResource(mDatabase, resource, sourceLanguageId); } /** * Returns the index id * @return */ public String getIndexId() { return mId; } /** * Returns a branch of the category list * @param sourcelanguageSlug * @param parentCategoryId * @return */ public ProjectCategory[] getCategoryBranch(String sourcelanguageSlug, long parentCategoryId) { return mDatabaseHelper.getCategoryBranch(mDatabase, sourcelanguageSlug, parentCategoryId); } /** * Builds a project index from json * @param catalog the json formatted project catalog * @return */ public synchronized boolean indexProjects(String catalog) { JSONArray items; try { items = new JSONArray(catalog); } catch (JSONException e) { Logger.e(this.getClass().getName(), "Failed to parse the projects catalog", e); return false; } for(int i = 0; i < items.length(); i ++ ) { try { JSONObject item = items.getJSONObject(i); Project project = Project.generateSimple(item); if(project != null) { JSONArray categoriesJson = item.getJSONArray("meta"); List<String> categorySlugs = new ArrayList<>(); for(int j = 0; j < categoriesJson.length(); j ++) { categorySlugs.add(categoriesJson.getString(j)); } // TODO: eventually we will pass in the chunk marker catalog info mDatabaseHelper.addProject(mDatabase, project.getId(), project.sort, project.dateModified, project.sourceLanguageCatalog, project.sourceLanguageCatalogServerDateModified, categorySlugs.toArray(new String[categorySlugs.size()])); mDatabase.yieldIfContendedSafely(); } } catch (JSONException e) { Logger.w(this.getClass().getName(), "Failed to parse a project", e); } } return true; } /** * Builds a source language index from json * @param projectSlug * @param catalog * @return */ public synchronized boolean indexSourceLanguages(String projectSlug, String catalog) { //KLUDGE: modify v2 sourceLanguages catalogJson to match expected catalogJson format JSONArray items; try { items = new JSONArray(catalog); } catch (JSONException e) { e.printStackTrace(); return false; } for (int i = 0; i < items.length(); i ++) { try { JSONObject item = items.getJSONObject(i); JSONObject language = item.getJSONObject("language"); Iterator<String> keys = language.keys(); while(keys.hasNext()) { String key = keys.next(); item.put(key, language.get(key)); } item.remove("language"); } catch (JSONException e) { e.printStackTrace(); } } //KLUDGE: end modify v2 long projectId = mDatabaseHelper.getProjectDBId(mDatabase, projectSlug); if(projectId > 0) { for (int i = 0; i < items.length(); i++) { try { JSONObject item = items.getJSONObject(i); SourceLanguage sourceLanguage = SourceLanguage.generate(item); if (sourceLanguage != null) { JSONArray categoriesJson = item.getJSONObject("project").getJSONArray("meta"); List<String> categoryNames = new ArrayList<>(); for(int j = 0; j < categoriesJson.length(); j ++) { categoryNames.add(categoriesJson.getString(j)); } mDatabaseHelper.addSourceLanguage(mDatabase, sourceLanguage.getId(), projectId, sourceLanguage.name, sourceLanguage.projectTitle, sourceLanguage.projectDescription, sourceLanguage.getDirection().toString(), sourceLanguage.dateModified, sourceLanguage.resourceCatalog, sourceLanguage.resourceCatalogServerDateModified, categoryNames.toArray(new String[categoryNames.size()])); mDatabase.yieldIfContendedSafely(); } } catch (JSONException e) { e.printStackTrace(); } } } else { return false; } return true; } /** * Builds a resource index from json * @param projectSlug * @param sourceLanguageSlug * @param catalog * @return */ public synchronized boolean indexResources(String projectSlug, String sourceLanguageSlug, String catalog) { JSONArray items; try { items = new JSONArray(catalog); } catch (JSONException e) { Logger.e(this.getClass().getName(), "Failed to parse the resources catalog for " + projectSlug + "-" + sourceLanguageSlug, e); return false; } long projectId = mDatabaseHelper.getProjectDBId(mDatabase, projectSlug); long sourceLanguageId = mDatabaseHelper.getSourceLanguageDBId(mDatabase, sourceLanguageSlug, projectId); for(int i = 0; i < items.length(); i ++ ) { try { JSONObject item = items.getJSONObject(i); Resource resource = Resource.generate(item); if(resource != null) { mDatabaseHelper.addResource(mDatabase, resource.getId(), sourceLanguageId, resource.getTitle(), resource.getCheckingLevel(), resource.getVersion(), resource.getDateModified(), resource.getSourceCatalogUrl(), resource.getSourceServerDateModified(), resource.getNotesCatalogUrl(), resource.getNotesServerDateModified(), resource.getWordsCatalogUrl(), resource.getWordsServerDateModified(), resource.getWordAssignmentsCatalogUrl(), resource.getWordAssignmentsServerDateModified(), resource.getQuestionsCatalogUrl(), resource.getQuestionsServerDateModified()); mDatabase.yieldIfContendedSafely(); } } catch (Exception e) { Logger.w(this.getClass().getName(), "Failed to parse a resource for " + projectSlug + "-" + sourceLanguageSlug, e); } } return true; } /** * Builds a translation academy index from json * @param sourceTranslation * @param catalog */ public synchronized boolean indexTranslationAcademy(SourceTranslation sourceTranslation, String catalog) { JSONArray items; try { JSONObject catalogJson = new JSONObject(catalog); items = catalogJson.getJSONArray("volumes"); } catch (JSONException e) { e.printStackTrace(); return false; } Resource resource = mDatabaseHelper.getResource(mDatabase, sourceTranslation.projectSlug, sourceTranslation.sourceLanguageSlug, sourceTranslation.resourceSlug); if(resource != null) { for(int i = 0; i < items.length(); i ++) { try { JSONObject volume = items.getJSONObject(i); JSONArray manuals = volume.getJSONArray("manuals"); // index volume String volSlug = volume.getString("id"); String volTitle = volume.getString("title"); long volumeId = mDatabaseHelper.addTranslationAcademyVolume(mDatabase, volSlug, resource.getDBId(), Security.md5(resource.getAcademyCatalogUrl()), volTitle); for(int j = 0; j < manuals.length(); j ++) { try { JSONObject manual = manuals.getJSONObject(j); JSONArray articles = manual.getJSONArray("articles"); // index manual String manSlug = manual.getString("id"); String manTitle = manual.getString("title"); long manualId = mDatabaseHelper.addTranslationAcademyManual(mDatabase, manSlug, volumeId, manTitle); for(int k = 0; k < articles.length(); k ++) { try { JSONObject article = articles.getJSONObject(k); // index article String artSlug = article.getString("id"); String artTitle = article.getString("title"); String artRef = article.getString("reference"); String artText = article.getString("text"); mDatabaseHelper.addTranslationAcademyArticle(mDatabase, artSlug, manualId, artTitle, artText, artRef); } catch (JSONException e) { Logger.w(this.getClass().getName(), "Failed to parse a translation academy article for " + sourceTranslation.getId(), e); } } } catch (JSONException e) { Logger.w(this.getClass().getName(), "Failed to parse a translation academy manual for " + sourceTranslation.getId(), e); } } } catch (JSONException e) { Logger.w(this.getClass().getName(), "Failed to parse a translation academy volume for " + sourceTranslation.getId(), e); } } } return true; } public synchronized void markSourceCatalogUpToDate(SourceTranslation sourceTranslation) { mDatabaseHelper.markSourceCatalogUpToDate(mDatabase, sourceTranslation.projectSlug, sourceTranslation.sourceLanguageSlug, sourceTranslation.resourceSlug); } public synchronized void markNotesCatalogUpToDate(SourceTranslation sourceTranslation) { mDatabaseHelper.markNotesCatalogUpToDate(mDatabase, sourceTranslation.projectSlug, sourceTranslation.sourceLanguageSlug, sourceTranslation.resourceSlug); } public synchronized void markQuestionsCatalogUpToDate(SourceTranslation sourceTranslation) { mDatabaseHelper.markQuestionsCatalogUpToDate(mDatabase, sourceTranslation.projectSlug, sourceTranslation.sourceLanguageSlug, sourceTranslation.resourceSlug); } public synchronized void markWordsCatalogUpToDate(SourceTranslation sourceTranslation) { mDatabaseHelper.markWordsCatalogUpToDate(mDatabase, sourceTranslation.projectSlug, sourceTranslation.sourceLanguageSlug, sourceTranslation.resourceSlug); } public synchronized void markWordAssignmentsCatalogUpToDate(SourceTranslation sourceTranslation) { mDatabaseHelper.markWordAssignmentsCatalogUpToDate(mDatabase, sourceTranslation.projectSlug, sourceTranslation.sourceLanguageSlug, sourceTranslation.resourceSlug); } public synchronized void markChunkMarkerCatalogUpToDate(String projectSlug) { mDatabaseHelper.markChunkMarkerCatalogUpToDate(mDatabase, projectSlug); } /** * Builds a source index from json * @param sourceTranslation * @param catalog * @return */ public synchronized boolean indexSource(SourceTranslation sourceTranslation, String catalog) { //KLUDGE: modify v2 sources catalogJson to match expected catalogJson format try { JSONObject catalogJson = new JSONObject(catalog); catalog = catalogJson.getJSONArray("chapters").toString(); } catch (JSONException e) { Logger.e(this.getClass().getName(), "Invalid catalog json",e); return false; } //KLUDGE: end modify v2 JSONArray items; try { items = new JSONArray(catalog); } catch (JSONException e) { e.printStackTrace(); return false; } long projectId = mDatabaseHelper.getProjectDBId(mDatabase, sourceTranslation.projectSlug); long sourceLanguageId = mDatabaseHelper.getSourceLanguageDBId(mDatabase, sourceTranslation.sourceLanguageSlug, projectId); long resourceId = mDatabaseHelper.getResourceDBId(mDatabase, sourceTranslation.resourceSlug, sourceLanguageId); for(int chapterIndex = 0; chapterIndex < items.length(); chapterIndex ++ ) { try { JSONObject chapterJson = items.getJSONObject(chapterIndex); Chapter chapter = Chapter.generate(chapterJson); if(chapter != null && chapterJson.has("frames")) { JSONArray frames = chapterJson.getJSONArray("frames"); long chapterId = mDatabaseHelper.addChapter(mDatabase, chapter.getId(), resourceId, chapter.reference, chapter.title); for (int frameIndex = 0; frameIndex < frames.length(); frameIndex ++) { try { JSONObject frameJson = frames.getJSONObject(frameIndex); Frame frame = Frame.generate(chapter.getId(), frameJson); if(frame != null) { mDatabaseHelper.addFrame(mDatabase, frame.getId(), chapterId, frame.body, frame.getFormat().toString(), frame.imageUrl); } mDatabase.yieldIfContendedSafely(); } catch (JSONException e) { Logger.e(this.getClass().getName(), "Failed to parse the frame in chapter " + chapter.getId() + " at index " + chapterIndex + " for source translation " + sourceTranslation.getId(), e); } } } } catch (JSONException e) { Logger.e(this.getClass().getName(), "Failed to parse the chapter at index " + chapterIndex + " for source translation " + sourceTranslation.getId(), e); } } return true; } /** * Builds a index of all the target languages * @param catalog * @return */ public boolean indexTargetLanguages(String catalog) { JSONArray items; try { items = new JSONArray(catalog); } catch (JSONException e) { e.printStackTrace(); return false; } for (int i = 0; i < items.length(); i ++) { try { JSONObject item = items.getJSONObject(i); TargetLanguage targetLanguage = TargetLanguage.generate(item); if(targetLanguage != null) { mDatabaseHelper.addTargetLanguage(mDatabase, targetLanguage.getId(), targetLanguage.getDirection().toString(), targetLanguage.name, targetLanguage.region); } mDatabase.yieldIfContendedSafely(); } catch (JSONException e) { e.printStackTrace(); } } return true; } /** * Builds a notes index from json * * @param sourceTranslation * @param catalog * @return */ public synchronized boolean indexTranslationNotes(SourceTranslation sourceTranslation, String catalog) { //KLUDGE: modify v2 notes catalogJson to match expected catalogJson format JSONArray items; try { items = new JSONArray(catalog); } catch (JSONException e) { Logger.e(this.getClass().getName(), "Failed to parse translation notes catalog for " + sourceTranslation.getId(), e); return false; } JSONObject formattedCatalog = new JSONObject(); for (int i = 0; i < items.length(); i ++) { try { JSONObject item = items.getJSONObject(i); String[] complexId = item.getString("id").split("-"); String chapterId = complexId[0]; String frameId = complexId[1]; JSONArray notesJson = item.getJSONArray("tn"); for(int j = 0; j < notesJson.length(); j ++) { JSONObject note = notesJson.getJSONObject(j); String noteId = Security.md5(note.getString("ref").trim().toLowerCase()); note.put("id", noteId); } // build chapter if(!formattedCatalog.has(chapterId)) { JSONObject newChapterJson = new JSONObject(); newChapterJson.put("id", chapterId); newChapterJson.put("frames", new JSONArray()); formattedCatalog.put(chapterId, newChapterJson); } // build frame JSONArray framesJson = formattedCatalog.getJSONObject(chapterId).getJSONArray("frames"); JSONObject newFrameJson = new JSONObject(); newFrameJson.put("id", frameId); newFrameJson.put("items", notesJson); framesJson.put(newFrameJson); } catch (JSONException e) { Logger.w(this.getClass().getName(), "Failed to parse a translation note for " + sourceTranslation.getId(), e); } } // repackage as json array Iterator x = formattedCatalog.keys(); JSONArray jsonArray = new JSONArray(); while (x.hasNext()){ String key = (String) x.next(); try { jsonArray.put(formattedCatalog.get(key)); } catch (JSONException e) { e.printStackTrace(); } } items = jsonArray; //KLUDGE: end modify v2 long projectId = mDatabaseHelper.getProjectDBId(mDatabase, sourceTranslation.projectSlug); long sourceLanguageId = mDatabaseHelper.getSourceLanguageDBId(mDatabase, sourceTranslation.sourceLanguageSlug, projectId); long resourceId = mDatabaseHelper.getResourceDBId(mDatabase, sourceTranslation.resourceSlug, sourceLanguageId); if(resourceId > 0) { // index for (int chapterIndex = 0; chapterIndex < items.length(); chapterIndex++) { try { JSONObject chapterJson = items.getJSONObject(chapterIndex); String chapterSlug = chapterJson.getString("id"); long chapterId = mDatabaseHelper.getChapterDBId(mDatabase, chapterSlug, resourceId); if(chapterId > 0) { JSONArray frames = chapterJson.getJSONArray("frames"); for (int frameIndex = 0; frameIndex < frames.length(); frameIndex++) { try { JSONObject frameJson = frames.getJSONObject(frameIndex); String frameSlug = frameJson.getString("id"); long frameId = mDatabaseHelper.getFrameDBId(mDatabase, frameSlug, chapterId); if(frameId > 0) { JSONArray frameItems = frameJson.getJSONArray("items"); for (int itemIndex = 0; itemIndex < frameItems.length(); itemIndex++) { try { JSONObject item = frameItems.getJSONObject(itemIndex); TranslationNote note = TranslationNote.generate(chapterSlug, frameSlug, item); if (note != null) { mDatabaseHelper.addTranslationNote(mDatabase, sourceTranslation.projectSlug, sourceTranslation.sourceLanguageSlug, sourceTranslation.resourceSlug, chapterSlug, frameSlug, note.getId(), frameId, note.getTitle(), note.getBody()); } mDatabase.yieldIfContendedSafely(); } catch (JSONException e) { Logger.w(this.getClass().getName(), "Failed to parse a translation note in frame " + chapterSlug + "-" + frameSlug + " for " + sourceTranslation.getId(), e); } } } } catch (JSONException e) { Logger.w(this.getClass().getName(), "Failed to parse a translation note in chapter " + chapterSlug + " for " + sourceTranslation.getId(), e); } } } } catch (JSONException e) { Logger.w(this.getClass().getName(), "Failed to parse a translation note for " + sourceTranslation.getId(), e); } } } return true; } /** * Builds a terms index from json * @param sourceTranslation * @param catalog * @return */ public synchronized boolean indexTranslationWords(SourceTranslation sourceTranslation, String catalog) { JSONArray items; try { items = new JSONArray(catalog); } catch (JSONException e) { e.printStackTrace(); return false; } Resource resource = mDatabaseHelper.getResource(mDatabase, sourceTranslation.projectSlug, sourceTranslation.sourceLanguageSlug, sourceTranslation.resourceSlug); if(resource != null) { for (int i = 0; i < items.length(); i++) { try { JSONObject item = items.getJSONObject(i); TranslationWord word = TranslationWord.generate(item); if (word != null) { mDatabaseHelper.addTranslationWord(mDatabase, word.getId(), resource.getDBId(), Security.md5(resource.getWordsCatalogUrl()), word.getTerm(), word.getDefinitionTitle(), word.getDefinition(), word.getExamples(), word.getAliases(), word.getSeeAlso()); } mDatabase.yieldIfContendedSafely(); } catch (JSONException e) { Logger.w(this.getClass().getName(), "Failed to parse a translation word for " + sourceTranslation.getId(), e); } } } return true; } /** * Builds a translationWord assignment index from json * @param sourceTranslation * @param catalog * @return */ public synchronized boolean indexTermAssignments(SourceTranslation sourceTranslation, String catalog) { //KLUDGE: modify v2 questions catalogJson to match expected catalogJson format JSONArray items; try { JSONObject catJson = new JSONObject(catalog); items = catJson.getJSONArray("chapters"); } catch (JSONException e) { Logger.e(this.getClass().getName(), "Failed to parse word assignments for " + sourceTranslation.getId(), e); return false; } //KLUDGE: end modify v2\ long projectId = mDatabaseHelper.getProjectDBId(mDatabase, sourceTranslation.projectSlug); long sourceLanguageId = mDatabaseHelper.getSourceLanguageDBId(mDatabase, sourceTranslation.sourceLanguageSlug, projectId); long resourceId = mDatabaseHelper.getResourceDBId(mDatabase, sourceTranslation.resourceSlug, sourceLanguageId); if(resourceId > 0) { // index for (int chapterIndex = 0; chapterIndex < items.length(); chapterIndex++) { try { JSONObject chapter = items.getJSONObject(chapterIndex); String chapterSlug = chapter.getString("id"); long chapterId = mDatabaseHelper.getChapterDBId(mDatabase, chapterSlug, resourceId); if(chapterId > 0) { JSONArray frames = chapter.getJSONArray("frames"); for (int frameIndex = 0; frameIndex < frames.length(); frameIndex++) { try { JSONObject frame = frames.getJSONObject(frameIndex); String frameSlug = frame.getString("id"); long frameId = mDatabaseHelper.getFrameDBId(mDatabase, frameSlug, chapterId); if(frameId > 0) { JSONArray frameItems = frame.getJSONArray("items"); for (int itemIndex = 0; itemIndex < frameItems.length(); itemIndex++) { try { JSONObject item = frameItems.getJSONObject(itemIndex); if (item.has("id")) { mDatabaseHelper.addTranslationWordToFrame(mDatabase, item.getString("id"), resourceId, frameId, sourceTranslation.projectSlug, sourceTranslation.sourceLanguageSlug, sourceTranslation.resourceSlug, chapterSlug, frameSlug); } } catch (JSONException e) { Logger.w(this.getClass().getName(), "Failed to parse a word assignment in frame " + chapterSlug + "-" + frameSlug + " for " + sourceTranslation.getId(), e); } } } } catch (JSONException e) { Logger.w(this.getClass().getName(), "Failed to parse a word assignment in chpater " + chapterSlug + " for " + sourceTranslation.getId(), e); } } } } catch (JSONException e) { Logger.w(this.getClass().getName(), "Failed to parse a word assignment for " + sourceTranslation.getId(), e); } } } return true; } /** * Builds a questions index from json * @param sourceTranslation * @param catalog * @return */ public synchronized boolean indexQuestions(SourceTranslation sourceTranslation, String catalog) { //KLUDGE: modify v2 questions catalogJson to match expected catalogJson format JSONArray items; try { items = new JSONArray(catalog); } catch (JSONException e) { Logger.e(this.getClass().getName(), "Failed to parse the questions catalog for " + sourceTranslation.getId(), e); return false; } JSONObject formattedCatalog = new JSONObject(); for (int i = 0; i < items.length(); i ++) { try { JSONObject item = items.getJSONObject(i); String chapterId = item.getString("id"); // build chapter if(!formattedCatalog.has(chapterId)) { JSONObject newChapterJson = new JSONObject(); newChapterJson.put("id", chapterId); newChapterJson.put("frames", new JSONObject()); formattedCatalog.put(chapterId, newChapterJson); } JSONObject framesJson = formattedCatalog.getJSONObject(chapterId).getJSONObject("frames"); // parse questions JSONArray questionsJson = item.getJSONArray("cq"); for(int j = 0; j < questionsJson.length(); j ++) { try { JSONObject question = questionsJson.getJSONObject(j); String questionId = Security.md5(question.getString("q").trim().toLowerCase()); question.put("id", questionId); JSONArray referencesJson = question.getJSONArray("ref"); for (int k = 0; k < referencesJson.length(); k++) { String[] complexId = referencesJson.getString(k).split("-"); String frameId = complexId[1]; // build frame if (!framesJson.has(frameId)) { JSONObject newFrameJson = new JSONObject(); newFrameJson.put("id", frameId); newFrameJson.put("items", new JSONArray()); framesJson.put(frameId, newFrameJson); } // add questions framesJson.getJSONObject(frameId).getJSONArray("items").put(question); } } catch (JSONException e) { Logger.w(this.getClass().getName(), "Failed to parse question in chapter " + chapterId + " for " + sourceTranslation.getId(), e); } } } catch (JSONException e) { Logger.w(this.getClass().getName(), "Failed to parse a question for " + sourceTranslation.getId(), e); } } // repackage as json array Iterator x = formattedCatalog.keys(); JSONArray jsonArray = new JSONArray(); while (x.hasNext()){ String chapterKey = (String) x.next(); try { JSONObject chapter = formattedCatalog.getJSONObject(chapterKey); JSONArray frames = new JSONArray(); Iterator y = chapter.getJSONObject("frames").keys(); while(y.hasNext()) { String frameKey = (String) y.next(); try { frames.put(chapter.getJSONObject("frames").get(frameKey)); } catch (JSONException e) { e.printStackTrace(); } } chapter.put("frames", frames); jsonArray.put(chapter); } catch (JSONException e) { e.printStackTrace(); } } items = jsonArray; //KLUDGE: end modify v2 long projectId = mDatabaseHelper.getProjectDBId(mDatabase, sourceTranslation.projectSlug); long sourceLanguageId = mDatabaseHelper.getSourceLanguageDBId(mDatabase, sourceTranslation.sourceLanguageSlug, projectId); long resourceId = mDatabaseHelper.getResourceDBId(mDatabase, sourceTranslation.resourceSlug, sourceLanguageId); if(resourceId > 0) { for (int chapterIndex = 0; chapterIndex < items.length(); chapterIndex++) { try { JSONObject chapter = items.getJSONObject(chapterIndex); String chapterSlug = chapter.getString("id"); long chapterId = mDatabaseHelper.getChapterDBId(mDatabase, chapterSlug, resourceId); if(chapterId > 0) { JSONArray frames = chapter.getJSONArray("frames"); for (int frameIndex = 0; frameIndex < frames.length(); frameIndex++) { try { JSONObject frame = frames.getJSONObject(frameIndex); String frameSlug = frame.getString("id"); long frameId = mDatabaseHelper.getFrameDBId(mDatabase, frameSlug, chapterId); if(frameId > 0) { JSONArray frameItems = frame.getJSONArray("items"); for (int itemIndex = 0; itemIndex < frameItems.length(); itemIndex++) { try { JSONObject item = frameItems.getJSONObject(itemIndex); CheckingQuestion question = CheckingQuestion.generate(chapterSlug, frameSlug, item); if (question != null) { mDatabaseHelper.addCheckingQuestion(mDatabase, sourceTranslation.projectSlug, sourceTranslation.sourceLanguageSlug, sourceTranslation.resourceSlug, chapterSlug, frameSlug, question.getId(), frameId, chapterId, question.getQuestion(), question.getAnswer()); } mDatabase.yieldIfContendedSafely(); } catch (JSONException e) { e.printStackTrace(); } } } } catch (JSONException e) { e.printStackTrace(); } } } } catch (JSONException e) { e.printStackTrace(); } } } return true; } /** * Builds a chunks index from json * @param projectSlug * @param catalog * @return */ public synchronized boolean indexChunkMarkers(String projectSlug, String catalog) { JSONArray items; try { items = new JSONArray(catalog); } catch (JSONException e) { Logger.e(this.getClass().getName(), "Failed to parse the chunk marker catalog for " + projectSlug, e); return false; } long projectId = mDatabaseHelper.getProjectDBId(mDatabase, projectSlug); if(projectId > 0) { for (int i = 0; i < items.length(); i ++) { try { JSONObject item = items.getJSONObject(i); mDatabaseHelper.addChunkMarker(mDatabase, item.getString("chp"), item.getString("firstvs"), projectId); mDatabase.yieldIfContendedSafely(); } catch (JSONException e) { Logger.w(this.getClass().getName(), "Failed to parse a chunk marker for " + projectSlug, e); } } } return true; } /** * Returns an array of projectS * @return */ public String[] getProjectSlugs() { // // TODO: 10/16/2015 see if we can avoid using this method return mDatabaseHelper.getProjectSlugs(mDatabase); } /** * Returns an array of source language ids * @param projectSlug * @return */ public String[] getSourceLanguageSlugs(String projectSlug) { long projectId = mDatabaseHelper.getProjectDBId(mDatabase, projectSlug); if(projectId > 0) { return mDatabaseHelper.getSourceLanguageSlugs(mDatabase, projectId); } return new String[0]; } /** * Returns an array of resource ids * @param projectSlug * @param sourceLanguageSlug * @return */ public String[] getResourceSlugs(String projectSlug, String sourceLanguageSlug) { long projectId = mDatabaseHelper.getProjectDBId(mDatabase, projectSlug); if(projectId > 0) { long sourceLanguageId = mDatabaseHelper.getSourceLanguageDBId(mDatabase, sourceLanguageSlug, projectId); if(sourceLanguageId > 0) { return mDatabaseHelper.getResourceSlugs(mDatabase, sourceLanguageId); } } return new String[0]; } /** * Returns an array of chapter ids * @param sourceTranslation * @return */ public String[] getChapterSlugs(SourceTranslation sourceTranslation) { long projectId = mDatabaseHelper.getProjectDBId(mDatabase, sourceTranslation.projectSlug); long sourceLanguageId = mDatabaseHelper.getSourceLanguageDBId(mDatabase, sourceTranslation.sourceLanguageSlug, projectId); long resourceId = mDatabaseHelper.getResourceDBId(mDatabase, sourceTranslation.resourceSlug, sourceLanguageId); if(resourceId > 0) { return mDatabaseHelper.getChapterSlugs(mDatabase, resourceId); } return new String[0]; } /** * Returns a list of chapters * @return */ @Deprecated public Chapter[] getChapters(SourceTranslation sourceTranslation) { long projectId = mDatabaseHelper.getProjectDBId(mDatabase, sourceTranslation.projectSlug); long sourceLanguageId = mDatabaseHelper.getSourceLanguageDBId(mDatabase, sourceTranslation.sourceLanguageSlug, projectId); long resourceId = mDatabaseHelper.getResourceDBId(mDatabase, sourceTranslation.resourceSlug, sourceLanguageId); if(resourceId > 0) { return mDatabaseHelper.getChapters(mDatabase, resourceId); } return new Chapter[0]; } /** * Returns an array of frame ids * @param sourceTranslation * @param chapterSlug * @return */ public String[] getFrameSlugs(SourceTranslation sourceTranslation, String chapterSlug) { long projectId = mDatabaseHelper.getProjectDBId(mDatabase, sourceTranslation.projectSlug); long sourceLanguageId = mDatabaseHelper.getSourceLanguageDBId(mDatabase, sourceTranslation.sourceLanguageSlug, projectId); long resourceId = mDatabaseHelper.getResourceDBId(mDatabase, sourceTranslation.resourceSlug, sourceLanguageId); long chapterId = mDatabaseHelper.getChapterDBId(mDatabase, chapterSlug, resourceId); if(chapterId > 0) { return mDatabaseHelper.getFrameSlugs(mDatabase, chapterId); } return new String[0]; } /** * Returns an array of frame contents * @param sourceTranslation * @param chapterSlug * @return */ public Frame[] getFrames(SourceTranslation sourceTranslation, String chapterSlug) { return mDatabaseHelper.getFrames(mDatabase, sourceTranslation.projectSlug, sourceTranslation.sourceLanguageSlug, sourceTranslation.resourceSlug, chapterSlug); } /** * Returns an array of target languages * @return */ public TargetLanguage[] getTargetLanguages() { return mDatabaseHelper.getTargetLanguages(mDatabase); } /** * Returns a target language * @param targetLanguageSlug * @return */ public TargetLanguage getTargetLanguage(String targetLanguageSlug) { return mDatabaseHelper.getTargetLanguage(mDatabase, targetLanguageSlug); } /** * Returns a target language * @param targetLanguageName * @return */ public TargetLanguage getTargetLanguageByName(String targetLanguageName) { return mDatabaseHelper.getTargetLanguageByName(mDatabase, targetLanguageName); } /** * Returns the number of target languages * @return */ public int getNumTargetLanguages() { return mDatabaseHelper.getTargetLanguagesLength(mDatabase); } /** * Returns an array of translationNote slugs * @param sourceTranslation * @param chapterSlug * @param frameSlug * @return */ public String[] getNoteSlugs(SourceTranslation sourceTranslation, String chapterSlug, String frameSlug) { long projectId = mDatabaseHelper.getProjectDBId(mDatabase, sourceTranslation.projectSlug); long sourceLanguageId = mDatabaseHelper.getSourceLanguageDBId(mDatabase, sourceTranslation.sourceLanguageSlug, projectId); long resourceId = mDatabaseHelper.getResourceDBId(mDatabase, sourceTranslation.resourceSlug, sourceLanguageId); long chapterId = mDatabaseHelper.getChapterDBId(mDatabase, chapterSlug, resourceId); long frameId = mDatabaseHelper.getFrameDBId(mDatabase, frameSlug, chapterId); if(frameId > 0) { return mDatabaseHelper.getTranslationNoteSlugs(mDatabase, frameId); } return new String[0]; } /** * Returns an array of translationWord slugs * @param sourceTranslation * @return */ public String[] getWordSlugs(SourceTranslation sourceTranslation) { long projectId = mDatabaseHelper.getProjectDBId(mDatabase, sourceTranslation.projectSlug); long sourceLanguageId = mDatabaseHelper.getSourceLanguageDBId(mDatabase, sourceTranslation.sourceLanguageSlug, projectId); long resourceId = mDatabaseHelper.getResourceDBId(mDatabase, sourceTranslation.resourceSlug, sourceLanguageId); if(resourceId > 0) { return mDatabaseHelper.getTranslationWordSlugs(mDatabase, resourceId); } return new String[0]; } /** * Returns an array of translationWords for a source translation * @param sourceTranslation * @return */ public TranslationWord[] getWords(SourceTranslation sourceTranslation) { return mDatabaseHelper.getTranslationWords(mDatabase, sourceTranslation.projectSlug, sourceTranslation.sourceLanguageSlug, sourceTranslation.resourceSlug); } /** * Returns an array of translationWords for a single frame * @param sourceTranslation * @param chapterSlug * @param frameSlug * @return */ public TranslationWord[] getWordsForFrame(SourceTranslation sourceTranslation, String chapterSlug, String frameSlug) { return mDatabaseHelper.getTranslationWordsForFrame(mDatabase, sourceTranslation.projectSlug, sourceTranslation.sourceLanguageSlug, sourceTranslation.resourceSlug, chapterSlug, frameSlug); } /** * Returns a translatonWord * @param sourceTranslation * @param wordSlug * @return */ @Nullable public TranslationWord getWord(SourceTranslation sourceTranslation, String wordSlug) { long projectId = mDatabaseHelper.getProjectDBId(mDatabase, sourceTranslation.projectSlug); long sourceLanguageId = mDatabaseHelper.getSourceLanguageDBId(mDatabase, sourceTranslation.sourceLanguageSlug, projectId); long resourceId = mDatabaseHelper.getResourceDBId(mDatabase, sourceTranslation.resourceSlug, sourceLanguageId); if(resourceId > 0) { return mDatabaseHelper.getTranslationWord(mDatabase, wordSlug, resourceId); } else { return null; } } /** * Returns a translation academy item * @param sourceTranslation * @param volume * @param manual * @param translationArticleSlug @return */ @Nullable public TranslationArticle getTranslationArticle(SourceTranslation sourceTranslation, String volume, String manual, String translationArticleSlug) { long projectId = mDatabaseHelper.getProjectDBId(mDatabase, sourceTranslation.projectSlug); long sourceLanguageId = mDatabaseHelper.getSourceLanguageDBId(mDatabase, sourceTranslation.sourceLanguageSlug, projectId); long resourceId = mDatabaseHelper.getResourceDBId(mDatabase, sourceTranslation.resourceSlug, sourceLanguageId); if(resourceId > 0) { return mDatabaseHelper.getTranslationArticle(mDatabase, resourceId, volume, manual, translationArticleSlug); } else { return null; } } /** * Returns an array of checkingQuestions * @param sourceTranslation * @param chapterSlug * @param frameSlug * @return */ public CheckingQuestion[] getCheckingQuestions(SourceTranslation sourceTranslation, String chapterSlug, String frameSlug) { return mDatabaseHelper.getCheckingQuestions(mDatabase, sourceTranslation.projectSlug, sourceTranslation.sourceLanguageSlug, sourceTranslation.resourceSlug, chapterSlug, frameSlug); } /** * Returns a project * The default language will be used for the project title and description * @param projectSlug * @return */ public synchronized Project getProject(String projectSlug) { String defaultLanguageCode = Locale.getDefault().getLanguage(); return getProject(projectSlug, defaultLanguageCode); } /** * Returns a project * @param projectSlug * @param sourceLanguageSlug * @return */ public synchronized Project getProject(String projectSlug, String sourceLanguageSlug) { return mDatabaseHelper.getProject(mDatabase, projectSlug, sourceLanguageSlug); } /** * Returns a source language * @param projectSlug * @param sourceLanguageSlug * @return */ public synchronized SourceLanguage getSourceLanguage(String projectSlug, String sourceLanguageSlug) { return mDatabaseHelper.getSourceLanguage(mDatabase, projectSlug, sourceLanguageSlug); } /** * Returns an array of source languages in the project * @param projectSlug * @return */ public synchronized SourceLanguage[] getSourceLanguages(String projectSlug) { return mDatabaseHelper.getSourceLanguages(mDatabase, projectSlug); } /** * Returns a source translation * @param projectSlug * @param sourceLanguageSlug * @param resourceSlug * @return */ public SourceTranslation getSourceTranslation(String projectSlug, String sourceLanguageSlug, String resourceSlug) { return mDatabaseHelper.getSourceTranslation(mDatabase, projectSlug, sourceLanguageSlug, resourceSlug); } /** * Returns an array of source translations that have updates available on the server. * @return */ public SourceTranslation[] getSourceTranslationsWithUpdates() { return mDatabaseHelper.getSourceTranslationsWithUpdates(mDatabase); } /** * Returns a resource * @param translation * @return */ public synchronized Resource getResource(SourceTranslation translation) { return mDatabaseHelper.getResource(mDatabase, translation.projectSlug, translation.sourceLanguageSlug, translation.resourceSlug); } /** * Returns an array of resources * @param projectSlug * @param sourceLanguageSlug * @return */ public synchronized Resource[] getResources(String projectSlug, String sourceLanguageSlug) { return mDatabaseHelper.getResources(mDatabase, projectSlug, sourceLanguageSlug); } /** * Returns a chapter * @param sourceTranslation * @param chapterSlug * @return */ @Nullable public Chapter getChapter(SourceTranslation sourceTranslation, String chapterSlug) { long projectId = mDatabaseHelper.getProjectDBId(mDatabase, sourceTranslation.projectSlug); long sourceLanguageId = mDatabaseHelper.getSourceLanguageDBId(mDatabase, sourceTranslation.sourceLanguageSlug, projectId); long resourceId = mDatabaseHelper.getResourceDBId(mDatabase, sourceTranslation.resourceSlug, sourceLanguageId); if(resourceId > 0) { return mDatabaseHelper.getChapter(mDatabase, chapterSlug, resourceId); } return null; } /** * Returns a frame * @param sourceTranslation * @param chapterSlug * @param frameSlug * @return */ @Nullable public Frame getFrame(SourceTranslation sourceTranslation, String chapterSlug, String frameSlug) { long projectId = mDatabaseHelper.getProjectDBId(mDatabase, sourceTranslation.projectSlug); long sourceLanguageId = mDatabaseHelper.getSourceLanguageDBId(mDatabase, sourceTranslation.sourceLanguageSlug, projectId); long resourceId = mDatabaseHelper.getResourceDBId(mDatabase, sourceTranslation.resourceSlug, sourceLanguageId); long chapterId = mDatabaseHelper.getChapterDBId(mDatabase, chapterSlug, resourceId); if(chapterId > 0) { return mDatabaseHelper.getFrame(mDatabase, frameSlug, chapterId); } return null; } /** * Returns the json object for a single checkingQuestion * @param sourceTranslation * @param chapterSlug * @param questionSlug * @return */ @Nullable public CheckingQuestion getCheckingQuestion(SourceTranslation sourceTranslation, String chapterSlug, String frameSlug, String questionSlug) { long projectId = mDatabaseHelper.getProjectDBId(mDatabase, sourceTranslation.projectSlug); long sourceLanguageId = mDatabaseHelper.getSourceLanguageDBId(mDatabase, sourceTranslation.sourceLanguageSlug, projectId); long resourceId = mDatabaseHelper.getResourceDBId(mDatabase, sourceTranslation.resourceSlug, sourceLanguageId); long chapterId = mDatabaseHelper.getChapterDBId(mDatabase, chapterSlug, resourceId); if(chapterId > 0) { return mDatabaseHelper.getCheckingQuestion(mDatabase, chapterId, frameSlug, questionSlug); } return null; } /** * Returns a translation note * @param sourceTranslation * @param chapterSlug * @param frameSlug * @param noteSlug * @return */ @Nullable public TranslationNote getNote(SourceTranslation sourceTranslation, String chapterSlug, String frameSlug, String noteSlug) { long projectId = mDatabaseHelper.getProjectDBId(mDatabase, sourceTranslation.projectSlug); long sourceLanguageId = mDatabaseHelper.getSourceLanguageDBId(mDatabase, sourceTranslation.sourceLanguageSlug, projectId); long resourceId = mDatabaseHelper.getResourceDBId(mDatabase, sourceTranslation.resourceSlug, sourceLanguageId); long chapterId = mDatabaseHelper.getChapterDBId(mDatabase, chapterSlug, resourceId); long frameId = mDatabaseHelper.getFrameDBId(mDatabase, frameSlug, chapterId); if(frameId > 0) { return mDatabaseHelper.getTranslationNote(mDatabase, noteSlug, frameId); } return null; } /** * Returns the body of the chapter * @param sourceTranslation * @param chapterSlug * @return */ public String getChapterBody(SourceTranslation sourceTranslation, String chapterSlug) { return mDatabaseHelper.getChapterBody(mDatabase, sourceTranslation.projectSlug, sourceTranslation.sourceLanguageSlug, sourceTranslation.resourceSlug, chapterSlug); } /** * Returns the format of the chapter body * @param sourceTranslation * @param chapterSlug * @return */ public TranslationFormat getChapterBodyFormat(SourceTranslation sourceTranslation, String chapterSlug) { return mDatabaseHelper.getChapterBodyFormat(mDatabase, sourceTranslation.projectSlug, sourceTranslation.sourceLanguageSlug, sourceTranslation.resourceSlug, chapterSlug); } /** * Returns the translation notes in a frame * @param sourceTranslation * @param chapterSlug * @param frameSlug * @return */ public TranslationNote[] getTranslationNotes(SourceTranslation sourceTranslation, String chapterSlug, String frameSlug) { return mDatabaseHelper.getTranslationNotes(mDatabase, sourceTranslation.projectSlug, sourceTranslation.sourceLanguageSlug, sourceTranslation.resourceSlug, chapterSlug, frameSlug); } /** * Returns the number of translatable items in the source translation. * This counts the frames, chapter titles, and chapter references. * Empty items will not be counted. * @param sourceTranslation * @return */ public int numTranslatable(SourceTranslation sourceTranslation) { return mDatabaseHelper.countTranslatableItems(mDatabase, sourceTranslation.projectSlug, sourceTranslation.sourceLanguageSlug, sourceTranslation.resourceSlug); } /** * Returns an array of projects * @param sourceLanguageSlug * @return */ public Project[] getProjects(String sourceLanguageSlug) { return mDatabaseHelper.getProjects(mDatabase, sourceLanguageSlug); } /** * Marks the source language catalog in the project as up to date * @param projectSlug */ public void markSourceLanguageCatalogUpToDate(String projectSlug) { mDatabaseHelper.markSourceLanguageCatalogUpToDate(mDatabase, projectSlug); } /** * Marks the resource catalog in source language has up to date * @param projectSlug * @param sourceLanguageSlug */ public void markResourceCatalogUpToDate(String projectSlug, String sourceLanguageSlug) { mDatabaseHelper.markResourceCatalogUpToDate(mDatabase, projectSlug, sourceLanguageSlug); } public void setExpired() { mDatabase.execSQL("UPDATE `resource`" + " SET `source_catalog_local_modified_at`=0," + " `translation_notes_catalog_local_modified_at`=0," + " `translation_words_catalog_local_modified_at`=0," + " `translation_word_assignments_catalog_local_modified_at`=0," + " `checking_questions_catalog_local_modified_at`=0" ); } /** * This is a temporary method for injecting the chunk marker urls into the project table * * @return * @deprecated you probably shouldn't use this method */ public boolean manuallyInjectChunkMarkerUrls() { return mDatabaseHelper.manuallyInjectChunkMarkerUrls(mDatabase); } /** * Returns an array of chunk markers for the project * @param projectSlug * @return */ public ChunkMarker[] getChunkMarkers(String projectSlug) { return mDatabaseHelper.getChunkMarkers(mDatabase, projectSlug); } }