net.bible.service.readingplan.ReadingPlanDao.java Source code

Java tutorial

Introduction

Here is the source code for net.bible.service.readingplan.ReadingPlanDao.java

Source

package net.bible.service.readingplan;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map.Entry;
import java.util.Properties;

import net.bible.android.BibleApplication;
import net.bible.android.SharedConstants;
import net.bible.service.common.AndRuntimeException;

import org.apache.commons.lang.StringUtils;
import org.crosswire.common.util.IOUtil;
import org.crosswire.jsword.versification.Versification;
import org.crosswire.jsword.versification.system.SystemKJV;
import org.crosswire.jsword.versification.system.SystemNRSVA;
import org.crosswire.jsword.versification.system.Versifications;

import android.content.res.AssetManager;
import android.content.res.Resources;
import android.util.Log;

/**
 * @author Martin Denham [mjdenham at gmail dot com]
 * @see gnu.lgpl.License for license details.<br>
 *      The copyright to this program is held by it's author.
 */
public class ReadingPlanDao {

    private String cachedPlanCode = "";
    private Properties cachedPlanProperties;

    private static final String READING_PLAN_FOLDER = SharedConstants.READINGPLAN_DIR_NAME;
    private static final File USER_READING_PLAN_FOLDER = SharedConstants.MANUAL_READINGPLAN_DIR;
    private static final String DOT_PROPERTIES = ".properties";
    private static final String VERSIFICATION = "Versification";
    private static final String DEFAULT_VERSIFICATION = SystemKJV.V11N_NAME;
    private static final String INCLUSIVE_VERSIFICATION = SystemNRSVA.V11N_NAME;

    private static final String TAG = "ReadingPlanDao";

    public List<ReadingPlanInfoDto> getReadingPlanList() {
        try {
            List<String> codes = getAllReadingPlanCodes();

            List<ReadingPlanInfoDto> planInfoList = new ArrayList<ReadingPlanInfoDto>();
            for (String code : codes) {
                planInfoList.add(getReadingPlanInfoDto(code));
            }

            return planInfoList;

        } catch (Exception e) {
            Log.e(TAG, "Error getting reading plans", e);
            throw new AndRuntimeException("Error getting reading plans", e);
        }
    }

    /** get a list of all days readings in a plan
     */
    public List<OneDaysReadingsDto> getReadingList(String planName) {

        ReadingPlanInfoDto planInfo = getReadingPlanInfoDto(planName);

        Properties properties = getPlanProperties(planName);

        List<OneDaysReadingsDto> list = new ArrayList<OneDaysReadingsDto>();
        for (Entry<Object, Object> entry : properties.entrySet()) {
            String key = (String) entry.getKey();
            String value = (String) entry.getValue();
            if (StringUtils.isNumeric(key)) {
                int day = Integer.parseInt(key);
                OneDaysReadingsDto daysReading = new OneDaysReadingsDto(day, value, planInfo);
                list.add(daysReading);
            }
        }
        Collections.sort(list);

        return list;
    }

    /** get readings for one day
     */
    public OneDaysReadingsDto getReading(String planName, int dayNo) {
        Properties properties = getPlanProperties(planName);

        String readings = (String) properties.get(Integer.toString(dayNo));
        Log.d(TAG, "Readings for day:" + readings);
        return new OneDaysReadingsDto(dayNo, readings, getReadingPlanInfoDto(planName));
    }

    /** get last day number - there may be missed days so cannot simply do props.size()
     */
    public int getNumberOfPlanDays(String planCode) {
        int maxDayNo = 0;

        for (Object oDayNo : getPlanProperties(planCode).keySet()) {
            String dayNoStr = (String) oDayNo;
            if (StringUtils.isNumeric(dayNoStr)) {
                int dayNo = Integer.parseInt(dayNoStr);
                maxDayNo = Math.max(maxDayNo, dayNo);
            } else {
                if (!VERSIFICATION.equalsIgnoreCase(dayNoStr)) {
                    Log.e(TAG, "Invalid day number:" + dayNoStr);
                }
            }
        }

        return maxDayNo;
    }

    /** 
     * Get versification specified in properties file e.g. 'Versification=Vulg'
     * Default to KJV.
     * If specified Versification is not found then use NRSVA because it includes most books possible 
     */
    private Versification getReadingPlanVersification(String planCode) {
        Versification versification = null;
        try {
            String versificationName = getPlanProperties(planCode).getProperty(VERSIFICATION,
                    DEFAULT_VERSIFICATION);
            versification = Versifications.instance().getVersification(versificationName);
        } catch (Exception e) {
            Log.e(TAG, "Error loading versification from Reading plan:" + planCode);
            versification = Versifications.instance().getVersification(INCLUSIVE_VERSIFICATION);
        }

        return versification;
    }

    private ReadingPlanInfoDto getReadingPlanInfoDto(String planCode) {
        Log.d(TAG, "Get reading plan info:" + planCode);
        ReadingPlanInfoDto info = new ReadingPlanInfoDto(planCode);
        int id = BibleApplication.getApplication().getResources().getIdentifier("rdg_plan_" + planCode, "string",
                "net.bible.android.activity");
        String desc = "";
        if (id != 0) {
            desc = BibleApplication.getApplication().getResources().getString(id);
        }
        info.setTitle(desc);

        info.setNumberOfPlanDays(getNumberOfPlanDays(planCode));
        info.setVersification(getReadingPlanVersification(planCode));

        return info;
    }

    /** look in assets/readingplan and sdcard/jsword/readingplan for reading plans and return a list of all codes
     */
    private List<String> getAllReadingPlanCodes() throws IOException {

        Resources resources = BibleApplication.getApplication().getResources();
        AssetManager assetManager = resources.getAssets();

        List<String> allCodes = new ArrayList<String>();

        String[] internalPlans = assetManager.list(READING_PLAN_FOLDER);
        allCodes.addAll(getReadingPlanCodes(internalPlans));

        String[] userPlans = USER_READING_PLAN_FOLDER.list();
        allCodes.addAll(getReadingPlanCodes(userPlans));

        return allCodes;
    }

    private List<String> getReadingPlanCodes(String[] files) {
        List<String> codes = new ArrayList<String>();
        if (files != null) {
            for (String file : files) {
                // this if statement ensures we only deal with .properties files - not folders or anything else
                if (file.endsWith(DOT_PROPERTIES)) {
                    // remove the file extension to get the code
                    codes.add(file.replace(DOT_PROPERTIES, ""));
                }
            }
        }
        return codes;
    }

    /* either load reading plan info from assets/readingplan or sdcard/jsword/readingplan
     */
    private synchronized Properties getPlanProperties(String planCode) {
        if (!planCode.equals(cachedPlanCode)) {
            Resources resources = BibleApplication.getApplication().getResources();
            AssetManager assetManager = resources.getAssets();
            String filename = planCode + DOT_PROPERTIES;

            // Read from the /assets directory
            Properties properties = new Properties();
            InputStream inputStream = null;
            try {
                // check to see if a user has created his own reading plan with this name
                File userReadingPlanFile = new File(USER_READING_PLAN_FOLDER, filename);
                boolean isUserPlan = userReadingPlanFile.exists();

                if (!isUserPlan) {
                    inputStream = assetManager.open(READING_PLAN_FOLDER + File.separator + filename);
                } else {
                    inputStream = new FileInputStream(userReadingPlanFile);
                }
                properties.load(inputStream);
                Log.d(TAG, "The properties are now loaded");
                Log.d(TAG, "properties: " + properties);

                // cache it so we don't constantly reload the properties
                cachedPlanCode = planCode;
                cachedPlanProperties = properties;

            } catch (IOException e) {
                System.err.println("Failed to open reading plan property file");
                e.printStackTrace();
            } finally {
                IOUtil.close(inputStream);
            }
        }
        return cachedPlanProperties;
    }
}