OpenSRP/opensrp-client-anc

View on GitHub
opensrp-anc/src/main/java/org/smartregister/anc/library/util/ANCJsonFormUtils.java

Summary

Maintainability
F
1 wk
Test Coverage
package org.smartregister.anc.library.util;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.core.util.Pair;

import com.google.common.reflect.TypeToken;
import com.vijay.jsonwizard.activities.FormConfigurationJsonFormActivity;
import com.vijay.jsonwizard.constants.JsonFormConstants;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Triple;
import org.jeasy.rules.api.Facts;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.joda.time.LocalDate;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.smartregister.anc.library.AncLibrary;
import org.smartregister.anc.library.BuildConfig;
import org.smartregister.anc.library.R;
import org.smartregister.anc.library.activity.EditJsonFormActivity;
import org.smartregister.anc.library.domain.YamlConfigItem;
import org.smartregister.anc.library.domain.YamlConfigWrapper;
import org.smartregister.anc.library.model.ContactSummaryModel;
import org.smartregister.anc.library.model.Task;
import org.smartregister.clientandeventmodel.Client;
import org.smartregister.clientandeventmodel.Event;
import org.smartregister.clientandeventmodel.FormEntityConstants;
import org.smartregister.domain.Photo;
import org.smartregister.domain.ProfileImage;
import org.smartregister.domain.form.FormLocation;
import org.smartregister.domain.tag.FormTag;
import org.smartregister.location.helper.LocationHelper;
import org.smartregister.repository.AllSharedPreferences;
import org.smartregister.repository.EventClientRepository;
import org.smartregister.repository.ImageRepository;
import org.smartregister.util.AssetHandler;
import org.smartregister.util.FormUtils;
import org.smartregister.util.ImageUtils;
import org.smartregister.view.LocationPickerView;
import org.smartregister.view.activity.DrishtiApplication;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;

import timber.log.Timber;

/**
 * Created by keyman on 27/06/2018.
 */
public class ANCJsonFormUtils extends org.smartregister.util.JsonFormUtils {
    public static final String METADATA = "metadata";
    public static final String ENCOUNTER_TYPE = "encounter_type";
    public static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("dd-MM-yyyy");
    public static final SimpleDateFormat EDD_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd");
    public static final String READ_ONLY = "read_only";
    public static final int REQUEST_CODE_GET_JSON = 3432;
    private static final String TAG = ANCJsonFormUtils.class.getCanonicalName();

    public static boolean isFieldRequired(JSONObject fieldObject) throws JSONException {
        boolean isValueRequired = false;
        if (fieldObject.has(JsonFormConstants.V_REQUIRED)) {
            JSONObject valueRequired = fieldObject.getJSONObject(JsonFormConstants.V_REQUIRED);
            String value = valueRequired.getString(JsonFormConstants.VALUE);
            isValueRequired = Boolean.parseBoolean(value);
        }
        //Don't check required for hidden, toaster notes, spacer and label widgets
        return (!fieldObject.getString(JsonFormConstants.TYPE).equals(JsonFormConstants.LABEL) &&
                !fieldObject.getString(JsonFormConstants.TYPE).equals(JsonFormConstants.SPACER) &&
                !fieldObject.getString(JsonFormConstants.TYPE).equals(JsonFormConstants.TOASTER_NOTES) &&
                !fieldObject.getString(JsonFormConstants.TYPE).equals(JsonFormConstants.HIDDEN)) &&
                isValueRequired;
    }

    public static JSONObject getFormAsJson(JSONObject form, String formName, String id, String currentLocationId)
            throws Exception {
        if (form == null) {
            return null;
        }

        String entityId = id;
        form.getJSONObject(METADATA).put(ANCJsonFormUtils.ENCOUNTER_LOCATION, currentLocationId);

        if (ConstantsUtils.JsonFormUtils.ANC_REGISTER.equals(formName)) {
            if (StringUtils.isNotBlank(entityId)) {
                entityId = entityId.replace("-", "");
            }

            addRegistrationLocationHierarchyQuestions(form);
            // Inject opensrp id into the form
            JSONArray field = ANCJsonFormUtils.fields(form);
            JSONObject ancId = getFieldJSONObject(field, ConstantsUtils.JsonFormKeyUtils.ANC_ID);
            if (ancId != null) {
                ancId.remove(ANCJsonFormUtils.VALUE);
                ancId.put(ANCJsonFormUtils.VALUE, entityId);
            }

        } else if (ConstantsUtils.JsonFormUtils.ANC_CLOSE.equals(formName)) {
            if (StringUtils.isNotBlank(entityId)) {
                // Inject entity id into the remove form
                form.remove(ANCJsonFormUtils.ENTITY_ID);
                form.put(ENTITY_ID, entityId);
            }
        } else {
            Timber.tag(TAG).w("Unsupported form requested for launch %s", formName);
        }
        Timber.d("form is %s", form.toString());
        return form;
    }

    private static void addRegistrationLocationHierarchyQuestions(@NonNull JSONObject form) {
        try {
            JSONArray fields = com.vijay.jsonwizard.utils.FormUtils.getMultiStepFormFields(form);
            AncMetadata metadata = AncLibrary.getInstance().getAncMetadata();
            ArrayList<String> allLevels = metadata.getLocationLevels();
            ArrayList<String> healthFacilities = metadata.getHealthFacilityLevels();
            List<String> defaultLocation = LocationHelper.getInstance().generateDefaultLocationHierarchy(allLevels);
            List<String> defaultFacility = LocationHelper.getInstance().generateDefaultLocationHierarchy(healthFacilities);
            List<FormLocation> entireTree = LocationHelper.getInstance().generateLocationHierarchyTree(true, allLevels);
            String defaultLocationString = AssetHandler.javaToJsonString(defaultLocation, new TypeToken<List<String>>() {
            }.getType());

            String defaultFacilityString = AssetHandler.javaToJsonString(defaultFacility, new TypeToken<List<String>>() {
            }.getType());

            String entireTreeString = AssetHandler.javaToJsonString(entireTree, new TypeToken<List<FormLocation>>() {
            }.getType());

            updateLocationTree(fields, defaultLocationString, defaultFacilityString, entireTreeString);
        } catch (Exception e) {
            Timber.e(e, "JsonFormUtils --> addRegLocHierarchyQuestions");
        }
    }

    private static void updateLocationTree(@NonNull JSONArray fields,
                                           @NonNull String defaultLocationString,
                                           @NonNull String defaultFacilityString,
                                           @NonNull String entireTreeString) {
        AncMetadata ancMetadata = AncLibrary.getInstance().getAncMetadata();
        if (ancMetadata.getFieldsWithLocationHierarchy() != null && !ancMetadata.getFieldsWithLocationHierarchy().isEmpty()) {
            for (int i = 0; i < fields.length(); i++) {
                JSONObject widget = fields.optJSONObject(i);
                if (ancMetadata.getFieldsWithLocationHierarchy().contains(widget.optString(JsonFormConstants.KEY))) {
                    if (StringUtils.isNotBlank(entireTreeString)) {
                        addLocationTree(widget.optString(JsonFormConstants.KEY), widget, entireTreeString, JsonFormConstants.TREE);
                    }
                    if (StringUtils.isNotBlank(defaultFacilityString)) {
                        addLocationTreeDefault(widget.optString(JsonFormConstants.KEY), widget, defaultLocationString);
                    }
                }
            }
        }
    }

    private static void addLocationTree(@NonNull String widgetKey, @NonNull JSONObject widget, @NonNull String updateString, @NonNull String treeType) {
        try {
            if (widget.optString(JsonFormConstants.KEY).equals(widgetKey)) {
                widget.put(treeType, new JSONArray(updateString));
            }
        } catch (JSONException e) {
            Timber.e(e, "JsonFormUtils --> addLocationTree");
        }
    }

    private static void addLocationTreeDefault(@NonNull String widgetKey, @NonNull JSONObject widget, @NonNull String updateString) {
        addLocationTree(widgetKey, widget, updateString, JsonFormConstants.DEFAULT);
    }

    public static JSONObject getFieldJSONObject(JSONArray jsonArray, String key) {
        if (jsonArray == null || jsonArray.length() == 0) {
            return null;
        }

        for (int i = 0; i < jsonArray.length(); i++) {
            JSONObject jsonObject = ANCJsonFormUtils.getJSONObject(jsonArray, i);
            String keyVal = ANCJsonFormUtils.getString(jsonObject, ANCJsonFormUtils.KEY);
            if (keyVal != null && keyVal.equals(key)) {
                return jsonObject;
            }
        }
        return null;
    }

    public static Pair<Client, Event> processRegistrationForm(AllSharedPreferences allSharedPreferences, String jsonString) {
        try {
            Triple<Boolean, JSONObject, JSONArray> registrationFormParams = validateParameters(jsonString);

            if (!registrationFormParams.getLeft()) {
                return null;
            }

            JSONObject jsonForm = registrationFormParams.getMiddle();
            JSONArray fields = registrationFormParams.getRight();

            String entityId = getEntityId(jsonForm);
            String encounterType = ANCJsonFormUtils.getString(jsonForm, ENCOUNTER_TYPE);
            JSONObject metadata = ANCJsonFormUtils.getJSONObject(jsonForm, METADATA);
            addLastInteractedWith(fields);
            getDobStrings(fields);
            String previousVisitsMap = initializeFirstContactValues(fields);
            processLocationFields(fields);

            FormTag formTag = getFormTag(allSharedPreferences);

            Client baseClient = org.smartregister.util.JsonFormUtils.createBaseClient(fields, formTag, entityId);
            Event baseEvent = org.smartregister.util.JsonFormUtils
                    .createEvent(fields, metadata, formTag, entityId, encounterType, DBConstantsUtils.DEMOGRAPHIC_TABLE_NAME);

            if (previousVisitsMap != null) {
                baseEvent.addDetails(ConstantsUtils.JsonFormKeyUtils.PREVIOUS_VISITS_MAP, previousVisitsMap);
            }
            tagSyncMetadata(allSharedPreferences, baseEvent);// tag docs

            return Pair.create(baseClient, baseEvent);
        } catch (Exception e) {
            Timber.e(e, "JsonFormUtils --> processRegistrationForm");
            return null;
        }
    }

    protected static void processLocationFields(@NonNull JSONArray fields) throws JSONException {
        for (int i = 0; i < fields.length(); i++) {
            if (fields.optJSONObject(i).has(JsonFormConstants.TYPE) &&
                    fields.optJSONObject(i).optString(JsonFormConstants.TYPE).equals(JsonFormConstants.TREE))
                try {
                    String rawValue = fields.optJSONObject(i).optString(JsonFormConstants.VALUE);
                    if (StringUtils.isNotBlank(rawValue)) {
                        JSONArray valueArray = new JSONArray(rawValue);
                        if (valueArray.length() > 0) {
                            String lastLocationName = valueArray.optString(valueArray.length() - 1);
                            String lastLocationId = LocationHelper.getInstance().getOpenMrsLocationId(lastLocationName);
                            fields.optJSONObject(i).put(JsonFormConstants.VALUE, lastLocationId);
                        }
                    }
                } catch (NullPointerException e) {
                    Timber.e(e);
                } catch (IllegalArgumentException e) {
                    Timber.e(e);
                }
        }
    }

    public static Triple<Boolean, JSONObject, JSONArray> validateParameters(String jsonString) {

        JSONObject jsonForm = ANCJsonFormUtils.toJSONObject(jsonString);
        JSONArray fields = ANCJsonFormUtils.fields(jsonForm);

        return Triple.of(jsonForm != null && fields != null, jsonForm, fields);
    }

    @NotNull
    private static String getEntityId(JSONObject jsonForm) {
        String entityId = ANCJsonFormUtils.getString(jsonForm, ANCJsonFormUtils.ENTITY_ID);
        if (StringUtils.isBlank(entityId)) {
            entityId = ANCJsonFormUtils.generateRandomUUIDString();
        }
        return entityId;
    }

    private static void addLastInteractedWith(JSONArray fields) throws JSONException {
        JSONObject lastInteractedWith = new JSONObject();
        lastInteractedWith.put(ConstantsUtils.KeyUtils.KEY, DBConstantsUtils.KeyUtils.LAST_INTERACTED_WITH);
        lastInteractedWith.put(ConstantsUtils.KeyUtils.VALUE, Calendar.getInstance().getTimeInMillis());
        fields.put(lastInteractedWith);
    }

    private static void getDobStrings(JSONArray fields) throws JSONException {
        JSONObject dobUnknownObject = getFieldJSONObject(fields, DBConstantsUtils.KeyUtils.DOB_UNKNOWN);
        JSONArray options = ANCJsonFormUtils.getJSONArray(dobUnknownObject, ConstantsUtils.JsonFormKeyUtils.OPTIONS);
        JSONObject option = ANCJsonFormUtils.getJSONObject(options, 0);
        String dobUnKnownString = option != null ? option.getString(ANCJsonFormUtils.VALUE) : null;

        if (StringUtils.isNotBlank(dobUnKnownString)) {
            dobUnknownObject.put(ANCJsonFormUtils.VALUE, Boolean.valueOf(dobUnKnownString) ? 1 : 0);
        }
    }

    /***
     * Initializes the values in the mother details table used by contact containers
     * @param fields {@link JSONArray}
     * @return
     * @throws JSONException
     */
    private static String initializeFirstContactValues(@NonNull JSONArray fields) throws JSONException {
        String strGroup = null;

        int nextContact = 1;

        String nextContactDate = Utils.convertDateFormat(Calendar.getInstance().getTime(), Utils.DB_DF);

        if (ConstantsUtils.DueCheckStrategy.CHECK_FOR_FIRST_CONTACT.equals(Utils.getDueCheckStrategy())) {
            HashMap<String, HashMap<String, String>> previousVisitsMap = Utils.buildRepeatingGroupValues(fields, ConstantsUtils.JsonFormKeyUtils.PREVIOUS_VISITS);
            if (!previousVisitsMap.isEmpty()) {

                nextContact = previousVisitsMap.size() + 1;

                strGroup = ANCJsonFormUtils.gson.toJson(previousVisitsMap);

                Set<Map.Entry<String, HashMap<String, String>>> previousVisitsMapSet = previousVisitsMap.entrySet();

                HashMap<String, String> previousVisitsMapItem = new LinkedHashMap<>();

                for (Map.Entry<String, HashMap<String, String>> entry : previousVisitsMapSet) {
                    previousVisitsMapItem = entry.getValue();
                }

                JSONObject lastContactDateJSONObject = getFieldJSONObject(fields, DBConstantsUtils.KeyUtils.LAST_CONTACT_RECORD_DATE);
                lastContactDateJSONObject.put(ANCJsonFormUtils.VALUE, previousVisitsMapItem.get(ConstantsUtils.JsonFormKeyUtils.VISIT_DATE));
            }
        }
        JSONObject nextContactJSONObject = getFieldJSONObject(fields, DBConstantsUtils.KeyUtils.NEXT_CONTACT);
        if (nextContactJSONObject.has(JsonFormConstants.VALUE) &&
                "".equals(nextContactJSONObject.getString(JsonFormConstants.VALUE))) {
            nextContactJSONObject.put(ANCJsonFormUtils.VALUE, nextContact);
        }

        JSONObject nextContactDateJSONObject = getFieldJSONObject(fields, DBConstantsUtils.KeyUtils.NEXT_CONTACT_DATE);
        if (nextContactDateJSONObject.has(JsonFormConstants.VALUE) &&
                "".equals(nextContactDateJSONObject.getString(JsonFormConstants.VALUE))) {
            nextContactDateJSONObject.put(ANCJsonFormUtils.VALUE, nextContactDate);
        }

        return strGroup;
    }


    @NotNull
    public static FormTag getFormTag(AllSharedPreferences allSharedPreferences) {
        FormTag formTag = new FormTag();
        formTag.providerId = allSharedPreferences.fetchRegisteredANM();
        formTag.appVersion = BuildConfig.VERSION_CODE;
        formTag.databaseVersion = AncLibrary.getInstance().getDatabaseVersion();
        return formTag;
    }

    public static void tagSyncMetadata(AllSharedPreferences allSharedPreferences, Event event) {
        String providerId = allSharedPreferences.fetchRegisteredANM();
        event.setProviderId(providerId);
        event.setLocationId(allSharedPreferences.fetchDefaultLocalityId(providerId));
        event.setChildLocationId(getChildLocationId(event.getLocationId(), allSharedPreferences));
        event.setTeam(allSharedPreferences.fetchDefaultTeam(providerId));
        event.setTeamId(allSharedPreferences.fetchDefaultTeamId(providerId));
        //event.setVersion(BuildConfig.EVENT_VERSION);
        event.setClientApplicationVersion(BuildConfig.VERSION_CODE);
        event.setClientDatabaseVersion(AncLibrary.getInstance().getDatabaseVersion());
    }

    @Nullable
    public static String getChildLocationId(@NonNull String defaultLocationId, @NonNull AllSharedPreferences allSharedPreferences) {
        String currentLocality = allSharedPreferences.fetchCurrentLocality();

        if (StringUtils.isNotBlank(currentLocality)) {
            String currentLocalityId = LocationHelper.getInstance().getOpenMrsLocationId(currentLocality);
            if (StringUtils.isNotBlank(currentLocalityId) && !defaultLocationId.equals(currentLocalityId)) {
                return currentLocalityId;
            }
        }

        return null;
    }

    public static void mergeAndSaveClient(Client baseClient) throws Exception {
        JSONObject updatedClientJson = new JSONObject(org.smartregister.util.JsonFormUtils.gson.toJson(baseClient));

        JSONObject originalClientJsonObject =
                AncLibrary.getInstance().getEcSyncHelper().getClient(baseClient.getBaseEntityId());

        JSONObject mergedJson = org.smartregister.util.JsonFormUtils.merge(originalClientJsonObject, updatedClientJson);

        //TODO Save edit log ?

        AncLibrary.getInstance().getEcSyncHelper().addClient(baseClient.getBaseEntityId(), mergedJson);
    }

    public static void saveImage(String providerId, String entityId, String imageLocation) {
        OutputStream outputStream = null;
        try {
            if (StringUtils.isBlank(imageLocation)) {
                return;
            }

            File file = FileUtil.createFileFromPath(imageLocation);
            if (!file.exists()) {
                return;
            }

            Bitmap compressedBitmap = AncLibrary.getInstance().getCompressor().compressToBitmap(file);
            if (compressedBitmap == null || StringUtils.isBlank(providerId) || StringUtils.isBlank(entityId)) {
                return;
            }

            if (!entityId.isEmpty()) {
                final String absoluteFileName = DrishtiApplication.getAppDir() + File.separator + entityId + ".JPEG";

                File outputFile = FileUtil.createFileFromPath(absoluteFileName);
                outputStream = FileUtil.createFileOutputStream(outputFile);
                Bitmap.CompressFormat compressFormat = Bitmap.CompressFormat.JPEG;
                compressedBitmap.compress(compressFormat, 100, outputStream);
                // insert into the db
                ProfileImage profileImage = getProfileImage(providerId, entityId, absoluteFileName);
                ImageRepository imageRepository = AncLibrary.getInstance().getContext().imageRepository();
                imageRepository.add(profileImage);
            }

        } catch (FileNotFoundException e) {
            Timber.e("Failed to save static image to disk");
        } catch (IOException e) {
            Timber.e(e, " --> saveImage");
        } finally {
            if (outputStream != null) {
                try {
                    outputStream.close();
                } catch (IOException e) {
                    Timber.e("Failed to close static images output stream after attempting to write image");
                }
            }
        }
    }

    @NotNull
    private static ProfileImage getProfileImage(String providerId, String entityId, String absoluteFileName) {
        ProfileImage profileImage = new ProfileImage();
        profileImage.setImageid(UUID.randomUUID().toString());
        profileImage.setAnmId(providerId);
        profileImage.setEntityID(entityId);
        profileImage.setFilepath(absoluteFileName);
        profileImage.setFilecategory(ConstantsUtils.FileCategoryUtils.PROFILE_PIC);
        profileImage.setSyncStatus(ImageRepository.TYPE_Unsynced);
        return profileImage;
    }

    public static String getString(String jsonString, String field) {
        return ANCJsonFormUtils.getString(ANCJsonFormUtils.toJSONObject(jsonString), field);
    }

    public static String getFieldValue(String jsonString, String key) {
        JSONObject jsonForm = ANCJsonFormUtils.toJSONObject(jsonString);
        if (jsonForm == null) {
            return null;
        }

        JSONArray fields = ANCJsonFormUtils.fields(jsonForm);
        if (fields == null) {
            return null;
        }

        return ANCJsonFormUtils.getFieldValue(fields, key);

    }

    public static String getAutoPopulatedJsonEditRegisterFormString(Context context, Map<String, String> womanClient) {
        try {
            JSONObject form = FormUtils.getInstance(context).getFormJson(ConstantsUtils.JsonFormUtils.ANC_REGISTER);
            LocationPickerView lpv = createLocationPickerView(context);
            if (lpv != null) {
                lpv.init();
            }

            Timber.d("Form is %s", form.toString());

            if (form != null) {
                form.put(ANCJsonFormUtils.ENTITY_ID, womanClient.get(DBConstantsUtils.KeyUtils.BASE_ENTITY_ID));
                form.put(ANCJsonFormUtils.ENCOUNTER_TYPE, ConstantsUtils.EventTypeUtils.UPDATE_REGISTRATION);

                JSONObject metadata = form.getJSONObject(ANCJsonFormUtils.METADATA);
                String lastLocationId =
                        lpv != null ? LocationHelper.getInstance().getOpenMrsLocationId(lpv.getSelectedItem()) : "";

                metadata.put(ANCJsonFormUtils.ENCOUNTER_LOCATION, lastLocationId);

                form.put(ConstantsUtils.CURRENT_OPENSRP_ID, womanClient.get(DBConstantsUtils.KeyUtils.ANC_ID).replace("-", ""));

                //inject opensrp id into the form
                JSONObject stepOne = form.getJSONObject(ANCJsonFormUtils.STEP1);
                JSONArray jsonArray = stepOne.getJSONArray(ANCJsonFormUtils.FIELDS);
                for (int i = 0; i < jsonArray.length(); i++) {
                    JSONObject jsonObject = jsonArray.getJSONObject(i);

                    processPopulatableFields(womanClient, jsonObject);

                }

                return form.toString();
            }
        } catch (Exception e) {
            Timber.e(e, "JsonFormUtils --> getAutoPopulatedJsonEditRegisterFormString");
        }

        return "";
    }

    private static LocationPickerView createLocationPickerView(Context context) {
        try {
            return new LocationPickerView(context);
        } catch (Exception e) {
            Timber.e(e, "JsonFormUtils --> createLocationPickerView");
            return null;
        }
    }

    protected static void processPopulatableFields(Map<String, String> womanClient, JSONObject jsonObject)
            throws JSONException {

        AncMetadata ancMetadata = AncLibrary.getInstance().getAncMetadata();

        if (jsonObject.getString(ANCJsonFormUtils.KEY).equalsIgnoreCase(ConstantsUtils.JsonFormKeyUtils.DOB_ENTERED)) {
            getDobUsingEdd(womanClient, jsonObject, DBConstantsUtils.KeyUtils.DOB);

        } else if (jsonObject.getString(ANCJsonFormUtils.KEY).equalsIgnoreCase(DBConstantsUtils.KeyUtils.HOME_ADDRESS)) {
            String homeAddress = womanClient.get(DBConstantsUtils.KeyUtils.HOME_ADDRESS);
            jsonObject.put(ANCJsonFormUtils.VALUE, homeAddress);

        } else if (jsonObject.getString(ANCJsonFormUtils.KEY).equalsIgnoreCase(ConstantsUtils.WOM_IMAGE)) {
            getPhotoFieldValue(womanClient, jsonObject);
        } else if (jsonObject.getString(ANCJsonFormUtils.KEY).equalsIgnoreCase(DBConstantsUtils.KeyUtils.DOB_UNKNOWN)) {
            jsonObject.put(ANCJsonFormUtils.READ_ONLY, false);
            JSONObject optionsObject = jsonObject.getJSONArray(ConstantsUtils.JsonFormKeyUtils.OPTIONS).getJSONObject(0);
            optionsObject.put(ANCJsonFormUtils.VALUE, womanClient.get(DBConstantsUtils.KeyUtils.DOB_UNKNOWN));

        } else if (jsonObject.getString(ANCJsonFormUtils.KEY).equalsIgnoreCase(ConstantsUtils.KeyUtils.AGE_ENTERED)) {
            jsonObject.put(ANCJsonFormUtils.READ_ONLY, false);
            if (StringUtils.isNotBlank(womanClient.get(DBConstantsUtils.KeyUtils.DOB))) {
                jsonObject.put(ANCJsonFormUtils.VALUE, Utils.getAgeFromDate(womanClient.get(DBConstantsUtils.KeyUtils.DOB)));
            }
        } else if (ancMetadata != null && ancMetadata.getFieldsWithLocationHierarchy() != null &&
                ancMetadata.getFieldsWithLocationHierarchy().contains(jsonObject.optString(ANCJsonFormUtils.KEY))) {
            reverseLocationTree(jsonObject, womanClient.get(jsonObject.optString(ANCJsonFormUtils.KEY)));
        } else if (jsonObject.getString(ANCJsonFormUtils.KEY).equalsIgnoreCase(DBConstantsUtils.KeyUtils.EDD)) {
            formatEdd(womanClient, jsonObject, DBConstantsUtils.KeyUtils.EDD);

        } else if (jsonObject.getString(ANCJsonFormUtils.KEY).equalsIgnoreCase(ConstantsUtils.JsonFormKeyUtils.ANC_ID)) {
            jsonObject.put(ANCJsonFormUtils.VALUE, womanClient.get(DBConstantsUtils.KeyUtils.ANC_ID).replace("-", ""));
        }  else if (womanClient.containsKey(jsonObject.getString(ANCJsonFormUtils.KEY))) {
            jsonObject.put(ANCJsonFormUtils.READ_ONLY, false);
            jsonObject.put(ANCJsonFormUtils.VALUE, womanClient.get(jsonObject.getString(ANCJsonFormUtils.KEY)));
        } else {
            Timber.e("ERROR:: Unprocessed Form Object Key %s", jsonObject.getString(ANCJsonFormUtils.KEY));
        }
    }

    private static void reverseLocationTree(@NonNull JSONObject jsonObject, @Nullable String entity) throws JSONException {
        List<String> entityHierarchy = null;
        if (entity != null) {
            if (ConstantsUtils.OTHER.equalsIgnoreCase(entity)) {
                entityHierarchy = new ArrayList<>();
                entityHierarchy.add(entity);
            } else {
                String locationId = LocationHelper.getInstance().getOpenMrsLocationId(entity);
                entityHierarchy = LocationHelper.getInstance().getOpenMrsLocationHierarchy(locationId, false);
            }
        }
        ArrayList<String> allLevels = AncLibrary.getInstance().getAncMetadata().getHealthFacilityLevels();
        List<FormLocation> entireTree = LocationHelper.getInstance().generateLocationHierarchyTree(true, allLevels);
        String entireTreeString = AssetHandler.javaToJsonString(entireTree, new TypeToken<List<FormLocation>>() {
        }.getType());
        String facilityHierarchyString = AssetHandler.javaToJsonString(entityHierarchy, new TypeToken<List<String>>() {
        }.getType());
        if (StringUtils.isNotBlank(facilityHierarchyString)) {
            jsonObject.put(JsonFormConstants.VALUE, facilityHierarchyString);
            jsonObject.put(JsonFormConstants.TREE, new JSONArray(entireTreeString));
        }
    }

    private static void getDobUsingEdd(Map<String, String> womanClient, JSONObject jsonObject, String birthDate)
            throws JSONException {
        String dobString = womanClient.get(birthDate);
        if (StringUtils.isNotBlank(dobString)) {
            Date dob = Utils.dobStringToDate(dobString);
            if (dob != null) {
                jsonObject.put(ANCJsonFormUtils.VALUE, DATE_FORMAT.format(dob));
            }
        }
    }

    private static void getPhotoFieldValue(Map<String, String> womanClient, JSONObject jsonObject) throws JSONException {
        Photo photo = ImageUtils.profilePhotoByClientID(womanClient.get(DBConstantsUtils.KeyUtils.BASE_ENTITY_ID),
                Utils.getProfileImageResourceIdentifier());

        if (photo != null && StringUtils.isNotBlank(photo.getFilePath())) {
            jsonObject.put(ANCJsonFormUtils.VALUE, photo.getFilePath());

        }
    }

    private static void formatEdd(Map<String, String> womanClient, JSONObject jsonObject, String eddDate)
            throws JSONException {
        String eddString = womanClient.get(eddDate);
        if (StringUtils.isNotBlank(eddString)) {
            Date edd = Utils.dobStringToDate(eddString);
            if (edd != null) {
                jsonObject.put(ANCJsonFormUtils.VALUE, EDD_DATE_FORMAT.format(edd));
            }
        }
    }

    public static void startFormForEdit(Activity context, int jsonFormActivityRequestCode, String metaData) {
        Intent intent = new Intent(context, EditJsonFormActivity.class);
        intent.putExtra(ConstantsUtils.IntentKeyUtils.JSON, metaData);
        intent.putExtra(JsonFormConstants.PERFORM_FORM_TRANSLATION, true);
        Timber.d("form is %s", metaData);
        context.startActivityForResult(intent, jsonFormActivityRequestCode);
    }

    public static Triple<Boolean, Event, Event> saveRemovedFromANCRegister(AllSharedPreferences allSharedPreferences, String jsonString, String providerId) {
        try {
            boolean isDeath = false;
            Triple<Boolean, JSONObject, JSONArray> registrationFormParams = validateParameters(jsonString);

            if (!registrationFormParams.getLeft()) {
                return null;
            }

            JSONObject jsonForm = registrationFormParams.getMiddle();
            JSONArray fields = registrationFormParams.getRight();

            String encounterType = ANCJsonFormUtils.getString(jsonForm, ENCOUNTER_TYPE);
            JSONObject metadata = ANCJsonFormUtils.getJSONObject(jsonForm, METADATA);

            String encounterLocation = null;

            try {
                encounterLocation = metadata.getString(ConstantsUtils.JsonFormKeyUtils.ENCOUNTER_LOCATION);
            } catch (JSONException e) {
                Timber.e(e, "JsonFormUtils --> saveRemovedFromANCRegister --> getEncounterLocation");
            }

            Date encounterDate = new Date();
            String entityId = ANCJsonFormUtils.getString(jsonForm, ANCJsonFormUtils.ENTITY_ID);

            Event event = (Event) new Event().withBaseEntityId(entityId) //should be different for main and subform
                    .withEventDate(encounterDate).withEventType(encounterType).withLocationId(encounterLocation)
                    .withProviderId(providerId).withEntityType(DBConstantsUtils.DEMOGRAPHIC_TABLE_NAME)
                    .withFormSubmissionId(ANCJsonFormUtils.generateRandomUUIDString()).withDateCreated(new Date());
            tagSyncMetadata(allSharedPreferences, event);

            for (int i = 0; i < fields.length(); i++) {
                JSONObject jsonObject = ANCJsonFormUtils.getJSONObject(fields, i);

                String value = ANCJsonFormUtils.getString(jsonObject, ANCJsonFormUtils.VALUE);
                if (StringUtils.isNotBlank(value)) {
                    ANCJsonFormUtils.addObservation(event, jsonObject);
                    if (jsonObject.get(ANCJsonFormUtils.KEY).equals(ConstantsUtils.JsonFormKeyUtils.ANC_CLOSE_REASON)) {
                        isDeath = "Woman Died".equalsIgnoreCase(value);
                    }
                }
            }

            Iterator<?> keys = metadata.keys();

            while (keys.hasNext()) {
                String key = (String) keys.next();
                JSONObject jsonObject = ANCJsonFormUtils.getJSONObject(metadata, key);
                String value = ANCJsonFormUtils.getString(jsonObject, ANCJsonFormUtils.VALUE);
                if (StringUtils.isNotBlank(value)) {
                    String entityVal = ANCJsonFormUtils.getString(jsonObject, ANCJsonFormUtils.OPENMRS_ENTITY);
                    if (entityVal != null) {
                        if (entityVal.equals(ANCJsonFormUtils.CONCEPT)) {
                            ANCJsonFormUtils.addToJSONObject(jsonObject, ANCJsonFormUtils.KEY, key);
                            ANCJsonFormUtils.addObservation(event, jsonObject);

                        } else if (entityVal.equals(ANCJsonFormUtils.ENCOUNTER)) {
                            String entityIdVal = ANCJsonFormUtils.getString(jsonObject, ANCJsonFormUtils.OPENMRS_ENTITY_ID);
                            if (entityIdVal.equals(FormEntityConstants.Encounter.encounter_date.name())) {
                                Date eDate = ANCJsonFormUtils.formatDate(value, false);
                                if (eDate != null) {
                                    event.setEventDate(eDate);
                                }
                            }
                        }
                    }
                }
            }

            //Update Child Entity to include death date
            Event updateChildDetailsEvent =
                    (Event) new Event().withBaseEntityId(entityId) //should be different for main and subform
                            .withEventDate(encounterDate).withEventType(ConstantsUtils.EventTypeUtils.UPDATE_REGISTRATION)
                            .withLocationId(encounterLocation).withProviderId(providerId)
                            .withEntityType(DBConstantsUtils.DEMOGRAPHIC_TABLE_NAME).withFormSubmissionId(ANCJsonFormUtils.generateRandomUUIDString())
                            .withDateCreated(new Date());
            tagSyncMetadata(allSharedPreferences, updateChildDetailsEvent);

            return Triple.of(isDeath, event, updateChildDetailsEvent);
        } catch (Exception e) {
            Timber.e(e, "JsonFormUtils --> saveRemovedFromANCRegister");
        }
        return null;
    }

    public static void launchANCCloseForm(Activity activity) {
        try {
            Intent intent = new Intent(activity, FormConfigurationJsonFormActivity.class);
            JSONObject form = new com.vijay.jsonwizard.utils.FormUtils().getFormJsonFromRepositoryOrAssets(activity.getApplicationContext(), ConstantsUtils.JsonFormUtils.ANC_CLOSE);
            if (form != null) {
                form.put(ConstantsUtils.JsonFormKeyUtils.ENTITY_ID, activity.getIntent().getStringExtra(ConstantsUtils.IntentKeyUtils.BASE_ENTITY_ID));
                intent.putExtra(ConstantsUtils.IntentKeyUtils.JSON, form.toString());
                intent.putExtra(JsonFormConstants.PERFORM_FORM_TRANSLATION, true);
                activity.startActivityForResult(intent, ANCJsonFormUtils.REQUEST_CODE_GET_JSON);
            }
        } catch (Exception e) {
            Timber.e(e, "JsonFormUtils --> launchANCCloseForm");
        }
    }

    public static void launchSiteCharacteristicsForm(Activity activity) {
        try {
            Intent intent = new Intent(activity, FormConfigurationJsonFormActivity.class);
            JSONObject form = new com.vijay.jsonwizard.utils.FormUtils().getFormJsonFromRepositoryOrAssets(activity.getApplicationContext(), ConstantsUtils.JsonFormUtils.ANC_SITE_CHARACTERISTICS);
            if (form != null) {
                form.put(ConstantsUtils.JsonFormKeyUtils.ENTITY_ID,
                        activity.getIntent().getStringExtra(ConstantsUtils.IntentKeyUtils.BASE_ENTITY_ID));
                intent.putExtra(ConstantsUtils.IntentKeyUtils.JSON, form.toString());
                intent.putExtra(JsonFormConstants.PERFORM_FORM_TRANSLATION, true);
                activity.startActivityForResult(intent, ANCJsonFormUtils.REQUEST_CODE_GET_JSON);
            }
        } catch (Exception e) {
            Timber.e(e, "JsonFormUtils --> launchSiteCharacteristicsForm");
        }
    }

    public static Map<String, String> processSiteCharacteristics(String jsonString) {
        try {
            Triple<Boolean, JSONObject, JSONArray> registrationFormParams = validateParameters(jsonString);
            if (!registrationFormParams.getLeft()) {
                return null;
            }

            Map<String, String> settings = new HashMap<>();
            JSONArray fields =
                    registrationFormParams.getMiddle().getJSONObject(ANCJsonFormUtils.STEP1).getJSONArray(ANCJsonFormUtils.FIELDS);

            for (int i = 0; i < fields.length(); i++) {
                if (!"label".equals(fields.getJSONObject(i).getString(ConstantsUtils.KeyUtils.TYPE))) {
                    settings.put(fields.getJSONObject(i).getString(ConstantsUtils.KeyUtils.KEY),
                            StringUtils.isBlank(fields.getJSONObject(i).getString(ConstantsUtils.KeyUtils.VALUE)) ? "0" :
                                    fields.getJSONObject(i).getString(ConstantsUtils.KeyUtils.VALUE));
                }
            }

            return settings;
        } catch (Exception e) {
            Timber.e(e, "JsonFormUtils --> processSiteCharacteristics");
            return null;
        }
    }

    public static String getAutoPopulatedSiteCharacteristicsEditFormString(Context context,
                                                                           Map<String, String> characteristics) {
        try {
            JSONObject form = FormUtils.getInstance(context).getFormJson(ConstantsUtils.JsonFormUtils.ANC_SITE_CHARACTERISTICS);
            Timber.d("Form is %s", form.toString());
            if (form != null) {
                form.put(ANCJsonFormUtils.ENCOUNTER_TYPE, ConstantsUtils.EventTypeUtils.SITE_CHARACTERISTICS);

                JSONObject stepOne = form.getJSONObject(ANCJsonFormUtils.STEP1);
                JSONArray jsonArray = stepOne.getJSONArray(ANCJsonFormUtils.FIELDS);
                for (int i = 0; i < jsonArray.length(); i++) {
                    JSONObject jsonObject = jsonArray.getJSONObject(i);
                    if (characteristics.containsKey(jsonObject.getString(ANCJsonFormUtils.KEY))) {
                        jsonObject.put(ANCJsonFormUtils.READ_ONLY, false);
                        jsonObject.put(ANCJsonFormUtils.VALUE,
                                "true".equals(characteristics.get(jsonObject.getString(ANCJsonFormUtils.KEY))) ? "1" : "0");
                    }

                }

                return form.toString();
            }
        } catch (Exception e) {
            Timber.e(e, "JsonFormUtils --> getAutoPopulatedSiteCharacteristicsEditFormString");
        }

        return "";
    }

    public static Pair<Event, Event> createVisitAndUpdateEvent(List<String> formSubmissionIDs,
                                                               Map<String, String> womanDetails) {
        if (formSubmissionIDs.size() < 1 && womanDetails.get(ConstantsUtils.REFERRAL) == null) {
            return null;
        }

        try {
            String baseEntityId = womanDetails.get(DBConstantsUtils.KeyUtils.BASE_ENTITY_ID);

            Event contactVisitEvent = Utils.createContactVisitEvent(formSubmissionIDs, womanDetails, String.valueOf(getOpenTasks(baseEntityId)));

            //Update client
            EventClientRepository db = AncLibrary.getInstance().getEventClientRepository();

            JSONObject clientForm = db.getClientByBaseEntityId(baseEntityId);
            JSONObject attributes = clientForm.getJSONObject(ConstantsUtils.JsonFormKeyUtils.ATTRIBUTES);
            attributes.put(DBConstantsUtils.KeyUtils.NEXT_CONTACT, womanDetails.get(DBConstantsUtils.KeyUtils.NEXT_CONTACT));
            attributes.put(DBConstantsUtils.KeyUtils.NEXT_CONTACT_DATE, womanDetails.get(DBConstantsUtils.KeyUtils.NEXT_CONTACT_DATE));
            attributes.put(DBConstantsUtils.KeyUtils.LAST_CONTACT_RECORD_DATE,
                    womanDetails.get(DBConstantsUtils.KeyUtils.LAST_CONTACT_RECORD_DATE));
            attributes.put(DBConstantsUtils.KeyUtils.CONTACT_STATUS, womanDetails.get(DBConstantsUtils.KeyUtils.CONTACT_STATUS));
            attributes.put(DBConstantsUtils.KeyUtils.YELLOW_FLAG_COUNT, womanDetails.get(DBConstantsUtils.KeyUtils.YELLOW_FLAG_COUNT));
            attributes.put(DBConstantsUtils.KeyUtils.RED_FLAG_COUNT, womanDetails.get(DBConstantsUtils.KeyUtils.RED_FLAG_COUNT));
            attributes.put(DBConstantsUtils.KeyUtils.EDD, womanDetails.get(DBConstantsUtils.KeyUtils.EDD));
            attributes.put(DBConstantsUtils.KeyUtils.ALT_NAME, womanDetails.get(DBConstantsUtils.KeyUtils.ALT_NAME));
            attributes.put(DBConstantsUtils.KeyUtils.PHONE_NUMBER, womanDetails.get(DBConstantsUtils.KeyUtils.PHONE_NUMBER));
            attributes.put(DBConstantsUtils.KeyUtils.ALT_PHONE_NUMBER, womanDetails.get(DBConstantsUtils.KeyUtils.ALT_PHONE_NUMBER));
            clientForm.put(ConstantsUtils.JsonFormKeyUtils.ATTRIBUTES, attributes);

            db.addorUpdateClient(baseEntityId, clientForm);

            Event updateClientEvent = createUpdateClientDetailsEvent(baseEntityId);

            return Pair.create(contactVisitEvent, updateClientEvent);

        } catch (Exception e) {
            Timber.e(e, " --> createContactVisitEvent");
            return null;
        }

    }

    public static Date getContactStartDate(String contactStartDate) {
        try {
            return new LocalDate(contactStartDate).toDate();
        } catch (Exception e) {
            return new LocalDate().toDate();
        }
    }

    private static JSONArray getOpenTasks(String baseEntityId) {
        List<Task> openTasks = AncLibrary.getInstance().getContactTasksRepository().getOpenTasks(baseEntityId);
        JSONArray openTaskArray = new JSONArray();
        if (openTasks != null && openTasks.size() > 0) {
            for (Task task : openTasks) {
                openTaskArray.put(task.getValue());
            }
        }
        return openTaskArray;
    }

    protected static Event createUpdateClientDetailsEvent(String baseEntityId) {

        Event updateChildDetailsEvent = (Event) new Event().withBaseEntityId(baseEntityId).withEventDate(new Date())
                .withEventType(ConstantsUtils.EventTypeUtils.UPDATE_REGISTRATION).withEntityType(DBConstantsUtils.DEMOGRAPHIC_TABLE_NAME)
                .withFormSubmissionId(ANCJsonFormUtils.generateRandomUUIDString()).withDateCreated(new Date());

        ANCJsonFormUtils
                .tagSyncMetadata(AncLibrary.getInstance().getContext().allSharedPreferences(), updateChildDetailsEvent);

        return updateChildDetailsEvent;
    }

    public static Event processContactFormEvent(JSONObject jsonForm, String baseEntityId) {
        AllSharedPreferences allSharedPreferences = AncLibrary.getInstance().getContext().allSharedPreferences();
        JSONArray fields = getMultiStepFormFields(jsonForm);

        String entityId = getString(jsonForm, ANCJsonFormUtils.ENTITY_ID);
        if (StringUtils.isBlank(entityId)) {
            entityId = baseEntityId;
        }

        String encounterType = getString(jsonForm, ENCOUNTER_TYPE);
        JSONObject metadata = getJSONObject(jsonForm, METADATA);

        FormTag formTag = getFormTag(allSharedPreferences);
        Event baseEvent = org.smartregister.util.JsonFormUtils
                .createEvent(fields, metadata, formTag, entityId, encounterType, DBConstantsUtils.DEMOGRAPHIC_TABLE_NAME);

        tagSyncMetadata(allSharedPreferences, baseEvent);// tag docs

        return baseEvent;
    }

    public static JSONObject readJsonFromAsset(Context context, String filePath) throws Exception {
        InputStream inputStream = context.getAssets().open(filePath + ".json");
        BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
        String jsonString;
        StringBuilder stringBuilder = new StringBuilder();
        while ((jsonString = reader.readLine()) != null) {
            stringBuilder.append(jsonString);
        }
        inputStream.close();
        return new JSONObject(stringBuilder.toString());
    }

    /**
     * Gets an expansion panel {@link JSONObject} value then check whether the test/tasks was `ordered` or `not done`.
     * If any either of this is selected then we mark it as not complete.
     *
     * @param field {@link JSONObject}
     * @return isComplete {@link Boolean}
     */
    public static boolean checkIfTaskIsComplete(JSONObject field) {
        boolean isComplete = true;
        try {
            if (field != null && field.has(JsonFormConstants.VALUE)) {
                JSONArray value = field.getJSONArray(JsonFormConstants.VALUE);
                if (value.length() > 1) {
                    JSONObject valueField = value.getJSONObject(0);
                    if (valueField != null && valueField.has(JsonFormConstants.VALUES)) {
                        JSONArray values = valueField.getJSONArray(JsonFormConstants.VALUES);
                        if (values.length() > 0) {
                            String selectedValue = values.getString(0);
                            if (selectedValue.contains(JsonFormConstants.AncRadioButtonOptionTypesUtils.ORDERED) || selectedValue.contains(JsonFormConstants.AncRadioButtonOptionTypesUtils.NOT_DONE)) {
                                isComplete = false;
                            }
                        }
                    }
                }
            }
        } catch (JSONException e) {
            Timber.e(e, " --> checkIfTaskIsComplete");
        }
        return isComplete;
    }

    public List<ContactSummaryModel> generateNextContactSchedule(String edd, List<String> contactSchedule,
                                                                 Integer lastContactSequence) {
        List<ContactSummaryModel> contactDates = new ArrayList<>();
        Integer contactSequence = lastContactSequence;
        if (StringUtils.isNotBlank(edd)) {
            LocalDate localDate = new LocalDate(edd);
            LocalDate lmpDate = localDate.minusWeeks(ConstantsUtils.DELIVERY_DATE_WEEKS);

            for (String contactWeeks : contactSchedule) {
                contactDates.add(new ContactSummaryModel(String.format(
                        AncLibrary.getInstance().getContext().getStringResource(R.string.contact_number),
                        contactSequence++),
                        Utils.convertDateFormat(lmpDate.plusWeeks(Integer.valueOf(contactWeeks)).toDate(),
                                Utils.CONTACT_SUMMARY_DF), lmpDate.plusWeeks(Integer.valueOf(contactWeeks)).toDate(),
                        contactWeeks));
            }
        }
        return contactDates;
    }

    /**
     * Creates and populates a constraint view to add the contacts tab view instead of using recycler views which introduce
     * lots of scroll complexities
     *
     * @param data
     * @param facts
     * @param position
     * @param context
     * @return constraintLayout
     */
    @NonNull
    public ConstraintLayout createListViewItems(List<YamlConfigWrapper> data, Facts facts, int position, Context context) {
        YamlConfigItem yamlConfigItem = data.get(position).getYamlConfigItem();

        ANCJsonFormUtils.Template template = getTemplate(yamlConfigItem.getTemplate());
        String output = "";
        if (!TextUtils.isEmpty(template.detail)) {
            output = Utils.fillTemplate(template.detail, facts);
        }

        LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        ConstraintLayout constraintLayout =
                (ConstraintLayout) inflater.inflate(R.layout.previous_contacts_preview_row, null);
        TextView sectionDetailTitle = constraintLayout.findViewById(R.id.overview_section_details_left);
        TextView sectionDetails = constraintLayout.findViewById(R.id.overview_section_details_right);


        sectionDetailTitle.setText(template.title);
        sectionDetails.setText(output);//Perhaps refactor to use Json Form Parser Implementation

        if (AncLibrary.getInstance().getAncRulesEngineHelper().getRelevance(facts, yamlConfigItem.getIsRedFont())) {
            sectionDetailTitle.setTextColor(context.getResources().getColor(R.color.overview_font_red));
            sectionDetails.setTextColor(context.getResources().getColor(R.color.overview_font_red));
        } else {
            sectionDetailTitle.setTextColor(context.getResources().getColor(R.color.overview_font_left));
            sectionDetails.setTextColor(context.getResources().getColor(R.color.overview_font_right));
        }

        sectionDetailTitle.setVisibility(View.VISIBLE);
        sectionDetails.setVisibility(View.VISIBLE);
        return constraintLayout;
    }

    public Template getTemplate(String rawTemplate) {
        Template template = new Template();

        if (rawTemplate.contains(":")) {
            String[] templateArray = rawTemplate.split(":");
            if (templateArray.length == 1) {
                template.title = templateArray[0].trim();
            } else if (templateArray.length > 1) {
                template.title = templateArray[0].trim();
                template.detail = templateArray[1].trim();
            }
        } else {
            template.title = rawTemplate;
            template.detail = "Yes";
        }

        return template;
    }

    public class Template {
        public String title = "";
        public String detail = "";
    }
}