<commit_before>package org.gnucash.android.ui.chart;

import android.graphics.Color;
import android.os.Bundle;
import android.util.Log;
import android.widget.LinearLayout;

import com.github.mikephil.charting.charts.BarChart;
import com.github.mikephil.charting.components.Legend;
import com.github.mikephil.charting.data.BarData;
import com.github.mikephil.charting.data.BarDataSet;
import com.github.mikephil.charting.data.BarEntry;
import com.github.mikephil.charting.utils.LargeValueFormatter;

import org.gnucash.android.R;
import org.gnucash.android.db.AccountsDbAdapter;
import org.gnucash.android.db.TransactionsDbAdapter;
import org.gnucash.android.model.Account;
import org.gnucash.android.model.AccountType;
import org.gnucash.android.ui.passcode.PassLockActivity;
import org.joda.time.LocalDateTime;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 *
 * @author <NAME> <<EMAIL>>
 */
public class BarChartActivity extends PassLockActivity {

    private static final String TAG = "BarChartActivity";
    private static final String X_AXIS_PATTERN = "MMM YY";

    private static final int[] COLORS = {
            Color.rgb(104, 241, 175), Color.RED
    };

    private BarChart mChart;
    private List<AccountType> mAccountTypeList;
    private Map<AccountType, Long> mEarliestTimestampsMap = new HashMap<AccountType, Long>();
    private Map<AccountType, Long> mLatestTimestampsMap = new HashMap<AccountType, Long>();
    private long mEarliestTransactionTimestamp;
    private long mLatestTransactionTimestamp;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        setContentView(R.layout.activity_line_chart);
        super.onCreate(savedInstanceState);

        mChart = new com.github.mikephil.charting.charts.BarChart(this);
        ((LinearLayout) findViewById(R.id.chart)).addView(mChart);
        mChart.setDescription("");
//        mChart.setValueFormatter(new LargeValueFormatter());
        mChart.setDrawValuesForWholeStack(false);
        mChart.setDrawBarShadow(false);
//        XLabels xl  = mChart.getXLabels();
//        xl.setCenterXLabelText(true);
        mChart.getAxisLeft().setValueFormatter(new LargeValueFormatter());
        mChart.getAxisRight().setEnabled(false);

//        mAccountTypeList = Arrays.asList(AccountType.EXPENSE, AccountType.INCOME);
        mAccountTypeList = Arrays.asList(AccountType.INCOME, AccountType.EXPENSE);
        setStackedData();

        Legend l = mChart.getLegend();
        l.setForm(Legend.LegendForm.SQUARE);
        l.setPosition(Legend.LegendPosition.RIGHT_OF_CHART_INSIDE);

        mChart.animateX(3000);
        mChart.invalidate();
    }

    protected void setStackedData() {
        AccountsDbAdapter mAccountsDbAdapter = AccountsDbAdapter.getInstance();

        setEarliestAndLatestTimestamps(mAccountTypeList);

        LocalDateTime start = new LocalDateTime(mEarliestTransactionTimestamp).withDayOfMonth(1).withMillisOfDay(0);
        LocalDateTime end = new LocalDateTime(mLatestTransactionTimestamp).withDayOfMonth(1).withMillisOfDay(0);
        Log.w(TAG, "X AXIS START DATE: " + start.toString("dd MM yyyy"));
        Log.w(TAG, "X AXIS END DATE: " + end.toString("dd MM yyyy"));

        Map<AccountType, List<String>> accountUIDMap = new HashMap<AccountType, List<String>>();
        for (AccountType accountType : mAccountTypeList) {
            List<String> accountUIDList = new ArrayList<String>();

            for (Account account : mAccountsDbAdapter.getSimpleAccountList()) {
                if (account.getAccountType() == accountType && !account.isPlaceholderAccount()) {
                    accountUIDList.add(account.getUID());

                }
                accountUIDMap.put(accountType, accountUIDList);
            }
        }

        ArrayList<BarDataSet> dataSets = new ArrayList<BarDataSet>();
        ArrayList<BarEntry> values = new ArrayList<BarEntry>();
        ArrayList<String> xVals = new ArrayList<String>();
        int z = 0;
        while (!start.isAfter(end)) {
            xVals.add(start.toString(X_AXIS_PATTERN));
            Log.i(TAG, "xVals " + start.toString("MM yy"));

            long startPeriod = start.dayOfMonth().withMinimumValue().millisOfDay().withMinimumValue().toDate().getTime();
            long endPeriod = start.dayOfMonth().withMaximumValue().millisOfDay().withMaximumValue().toDate().getTime();

            float stackedValues[] = new float[mAccountTypeList.size()];
            int i = 0;
            for (Map.Entry<AccountType, List<String>> entry : accountUIDMap.entrySet()) {
                float balance = (float) mAccountsDbAdapter.getAccountsBalance(entry.getValue(), startPeriod, endPeriod).absolute().asDouble();
                stackedValues[i++] = balance;
                Log.w(TAG, entry.getKey() + "" + start.toString(" MMMM yyyy") + ", balance = " + balance);
            }
            values.add(new BarEntry(stackedValues, z));
            z++;

            start = start.plusMonths(1);
        }

        BarDataSet set = new BarDataSet(values, "");
//        set.setValueFormatter();
        set.setStackLabels(new String[] { AccountType.INCOME.toString(), AccountType.EXPENSE.toString() });
        set.setColors(COLORS);

        dataSets.add(set);

        BarData bd = new BarData(xVals, dataSets);
        mChart.setData(bd);
    }

    private void setEarliestAndLatestTimestamps(List<AccountType> accountTypeList) {
        TransactionsDbAdapter transactionsDbAdapter = TransactionsDbAdapter.getInstance();
        for (AccountType type : accountTypeList) {
            mEarliestTimestampsMap.put(type, transactionsDbAdapter.getTimestampOfEarliestTransaction(type));
            mLatestTimestampsMap.put(type, transactionsDbAdapter.getTimestampOfLatestTransaction(type));
        }

        List<Long> timestamps = new ArrayList<Long>(mEarliestTimestampsMap.values());
        timestamps.addAll(mLatestTimestampsMap.values());
        Collections.sort(timestamps);
        mEarliestTransactionTimestamp = timestamps.get(0);
        mLatestTransactionTimestamp = timestamps.get(timestamps.size() - 1);
    }

}<commit_msg>Ability to select bar char's stack<commit_after>package org.gnucash.android.ui.chart;

import android.graphics.Color;
import android.os.Bundle;
import android.util.Log;
import android.widget.LinearLayout;
import android.widget.TextView;

import com.github.mikephil.charting.charts.BarChart;
import com.github.mikephil.charting.components.Legend;
import com.github.mikephil.charting.data.BarData;
import com.github.mikephil.charting.data.BarDataSet;
import com.github.mikephil.charting.data.BarEntry;
import com.github.mikephil.charting.data.Entry;
import com.github.mikephil.charting.listener.OnChartValueSelectedListener;
import com.github.mikephil.charting.utils.Highlight;
import com.github.mikephil.charting.utils.LargeValueFormatter;

import org.gnucash.android.R;
import org.gnucash.android.db.AccountsDbAdapter;
import org.gnucash.android.db.TransactionsDbAdapter;
import org.gnucash.android.model.Account;
import org.gnucash.android.model.AccountType;
import org.gnucash.android.ui.passcode.PassLockActivity;
import org.joda.time.LocalDateTime;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 *
 * @author <NAME> <<EMAIL>>
 */
public class BarChartActivity extends PassLockActivity implements OnChartValueSelectedListener {

    private static final String TAG = "BarChartActivity";
    private static final String X_AXIS_PATTERN = "MMM YY";

    private static final int[] COLORS = {
            Color.rgb(104, 241, 175), Color.RED
    };

    private BarChart mChart;
    private List<AccountType> mAccountTypeList;
    private Map<AccountType, Long> mEarliestTimestampsMap = new HashMap<AccountType, Long>();
    private Map<AccountType, Long> mLatestTimestampsMap = new HashMap<AccountType, Long>();
    private long mEarliestTransactionTimestamp;
    private long mLatestTransactionTimestamp;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        setContentView(R.layout.activity_line_chart);
        super.onCreate(savedInstanceState);

        mChart = new com.github.mikephil.charting.charts.BarChart(this);
        ((LinearLayout) findViewById(R.id.chart)).addView(mChart);
        mChart.setOnChartValueSelectedListener(this);
        mChart.setDescription("");
//        mChart.setValueFormatter(new LargeValueFormatter());
        mChart.setDrawValuesForWholeStack(false);
        mChart.setDrawBarShadow(false);
//        XLabels xl  = mChart.getXLabels();
//        xl.setCenterXLabelText(true);
        mChart.getAxisLeft().setValueFormatter(new LargeValueFormatter());
        mChart.getAxisRight().setEnabled(false);

//        mAccountTypeList = Arrays.asList(AccountType.EXPENSE, AccountType.INCOME);
        mAccountTypeList = Arrays.asList(AccountType.INCOME, AccountType.EXPENSE);
        setStackedData();

        Legend l = mChart.getLegend();
        l.setForm(Legend.LegendForm.SQUARE);
        l.setPosition(Legend.LegendPosition.RIGHT_OF_CHART_INSIDE);

        mChart.animateX(3000);
        mChart.invalidate();
    }

    protected void setStackedData() {
        AccountsDbAdapter mAccountsDbAdapter = AccountsDbAdapter.getInstance();

        setEarliestAndLatestTimestamps(mAccountTypeList);

        LocalDateTime start = new LocalDateTime(mEarliestTransactionTimestamp).withDayOfMonth(1).withMillisOfDay(0);
        LocalDateTime end = new LocalDateTime(mLatestTransactionTimestamp).withDayOfMonth(1).withMillisOfDay(0);
        Log.w(TAG, "X AXIS START DATE: " + start.toString("dd MM yyyy"));
        Log.w(TAG, "X AXIS END DATE: " + end.toString("dd MM yyyy"));

        Map<AccountType, List<String>> accountUIDMap = new HashMap<AccountType, List<String>>();
        for (AccountType accountType : mAccountTypeList) {
            List<String> accountUIDList = new ArrayList<String>();

            for (Account account : mAccountsDbAdapter.getSimpleAccountList()) {
                if (account.getAccountType() == accountType && !account.isPlaceholderAccount()) {
                    accountUIDList.add(account.getUID());

                }
                accountUIDMap.put(accountType, accountUIDList);
            }
        }

        ArrayList<BarDataSet> dataSets = new ArrayList<BarDataSet>();
        ArrayList<BarEntry> values = new ArrayList<BarEntry>();
        ArrayList<String> xVals = new ArrayList<String>();
        int z = 0;
        while (!start.isAfter(end)) {
            xVals.add(start.toString(X_AXIS_PATTERN));
            Log.i(TAG, "xVals " + start.toString("MM yy"));

            long startPeriod = start.dayOfMonth().withMinimumValue().millisOfDay().withMinimumValue().toDate().getTime();
            long endPeriod = start.dayOfMonth().withMaximumValue().millisOfDay().withMaximumValue().toDate().getTime();

            float stackedValues[] = new float[mAccountTypeList.size()];
            int i = 0;
            for (Map.Entry<AccountType, List<String>> entry : accountUIDMap.entrySet()) {
                float balance = (float) mAccountsDbAdapter.getAccountsBalance(entry.getValue(), startPeriod, endPeriod).absolute().asDouble();
                stackedValues[i++] = balance;
                Log.w(TAG, entry.getKey() + "" + start.toString(" MMMM yyyy") + ", balance = " + balance);
            }
            values.add(new BarEntry(stackedValues, z));
            z++;

            start = start.plusMonths(1);
        }

        BarDataSet set = new BarDataSet(values, "");
//        set.setValueFormatter();
        set.setStackLabels(new String[] { AccountType.INCOME.toString(), AccountType.EXPENSE.toString() });
        set.setColors(COLORS);

        dataSets.add(set);

        BarData bd = new BarData(xVals, dataSets);
        mChart.setData(bd);
    }

    private void setEarliestAndLatestTimestamps(List<AccountType> accountTypeList) {
        TransactionsDbAdapter transactionsDbAdapter = TransactionsDbAdapter.getInstance();
        for (AccountType type : accountTypeList) {
            mEarliestTimestampsMap.put(type, transactionsDbAdapter.getTimestampOfEarliestTransaction(type));
            mLatestTimestampsMap.put(type, transactionsDbAdapter.getTimestampOfLatestTransaction(type));
        }

        List<Long> timestamps = new ArrayList<Long>(mEarliestTimestampsMap.values());
        timestamps.addAll(mLatestTimestampsMap.values());
        Collections.sort(timestamps);
        mEarliestTransactionTimestamp = timestamps.get(0);
        mLatestTransactionTimestamp = timestamps.get(timestamps.size() - 1);
    }

    @Override
    public void onValueSelected(Entry e, int dataSetIndex, Highlight h) {
        if (e == null) return;
        ((TextView) findViewById(R.id.selected_chart_slice))
                .setText(mChart.getData().getXVals().get(e.getXIndex()) + " - " + e.getVal()
                        + " (" + String.format("%.2f", (e.getVal() / mChart.getData().getDataSetByIndex(dataSetIndex).getYValueSum()) * 100) + " %)");
    }

    @Override
    public void onNothingSelected() {
        ((TextView) findViewById(R.id.selected_chart_slice)).setText("");
    }
}
{'fraction_non_alphanumeric': 0.1170005980861244, 'fraction_numerical': 0.0035885167464114833, 'mean_word_length': 3.460486828942981, 'pattern_counts': {'":': 0, '<': 53, '<?xml version=': 0, '>': 53, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3228629', 'n_tokens_mistral': 3990, 'n_tokens_neox': 3880, 'n_words': 647}