org.projectbuendia.client.ui.patientcreation.PatientCreationController.java Source code

Java tutorial

Introduction

Here is the source code for org.projectbuendia.client.ui.patientcreation.PatientCreationController.java

Source

// Copyright 2015 The Project Buendia Authors
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License.  You may obtain a copy
// of the License at: http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software distrib-
// uted under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES
// OR CONDITIONS OF ANY KIND, either express or implied.  See the License for
// specific language governing permissions and limitations under the License.

package org.projectbuendia.client.ui.patientcreation;

import com.android.volley.VolleyError;
import com.google.common.base.Optional;

import org.joda.time.DateTime;
import org.joda.time.LocalDate;
import org.projectbuendia.client.App;
import org.projectbuendia.client.R;
import org.projectbuendia.client.data.app.AppLocationTree;
import org.projectbuendia.client.data.app.AppModel;
import org.projectbuendia.client.data.app.AppPatient;
import org.projectbuendia.client.data.app.AppPatientDelta;
import org.projectbuendia.client.events.CrudEventBus;
import org.projectbuendia.client.events.data.AppLocationTreeFetchedEvent;
import org.projectbuendia.client.events.data.PatientAddFailedEvent;
import org.projectbuendia.client.events.data.SingleItemCreatedEvent;
import org.projectbuendia.client.events.data.SingleItemFetchFailedEvent;
import org.projectbuendia.client.model.Zone;
import org.projectbuendia.client.utils.LocaleSelector;
import org.projectbuendia.client.utils.Logger;
import org.projectbuendia.client.utils.Utils;

/** Controller for {@link PatientCreationActivity}. */
final class PatientCreationController {

    private static final Logger LOG = Logger.create();

    static final int AGE_UNKNOWN = 0;
    static final int AGE_YEARS = 1;
    static final int AGE_MONTHS = 2;

    static final int SEX_UNKNOWN = 0;
    static final int SEX_MALE = 1;
    static final int SEX_FEMALE = 2;

    public interface Ui {

        static final int FIELD_UNKNOWN = 0;
        static final int FIELD_ID = 1;
        static final int FIELD_GIVEN_NAME = 2;
        static final int FIELD_FAMILY_NAME = 3;
        static final int FIELD_AGE = 4;
        static final int FIELD_AGE_UNITS = 5;
        static final int FIELD_SEX = 6;
        static final int FIELD_LOCATION = 7;
        static final int FIELD_ADMISSION_DATE = 8;
        static final int FIELD_SYMPTOMS_ONSET_DATE = 9;

        void setLocationTree(AppLocationTree locationTree);

        /** Adds a validation error message for a specific field. */
        void showValidationError(int field, int messageResource, String... messageArgs);

        /** Clears the validation error messages from all fields. */
        void clearValidationErrors();

        /** Invoked when the server RPC to create a patient fails. */
        void showErrorMessage(int errorResource);

        /** Invoked when the server RPC to create a patient fails. */
        void showErrorMessage(String errorString);

        /** Invoked when the server RPC to create a patient succeeds. */
        void quitActivity();
    }

    private final Ui mUi;
    private final CrudEventBus mCrudEventBus;
    private final AppModel mModel;

    private final EventSubscriber mEventBusSubscriber;

    private AppLocationTree mLocationTree;

    public PatientCreationController(Ui ui, CrudEventBus crudEventBus, AppModel model) {
        mUi = ui;
        mCrudEventBus = crudEventBus;
        mModel = model;
        mEventBusSubscriber = new EventSubscriber();
    }

    /**
     * Initializes the controller, setting async operations going to collect data required by the
     * UI.
     */
    public void init() {
        mCrudEventBus.register(mEventBusSubscriber);
        mModel.fetchLocationTree(mCrudEventBus, LocaleSelector.getCurrentLocale().getLanguage());
    }

    /** Releases any resources used by the controller. */
    public void suspend() {
        mCrudEventBus.unregister(mEventBusSubscriber);
        if (mLocationTree != null) {
            mLocationTree.close();
        }
    }

    public boolean createPatient(String id, String givenName, String familyName, String age, int ageUnits, int sex,
            LocalDate admissionDate, LocalDate symptomsOnsetDate, String locationUuid) {
        // Validate the input.
        mUi.clearValidationErrors();
        boolean hasValidationErrors = false;
        if (id == null || id.equals("")) {
            mUi.showValidationError(Ui.FIELD_ID, R.string.patient_validation_missing_id);
            hasValidationErrors = true;
        }
        if (age == null || age.equals("")) {
            mUi.showValidationError(Ui.FIELD_AGE, R.string.patient_validation_missing_age);
            hasValidationErrors = true;
        }
        if (admissionDate == null) {
            mUi.showValidationError(Ui.FIELD_ADMISSION_DATE, R.string.patient_validation_missing_admission_date);
            hasValidationErrors = true;
        }
        int ageInt = 0;
        try {
            ageInt = Integer.parseInt(age);
        } catch (NumberFormatException e) {
            mUi.showValidationError(Ui.FIELD_AGE, R.string.patient_validation_whole_number_age_required);
            hasValidationErrors = true;
        }
        if (ageInt < 0) {
            mUi.showValidationError(Ui.FIELD_AGE, R.string.patient_validation_negative_age);
            hasValidationErrors = true;
        }
        if (ageUnits != AGE_YEARS && ageUnits != AGE_MONTHS) {
            mUi.showValidationError(Ui.FIELD_AGE_UNITS, R.string.patient_validation_select_years_or_months);
            hasValidationErrors = true;
        }
        if (sex != SEX_MALE && sex != SEX_FEMALE) {
            mUi.showValidationError(Ui.FIELD_SEX, R.string.patient_validation_select_gender);
            hasValidationErrors = true;
        }
        if (admissionDate != null && admissionDate.isAfter(LocalDate.now())) {
            mUi.showValidationError(Ui.FIELD_ADMISSION_DATE, R.string.patient_validation_future_admission_date);
            hasValidationErrors = true;
        }
        if (symptomsOnsetDate != null && symptomsOnsetDate.isAfter(LocalDate.now())) {
            mUi.showValidationError(Ui.FIELD_SYMPTOMS_ONSET_DATE, R.string.patient_validation_future_onset_date);
            hasValidationErrors = true;
        }

        Utils.logUserAction("add_patient_submitted", "valid", "" + !hasValidationErrors);
        if (hasValidationErrors) {
            return false;
        }

        AppPatientDelta patientDelta = new AppPatientDelta();
        patientDelta.id = Optional.of(id);
        patientDelta.givenName = Optional.of(Utils.nameOrUnknown(givenName));
        patientDelta.familyName = Optional.of(Utils.nameOrUnknown(familyName));
        patientDelta.birthdate = Optional.of(getBirthdateFromAge(ageInt, ageUnits));
        patientDelta.gender = Optional.of(sex);
        patientDelta.assignedLocationUuid = Optional.of(Utils.valueOrDefault(locationUuid, Zone.DEFAULT_LOCATION));
        patientDelta.admissionDate = Optional.of(admissionDate);
        patientDelta.firstSymptomDate = Optional.fromNullable(symptomsOnsetDate);

        mModel.addPatient(mCrudEventBus, patientDelta);

        return true;
    }

    private DateTime getBirthdateFromAge(int ageInt, int ageUnits) {
        DateTime now = DateTime.now();
        switch (ageUnits) {
        case AGE_YEARS:
            return now.minusYears(ageInt);
        case AGE_MONTHS:
            return now.minusMonths(ageInt);
        default:
            return null;
        }
    }

    @SuppressWarnings("unused") // Called by reflection from EventBus.
    private final class EventSubscriber {

        public void onEventMainThread(AppLocationTreeFetchedEvent event) {
            mUi.setLocationTree(event.tree);
            if (mLocationTree != null) {
                mLocationTree.close();
            }
            mLocationTree = event.tree;
        }

        public void onEventMainThread(SingleItemCreatedEvent<AppPatient> event) {
            Utils.logEvent("add_patient_succeeded");
            mUi.quitActivity();
        }

        public void onEventMainThread(PatientAddFailedEvent event) {
            switch (event.reason) {
            case PatientAddFailedEvent.REASON_CLIENT:
                mUi.showErrorMessage(R.string.patient_creation_client_error);
                break;
            case PatientAddFailedEvent.REASON_NETWORK:
                // For network errors, include the VolleyError message, if available.
                if (event.exception != null && event.exception.getCause() != null
                        && event.exception.getCause() instanceof VolleyError
                        && event.exception.getCause().getMessage() != null) {
                    mUi.showErrorMessage(
                            App.getInstance().getString(R.string.patient_creation_network_error_with_reason,
                                    event.exception.getCause().getMessage()));
                } else {
                    mUi.showErrorMessage(R.string.patient_creation_network_error);
                }
                break;
            case PatientAddFailedEvent.REASON_INVALID_ID:
                mUi.showErrorMessage(R.string.patient_creation_invalid_id_error);
                break;
            case PatientAddFailedEvent.REASON_DUPLICATE_ID:
                mUi.showErrorMessage(R.string.patient_creation_duplicate_id_error);
                break;
            case PatientAddFailedEvent.REASON_INVALID_FAMILY_NAME:
                mUi.showErrorMessage(R.string.patient_creation_invalid_family_name_error);
                break;
            case PatientAddFailedEvent.REASON_INVALID_GIVEN_NAME:
                mUi.showErrorMessage(R.string.patient_creation_invalid_given_name_error);
                break;
            case PatientAddFailedEvent.REASON_SERVER:
                mUi.showErrorMessage(R.string.patient_creation_server_error);
                break;
            case PatientAddFailedEvent.REASON_INTERRUPTED:
                mUi.showErrorMessage(R.string.patient_creation_interrupted_error);
                break;
            case PatientAddFailedEvent.REASON_UNKNOWN:
            default:
                if (event.exception == null || event.exception.getMessage() == null) {
                    mUi.showErrorMessage(R.string.patient_creation_unknown_error);
                } else {
                    mUi.showErrorMessage(event.exception.getMessage());
                }
            }
            LOG.e(event.exception, "Patient add failed");
            Utils.logEvent("add_patient_failed", "reason", "" + event.reason);
        }

        public void onEventMainThread(SingleItemFetchFailedEvent event) {
            mUi.showErrorMessage(event.error);
        }
    }
}