/*
* 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.AlertDialog;
import android.content.DialogInterface;
import android.graphics.Color;
import android.os.Bundle;
import android.os.Handler;
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.support.v7.widget.Toolbar;
import android.text.SpannableString;
import android.text.style.ForegroundColorSpan;
import android.text.style.RelativeSizeSpan;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
import com.astuetz.PagerSlidingTabStrip;
import com.j256.ormlite.misc.TransactionManager;
import com.nispok.snackbar.Snackbar;
import com.nispok.snackbar.SnackbarManager;
import com.nispok.snackbar.enums.SnackbarType;
import org.joda.time.DateTime;
import org.joda.time.LocalTime;
import java.util.ArrayList;
import java.util.List;
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.database.DB;
import es.usc.citius.servando.calendula.events.PersistenceEvents;
import es.usc.citius.servando.calendula.fragments.ScheduleSummaryFragment;
import es.usc.citius.servando.calendula.fragments.ScheduleTimetableFragment;
import es.usc.citius.servando.calendula.fragments.SelectMedicineListFragment;
import es.usc.citius.servando.calendula.persistence.DailyScheduleItem;
import es.usc.citius.servando.calendula.persistence.Medicine;
import es.usc.citius.servando.calendula.persistence.Patient;
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.ScheduleHelper;
import es.usc.citius.servando.calendula.util.ScreenUtils;
import es.usc.citius.servando.calendula.util.Snack;
//import es.usc.citius.servando.calendula.fragments.MedicineCreateOrEditFragment;
public class ScheduleCreationActivity extends CalendulaActivity implements ViewPager.OnPageChangeListener {
public static final String TAG = ScheduleCreationActivity.class.getName();
/**
* 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;
Schedule mSchedule;
/**
* The {@link ViewPager} that will host the section contents.
*/
ViewPager mViewPager;
long mScheduleId;
PagerSlidingTabStrip tabs;
MenuItem removeItem;
Toolbar toolbar;
boolean autoStepDone = false;
int pColor;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_schedules);
pColor = DB.patients().getActive(this).color();
setupToolbar(null, pColor);
setupStatusBar(pColor);
subscribeToEvents();
processIntent();
mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager());
TextView title = ((TextView) findViewById(R.id.textView2));
title.setBackgroundColor(pColor);
title.setText(getString(mScheduleId != -1 ? R.string.title_edit_schedule_activity : R.string.title_create_schedule_activity));
// Set up the ViewPager with the sections adapter.
mViewPager = (ViewPager) findViewById(R.id.pager);
mViewPager.setAdapter(mSectionsPagerAdapter);
mViewPager.setOnPageChangeListener(this);
mViewPager.setOffscreenPageLimit(3);
tabs = (PagerSlidingTabStrip) findViewById(R.id.tabs);
tabs.setOnPageChangeListener(this);
tabs.setAllCaps(true);
tabs.setShouldExpand(true);
tabs.setDividerPadding(3);
tabs.setDividerColor(getResources().getColor(R.color.white_50));
tabs.setDividerColor(getResources().getColor(R.color.transparent));
tabs.setIndicatorHeight(ScreenUtils.dpToPx(getResources(),4));
tabs.setIndicatorColor(ScreenUtils.equivalentNoAlpha(pColor, 0.8f));
tabs.setTextColor(Color.parseColor("#222222"));
tabs.setUnderlineColor(ScreenUtils.equivalentNoAlpha(pColor, 0.5f));
tabs.setViewPager(mViewPager);
if (mSchedule != null) {
mViewPager.setCurrentItem(1);
}
findViewById(R.id.add_button).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
saveSchedule();
}
});
}
private void processIntent() {
mScheduleId = getIntent().getLongExtra(CalendulaApp.INTENT_EXTRA_SCHEDULE_ID, -1);
int scheduleType = getIntent().getIntExtra("scheduleType", -1);
if (mScheduleId != -1) {
Schedule s = Schedule.findById(mScheduleId);
if (s != null) {
ScheduleHelper.instance().setSelectedMed(s.medicine());
ScheduleHelper.instance().setTimesPerDay(s.items().size());
ScheduleHelper.instance().setSelectedScheduleIdx(s.items().size() - 1);
ScheduleHelper.instance().setScheduleItems(s.items());
ScheduleHelper.instance().setSchedule(s);
mSchedule = s;
} else {
Snack.show("Schedule not found :(", this);
}
} else if (scheduleType != -1) {
ScheduleHelper.instance().setScheduleType(scheduleType);
}
}
public void createSchedule() {
try {
final Schedule s = ScheduleHelper.instance().getSchedule();
TransactionManager.callInTransaction(DB.helper().getConnectionSource(), new Callable<Object>() {
@Override
public Object call() throws Exception {
// save schedule
final Patient patient = DB.patients().getActive(getBaseContext());
s.setMedicine(ScheduleHelper.instance().getSelectedMed());
s.setPatient(patient);
s.save();
Log.d(TAG, "Saving schedule..." + s.toString());
if (!s.repeatsHourly()) {
for (ScheduleItem item : ScheduleHelper.instance().getScheduleItems()) {
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);
return null;
}
});
ScheduleHelper.instance().clear();
AlarmScheduler.instance().onCreateOrUpdateSchedule(s, ScheduleCreationActivity.this);
Log.d(TAG, "Schedule saved successfully!");
Snack.show(R.string.schedule_created_message, this);
CalendulaApp.eventBus().post(PersistenceEvents.SCHEDULE_EVENT);
finish();
} catch (Exception e) {
Snack.show("Error creating schedule", this);
e.printStackTrace();
}
}
public void updateSchedule() {
try {
final Schedule s = mSchedule;
TransactionManager.callInTransaction(DB.helper().getConnectionSource(), new Callable<Object>() {
@Override
public Object call() throws Exception {
// save schedule
s.setMedicine(ScheduleHelper.instance().getSelectedMed());
final Patient patient = s.patient();
List<Long> routinesTaken = new ArrayList<Long>();
if (!s.repeatsHourly()) {
// remove days if changed
boolean[] days = s.days();
for (DailyScheduleItem dsi : DB.dailyScheduleItems().findBySchedule(s)) {
if(days[dsi.date().getDayOfWeek()-1]){
DB.dailyScheduleItems().remove(dsi);
}
}
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 : ScheduleHelper.instance().getScheduleItems()) {
ScheduleItem item = new ScheduleItem();
item.setDose(i.dose());
item.setRoutine(i.routine());
item.setSchedule(s);
item.save();
// add to daily schedule
DailyAgenda.instance().addItem(patient, item,routinesTaken.contains(item.routine().getId()));
}
} else {
DB.dailyScheduleItems().removeAllFrom(s);
for (DateTime time : s.hourlyItemsToday()) {
LocalTime timeToday = time.toLocalTime();
DailyAgenda.instance().addItem(patient, s, timeToday);
}
}
// save and fire event
DB.schedules().saveAndFireEvent(s);
return null;
}
});
ScheduleHelper.instance().clear();
AlarmScheduler.instance().onCreateOrUpdateSchedule(s, ScheduleCreationActivity.this);
Log.d(TAG, "Schedule saved successfully!");
Toast.makeText(this, R.string.schedule_created_message, Toast.LENGTH_SHORT).show();
finish();
} catch (Exception e) {
Toast.makeText(this, "Error creating schedule!", Toast.LENGTH_SHORT).show();
e.printStackTrace();
}
}
public void saveSchedule() {
if (!validateBeforeSave()) {
return;
}
if (mSchedule != null) {
updateSchedule();
} else {
createSchedule();
}
}
boolean validateBeforeSave() {
if (ScheduleHelper.instance().getSelectedMed() == null) {
mViewPager.setCurrentItem(0);
showSnackBar(R.string.create_schedule_unselected_med);
return false;
}
for (ScheduleItem i : ScheduleHelper.instance().getScheduleItems()) {
if (i.routine() == null) {
mViewPager.setCurrentItem(1);
showSnackBar(R.string.create_schedule_incomplete_items);
return false;
}
}
for (ScheduleItem i : ScheduleHelper.instance().getScheduleItems()) {
if (i.dose() <= 0) {
mViewPager.setCurrentItem(1);
showSnackBar(R.string.create_schedule_incomplete_doses);
return false;
}
}
if (ScheduleHelper.instance().getSchedule().type() == Schedule.SCHEDULE_TYPE_CYCLE && (
ScheduleHelper.instance().getSchedule().getCycleRest() <= 0
|| ScheduleHelper.instance().getSchedule().getCycleDays() <= 0)) {
showSnackBar(R.string.cycle_period_cero_message);
return false;
}
return true;
}
private void showSnackBar(int string) {
SnackbarManager.show(
Snackbar.with(getApplicationContext())
.actionLabel("OK")
.actionColor(getResources().getColor(R.color.android_orange_darker))
.type(SnackbarType.MULTI_LINE)
.textColor(getResources().getColor(R.color.white_80)) // change the text color
.color(getResources().getColor(R.color.android_orange_dark)) // change the background color
.text(getResources().getString(string)), this);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.schedules, menu);
removeItem = menu.findItem(R.id.action_remove);
removeItem.setVisible(mScheduleId != -1 ? true : false);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_remove:
showDeleteConfirmationDialog(mSchedule);
return true;
default:
finish();
return true;
}
}
public void onMedicineSelected(Medicine m, boolean step) {
ScheduleHelper.instance().setSelectedMed(m);
if (!step) {
autoStepDone = true;
}
if (!autoStepDone) {
autoStepDone = true;
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
mViewPager.setCurrentItem(1);
}
}, 500);
}
if (mScheduleId == -1) {
String titleStart = getString(R.string.title_create_schedule_activity);
String medName = " (" + m.name() + ")";
String fullTitle = titleStart + medName;
SpannableString title = new SpannableString(fullTitle);
title.setSpan(new RelativeSizeSpan(0.7f), titleStart.length(), titleStart.length() + medName.length(), 0);
title.setSpan(new ForegroundColorSpan(getResources().getColor(R.color.white_50)), titleStart.length(), titleStart.length() + medName.length(), 0);
getSupportActionBar().setTitle(title);
}
}
public void onScheduleTypeSelected() {
((ScheduleTimetableFragment) getViewPagerFragment(2)).onTypeSelected();
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
mViewPager.setCurrentItem(2);
}
}, 500);
}
public void onDoseSelectedWithNoMed() {
mViewPager.setCurrentItem(0);
Snack.show(getString(R.string.create_schedule_select_med_before_dose), this);
}
void showDeleteConfirmationDialog(final Schedule s) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage(String.format(getString(R.string.remove_medicine_message_short), s.medicine().name()))
.setCancelable(true)
.setPositiveButton(getString(R.string.dialog_yes_option), new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
DB.schedules().deleteCascade(s, true);
finish();
}
})
.setNegativeButton(getString(R.string.dialog_no_option), new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
dialog.cancel();
}
});
AlertDialog alert = builder.create();
alert.show();
}
@Override
public void onPageScrolled(int i, float v, int i2) {
}
@Override
public void onPageSelected(int page) {
}
@Override
public void onPageScrollStateChanged(int i) {
}
@Override
protected void onDestroy() {
unsubscribeFromEvents();
ScheduleHelper.instance().clear();
super.onDestroy();
}
Fragment getViewPagerFragment(int position) {
return getSupportFragmentManager().findFragmentByTag(FragmentUtils.makeViewPagerFragmentName(R.id.pager, position));
}
@Override
protected void onPause() {
super.onPause();
overridePendingTransition(0, 0);
}
public void onEvent(PersistenceEvents.MedicineAddedEvent event) {
Log.d("onEvent", event.id + " ----");
((SelectMedicineListFragment) getViewPagerFragment(0)).setSelectedMed(event.id);
}
/**
* A {@link FragmentPagerAdapter} that returns a fragment corresponding to
* one of the sections/tabs/pages.
*/
public class SectionsPagerAdapter extends FragmentPagerAdapter
// implements PagerSlidingTabStrip.IconTabProvider
{
public SectionsPagerAdapter(FragmentManager fm) {
super(fm);
}
@Override
public Fragment getItem(int position) {
// getItem is called to instantiate the fragment for the given page.
// Return a PlaceholderFragment (defined as a static inner class below).
if (position == 1) {
return new ScheduleTimetableFragment();
} /*else if (position == 1) {
return new ScheduleTypeFragment();
} */ else if (position == 0) {
return new SelectMedicineListFragment();
} else {
return new ScheduleSummaryFragment();
}
}
@Override
public CharSequence getPageTitle(int position) {
if (position == 0) {
return getString(R.string.medicine);
} /*else if (position == 1) {
return getString(R.string.schedule_type);
}*/ else if (position == 1) {
return getString(R.string.schedule);
} else {
return getString(R.string.summary);
}
}
@Override
public int getCount() {
// Show 3 total pages.
return 3;
}
}
}