app/src/main/java/ve/com/abicelis/creditcardexpensemanager/app/utils/Constants.java
public class Constants {
    public static final String PREFS_NAME = "CCManagerPreferences";
    public static final String ACTIVE_CC_ID = "ActiveCCId";

    public static final int EXPENSE_DETAIL_ACTIVITY_REQUEST_CODE = 283;
    public static final int RESULT_REFRESH_DATA = 5;
}
app/src/main/java/ve/com/abicelis/creditcardexpensemanager/model/Expense.java
public class Expense implements Serializable {

    private int id;
    private String description;
    byte[] thumbnail;
    String fullImagePath;
    BigDecimal amount;
    Currency currency;
    Calendar date;
    ExpenseCategory expenseCategory;
    ExpenseType expenseType;


    public Expense (@NonNull String description, @Nullable byte[] thumbnail, @Nullable String fullImagePath, @NonNull BigDecimal amount, @NonNull Currency currency, @NonNull Calendar date, @NonNull ExpenseCategory expenseCategory, @NonNull ExpenseType expenseType) {
        this.description = description;
        this.fullImagePath = fullImagePath;
        this.amount = amount;
        this.currency = currency;
        this.expenseCategory = expenseCategory;
        this.expenseType = expenseType;

        this.thumbnail = thumbnail;
        if(this.thumbnail != null && this.thumbnail.equals(new byte[0]) )   //if thumbnail is empty byte array -> null
            this.thumbnail = null;

        this.date = Calendar.getInstance();
        this.date.setTimeZone(date.getTimeZone());
        this.date.setTimeInMillis(date.getTimeInMillis());
    }

    public Expense (int id, String description, byte[] thumbnail, String fullImagePath, BigDecimal amount, Currency currency, Calendar date, ExpenseCategory expenseCategory, ExpenseType expenseType) {
        this(description, thumbnail, fullImagePath, amount, currency, date, expenseCategory, expenseType);
        this.id = id;
    }

    public int getId() {
        return id;
    }

    public String getDescription() {
        return description;
    }

    public byte[] getThumbnail() {
        return thumbnail;
    }

    public String getFullImagePath() {
        return fullImagePath;
    }

    public Bitmap getFullImage() throws FileNotFoundException {
        Bitmap fullImage = BitmapFactory.decodeFile(fullImagePath);

        if(fullImage == null)
            throw new FileNotFoundException("This image does not exist, has probably been deleted");

        return fullImage;
    }

    public BigDecimal getAmount() {
        return amount;
    }

    public Currency getCurrency() {
        return currency;
    }

    public Calendar getDate() {
        return date;
    }


    public ExpenseCategory getExpenseCategory() {
        return expenseCategory;
    }

    public ExpenseType getExpenseType() {
        return expenseType;
    }



    @Override
    public String toString() {
        return  "ID=" + id + "\r\n" +
                " description=" + description + "\r\n" +
                " amount=" + amount + "\r\n" +
                " currency=" + currency + "\r\n" +
                " date=" + date + "\r\n" +
                " expenseCategory=" + expenseCategory + "\r\n" +
                " expenseType=" + expenseType;
    }
}
app/src/main/java/ve/com/abicelis/creditcardexpensemanager/model/CreditPeriod.java
public class CreditPeriod {

    public static final int PERIOD_NAME_LARGEST_MONTH = 0;
    public static final int PERIOD_NAME_COMPLETE = 1;
    public static final int PERIOD_NAME_COMPLETE_NUMERIC = 2;

    private int id = -1;
    private String periodName;
    private int periodNameStyle;
    private Calendar startDate;
    private Calendar endDate;
    private BigDecimal creditLimit;

    private List<Expense> expenses = new ArrayList<>();
    private List<Payment> payments = new ArrayList<>();


    public CreditPeriod(int periodNameStyle, Calendar startDate, Calendar endDate, BigDecimal creditLimit) {
        this.periodNameStyle = periodNameStyle;
        this.creditLimit = creditLimit;

        this.startDate = Calendar.getInstance();
        this.startDate.setTimeZone(startDate.getTimeZone());
        this.startDate.setTimeInMillis(startDate.getTimeInMillis());

        this.endDate = Calendar.getInstance();
        this.endDate.setTimeZone(endDate.getTimeZone());
        this.endDate.setTimeInMillis(endDate.getTimeInMillis());
    }

    public CreditPeriod(int id, int periodNameStyle, Calendar startDate, Calendar endDate, BigDecimal creditLimit) {
        this(periodNameStyle, startDate, endDate, creditLimit);

        this.id = id;
    }

    public CreditPeriod(int id, int periodNameStyle, Calendar startDate, Calendar endDate, BigDecimal creditLimit, List<Expense> expenses, List<Payment> payments) {
        this(id, periodNameStyle, startDate, endDate, creditLimit);

        this.expenses = expenses;
        this.payments = payments;
    }



    public int getId() {
        return id;
    }



    /**
     * returns periodName String according to periodNameStyle, which can be either
     * PERIOD_NAME_LARGEST_MONTH    -> "February", "March"  or
     * PERIOD_NAME_COMPLETE         -> "Feb 4 - Mar 3"      or
     * PERIOD_NAME_COMPLETE_NUMERIC -> "02/04 - 03/03"
     */
    public String getPeriodName() {
        if(periodName == null) {
            StringBuilder sb = new StringBuilder(40);
            switch(periodNameStyle) {
                case PERIOD_NAME_LARGEST_MONTH:
                    if (getStartDate().get(Calendar.DAY_OF_MONTH) <= 15)
                        periodName = getStartDate().getDisplayName(Calendar.MONTH, Calendar.LONG, Locale.getDefault());
                    else
                        periodName = getEndDate().getDisplayName(Calendar.MONTH, Calendar.LONG, Locale.getDefault());
                    break;

                case PERIOD_NAME_COMPLETE:
                    sb.append(getStartDate().getDisplayName(Calendar.MONTH, Calendar.SHORT, Locale.getDefault()));
                    sb.append(" ");
                    sb.append(getStartDate().get(Calendar.DAY_OF_MONTH));
                    sb.append(" - ");
                    sb.append(getEndDate().getDisplayName(Calendar.MONTH, Calendar.SHORT, Locale.getDefault()));
                    sb.append(" ");
                    sb.append(getEndDate().get(Calendar.DAY_OF_MONTH));
                    periodName = sb.toString();
                    break;

                case PERIOD_NAME_COMPLETE_NUMERIC:
                    sb.append(getStartDate().get(Calendar.MONTH) + 1);
                    sb.append(" ");
                    sb.append(getStartDate().get(Calendar.DAY_OF_MONTH));
                    sb.append(" - ");
                    sb.append(getEndDate().get(Calendar.MONTH) + 1);
                    sb.append(" ");
                    sb.append(getEndDate().get(Calendar.DAY_OF_MONTH));
                    periodName = sb.toString();
                    break;

                default:
                    periodName = "ERROR: undefined periodNameStyle";
            }
        }

        return periodName;
    }

    public int getPeriodNameStyle() {
        return periodNameStyle;
    }

    public Calendar getStartDate() {
        return startDate;
    }

    public Calendar getEndDate() {
        return endDate;
    }

    public BigDecimal getCreditLimit() {
        return creditLimit;
    }

    public void setCreditLimit(BigDecimal creditLimit) {
        this.creditLimit = new BigDecimal(creditLimit.toPlainString());
    }

    public List<Expense> getExpenses() {
        return expenses;
    }

    public void setExpenses(List<Expense> expenses) {
        this.expenses = expenses;
    }

    public List<Payment> getPayments() {
        return payments;
    }

    public void setPayments(List<Payment> payments) {
        this.payments = payments;
    }

    /**
     * Returns the sum of all the expenses, minus all the payments for this CreditPeriod
     * Positive value means there are unpaid expenses
     * @return
     */
    public BigDecimal getExpensesTotal() {
        BigDecimal balance = new BigDecimal(0);

        for (Expense e: expenses) {
            balance = balance.add(e.getAmount());
        }

        for (Payment p : payments) {
            balance = balance.subtract(p.getAmount());
        }

        return balance;
    }

    /**
     * Returns the sum of all the expenses, minus all the payments for this CreditPeriod
     * Positive value means there are unpaid expenses
     * @return
     */
    public List<BigDecimal> getExpensesByCategory() {

        int categoryIndex;
        int numCategories = ExpenseCategory.values().length;
        List<BigDecimal> expenseByCategory = new ArrayList<>();

        //Initialize expenseByCategory
        for (int i = 0; i < numCategories; ++i) {
            expenseByCategory.add(new BigDecimal(0));
        }

        //Iterate through expenses, accumulate expenses by category inside expenseByCategory list
        for (Expense e : expenses) {
            categoryIndex = e.getExpenseCategory().getIndex();
            BigDecimal currentVal = expenseByCategory.get(categoryIndex);
            expenseByCategory.set(categoryIndex, currentVal.add(e.amount));
        }

        return expenseByCategory;
    }


    /**
     * Returns creditLimit - expensesTotal = the available credit
     */
    public BigDecimal getAvailableCredit() {
        return getCreditLimit().subtract(getExpensesTotal());
    }


    /**
     * Returns the days in this period, startDate - endDate
     */
    public int getTotalDaysInPeriod() {

        // Create copies so we don't update the original calendars.
        Calendar start = Calendar.getInstance();
        start.setTimeZone(startDate.getTimeZone());
        start.setTimeInMillis(startDate.getTimeInMillis());

        Calendar end = Calendar.getInstance();
        end.setTimeZone(endDate.getTimeZone());
        end.setTimeInMillis(endDate.getTimeInMillis());

        // Add one millisecond so that the subtraction below works.
        // If end = Aug 5 23:59:59 we add one millisecond
        // so end = Aug 6 00:00:00 so that Aug 5 counts
        end.add(Calendar.MILLISECOND, 1);


        // At this point, each calendar is set to midnight on
        // their respective days. Now use TimeUnit.MILLISECONDS to
        // compute the number of full days between the two of them.
        int days = (int)TimeUnit.MILLISECONDS.toDays(Math.abs(end.getTimeInMillis() - start.getTimeInMillis()));
        return days;
    }

    public List<DailyExpense> getDailyExpenses() {
        List<DailyExpense> dailyExpenses = new ArrayList<>();

        Calendar cal = Calendar.getInstance();
        cal.setTimeZone(startDate.getTimeZone());
        cal.setTimeInMillis(startDate.getTimeInMillis());

        for (int i = 0; i < getTotalDaysInPeriod(); i++) {
            dailyExpenses.add(i, new DailyExpense(cal, new BigDecimal(0)));

            cal.add(Calendar.DAY_OF_MONTH, 1);
        }

        for (Expense expense: expenses) {
            int index = getDateIndex(expense.getDate());
            dailyExpenses.get(index).addToAmount(expense.getAmount());
        }

        return dailyExpenses;
    }


    public List<DailyExpense> getAccumulatedDailyExpenses() {
        List<DailyExpense> dailyAccumulatedExpenses = getDailyExpenses();
        BigDecimal accumulatedExpenses = new BigDecimal(0);

        Calendar cal = Calendar.getInstance();
        cal.setTimeZone(startDate.getTimeZone());
        cal.setTimeInMillis(startDate.getTimeInMillis());

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

            accumulatedExpenses = accumulatedExpenses.add(dailyAccumulatedExpenses.get(i).getAmount());
            dailyAccumulatedExpenses.remove(i);
            dailyAccumulatedExpenses.add(i, new DailyExpense(cal, accumulatedExpenses));

            cal.add(Calendar.DAY_OF_MONTH, 1);
        }
        return dailyAccumulatedExpenses;
    }


    private Calendar getStartOfDay(Calendar date) {

        Calendar cal = Calendar.getInstance();
        cal.setTimeZone(date.getTimeZone());
        cal.setTimeInMillis(date.getTimeInMillis());

        cal.set(Calendar.HOUR_OF_DAY, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MILLISECOND, 0);

        return cal;
    }

    public int getDateIndex(Calendar dateToBeIndexed) {

        // Create copies so we don't update the original calendars.
        Calendar start = Calendar.getInstance();
        start.setTimeZone(startDate.getTimeZone());
        start.setTimeInMillis(startDate.getTimeInMillis());

        Calendar end = Calendar.getInstance();
        end.setTimeZone(dateToBeIndexed.getTimeZone());
        end.setTimeInMillis(dateToBeIndexed.getTimeInMillis());

        // Set the copies to be at midnight, but keep the day information.
        start.set(Calendar.HOUR_OF_DAY, 0);
        start.set(Calendar.MINUTE, 0);
        start.set(Calendar.SECOND, 0);
        start.set(Calendar.MILLISECOND, 0);
        end.set(Calendar.HOUR_OF_DAY, 0);
        end.set(Calendar.MINUTE, 0);
        end.set(Calendar.SECOND, 0);
        end.set(Calendar.MILLISECOND, 0);

        // At this point, each calendar is set to midnight on
        // their respective days. Now use TimeUnit.MILLISECONDS to
        // compute the number of full days between the two of them.


        int days = (int) TimeUnit.MILLISECONDS.toDays(Math.abs(end.getTimeInMillis() - start.getTimeInMillis()));
        return days;
    }

    @Override
    public String toString() {
        return  "ID=" + id + "\r\n" +
                " periodName=" + periodName + "\r\n" +
                " periodNameStyle=" + periodNameStyle + "\r\n" +
                " startDate=" + startDate.getTimeInMillis() + "\r\n" +
                " endDate=" + endDate.getTimeInMillis() + "\r\n" +
                " creditLimit=" + creditLimit;
    }

}
app/src/main/java/ve/com/abicelis/creditcardexpensemanager/enums/ExpenseCategory.java
public enum ExpenseCategory {

    FOOD(0, "Food", R.color.expense_category_1),
    LEISURE(1, "Leisure", R.color.expense_category_2),
    ENTERTAINMENT(2, "Entertainment", R.color.expense_category_3),
    CLOTHING(3, "Clothing", R.color.expense_category_4),
    EDUCATION(4, "Education", R.color.expense_category_5);



    private int mIndex;
    private String mFriendlyName;
    private int mColor;

    ExpenseCategory(int index, String friendlyName, int color) {

        mIndex = index;
        mFriendlyName = friendlyName;
        mColor = color;
    }


    public String getCode(){
        return this.name();
    }

    public int getColor() {
        return mColor;
    }

    public String getFriendlyName() {
        return mFriendlyName;
    }

    @Override
    public String toString() {
        return mFriendlyName;
    }

    public int getIndex() {
       return mIndex;
    }

    public static ExpenseCategory getByExpenseCategoryId(int expenseCategoryId) {

        for(ExpenseCategory expenseCategory : ExpenseCategory.values()) {
            if(expenseCategory.getIndex() == expenseCategoryId)
                return expenseCategory;
        }
        throw new IllegalArgumentException(String.valueOf(expenseCategoryId));
    }

}
app/src/main/java/ve/com/abicelis/creditcardexpensemanager/exceptions/CreditCardNotFoundException.java
public class CreditCardNotFoundException extends Exception {

    public static final String DEFAULT_MESSAGE = "Credit Card does not exist";

    public CreditCardNotFoundException(String message) {
        super(message);
    }

    public CreditCardNotFoundException(String message, Throwable cause) {
        super(message, cause);
    }
}
app/src/main/java/ve/com/abicelis/creditcardexpensemanager/model/CreditCard.java
public class CreditCard implements Serializable {

    private int id;
    private String cardAlias;
    private String bankName;
    private String cardNumber;
    private Currency currency;
    private CreditCardType cardType;
    private Calendar cardExpiration;
    private int closingDay;         // Fecha de corte: Fecha de cierre de operaciones del mes, para efectos de registros y cobros.
    private int dueDay;             // Fecha Limite de Pago: Fecha máxima para el próximo pago sin generar incumplimiento e intereses de mora.
    private CreditCardBackground creditCardBackground;


    private Map<Integer, CreditPeriod> creditPeriods;

    public CreditCard(String cardAlias, String bankName, String cardNumber, @NonNull Currency currency, @NonNull CreditCardType cardType, @NonNull Calendar cardExpiration, int closingDay, int dueDay, @NonNull CreditCardBackground creditCardBackground) {
        this.cardAlias = cardAlias;
        this.bankName = bankName;
        this.cardNumber = cardNumber;
        this.currency = currency;
        this.cardType = cardType;

        this.cardExpiration = Calendar.getInstance();
        this.cardExpiration.setTimeZone(cardExpiration.getTimeZone());
        this.cardExpiration.setTimeInMillis(cardExpiration.getTimeInMillis());

        this.dueDay = dueDay;
        this.closingDay = closingDay;
        this.creditCardBackground = creditCardBackground;
    }

    public CreditCard(int id, String cardAlias, String bankName, String cardNumber, @NonNull Currency currency, @NonNull CreditCardType cardType, @NonNull Calendar cardExpiration, int closingDay, int dueDay, @NonNull CreditCardBackground creditCardBackground) {
        this(cardAlias, bankName, cardNumber, currency, cardType, cardExpiration, closingDay, dueDay, creditCardBackground);
        this.id = id;
    }

    public CreditCard(int id, String cardAlias, String bankName, String cardNumber, @NonNull Currency currency, @NonNull CreditCardType cardType, @NonNull Calendar cardExpiration, int closingDay, int dueDay, @NonNull CreditCardBackground creditCardBackground, @NonNull Map<Integer, CreditPeriod> creditPeriods) {
        this(id, cardAlias, bankName, cardNumber, currency, cardType, cardExpiration, closingDay, dueDay, creditCardBackground);
        this.creditPeriods = creditPeriods;
    }



    public int getId() {
        return id;
    }


    public String getCardAlias() {
        return cardAlias;
    }

    public void setCardAlias(String cardAlias) {
        this.cardAlias = cardAlias;
    }

    public String getBankName() {
        return bankName;
    }

    public void setBankName(String bankName) {
        this.bankName = bankName;
    }

    public String getCardNumber() {
        return cardNumber;
    }

    public void setCardNumber(String cardNumber) {
        this.cardNumber = cardNumber;
    }

    public Currency getCurrency() {
        return currency;
    }

    public void setCurrency(Currency currency) {
        this.currency = currency;
    }

    public CreditCardType getCardType() {
        return cardType;
    }

    public void setCardType(CreditCardType cardType) {
        this.cardType = cardType;
    }

    public Calendar getCardExpiration() {
        return cardExpiration;
    }

    public void setCardExpiration(Calendar cardExpiration) {
        this.cardExpiration = Calendar.getInstance();
        this.cardExpiration.setTimeZone(cardExpiration.getTimeZone());
        this.cardExpiration.setTimeInMillis(cardExpiration.getTimeInMillis());
    }

    public String getShortCardExpirationString() {
        if(cardExpiration == null)
            return "-/-";

        SimpleDateFormat formatter = new SimpleDateFormat("MM/yy", Locale.getDefault());
        return formatter.format(cardExpiration.getTime());
    }

    public String getLongCardExpirationString() {
        if(cardExpiration == null)
            return "-";

        SimpleDateFormat formatter = new SimpleDateFormat("MMM dd, yyyy", Locale.getDefault());
        return formatter.format(cardExpiration.getTime());
    }

    public int getClosingDay() {
        return closingDay;
    }

    public void setClosingDay(int closingDay) {
        this.closingDay = closingDay;
    }

    public int getDueDay() {
        return dueDay;
    }

    public void setDueDay(int dueDay) {
        this.dueDay = dueDay;
    }

    public CreditCardBackground getCreditCardBackground() {
        return creditCardBackground;
    }

    public Map<Integer, CreditPeriod> getCreditPeriods() {
        return creditPeriods;
    }

    public void setCreditPeriods(Map<Integer, CreditPeriod> creditPeriods) {
        this.creditPeriods = creditPeriods;
    }

    /**
     * Returns a List of Credit Cards based on the number of existing CreditCardBackgrounds, instantiated with default values
     * @return List<CreditCard>
     */
    public static List<CreditCard> getCreditCardBackgroundTypesList(Context context) {
        List<CreditCard> creditCards = new ArrayList<>();

        String defaultAlias = context.getResources().getString(R.string.activity_add_new_cc_alias);
        String defaultBankName = context.getResources().getString(R.string.activity_add_new_cc_bank);
        String defaultCardNumber = context.getResources().getString(R.string.activity_add_new_cc_number);
        Calendar defaultExpiration = Calendar.getInstance();
        defaultExpiration.add(Calendar.YEAR, 5);

        for (CreditCardBackground c : CreditCardBackground.values()) {
            creditCards.add(new CreditCard(defaultAlias, defaultBankName, defaultCardNumber, Currency.USD, CreditCardType.AMEX, defaultExpiration, 0, 0, c));
        }

        return creditCards;
    }

    @Override
    public String toString() {
        return  "ID=" + id + "\r\n" +
                " cardAlias=" + cardAlias + "\r\n" +
                " cardNumber=" + cardNumber + "\r\n" +
                " currency=" + currency + "\r\n" +
                " cardType=" + cardType + "\r\n" +
                " cardExpiration=" + cardExpiration + "\r\n" +
                " closingDay=" + closingDay + "\r\n" +
                " dueDay=" + dueDay + "\r\n" +
                " creditPeriods=" + creditPeriods;
    }
}
app/src/main/java/ve/com/abicelis/creditcardexpensemanager/app/utils/SharedPreferencesUtils.java
public class SharedPreferencesUtils {

    private static SharedPreferences getSharedPreferences(Context context) {
        return context.getSharedPreferences(Constants.PREFS_NAME, Context.MODE_PRIVATE);
    }

    private static void checkIfPreferenceExists(Context context, String preferenceName) throws SharedPreferenceNotFoundException {
        if(!getSharedPreferences(context).contains(preferenceName))
            throw new SharedPreferenceNotFoundException(preferenceName + " does not exist");
    }

    public static void setString(Context context, String preferenceName, String value) {
        getSharedPreferences(context).edit().putString(preferenceName, value).commit();
    }
    public static void setInt(Context context, String preferenceName, int value) {
        getSharedPreferences(context).edit().putInt(preferenceName, value).commit();
    }
    public static void setBoolean(Context context, String preferenceName, boolean value) {
        getSharedPreferences(context).edit().putBoolean(preferenceName, value).commit();
    }
    public static void setLong(Context context, String preferenceName, long value) {
        getSharedPreferences(context).edit().putLong(preferenceName, value).commit();
    }
    public static void setFloat(Context context, String preferenceName, float value) {
        getSharedPreferences(context).edit().putFloat(preferenceName, value).commit();
    }

    public static String getString(Context context, String preferenceName) throws SharedPreferenceNotFoundException {
        checkIfPreferenceExists(context, preferenceName);
        return getSharedPreferences(context).getString(preferenceName, "");
    }
    public static int getInt(Context context, String preferenceName) throws SharedPreferenceNotFoundException {
        checkIfPreferenceExists(context, preferenceName);
        return getSharedPreferences(context).getInt(preferenceName, 0);
    }
    public static boolean getBoolean(Context context, String preferenceName) throws SharedPreferenceNotFoundException {
        checkIfPreferenceExists(context, preferenceName);
        return getSharedPreferences(context).getBoolean(preferenceName, false);
    }
    public static long getLong(Context context, String preferenceName) throws SharedPreferenceNotFoundException {
        checkIfPreferenceExists(context, preferenceName);
        return getSharedPreferences(context).getLong(preferenceName, 0);
    }
    public static float getFloat(Context context, String preferenceName) throws SharedPreferenceNotFoundException {
        checkIfPreferenceExists(context, preferenceName);
        return getSharedPreferences(context).getFloat(preferenceName, 0);
    }

}
app/src/main/java/ve/com/abicelis/creditcardexpensemanager/exceptions/SharedPreferenceNotFoundException.java
public class SharedPreferenceNotFoundException extends Exception {

    public static final String DEFAULT_MESSAGE = "Preference not found";

    public SharedPreferenceNotFoundException(String message) {
        super(message);
    }

    public SharedPreferenceNotFoundException(String message, Throwable cause) {
        super(message, cause);
    }
}
app/src/main/java/ve/com/abicelis/creditcardexpensemanager/exceptions/CreditPeriodNotFoundException.java
public class CreditPeriodNotFoundException extends Exception {

    public static final String DEFAULT_MESSAGE = "Credit Period does not exist";

    public CreditPeriodNotFoundException(String message) {
        super(message);
    }

    public CreditPeriodNotFoundException(String message, Throwable cause) {
        super(message, cause);
    }
}
app/src/main/java/ve/com/abicelis/creditcardexpensemanager/database/ExpenseManagerDAO.java
public class ExpenseManagerDAO {

    private ExpenseManagerDbHelper mDatabaseHelper;

    public ExpenseManagerDAO(Context context) {
        mDatabaseHelper = new ExpenseManagerDbHelper(context);

    }

    /**
     * Returns a List of stored Credit Cards.
     * Note: The Credit Cards will not contain CreditPeriods, Expenses or Payments.
     */
    public List<CreditCard> getCreditCardList() {

        List<CreditCard> creditCards = new ArrayList<>();
        SQLiteDatabase db = mDatabaseHelper.getReadableDatabase();

        Cursor cursor = db.query(ExpenseManagerContract.CreditCardTable.TABLE_NAME, null, null, null, null, null, null);

        try {
            while (cursor.moveToNext()) {
                creditCards.add(getCreditCardFromCursor(cursor));
            }
        } finally {
            cursor.close();
        }

        return creditCards;
    }

    /**
     * Returns a List of CreditPeriods associated with ccardId.
     * Note: The periods will not contain Expenses or Payments.
     * @param cardId The ID of the Credit Card
     */
    public List<CreditPeriod> getCreditPeriodListFromCard(int cardId) {
        List<CreditPeriod> creditPeriods = new ArrayList<>();
        SQLiteDatabase db = mDatabaseHelper.getReadableDatabase();

        Cursor cursor =  db.query(ExpenseManagerContract.CreditPeriodTable.TABLE_NAME, null,
                ExpenseManagerContract.CreditPeriodTable.COLUMN_NAME_FOREIGN_KEY_CREDIT_CARD.getName() + " == " + cardId, null, null, null,
                ExpenseManagerContract.CreditPeriodTable.COLUMN_NAME_START_DATE.getName() + " DESC");

        try {
            while (cursor.moveToNext()) {
                creditPeriods.add(getCreditPeriodFromCursor(cursor));
            }
        } finally {
            cursor.close();
        }

        return creditPeriods;
    }



    /**
     * Finds a CreditCard with the supplied cardId, will not return creditPeriods associated with
     * the card
     * @param cardId The ID of the Credit Card
     */
    public CreditCard getCreditCard(int cardId) throws CreditCardNotFoundException {
        String[] selectionArgs = new String[]{String.valueOf(cardId)};
        SQLiteDatabase db = mDatabaseHelper.getReadableDatabase();

        Cursor cursor =  db.query(ExpenseManagerContract.CreditCardTable.TABLE_NAME, null,
                ExpenseManagerContract.CreditCardTable._ID + " =? ", selectionArgs, null, null, null);

        if(cursor.getCount() == 0)
            throw new CreditCardNotFoundException("Specified Credit Card not found in the database. Passed value=" + cardId);
        if(cursor.getCount() > 1)
            throw new CreditCardNotFoundException("Database UNIQUE constraint failure, more than one record found. Passed value=" + cardId);

        cursor.moveToNext();
        return getCreditCardFromCursor(cursor);
    }

    /**
     * Returns a Credit Card with the supplied cardId and the specified periodIndex.
     * Note: PeriodIndex must be either zero (returns credit period contaning current date) or a
     * negative value (-1 returns previous credit period, and so on)
     * @param cardId The ID of the Credit Card
     * @param periodIndex An integer <= 0
     */
    public CreditCard getCreditCardWithCreditPeriod(int cardId, int periodIndex) throws CreditCardNotFoundException, CreditPeriodNotFoundException, InvalidParameterException{
        if(periodIndex > 0)
            throw new InvalidParameterException("PeriodIndex must be >=0. Passed value=" + periodIndex);

        CreditCard creditCard = getCreditCard(cardId);

        //Get ordered (DESC) list of credit periods
        List<CreditPeriod> creditPeriods = getCreditPeriodListFromCard(cardId);

        //Find the creditPeriod according to periodIndex
        CreditPeriod cp = getCreditPeriodFromPeriodIndex(creditPeriods, periodIndex, creditCard.getClosingDay());

        //Create Map and set it on the Credit Card
        Map<Integer, CreditPeriod> creditPeriodMap = new HashMap<>();
        creditPeriodMap.put(periodIndex, cp);
        creditCard.setCreditPeriods(creditPeriodMap);

        return creditCard;
    }


    /**
     * Returns a Credit Card with the supplied cardId and as many credit periods as numPeriods
     * indicates. Counting backwards starting on periodIndex.
     * Note: PeriodIndex must be either zero (current creditPriod) or a
     * negative value (-1 refers to the previous credit period, and so on)
     * Note2: Passing periodIndex=-1, numPeriods=3 will return three periods (Period -1, -2 and -3)
     * @param cardId The ID of the Credit Card
     * @param periodIndex An integer <= 0
     * @param numPeriods An integer >= 1
     */
    public CreditCard getCreditCardWithCreditPeriodRange(int cardId, int periodIndex, int numPeriods) throws CreditCardNotFoundException, CreditPeriodNotFoundException, InvalidParameterException {
        if (periodIndex > 0)
            throw new InvalidParameterException("PeriodIndex must be less or equal than 0. Passed value=" + periodIndex);
        if (numPeriods <= 0)
            throw new InvalidParameterException("NumPeriods must be more or equal than 1. Passed value=" + periodIndex);

        CreditCard creditCard = getCreditCard(cardId);

        //Get ordered (DESC) list of credit periods
        List<CreditPeriod> creditPeriods = getCreditPeriodListFromCard(cardId);

        Map<Integer, CreditPeriod> creditPeriodMap = new HashMap<>();

        //Find the creditPeriod according to periodIndex
        for (int i = periodIndex; i > (periodIndex-numPeriods); --i) {
            CreditPeriod cp = getCreditPeriodFromPeriodIndex(creditPeriods, i, creditCard.getClosingDay());
            creditPeriodMap.put(i, cp);
        }

        //Set creditPeriods in creditCard and return
        creditCard.setCreditPeriods(creditPeriodMap);
        return creditCard;
    }


    /**
     * Returns a Credit Period from a List of creditPeriods which complies with the supplied
     * periodIndex and closingDay.
     * Note: PeriodIndex must be either zero (returns credit period contaning current date) or a
     * negative value (-1 returns previous credit period, and so on)
     * Note2: closingDay must be between 1 and 28.
     * @param creditPeriods List of Credit Periods to search into
     * @param periodIndex An integer <= 0
     * @param closingDay An integer between 1 and 28
     */
    private CreditPeriod getCreditPeriodFromPeriodIndex(List<CreditPeriod> creditPeriods, int periodIndex, int closingDay) throws CreditPeriodNotFoundException, InvalidParameterException {
        if(closingDay < 1 || closingDay > 28)
            throw new InvalidParameterException("ClosingDay must be between 1 and 28. Passed value=" + closingDay);
        if(periodIndex > 0)
            throw new InvalidParameterException("PeriodIndex must be >=0. Passed value=" + periodIndex);
        if(creditPeriods == null || creditPeriods.size() == 0)
            throw new InvalidParameterException("creditPeriods is null or empty");

        //Get a day which will be between the starting and ending dates of the wanted creditPeriod
        Calendar day = Calendar.getInstance();
        if(periodIndex != 0)
            day.add(Calendar.MONTH, periodIndex);

        for (CreditPeriod cp : creditPeriods) {
            if(cp.getStartDate().compareTo(day) <=0 && cp.getEndDate().compareTo(day) >=0) {
                cp.setExpenses(getExpensesFromCreditPeriod(cp.getId()));
                cp.setPayments(getPaymentsFromCreditPeriod(cp.getId()));
                return cp;

            }
        }

        throw new CreditPeriodNotFoundException("Credit period (index " + periodIndex + ") not found in passed creditPeriods List");
    }

    /**
     * Returns a Credit Period with the supplied periodId, containing its Expenses and Payments
     * @param periodId The ID of the Credit Period
     */
    public CreditPeriod getCreditPeriodFromPeriodId(int periodId) throws CreditPeriodNotFoundException {
        SQLiteDatabase db = mDatabaseHelper.getReadableDatabase();
        CreditPeriod creditPeriod;

        Cursor cursor =  db.query(ExpenseManagerContract.CreditPeriodTable.TABLE_NAME, null, ExpenseManagerContract.CreditPeriodTable._ID + " == " + periodId, null, null, null, null);

        if(cursor.getCount() == 0)
            throw new CreditPeriodNotFoundException("Specified Credit Period not found in the database. Passed value=" + periodId);
        if(cursor.getCount() > 1)
            throw new CreditPeriodNotFoundException("Database UNIQUE constraint failure, more than one record found. Passed Value=" + periodId);

        try{
            cursor.moveToNext();
            creditPeriod = getCreditPeriodFromCursor(cursor);
            creditPeriod.setExpenses(getExpensesFromCreditPeriod(periodId));
            creditPeriod.setPayments(getPaymentsFromCreditPeriod(periodId));
        } finally {
            cursor.close();
        }

        return creditPeriod;
    }


    /**
     * Returns a List of Expenses, given a creditPeriodId
     * @param periodId the Id of the Credit period
     */
    public List<Expense> getExpensesFromCreditPeriod(int periodId) {
        List<Expense> expenses = new ArrayList<>();
        SQLiteDatabase db = mDatabaseHelper.getReadableDatabase();

        Cursor cursor =  db.query(ExpenseManagerContract.ExpenseTable.TABLE_NAME, null,
                ExpenseManagerContract.ExpenseTable.COLUMN_NAME_FOREIGN_KEY_CREDIT_PERIOD.getName() + " == " + periodId,
                null, null, null, ExpenseManagerContract.ExpenseTable.COLUMN_NAME_DATE.getName() + " DESC");


        try {
            while (cursor.moveToNext()) {
                expenses.add(getExpenseFromCursor(cursor));
            }
        } finally {
            cursor.close();
        }

        return expenses;
    }

    /**
     * Returns a List of Payments, given a creditPeriodId
     * @param periodId the Id of the Credit period
     */
    public List<Payment> getPaymentsFromCreditPeriod(int periodId) {
        List<Payment> payments = new ArrayList<>();
        SQLiteDatabase db = mDatabaseHelper.getReadableDatabase();

        Cursor cursor =  db.query(ExpenseManagerContract.PaymentTable.TABLE_NAME, null,
                ExpenseManagerContract.PaymentTable.COLUMN_NAME_FOREIGN_KEY_CREDIT_PERIOD.getName() + " == " + periodId,
                null, null, null, ExpenseManagerContract.PaymentTable.COLUMN_NAME_DATE.getName() + " DESC");

        try {
            while (cursor.moveToNext()) {
                payments.add(getPaymentFromCursor(cursor));
            }
        } finally {
            cursor.close();
        }

        return payments;
    }


    /**
     * Returns an Expenses, given an Expense ID
     * @param expenseId the Id of the Expense
     */
    public Expense getExpense(int expenseId) throws CouldNotGetDataException {
        SQLiteDatabase db = mDatabaseHelper.getReadableDatabase();
        String[] selectionArgs = new String[]{String.valueOf(expenseId)};


        Cursor cursor =  db.query(ExpenseManagerContract.ExpenseTable.TABLE_NAME, null,
                ExpenseManagerContract.ExpenseTable._ID + " =? ",
                selectionArgs, null, null, null);


        if(cursor.getCount() == 0)
            throw new CouldNotGetDataException("Expense not found for ID = " + expenseId);


        cursor.moveToNext();
        return getExpenseFromCursor(cursor);
    }



    /* Delete data from database */

    /**
     * Deletes a credit card, with its associated credit periods, expenses and payments
     */
    public boolean deleteCreditCard(int creditCardId) throws CouldNotDeleteDataException {

        //Fetch all credit periods and delete associated expenses and payments
        for( CreditPeriod cp : getCreditPeriodListFromCard(creditCardId)) {
            deleteExpensesFromCreditPeriod(cp.getId());
            deletePaymentsFromCreditPeriod(cp.getId());
            deleteCreditPeriod(cp.getId());
        }

        //Finally, delete the credit card
        SQLiteDatabase db = mDatabaseHelper.getWritableDatabase();
        String[] whereArgs = new String[]{String.valueOf(creditCardId)};

        return db.delete(ExpenseManagerContract.CreditCardTable.TABLE_NAME,
                ExpenseManagerContract.CreditCardTable._ID + " =?",
                whereArgs) > 0;
    }

    public boolean deleteCreditPeriod(int creditPeriodId) throws CouldNotDeleteDataException {
        SQLiteDatabase db = mDatabaseHelper.getWritableDatabase();
        String[] whereArgs = new String[]{String.valueOf(creditPeriodId)};

        return db.delete(ExpenseManagerContract.CreditPeriodTable.TABLE_NAME,
                ExpenseManagerContract.CreditPeriodTable._ID + " =?",
                whereArgs) > 0;
    }


    public boolean deleteExpensesFromCreditPeriod(int creditPeriodId) throws CouldNotDeleteDataException {
        SQLiteDatabase db = mDatabaseHelper.getWritableDatabase();
        String[] whereArgs = new String[]{String.valueOf(creditPeriodId)};

        return db.delete(ExpenseManagerContract.ExpenseTable.TABLE_NAME,
                ExpenseManagerContract.ExpenseTable.COLUMN_NAME_FOREIGN_KEY_CREDIT_PERIOD.getName() + " =?",
                whereArgs) > 0;
    }

    public boolean deleteExpense(int expenseId) throws CouldNotDeleteDataException {
        SQLiteDatabase db = mDatabaseHelper.getWritableDatabase();
        String[] whereArgs = new String[]{String.valueOf(expenseId)};

        return db.delete(ExpenseManagerContract.ExpenseTable.TABLE_NAME,
                ExpenseManagerContract.ExpenseTable._ID + " =?",
                whereArgs) > 0;
    }



    public boolean deletePaymentsFromCreditPeriod(int creditPeriodId) throws CouldNotDeleteDataException {
        SQLiteDatabase db = mDatabaseHelper.getWritableDatabase();
        String[] whereArgs = new String[]{String.valueOf(creditPeriodId)};

        return db.delete(ExpenseManagerContract.PaymentTable.TABLE_NAME,
                ExpenseManagerContract.PaymentTable.COLUMN_NAME_FOREIGN_KEY_CREDIT_PERIOD.getName() + " =?",
                whereArgs) > 0;
    }

    public boolean deletePayment(int paymentId) throws CouldNotDeleteDataException {
        SQLiteDatabase db = mDatabaseHelper.getWritableDatabase();
        String[] whereArgs = new String[]{String.valueOf(paymentId)};

        return db.delete(ExpenseManagerContract.PaymentTable.TABLE_NAME,
                ExpenseManagerContract.PaymentTable._ID + " =?",
                whereArgs) > 0;
    }




    /* Update data on database */
    public long updateCreditCard(CreditCard creditCard) throws CouldNotUpdateDataException {
        SQLiteDatabase db = mDatabaseHelper.getWritableDatabase();

        //Set values
        ContentValues values = getValuesFromCreditCard(creditCard);

        //Which row to update
        String selection = ExpenseManagerContract.CreditCardTable._ID + " =? ";
        String[] selectionArgs = { String.valueOf(creditCard.getId()) };

        int count = db.update(
                ExpenseManagerContract.CreditCardTable.TABLE_NAME,
                values,
                selection,
                selectionArgs);

        return count;
    }

    public long updateExpense(Expense expense) throws CouldNotUpdateDataException {
        SQLiteDatabase db = mDatabaseHelper.getWritableDatabase();

        //Set values
        ContentValues values = getValuesFromExpense(expense);

        //Which row to update
        String selection = ExpenseManagerContract.ExpenseTable._ID + " =? ";
        String[] selectionArgs = { String.valueOf(expense.getId()) };

        int count = db.update(
                ExpenseManagerContract.ExpenseTable.TABLE_NAME,
                values,
                selection,
                selectionArgs);

        return count;
    }

    public long updateCreditPeriod(int creditCardId, CreditPeriod creditPeriod) throws CouldNotUpdateDataException {
        SQLiteDatabase db = mDatabaseHelper.getWritableDatabase();

        //Set values
        ContentValues values = getValuesFromCreditPeriod(creditCardId, creditPeriod);

        //Which row to update
        String selection = ExpenseManagerContract.CreditPeriodTable._ID + " =? ";
        String[] selectionArgs = { String.valueOf(creditPeriod.getId()) };

        int count = db.update(
                ExpenseManagerContract.CreditPeriodTable.TABLE_NAME,
                values,
                selection,
                selectionArgs);

        return count;
    }



    /* Insert data into database */

    public long insertCreditCard(CreditCard creditcard, BigDecimal firstCreditPeriodLimit) throws CouldNotInsertDataException {
        SQLiteDatabase db = mDatabaseHelper.getWritableDatabase();

        ContentValues values = new ContentValues();
        values.put(ExpenseManagerContract.CreditCardTable.COLUMN_NAME_CARD_ALIAS.getName(), creditcard.getCardAlias());
        values.put(ExpenseManagerContract.CreditCardTable.COLUMN_NAME_BANK_NAME.getName(), creditcard.getBankName());
        values.put(ExpenseManagerContract.CreditCardTable.COLUMN_NAME_CARD_NUMBER.getName(), creditcard.getCardNumber());
        values.put(ExpenseManagerContract.CreditCardTable.COLUMN_NAME_CURRENCY.getName(), creditcard.getCurrency().getCode());
        values.put(ExpenseManagerContract.CreditCardTable.COLUMN_NAME_CARD_TYPE.getName(), creditcard.getCardType().getCode());
        values.put(ExpenseManagerContract.CreditCardTable.COLUMN_NAME_CLOSING_DAY.getName(), creditcard.getClosingDay());
        values.put(ExpenseManagerContract.CreditCardTable.COLUMN_NAME_DUE_DAY.getName(), creditcard.getDueDay());
        values.put(ExpenseManagerContract.CreditCardTable.COLUMN_NAME_BACKGROUND.getName(), creditcard.getCreditCardBackground().getCode());

        if(creditcard.getCardExpiration() != null)
            values.put(ExpenseManagerContract.CreditCardTable.COLUMN_NAME_CARD_EXPIRATION.getName(), creditcard.getCardExpiration().getTimeInMillis());
        else
            values.put(ExpenseManagerContract.CreditCardTable.COLUMN_NAME_CARD_EXPIRATION.getName(), "");

        long newRowId;
        newRowId = db.insert(ExpenseManagerContract.CreditCardTable.TABLE_NAME, null, values);

        if(newRowId == -1)
            throw new CouldNotInsertDataException("There was a problem inserting the Credit Card: " + creditcard.toString());
        else {
            //Insert first creditPeriod
            insertCurrentCreditPeriod(newRowId, creditcard.getClosingDay(), firstCreditPeriodLimit);
        }

        return newRowId;

    }

    /**
     * Inserts a creditPeriod associated to a creditCard, which engulfs the current date (today), given a closing date
     * @param creditCardId the Id of the CreditCard to associate the CreditPeriod
     * @param  closingDay the credit card's closing day
     * @param creditPeriodLimit BigDecimal value of the currency limit of the period
     */
    public long insertCurrentCreditPeriod(long creditCardId, int closingDay, BigDecimal creditPeriodLimit) throws CouldNotInsertDataException {
        //Insert first creditPeriod

        // Set dates to be at midnight (start of day) today.
        Calendar startDate = Calendar.getInstance();
        startDate.set(Calendar.HOUR_OF_DAY, 0);
        startDate.set(Calendar.MINUTE, 0);
        startDate.set(Calendar.SECOND, 0);
        startDate.set(Calendar.MILLISECOND, 0);
        startDate.set(Calendar.DAY_OF_MONTH, closingDay);

        Calendar endDate = Calendar.getInstance();
        endDate.setTimeInMillis(startDate.getTimeInMillis());

        //Check if closingDay if before or after today
        if(closingDay <= Calendar.getInstance().get(Calendar.DAY_OF_MONTH))
            endDate.add(Calendar.MONTH, 1);
        else
            startDate.add(Calendar.MONTH, -1);

        endDate.add(Calendar.MILLISECOND, -1);

        CreditPeriod creditPeriod = new CreditPeriod(CreditPeriod.PERIOD_NAME_COMPLETE, startDate, endDate, creditPeriodLimit);
        return insertCreditPeriod(creditCardId, creditPeriod);
    }

    public long insertCreditPeriod(long creditCardId, CreditPeriod creditPeriod) throws CouldNotInsertDataException {
        SQLiteDatabase db = mDatabaseHelper.getWritableDatabase();

        ContentValues values = new ContentValues();
        values.put(ExpenseManagerContract.CreditPeriodTable.COLUMN_NAME_FOREIGN_KEY_CREDIT_CARD.getName(), creditCardId);
        values.put(ExpenseManagerContract.CreditPeriodTable.COLUMN_NAME_PERIOD_NAME_STYLE.getName(), creditPeriod.getPeriodNameStyle());
        values.put(ExpenseManagerContract.CreditPeriodTable.COLUMN_NAME_START_DATE.getName(), creditPeriod.getStartDate().getTimeInMillis());
        values.put(ExpenseManagerContract.CreditPeriodTable.COLUMN_NAME_END_DATE.getName(), creditPeriod.getEndDate().getTimeInMillis());
        values.put(ExpenseManagerContract.CreditPeriodTable.COLUMN_NAME_CREDIT_LIMIT.getName(), creditPeriod.getCreditLimit().toPlainString());


        long newRowId = -1;
        newRowId = db.insert(ExpenseManagerContract.CreditPeriodTable.TABLE_NAME, null, values);

        if(newRowId == -1)
            throw new CouldNotInsertDataException("There was a problem inserting the Credit Period: " + creditPeriod.toString());

        return newRowId;

    }

    public long insertExpense(int creditPeriodId, Expense expense) throws CouldNotInsertDataException {
        SQLiteDatabase db = mDatabaseHelper.getWritableDatabase();

        ContentValues values = getValuesFromExpense(expense);
        values.put(ExpenseManagerContract.ExpenseTable.COLUMN_NAME_FOREIGN_KEY_CREDIT_PERIOD.getName(), creditPeriodId);

        long newRowId;
        newRowId = db.insert(ExpenseManagerContract.ExpenseTable.TABLE_NAME, null, values);

        if(newRowId == -1)
            throw new CouldNotInsertDataException("There was a problem inserting the Expense: " + expense.toString());

        return newRowId;
    }


    public long insertPayment(int creditPeriodId, Payment payment) throws CouldNotInsertDataException {
        SQLiteDatabase db = mDatabaseHelper.getWritableDatabase();

        ContentValues values = new ContentValues();
        values.put(ExpenseManagerContract.PaymentTable.COLUMN_NAME_FOREIGN_KEY_CREDIT_PERIOD.getName(), creditPeriodId);
        values.put(ExpenseManagerContract.PaymentTable.COLUMN_NAME_DESCRIPTION.getName(), payment.getDescription());
        values.put(ExpenseManagerContract.PaymentTable.COLUMN_NAME_AMOUNT.getName(), payment.getAmount().toPlainString());
        values.put(ExpenseManagerContract.PaymentTable.COLUMN_NAME_CURRENCY.getName(), payment.getCurrency().getCode());
        values.put(ExpenseManagerContract.PaymentTable.COLUMN_NAME_DATE.getName(), payment.getDate().getTimeInMillis());


        long newRowId;
        newRowId = db.insert(ExpenseManagerContract.ExpenseTable.TABLE_NAME, null, values);

        if(newRowId == -1)
            throw new CouldNotInsertDataException("There was a problem inserting the Payment: " + payment.toString());

        return newRowId;
    }



    /* Model to ContentValues */
    private ContentValues getValuesFromExpense(Expense expense) {
        ContentValues values = new ContentValues();
        values.put(ExpenseManagerContract.ExpenseTable.COLUMN_NAME_DESCRIPTION.getName(), expense.getDescription());
        values.put(ExpenseManagerContract.ExpenseTable.COLUMN_NAME_THUMBNAIL.getName(), expense.getThumbnail());
        values.put(ExpenseManagerContract.ExpenseTable.COLUMN_NAME_FULL_IMAGE_PATH.getName(), expense.getFullImagePath());
        values.put(ExpenseManagerContract.ExpenseTable.COLUMN_NAME_AMOUNT.getName(), expense.getAmount().toPlainString());
        values.put(ExpenseManagerContract.ExpenseTable.COLUMN_NAME_CURRENCY.getName(), expense.getCurrency().getCode());
        values.put(ExpenseManagerContract.ExpenseTable.COLUMN_NAME_DATE.getName(), expense.getDate().getTimeInMillis());
        values.put(ExpenseManagerContract.ExpenseTable.COLUMN_NAME_EXPENSE_CATEGORY.getName(), expense.getExpenseCategory().getCode());
        values.put(ExpenseManagerContract.ExpenseTable.COLUMN_NAME_EXPENSE_TYPE.getName(), expense.getExpenseType().getCode());
        return values;
    }

    private ContentValues getValuesFromCreditCard(CreditCard creditCard) {
        ContentValues values = new ContentValues();
        values.put(ExpenseManagerContract.CreditCardTable.COLUMN_NAME_CARD_ALIAS.getName(), creditCard.getCardAlias());
        values.put(ExpenseManagerContract.CreditCardTable.COLUMN_NAME_BANK_NAME.getName(), creditCard.getBankName());
        values.put(ExpenseManagerContract.CreditCardTable.COLUMN_NAME_CARD_NUMBER.getName(), creditCard.getCardNumber());
        values.put(ExpenseManagerContract.CreditCardTable.COLUMN_NAME_CURRENCY.getName(), creditCard.getCurrency().getCode());
        values.put(ExpenseManagerContract.CreditCardTable.COLUMN_NAME_CARD_TYPE.getName(), creditCard.getCardType().getCode());
        values.put(ExpenseManagerContract.CreditCardTable.COLUMN_NAME_CARD_EXPIRATION.getName(), creditCard.getCardExpiration().getTimeInMillis());
        values.put(ExpenseManagerContract.CreditCardTable.COLUMN_NAME_CLOSING_DAY.getName(), creditCard.getClosingDay());
        values.put(ExpenseManagerContract.CreditCardTable.COLUMN_NAME_DUE_DAY.getName(), creditCard.getDueDay());
        values.put(ExpenseManagerContract.CreditCardTable.COLUMN_NAME_BACKGROUND.getName(), creditCard.getCreditCardBackground().getCode());
        return values;
    }

    private ContentValues getValuesFromCreditPeriod(int creditCardId, CreditPeriod creditPeriod) {
        ContentValues values = new ContentValues();
        values.put(ExpenseManagerContract.CreditPeriodTable.COLUMN_NAME_FOREIGN_KEY_CREDIT_CARD.getName(), creditCardId);
        values.put(ExpenseManagerContract.CreditPeriodTable.COLUMN_NAME_PERIOD_NAME_STYLE.getName(), creditPeriod.getPeriodNameStyle());
        values.put(ExpenseManagerContract.CreditPeriodTable.COLUMN_NAME_START_DATE.getName(), creditPeriod.getStartDate().getTimeInMillis());
        values.put(ExpenseManagerContract.CreditPeriodTable.COLUMN_NAME_END_DATE.getName(), creditPeriod.getEndDate().getTimeInMillis());
        values.put(ExpenseManagerContract.CreditPeriodTable.COLUMN_NAME_CREDIT_LIMIT.getName(), creditPeriod.getCreditLimit().toPlainString());
        return values;
    }


    /* Cursor to Model */

    private CreditCard getCreditCardFromCursor(Cursor cursor) {
        int id = cursor.getInt(cursor.getColumnIndex(ExpenseManagerContract.CreditCardTable._ID));
        String cardAlias = cursor.getString(cursor.getColumnIndex(ExpenseManagerContract.CreditCardTable.COLUMN_NAME_CARD_ALIAS.getName()));
        String bankName = cursor.getString(cursor.getColumnIndex(ExpenseManagerContract.CreditCardTable.COLUMN_NAME_BANK_NAME.getName()));
        String cardNumber = cursor.getString(cursor.getColumnIndex(ExpenseManagerContract.CreditCardTable.COLUMN_NAME_CARD_NUMBER.getName()));
        Currency currency = Currency.valueOf(cursor.getString(cursor.getColumnIndex(ExpenseManagerContract.CreditCardTable.COLUMN_NAME_CURRENCY.getName())));
        CreditCardType cardType = CreditCardType.valueOf(cursor.getString(cursor.getColumnIndex(ExpenseManagerContract.CreditCardTable.COLUMN_NAME_CARD_TYPE.getName())));
        int closingDay = cursor.getInt(cursor.getColumnIndex(ExpenseManagerContract.CreditCardTable.COLUMN_NAME_CLOSING_DAY.getName()));
        int dueDay = cursor.getInt(cursor.getColumnIndex(ExpenseManagerContract.CreditCardTable.COLUMN_NAME_DUE_DAY.getName()));
        CreditCardBackground creditCardBackground = CreditCardBackground.valueOf(cursor.getString(cursor.getColumnIndex(ExpenseManagerContract.CreditCardTable.COLUMN_NAME_BACKGROUND.getName())));


        Calendar cardExpiration = null;
        if(!cursor.getString(cursor.getColumnIndex(ExpenseManagerContract.CreditCardTable.COLUMN_NAME_CARD_EXPIRATION.getName())).isEmpty()) {
            cardExpiration = Calendar.getInstance();
            cardExpiration.setTimeInMillis(cursor.getLong(cursor.getColumnIndex(ExpenseManagerContract.CreditCardTable.COLUMN_NAME_CARD_EXPIRATION.getName())));
        }

        return new CreditCard(id, cardAlias, bankName, cardNumber, currency, cardType, cardExpiration, closingDay, dueDay, creditCardBackground);
    }


    private CreditPeriod getCreditPeriodFromCursor(Cursor cursor) {
        int id = cursor.getInt(cursor.getColumnIndex(ExpenseManagerContract.CreditPeriodTable._ID));
        int periodNameStyle = cursor.getInt(cursor.getColumnIndex(ExpenseManagerContract.CreditPeriodTable.COLUMN_NAME_PERIOD_NAME_STYLE.getName()));
        Calendar startDate = Calendar.getInstance();
        startDate.setTimeInMillis(cursor.getLong(cursor.getColumnIndex(ExpenseManagerContract.CreditPeriodTable.COLUMN_NAME_START_DATE.getName())));
        Calendar endDate = Calendar.getInstance();
        endDate.setTimeInMillis(cursor.getLong(cursor.getColumnIndex(ExpenseManagerContract.CreditPeriodTable.COLUMN_NAME_END_DATE.getName())));
        BigDecimal creditLimit =  new BigDecimal(cursor.getString(cursor.getColumnIndex(ExpenseManagerContract.CreditPeriodTable.COLUMN_NAME_CREDIT_LIMIT.getName())));

        return new CreditPeriod(id, periodNameStyle, startDate, endDate, creditLimit);
    }


    private Expense getExpenseFromCursor(Cursor cursor) {

        int id = cursor.getInt(cursor.getColumnIndex(ExpenseManagerContract.ExpenseTable._ID));
        String description = cursor.getString(cursor.getColumnIndex(ExpenseManagerContract.ExpenseTable.COLUMN_NAME_DESCRIPTION.getName()));
        byte[] image = cursor.getBlob(cursor.getColumnIndex(ExpenseManagerContract.ExpenseTable.COLUMN_NAME_THUMBNAIL.getName()));
        String fullImagePath = cursor.getString(cursor.getColumnIndex(ExpenseManagerContract.ExpenseTable.COLUMN_NAME_FULL_IMAGE_PATH.getName()));
        BigDecimal amount = new BigDecimal(cursor.getString(cursor.getColumnIndex(ExpenseManagerContract.ExpenseTable.COLUMN_NAME_AMOUNT.getName())));
        Currency currency = Currency.valueOf(cursor.getString(cursor.getColumnIndex(ExpenseManagerContract.ExpenseTable.COLUMN_NAME_CURRENCY.getName())));
        Calendar date = Calendar.getInstance();
        date.setTimeInMillis(cursor.getLong(cursor.getColumnIndex(ExpenseManagerContract.ExpenseTable.COLUMN_NAME_DATE.getName())));
        ExpenseCategory expenseCategory = ExpenseCategory.valueOf(cursor.getString(cursor.getColumnIndex(ExpenseManagerContract.ExpenseTable.COLUMN_NAME_EXPENSE_CATEGORY.getName())));
        ExpenseType expenseType = ExpenseType.valueOf(cursor.getString(cursor.getColumnIndex(ExpenseManagerContract.ExpenseTable.COLUMN_NAME_EXPENSE_TYPE.getName())));

        return new Expense(id, description, image, fullImagePath, amount, currency, date, expenseCategory, expenseType);
    }


    private Payment getPaymentFromCursor(Cursor cursor) {

        int id = cursor.getInt(cursor.getColumnIndex(ExpenseManagerContract.PaymentTable._ID));
        String description = cursor.getString(cursor.getColumnIndex(ExpenseManagerContract.PaymentTable.COLUMN_NAME_DESCRIPTION.getName()));
        BigDecimal amount = new BigDecimal(cursor.getString(cursor.getColumnIndex(ExpenseManagerContract.PaymentTable.COLUMN_NAME_AMOUNT.getName())));
        Currency currency = Currency.valueOf(cursor.getString(cursor.getColumnIndex(ExpenseManagerContract.PaymentTable.COLUMN_NAME_CURRENCY.getName())));
        Calendar date = Calendar.getInstance();
        date.setTimeInMillis(cursor.getLong(cursor.getColumnIndex(ExpenseManagerContract.PaymentTable.COLUMN_NAME_DATE.getName())));

        return new Payment(id, description, amount, currency, date);
    }
}


Question: package ve.com.abicelis.creditcardexpensemanager.app.fragments;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v4.content.ContextCompat;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.RelativeLayout;
import android.widget.Toast;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import lecho.lib.hellocharts.model.PieChartData;
import lecho.lib.hellocharts.model.SliceValue;
import lecho.lib.hellocharts.view.PieChartView;
import ve.com.abicelis.creditcardexpensemanager.R;
import ve.com.abicelis.creditcardexpensemanager.app.utils.Constants;
import ve.com.abicelis.creditcardexpensemanager.app.utils.SharedPreferencesUtils;
import ve.com.abicelis.creditcardexpensemanager.database.ExpenseManagerDAO;
import ve.com.abicelis.creditcardexpensemanager.enums.ExpenseCategory;
import ve.com.abicelis.creditcardexpensemanager.exceptions.CreditCardNotFoundException;
import ve.com.abicelis.creditcardexpensemanager.exceptions.CreditPeriodNotFoundException;
import ve.com.abicelis.creditcardexpensemanager.exceptions.SharedPreferenceNotFoundException;
import ve.com.abicelis.creditcardexpensemanager.model.CreditCard;
import ve.com.abicelis.creditcardexpensemanager.model.CreditPeriod;
import ve.com.abicelis.creditcardexpensemanager.model.Expense;




/**
 * Created by abice on 30/1/2017.
 */

public class ChartCategoryFragment extends Fragment {


    //UI
    private PieChartView chart;
    private RelativeLayout mNoExpensesContainer;

    //DATA
    private boolean chartIsVisible = false;
    private int activeCreditCardId;
    private ExpenseManagerDAO dao;
    private PieChartData data;
Answer:     CreditPeriod creditPeriod;