/* * Geopaparazzi - Digital field mapping on Android based devices * Copyright (C) 2016 HydroloGIS (www.hydrologis.com) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package eu.geopaparazzi.library.forms; import android.content.Context; import android.content.res.AssetManager; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import java.io.File; import java.io.FileOutputStream; import java.io.InputStream; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Set; import eu.geopaparazzi.library.core.ResourcesManager; import eu.geopaparazzi.library.profiles.Profile; import eu.geopaparazzi.library.profiles.ProfilesHandler; import eu.geopaparazzi.library.util.FileUtilities; import eu.geopaparazzi.library.util.debug.Debug; import static eu.geopaparazzi.library.forms.FormUtilities.ATTR_FORMNAME; import static eu.geopaparazzi.library.forms.FormUtilities.ATTR_FORMS; import static eu.geopaparazzi.library.forms.FormUtilities.ATTR_SECTIONNAME; import static eu.geopaparazzi.library.forms.FormUtilities.TAG_FORMITEMS; import static eu.geopaparazzi.library.forms.FormUtilities.TAG_FORMS; import static eu.geopaparazzi.library.forms.FormUtilities.TAG_ITEM; import static eu.geopaparazzi.library.forms.FormUtilities.TAG_ITEMS; import static eu.geopaparazzi.library.forms.FormUtilities.TAG_LONGNAME; import static eu.geopaparazzi.library.forms.FormUtilities.TAG_SHORTNAME; import static eu.geopaparazzi.library.forms.FormUtilities.TAG_VALUES; /** * Singleton that takes care of tags. * <p/> * <p>The tags are looked for in the following places:</p> * <ul> * <li>a file named <b>tags.json</b> inside the application folder (Which * is retrieved via {@link ResourcesManager#getApplicationSupporterDir()} </li> * <li>or, if the above is missing, a file named <b>tags/tags.json</b> in * the asset folder of the project. In that case the file is copied over * to the file in the first point.</li> * </ul> * <p> * <p> * The tags file is subdivided as follows: * <p> * [{ * "sectionname": "scheda_sisma", * "sectiondescription": "this produces a button names scheda_sisma", * "forms": [ * { * "formname": "Name of the section, used in the fragments list", * "formitems": [ * .... * .... * ] * },{ * "formname": "This name produces a second fragment", * "formitems": [ * .... * .... * ] * } * ] * },{ * "sectionname": "section 2", * "sectiondescription": "this produces a second button", * "forms": [ * { * "formname": "this produces one fragment in the list", * "formitems": [ * .... * .... * ] * },{ * <p> * } * ] * }] * * @author Andrea Antonello (www.hydrologis.com) */ @SuppressWarnings("nls") public class TagsManager { /** * The tags file name. */ public static String TAGSFILENAME = "tags.json"; private LinkedHashMap<String, JSONObject> sectionsMap = null; private static TagsManager tagsManager; /** * Gets the manager singleton. * * @param context the context to use. * @return the {@link TagsManager} singleton. * @throws Exception if something goes wrong. */ public static synchronized TagsManager getInstance(Context context) throws Exception { if (tagsManager == null) { tagsManager = new TagsManager(); tagsManager.getFileTags(context); } return tagsManager; } /** * Reset the tags manager, forcing a new reread of the tags. */ public static void reset() { tagsManager = null; } /** * Performs the first data reading. Necessary for everything else. * * @param context the context to use. * @throws Exception */ private void getFileTags(Context context) throws Exception { if (sectionsMap == null) { sectionsMap = new LinkedHashMap<String, JSONObject>(); } File tagsFile = null; if (ProfilesHandler.INSTANCE.getActiveProfile() != null) { Profile activeProfile = ProfilesHandler.INSTANCE.getActiveProfile(); if (activeProfile.tagsPath!=null) { tagsFile = new File(activeProfile.tagsPath); if (!tagsFile.exists()) tagsFile = null; } } if (tagsFile == null) { File applicationDir = ResourcesManager.getInstance(context).getApplicationSupporterDir(); tagsFile = new File(applicationDir, TAGSFILENAME); if (!tagsFile.exists() || Debug.doOverwriteTags) { AssetManager assetManager = context.getAssets(); InputStream inputStream = assetManager.open("tags/tags.json"); FileUtilities.copyFile(inputStream, new FileOutputStream(tagsFile)); } } if (tagsFile.exists()) { sectionsMap.clear(); String tagsFileString = FileUtilities.readfile(tagsFile); JSONArray sectionsArrayObj = new JSONArray(tagsFileString); int tagsNum = sectionsArrayObj.length(); for (int i = 0; i < tagsNum; i++) { JSONObject jsonObject = sectionsArrayObj.getJSONObject(i); if (jsonObject.has(ATTR_SECTIONNAME)) { String sectionName = jsonObject.get(ATTR_SECTIONNAME).toString(); sectionsMap.put(sectionName, jsonObject); } } } } /** * @return the section names. */ public Set<String> getSectionNames() { return sectionsMap.keySet(); } /** * get a section obj by name. * * @param name thename. * @return the section object. */ public JSONObject getSectionByName(String name) { return sectionsMap.get(name); } /** * get form name from a section obj. * * @param section the section. * @return the name. * @throws JSONException if something goes wrong. */ public static List<String> getFormNames4Section(JSONObject section) throws JSONException { List<String> names = new ArrayList<String>(); JSONArray jsonArray = section.getJSONArray(ATTR_FORMS); if (jsonArray != null && jsonArray.length() > 0) { for (int i = 0; i < jsonArray.length(); i++) { JSONObject jsonObject = jsonArray.getJSONObject(i); if (jsonObject.has(ATTR_FORMNAME)) { String formName = jsonObject.getString(ATTR_FORMNAME); names.add(formName); } } } return names; } /** * Get the form for a name. * * @param formName the name. * @param section the section object containing the form. * @return the form object. * @throws JSONException if something goes wrong. */ public static JSONObject getForm4Name(String formName, JSONObject section) throws JSONException { JSONArray jsonArray = section.getJSONArray(ATTR_FORMS); if (jsonArray != null && jsonArray.length() > 0) { for (int i = 0; i < jsonArray.length(); i++) { JSONObject jsonObject = jsonArray.getJSONObject(i); if (jsonObject.has(ATTR_FORMNAME)) { String tmpFormName = jsonObject.getString(ATTR_FORMNAME); if (tmpFormName.equals(formName)) { return jsonObject; } } } } return null; } /** * Convert a string to a {@link TagObject}. * * @param jsonString the string. * @return the object. * @throws JSONException if something goes wrong. */ public static TagObject stringToTagObject(String jsonString) throws JSONException { JSONObject jsonObject = new JSONObject(jsonString); String shortname = jsonObject.getString(TAG_SHORTNAME); String longname = jsonObject.getString(TAG_LONGNAME); TagObject tag = new TagObject(); tag.shortName = shortname; tag.longName = longname; if (jsonObject.has(TAG_FORMS)) { tag.hasForm = true; } tag.jsonString = jsonString; return tag; } /** * Utility method to get the formitems of a form object. * <p> * <p>Note that the entering json object has to be one * object of the main array, not THE main array itself, * i.e. a choice was already done. * * @param formObj the single object. * @return the array of items of the contained form or <code>null</code> if * no form is contained. * @throws JSONException if something goes wrong. */ public static JSONArray getFormItems(JSONObject formObj) throws JSONException { if (formObj.has(TAG_FORMITEMS)) { return formObj.getJSONArray(TAG_FORMITEMS); } return new JSONArray(); } /** * Utility method to get the combo items of a formitem object. * * @param formItem the json form <b>item</b>. * @return the array of items. * @throws JSONException if something goes wrong. */ public static JSONArray getComboItems(JSONObject formItem) throws JSONException { if (formItem.has(TAG_VALUES)) { JSONObject valuesObj = formItem.getJSONObject(TAG_VALUES); if (valuesObj.has(TAG_ITEMS)) { return valuesObj.getJSONArray(TAG_ITEMS); } } return null; } /** * @param comboItems combo items object. * @return the string names. * @throws JSONException if something goes wrong. */ public static String[] comboItems2StringArray(JSONArray comboItems) throws JSONException { int length = comboItems.length(); String[] itemsArray = new String[length]; for (int i = 0; i < length; i++) { JSONObject itemObj = comboItems.getJSONObject(i); if (itemObj.has(TAG_ITEM)) { itemsArray[i] = itemObj.getString(TAG_ITEM).trim(); } else { itemsArray[i] = " - "; } } return itemsArray; } /** * Extract the combo values map. * * @param formItem the json object. * @return the map of combo items. * @throws JSONException if something goes wrong. */ public static LinkedHashMap<String, List<String>> extractComboValuesMap(JSONObject formItem) throws JSONException { LinkedHashMap<String, List<String>> valuesMap = new LinkedHashMap<String, List<String>>(); if (formItem.has(TAG_VALUES)) { JSONObject valuesObj = formItem.getJSONObject(TAG_VALUES); JSONArray names = valuesObj.names(); int length = names.length(); for (int i = 0; i < length; i++) { String name = names.getString(i); List<String> valuesList = new ArrayList<String>(); JSONArray itemsArray = valuesObj.getJSONArray(name); int length2 = itemsArray.length(); for (int j = 0; j < length2; j++) { JSONObject itemObj = itemsArray.getJSONObject(j); if (itemObj.has(TAG_ITEM)) { valuesList.add(itemObj.getString(TAG_ITEM).trim()); } else { valuesList.add(" - "); } } valuesMap.put(name, valuesList); } } return valuesMap; } /** * The tag object. */ public static class TagObject { /** * */ public String shortName; /** * */ public String longName; /** * */ public boolean hasForm; /** * */ public String jsonString; } }