es.usc.citius.servando.calendula.activities.ConfirmSchedulesActivity.java Source code

Java tutorial

Introduction

Here is the source code for es.usc.citius.servando.calendula.activities.ConfirmSchedulesActivity.java

Source

/*
 *    Calendula - An assistant for personal medication management.
 *    Copyright (C) 2016 CITIUS - USC
 *
 *    Calendula 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 software.  If not, see <http://www.gnu.org/licenses/>.
 */

package es.usc.citius.servando.calendula.activities;

import android.app.ProgressDialog;
import android.graphics.Color;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ImageButton;
import android.widget.TextView;
import android.widget.Toast;

import com.getbase.floatingactionbutton.FloatingActionButton;
import com.google.gson.Gson;
import com.j256.ormlite.misc.TransactionManager;

import org.joda.time.DateTime;
import org.joda.time.LocalTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;

import es.usc.citius.servando.calendula.CalendulaActivity;
import es.usc.citius.servando.calendula.CalendulaApp;
import es.usc.citius.servando.calendula.R;
import es.usc.citius.servando.calendula.activities.qrWrappers.PickupWrapper;
import es.usc.citius.servando.calendula.activities.qrWrappers.PrescriptionListWrapper;
import es.usc.citius.servando.calendula.activities.qrWrappers.PrescriptionWrapper;
import es.usc.citius.servando.calendula.database.DB;
import es.usc.citius.servando.calendula.events.PersistenceEvents;
import es.usc.citius.servando.calendula.fragments.ScheduleConfirmationEndFragment;
import es.usc.citius.servando.calendula.fragments.ScheduleConfirmationStartFragment;
import es.usc.citius.servando.calendula.fragments.ScheduleImportFragment;
import es.usc.citius.servando.calendula.persistence.DailyScheduleItem;
import es.usc.citius.servando.calendula.persistence.HomogeneousGroup;
import es.usc.citius.servando.calendula.persistence.Medicine;
import es.usc.citius.servando.calendula.persistence.Patient;
import es.usc.citius.servando.calendula.persistence.PickupInfo;
import es.usc.citius.servando.calendula.persistence.Prescription;
import es.usc.citius.servando.calendula.persistence.Presentation;
import es.usc.citius.servando.calendula.persistence.Schedule;
import es.usc.citius.servando.calendula.persistence.ScheduleItem;
import es.usc.citius.servando.calendula.scheduling.AlarmScheduler;
import es.usc.citius.servando.calendula.scheduling.DailyAgenda;
import es.usc.citius.servando.calendula.util.FragmentUtils;
import es.usc.citius.servando.calendula.util.ScreenUtils;
import es.usc.citius.servando.calendula.util.Snack;
import es.usc.citius.servando.calendula.util.Strings;

public class ConfirmSchedulesActivity extends CalendulaActivity implements ViewPager.OnPageChangeListener {

    private static final String TAG = "ConfirmSchedules.class";
    /**
     * The {@link android.support.v4.view.PagerAdapter} that will provide
     * fragments for each of the sections. We use a
     * {@link FragmentPagerAdapter} derivative, which will keep every
     * loaded fragment in memory. If this becomes too memory intensive, it
     * may be best to switch to a
     * {@link android.support.v4.app.FragmentStatePagerAdapter}.
     */
    SectionsPagerAdapter mSectionsPagerAdapter;

    /**
     * The {@link ViewPager} that will host the section contents.
     */
    ViewPager mViewPager;

    List<PrescriptionWrapper> prescriptionList;
    int scheduleCount;

    FloatingActionButton fab;

    TextView medName;
    TextView title;

    ImageButton routinesItem;
    ImageButton hourlyItem;
    ImageButton cycleItem;

    View scheduleTypeSelector;
    View readingQrBox;

    DateTimeFormatter df = DateTimeFormat.forPattern("yyMMdd");
    private String qrData;
    private Patient patient;
    int color;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_confirm_schedules);
        patient = DB.patients().getActive(this);
        color = patient.color();
        int dark = ScreenUtils.equivalentNoAlpha(color, Color.BLACK, 0.85f);

        findViewById(R.id.activity_layout).setBackgroundColor(dark);
        setupToolbar(null, color);
        setupStatusBar(color);

        title = (TextView) findViewById(R.id.textView);
        medName = (TextView) findViewById(R.id.textView2);
        fab = (FloatingActionButton) findViewById(R.id.add_button);
        scheduleTypeSelector = findViewById(R.id.schedule_type_selector);
        readingQrBox = findViewById(R.id.reading_qr_box);

        medName.setBackgroundColor(color);
        scheduleTypeSelector.setBackgroundColor(dark);

        routinesItem = (ImageButton) findViewById(R.id.schedule_type_routines);
        hourlyItem = (ImageButton) findViewById(R.id.schedule_type_hourly);
        cycleItem = (ImageButton) findViewById(R.id.schedule_type_period);

        View.OnClickListener l = new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                onClickScheduleTypeButton(v.getId());
            }
        };

        routinesItem.setOnClickListener(l);
        hourlyItem.setOnClickListener(l);
        cycleItem.setOnClickListener(l);

        qrData = getIntent().getStringExtra("qr_data");
        try {
            new ProcessQRTask().execute(qrData);
        } catch (Exception e) {
            Log.e(TAG, "Error processing QR", e);
            Toast.makeText(this, "Error inesperado actualizando!", Toast.LENGTH_LONG).show();
            finish();
        }
    }

    private List<PrescriptionWrapper> filterValidPrescriptions(PrescriptionListWrapper prescriptionListWrapper) {
        List<PrescriptionWrapper> p = new ArrayList<>();

        for (PrescriptionWrapper pw : prescriptionListWrapper.p) {
            if (pw.cn != null) {
                Prescription pr = Prescription.findByCn(pw.cn);
                boolean prescriptionExists = pr != null;
                boolean medExists = DB.medicines().findOneBy(Medicine.COLUMN_CN, pw.cn) != null;

                if (prescriptionExists) {
                    pw.exists = medExists;
                    pw.prescription = pr;
                    p.add(pw);
                }
            } else if (pw.g != null) {

                HomogeneousGroup group = findGroup(pw.g);
                if (group != null) {
                    Log.d("ConfirmSchedulesAct", "Found group: " + group.name);
                    pw.exists = true;
                    pw.isGroup = true;
                    pw.group = group;
                    p.add(pw);
                }
            }

            if (pw.pk != null) {
                for (PickupWrapper pkw : pw.pk) {
                    Log.d("ConfirmSchedulesAct", "Pickup : " + df.parseDateTime(pkw.f).toString("dd/MM/yyyy"));
                    Log.d("ConfirmSchedulesAct", "Pickup : " + df.parseDateTime(pkw.t).toString("dd/MM/yyyy"));
                    Log.d("ConfirmSchedulesAct", "Pickup : " + pkw.tk);
                }
            }
        }
        return p;
    }

    private HomogeneousGroup findGroup(String g) {
        return DB.groups().findOneBy(HomogeneousGroup.COLUMN_GROUP, g);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.confirm_schedules, menu);
        return true;
    }

    private void hideScheduleTypeSelector() {
        scheduleTypeSelector.setVisibility(View.INVISIBLE);
    }

    private void showScheduleTypeSelector() {
        if (scheduleTypeSelector.getVisibility() != View.VISIBLE) {
            scheduleTypeSelector.setVisibility(View.VISIBLE);
        }
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
        default:
            finish();
            return true;
        }
    }

    public void onClickScheduleTypeButton(int id) {
        Fragment f = getViewPagerFragment(mViewPager.getCurrentItem());

        routinesItem.setAlpha(0.3f);
        hourlyItem.setAlpha(0.3f);
        cycleItem.setAlpha(0.3f);

        if (f instanceof ScheduleImportFragment) {
            if (id == R.id.schedule_type_routines) {
                routinesItem.setAlpha(1f);
                ((ScheduleImportFragment) f).changeScheduleType(Schedule.SCHEDULE_TYPE_EVERYDAY);
            } else if (id == R.id.schedule_type_hourly) {
                hourlyItem.setAlpha(1f);
                ((ScheduleImportFragment) f).changeScheduleType(Schedule.SCHEDULE_TYPE_HOURLY);
            } else if (id == R.id.schedule_type_period) {
                cycleItem.setAlpha(1f);
                ((ScheduleImportFragment) f).changeScheduleType(Schedule.SCHEDULE_TYPE_CYCLE);
            }
        }
    }

    public Map<Schedule, PrescriptionWrapper> getScheduleInfo() {
        Map<Schedule, PrescriptionWrapper> schedules = new HashMap<>();
        for (int i = 0; i < scheduleCount; i++) {
            Fragment f = getViewPagerFragment(i + 1);
            if (f instanceof ScheduleImportFragment) {
                ScheduleImportFragment importFragment = (ScheduleImportFragment) f;
                schedules.put(importFragment.getSchedule(), importFragment.getPrescriptionWrapper());
            }
        }
        return schedules;
    }

    public List<Schedule> getSchedules() {
        List<Schedule> schedules = new ArrayList<>();
        for (int i = 0; i < scheduleCount; i++) {
            Fragment f = getViewPagerFragment(i + 1);
            if (f instanceof ScheduleImportFragment) {
                schedules.add(((ScheduleImportFragment) f).getSchedule());
            }
        }
        return schedules;
    }

    private void saveSchedules() {

        final ProgressDialog progress = ProgressDialog.show(this, "Calendula", "Actualizando pautas...", true);

        AsyncTask<Void, Void, Boolean> task = new AsyncTask<Void, Void, Boolean>() {
            @Override
            protected Boolean doInBackground(Void... arg0) {
                try {
                    TransactionManager.callInTransaction(DB.helper().getConnectionSource(), new Callable<Object>() {
                        @Override
                        public Object call() throws Exception {

                            for (int i = 0; i < scheduleCount; i++) {

                                Log.d("PRESCRIPTION", "Item " + i);

                                Fragment f = getViewPagerFragment(i + 1);

                                if (f instanceof ScheduleImportFragment) {

                                    Log.d("PRESCRIPTION", "Fragment " + i);

                                    ScheduleImportFragment c = (ScheduleImportFragment) f;

                                    if (c.validate()) {
                                        PrescriptionWrapper w = prescriptionList.get(i);
                                        Log.d("PRESCRIPTION", "Validate!");
                                        String cn = w.cn;
                                        Medicine m = null;
                                        if (cn != null) {
                                            m = DB.medicines().findByCnAndPatient(cn, patient);
                                            if (m == null) {
                                                Log.d("PRESCRIPTION", "Saving medicine!");
                                                m = Medicine.fromPrescription(Prescription.findByCn(cn));
                                                m.setPatient(patient);
                                                m.save();
                                            }
                                        } else if (w.isGroup) {
                                            m = DB.medicines().findByGroupAndPatient(w.group.getId(), patient);
                                            if (m == null) {
                                                m = new Medicine(Strings.firstPart(w.group.name));
                                                m.setHomogeneousGroup(w.group.getId());
                                                Presentation pres = Presentation.expected(w.group.name,
                                                        w.group.name);
                                                m.setPresentation(pres != null ? pres : Presentation.PILLS);
                                                m.setPatient(patient);
                                                m.save();
                                            }
                                        } else {
                                            throw new RuntimeException(
                                                    " Prescription must have a cn or group reference");
                                        }

                                        Schedule s = c.getSchedule();
                                        Schedule prev = DB.schedules().findByMedicineAndPatient(m, patient);
                                        // TODO: find by med and patient
                                        if (prev != null) {
                                            Log.d("PRESCRIPTION", "Found previous schedule for med " + m.getId());
                                            updateSchedule(prev, s, c.getScheduleItems());
                                        } else {
                                            Log.d("PRESCRIPTION",
                                                    "Not found previous schedule for med " + m.getId());
                                            createSchedule(s, c.getScheduleItems(), m);
                                        }

                                        if (m != null) {
                                            // remove old pickups before inserting the new ones
                                            DB.pickups().removeByMed(m);
                                        }

                                        if (m != null && w.pk != null && w.pk.size() > 0) {

                                            for (PickupWrapper pkw : w.pk) {
                                                PickupInfo pickupInfo = new PickupInfo();
                                                pickupInfo.setTo(df.parseLocalDate(pkw.t).plusMonths(19));
                                                pickupInfo.setFrom(df.parseLocalDate(pkw.f).plusMonths(19));
                                                pickupInfo.taken(pkw.tk == 1 ? true : false);
                                                pickupInfo.setMedicine(m);
                                                DB.pickups().save(pickupInfo);
                                            }
                                        }
                                    } else {
                                        mViewPager.setCurrentItem(i + 1);
                                        Snack.show("Hmmmmmm....", ConfirmSchedulesActivity.this);
                                    }
                                }
                            }
                            CalendulaApp.eventBus().post(PersistenceEvents.SCHEDULE_EVENT);
                            AlarmScheduler.instance().updateAllAlarms(ConfirmSchedulesActivity.this);
                            return null;
                        }
                    });

                    return true;

                } catch (Exception e) {
                    Log.e("ConfirmSchedulesAct", "Error saving prescriptions", e);
                    return false;
                }
            }

            @Override
            protected void onPostExecute(Boolean result) {
                if (progress != null) {
                    progress.dismiss();
                }
                if (result) {
                    finish();
                }
            }
        };

        task.execute((Void[]) null);
    }

    public void createSchedule(final Schedule s, List<ScheduleItem> items, Medicine m) {

        // save schedule
        s.setMedicine(m);
        s.setPatient(patient);
        s.setScanned(true);
        s.save();
        Log.d(TAG, "Saving schedule..." + s.toString());

        if (!s.repeatsHourly()) {
            for (ScheduleItem item : items) {
                item.setSchedule(s);
                item.save();
                Log.d(TAG, "Saving item..." + item.getId());
                // add to daily schedule
                DailyAgenda.instance().addItem(patient, item, false);
            }
        } else {
            for (DateTime time : s.hourlyItemsToday()) {
                LocalTime timeToday = time.toLocalTime();
                DailyAgenda.instance().addItem(patient, s, timeToday);
            }
        }
        // save and fire event
        DB.schedules().saveAndFireEvent(s);
        AlarmScheduler.instance().onCreateOrUpdateSchedule(s, ConfirmSchedulesActivity.this);
    }

    public void updateSchedule(final Schedule s, final Schedule current, List<ScheduleItem> items) {

        s.setType(current.type());
        s.setDays(current.days());
        s.setDose(current.dose());
        s.setStart(current.start());
        s.setRepetition(current.rule());
        s.setCycle(current.getCycleDays(), current.getCycleRest());
        s.setStartTime(current.startTime());

        List<Long> routinesTaken = new ArrayList<Long>();

        if (!s.repeatsHourly()) {
            for (ScheduleItem item : s.items()) {
                DailyScheduleItem d = DailyScheduleItem.findByScheduleItem(item);
                // if taken today, add to the list
                if (d != null && d.takenToday()) {
                    routinesTaken.add(item.routine().getId());
                }
                item.deleteCascade();
            }

            // save new items
            for (ScheduleItem i : items) {
                ScheduleItem item = new ScheduleItem();
                item.setDose(i.dose());
                item.setRoutine(i.routine());
                item.setSchedule(s);
                item.save();
                // add to daily schedule
                DailyScheduleItem dsi = new DailyScheduleItem(item);
                dsi.setPatient(patient);
                if (routinesTaken.contains(item.routine().getId())) {
                    dsi.setTakenToday(true);
                }
                dsi.save();
            }
        } else {
            DB.dailyScheduleItems().removeAllFrom(s);
            for (DateTime time : s.hourlyItemsToday()) {
                LocalTime timeToday = time.toLocalTime();
                DailyScheduleItem dsi = new DailyScheduleItem(s, timeToday);
                dsi.setPatient(patient);
                dsi.save();
                Log.d(TAG, "Saving daily schedule item..." + dsi.getId() + " timeToday: "
                        + timeToday.toString("kk:mm"));
            }
        }
        // save and fire event
        DB.schedules().saveAndFireEvent(s);
        AlarmScheduler.instance().onCreateOrUpdateSchedule(s, ConfirmSchedulesActivity.this);
    }

    private void updatePageTitle(int i) {
        if (i == 0) {
            title.setText(scheduleCount + " " + getString(R.string.scan_prescriptions));
            medName.setText(getString(R.string.scan_review_title));
        } else if (i == scheduleCount + 1) {
            title.setText(scheduleCount + " " + getString(R.string.scan_prescriptions));
            medName.setText(getString(R.string.confirm));
        } else {
            PrescriptionWrapper pw = prescriptionList.get(i - 1);
            if (pw.cn != null) {
                if (pw.prescription == null) {
                    pw.prescription = Prescription.findByCn(pw.cn);
                }
                medName.setText(Strings.toProperCase(pw.prescription.name));

            } else if (pw.isGroup) {
                medName.setText(pw.group.name);
            }
            title.setText(getResources().getString(R.string.confirm_prescription_x_of_y, i, scheduleCount));
        }
    }

    @Override
    public void onPageScrolled(int i, float v, int i2) {

    }

    @Override
    public void onPageSelected(int i) {
        updatePageTitle(i);

        Log.d("ConfirmSchedulesAct", " Page Selected: " + i);

        if (i == 0) {
            hideScheduleTypeSelector();
            fab.setVisibility(View.INVISIBLE);
        } else if (i == scheduleCount + 1) {
            hideScheduleTypeSelector();
            fab.setVisibility(View.VISIBLE);
        } else {
            showScheduleTypeSelector();
            fab.setVisibility(View.INVISIBLE);
            updateScheduleTypeSelector(i);
        }
    }

    public void updateScheduleTypeSelector(int page) {
        Fragment f = getViewPagerFragment(page);

        routinesItem.setAlpha(0.3f);
        hourlyItem.setAlpha(0.3f);
        cycleItem.setAlpha(0.3f);

        int type = ((ScheduleImportFragment) f).getSchedule().type();

        Log.d("Confirm", "Type: " + type);

        if (f instanceof ScheduleImportFragment) {
            if (type == Schedule.SCHEDULE_TYPE_HOURLY) {
                hourlyItem.setAlpha(1f);
            } else if (type == Schedule.SCHEDULE_TYPE_CYCLE) {
                cycleItem.setAlpha(1f);
            } else {
                routinesItem.setAlpha(1f);
            }
        }
    }

    @Override
    public void onPageScrollStateChanged(int i) {

    }

    public List<PrescriptionWrapper> getPrescriptions() {
        return prescriptionList;
    }

    /**
     * A {@link FragmentPagerAdapter} that returns a fragment corresponding to
     * one of the sections/tabs/pages.
     */
    public class SectionsPagerAdapter extends FragmentPagerAdapter {

        int scheduleCount;

        public SectionsPagerAdapter(FragmentManager fm, int scheduleCount) {
            super(fm);
            this.scheduleCount = scheduleCount;
        }

        @Override
        public Fragment getItem(int position) {

            Log.d("ScanQR", "Position: " + position);

            if (position == 0) {
                return ScheduleConfirmationStartFragment.newInstance();
            } else if (position == scheduleCount + 1) {
                return ScheduleConfirmationEndFragment.newInstance();
            } else {
                // getItem is called to instantiate the fragment for the given page.
                // Return a PlaceholderFragment (defined as a static inner class below).            
                PrescriptionWrapper pw = prescriptionList.get(position - 1);
                return ScheduleImportFragment.newInstance(pw);
            }
        }

        @Override
        public int getCount() {
            return scheduleCount + 2;
        }

        @Override
        public CharSequence getPageTitle(int position) {
            return "";
        }
    }

    public PrescriptionListWrapper parseQRData(String data) {
        Log.d(TAG, "QRDATA: " + data);
        return new Gson().fromJson(data, PrescriptionListWrapper.class);
    }

    public void next() {
        int next = mViewPager.getCurrentItem() + 1;
        int size = mSectionsPagerAdapter.getCount();
        if (next < size) {
            mViewPager.setCurrentItem(next);
        }
    }

    Fragment getViewPagerFragment(int position) {
        return getSupportFragmentManager()
                .findFragmentByTag(FragmentUtils.makeViewPagerFragmentName(R.id.pager, position));
    }

    private class ProcessQRTask extends AsyncTask<String, Integer, Long> {

        ProgressDialog dialog;

        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            dialog = new ProgressDialog(ConfirmSchedulesActivity.this);
            dialog.setMessage("Processing QR info ...");
        }

        protected Long doInBackground(String... data) {
            String qrData = data[0];

            if (qrData != null) {
                try {
                    prescriptionList = filterValidPrescriptions(parseQRData(qrData));
                    Long sCount = (long) prescriptionList.size();
                    if (sCount > 0) {
                        return sCount;
                    } else {
                        return 0l;
                    }
                } catch (Exception e) {
                    Log.e(TAG, "Error processing QR", e);
                    return -1l;
                }
            } else {
                return -1l;
            }
        }

        protected void onPostExecute(Long schedules) {

            scheduleCount = schedules.intValue();

            if (schedules == -1) {
                Toast.makeText(ConfirmSchedulesActivity.this, "Error inesperado actualizando!", Toast.LENGTH_LONG)
                        .show();
                finish();
            } else if (schedules == 0) {
                Toast.makeText(ConfirmSchedulesActivity.this, "No se encontraron prescripciones vlidas!",
                        Toast.LENGTH_SHORT).show();
            } else {
                updatePageTitle(0);
                fab.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        saveSchedules();
                    }
                });
                // Create the adapter that will return a fragment for each of the three
                // primary sections of the activity.
                mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager(), scheduleCount);
                // Set up the ViewPager with the sections adapter.
                mViewPager = (ViewPager) findViewById(R.id.pager);
                mViewPager.setOnPageChangeListener(ConfirmSchedulesActivity.this);
                mViewPager.setAdapter(mSectionsPagerAdapter);
                mViewPager.setOffscreenPageLimit(20);
                hideScheduleTypeSelector();
                readingQrBox.setVisibility(View.GONE);
            }
            if (dialog.isShowing()) {
                dialog.dismiss();
            }
        }
    }

}