com.wildplot.android.ankistats.CardsTypes.java Source code

Java tutorial

Introduction

Here is the source code for com.wildplot.android.ankistats.CardsTypes.java

Source

/****************************************************************************************
 * Copyright (c) 2011 Norbert Nagold <norbert.nagold@gmail.com>                         *
 * Copyright (c) 2014 Michael Goldbach <trashcutter@googlemail.com>                     *
 *                                                                                      *
 * This program 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 program.  If not, see <http://www.gnu.org/licenses/>.                           *
 ****************************************************************************************/
package com.wildplot.android.ankistats;

import android.database.Cursor;
import android.graphics.Bitmap;
import android.util.Log;
import android.widget.ImageView;
import com.wildplot.android.rendering.*;
import com.wildplot.android.rendering.graphics.wrapper.BufferedImage;
import com.wildplot.android.rendering.graphics.wrapper.Color;
import com.wildplot.android.rendering.graphics.wrapper.Graphics2D;
import com.wildplot.android.rendering.graphics.wrapper.Rectangle;
import org.json.JSONException;
import org.json.JSONObject;

import java.util.ArrayList;

/**
 * Created by mig on 06.07.2014.
 */
public class CardsTypes {
    private AnkiDb mAnkiDb;
    private ImageView mImageView;
    private CollectionData mCollectionData;

    private int mFrameThickness = 60;
    private int targetPixelDistanceBetweenTics = 150;

    private int mMaxCards = 0;
    private int mMaxElements = 0;
    private int mType;
    private int mTitle;
    private boolean mBackwards;
    private int[] mValueLabels;
    private int[] mColors;
    private int[] mAxisTitles;
    private double[][] mSeriesList;
    private double mBarThickness = 0.8;
    private double[][] mCumulative;

    public CardsTypes(AnkiDb ankiDb, ImageView imageView, CollectionData collectionData) {
        mAnkiDb = ankiDb;
        mImageView = imageView;
        mCollectionData = collectionData;
    }

    public Bitmap renderChart(int type) {
        calculateCardsTypes(type);
        int height = mImageView.getMeasuredHeight();
        int width = mImageView.getMeasuredWidth();

        if (height <= 0 || width <= 0) {
            return null;
        }

        BufferedImage bufferedFrameImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
        Graphics2D g = bufferedFrameImage.createGraphics();
        Rectangle rect = new Rectangle(width, height);
        g.setClip(rect);
        g.setColor(Color.BLACK);
        float textSize = AnkiStatsApplication.getInstance().getmStandardTextSize() * 0.75f;
        g.setFontSize(textSize);

        float FontHeigth = g.getFontMetrics().getHeight(true);
        mFrameThickness = Math.round(FontHeigth * 4.0f);
        //System.out.println("frame thickness: " + mFrameThickness);

        PlotSheet plotSheet = new PlotSheet(0, 15, 0, 15);
        plotSheet.setFrameThickness(mFrameThickness);
        plotSheet.unsetBorder();
        PieChart pieChart = new PieChart(plotSheet, mSeriesList[0]);

        Color[] colors = { new Color(mImageView.getResources().getColor(mColors[0])),
                new Color(mImageView.getResources().getColor(mColors[1])),
                new Color(mImageView.getResources().getColor(mColors[2])),
                new Color(mImageView.getResources().getColor(mColors[3])) };
        pieChart.setColors(colors);
        pieChart.setName(mImageView.getResources().getString(mValueLabels[0]) + ": " + (int) mSeriesList[0][0]);
        LegendDrawable legendDrawable1 = new LegendDrawable();
        LegendDrawable legendDrawable2 = new LegendDrawable();
        LegendDrawable legendDrawable3 = new LegendDrawable();
        legendDrawable1.setColor(new Color(mImageView.getResources().getColor(mColors[1])));
        legendDrawable2.setColor(new Color(mImageView.getResources().getColor(mColors[2])));
        legendDrawable3.setColor(new Color(mImageView.getResources().getColor(mColors[3])));

        legendDrawable1
                .setName(mImageView.getResources().getString(mValueLabels[1]) + ": " + (int) mSeriesList[0][1]);
        legendDrawable2
                .setName(mImageView.getResources().getString(mValueLabels[2]) + ": " + (int) mSeriesList[0][2]);
        legendDrawable3
                .setName(mImageView.getResources().getString(mValueLabels[3]) + ": " + (int) mSeriesList[0][3]);

        plotSheet.setFontSize(textSize);
        plotSheet.addDrawable(pieChart);
        plotSheet.addDrawable(legendDrawable1);
        plotSheet.addDrawable(legendDrawable2);
        plotSheet.addDrawable(legendDrawable3);

        plotSheet.paint(g);
        Bitmap bitmap = bufferedFrameImage.getBitmap();
        bitmap.prepareToDraw();
        return bitmap;
    }

    public boolean calculateCardsTypes(int type) {
        mTitle = R.string.stats_cards_types;
        mAxisTitles = new int[] { R.string.stats_answer_type, R.string.stats_answers,
                R.string.stats_cumulative_correct_percentage };

        mValueLabels = new int[] { R.string.statistics_mature, R.string.statistics_young_and_learn,
                R.string.statistics_unlearned, R.string.statistics_suspended };
        mColors = new int[] { R.color.stats_mature, R.color.stats_young, R.color.stats_unseen,
                R.color.stats_suspended };

        mType = type;

        ArrayList<double[]> list = new ArrayList<double[]>();
        double[] pieData;
        Cursor cur = null;
        String query = "select " + "sum(case when queue=2 and ivl >= 21 then 1 else 0 end), -- mtr\n"
                + "sum(case when queue in (1,3) or (queue=2 and ivl < 21) then 1 else 0 end), -- yng/lrn\n"
                + "sum(case when queue=0 then 1 else 0 end), -- new\n"
                + "sum(case when queue<0 then 1 else 0 end) -- susp\n" + "from cards where did in "
                + _limitWholeOnly();
        Log.d(AnkiStatsApplication.TAG, "CardsTypes query: " + query);

        try {
            cur = mAnkiDb.getDatabase().rawQuery(query, null);

            cur.moveToFirst();
            pieData = new double[] { cur.getDouble(0), cur.getDouble(1), cur.getDouble(2), cur.getDouble(3) };

        } finally {
            if (cur != null && !cur.isClosed()) {
                cur.close();
            }
        }

        //TODO adjust for CardsTypes, for now only copied from intervals
        // small adjustment for a proper chartbuilding with achartengine
        //        if (list.size() == 0 || list.get(0)[0] > 0) {
        //            list.add(0, new double[] { 0, 0, 0 });
        //        }
        //        if (num == -1 && list.size() < 2) {
        //            num = 31;
        //        }
        //        if (type != Utils.TYPE_LIFE && list.get(list.size() - 1)[0] < num) {
        //            list.add(new double[] { num, 0, 0 });
        //        } else if (type == Utils.TYPE_LIFE && list.size() < 2) {
        //            list.add(new double[] { Math.max(12, list.get(list.size() - 1)[0] + 1), 0, 0 });
        //        }

        mSeriesList = new double[1][4];
        mSeriesList[0] = pieData;
        return list.size() > 0;
    }

    public double ticsCalcX(int pixelDistance, Rectangle field) {
        double deltaRange = mMaxElements - 0;
        int ticlimit = field.width / pixelDistance;
        double tics = Math.pow(10, (int) Math.log10(deltaRange / ticlimit));
        while (2.0 * (deltaRange / (tics)) <= ticlimit) {
            tics /= 2.0;
        }
        while ((deltaRange / (tics)) / 2 >= ticlimit) {
            tics *= 2.0;
        }
        return tics;
    }

    public double ticsCalcY(int pixelDistance, Rectangle field) {
        double deltaRange = mMaxCards - 0;
        int ticlimit = field.height / pixelDistance;
        double tics = Math.pow(10, (int) Math.log10(deltaRange / ticlimit));
        while (2.0 * (deltaRange / (tics)) <= ticlimit) {
            tics /= 2.0;
        }
        while ((deltaRange / (tics)) / 2 >= ticlimit) {
            tics *= 2.0;
        }
        return tics;
    }

    public double ticsCalc(int pixelDistance, Rectangle field, double deltaRange) {
        int ticlimit = field.height / pixelDistance;
        double tics = Math.pow(10, (int) Math.log10(deltaRange / ticlimit));
        while (2.0 * (deltaRange / (tics)) <= ticlimit) {
            tics /= 2.0;
        }
        while ((deltaRange / (tics)) / 2 >= ticlimit) {
            tics *= 2.0;
        }
        return tics;
    }

    /**
     * Daily cutoff ************************************************************* **********************************
     * This function uses GregorianCalendar so as to be sensitive to leap years, daylight savings, etc.
     */
    private String _limitWholeOnly() {

        ArrayList<Long> ids = new ArrayList<Long>();
        for (JSONObject d : mCollectionData.allDecks()) {
            try {
                ids.add(d.getLong("id"));
            } catch (JSONException e) {
                throw new RuntimeException(e);
            }
        }
        return Utils.ids2str(Utils.arrayList2array(ids));

    }

    private String _revlogLimitWholeOnly() {
        return "";
    }

}