de.dreier.mytargets.features.scoreboard.HtmlUtils.java Source code

Java tutorial

Introduction

Here is the source code for de.dreier.mytargets.features.scoreboard.HtmlUtils.java

Source

/*
 * Copyright (C) 2017 Florian Dreier
 *
 * This file is part of MyTargets.
 *
 * MyTargets is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2
 * as published by the Free Software Foundation.
 *
 * MyTargets 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.
 */

package de.dreier.mytargets.features.scoreboard;

import android.support.annotation.NonNull;
import android.support.v4.util.Pair;
import android.text.TextUtils;

import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Map;

import de.dreier.mytargets.R;
import de.dreier.mytargets.app.ApplicationInstance;
import de.dreier.mytargets.features.settings.SettingsManager;
import de.dreier.mytargets.shared.models.SelectableZone;
import de.dreier.mytargets.shared.models.Target;
import de.dreier.mytargets.shared.models.db.Arrow;
import de.dreier.mytargets.shared.models.db.Bow;
import de.dreier.mytargets.shared.models.db.End;
import de.dreier.mytargets.shared.models.db.Round;
import de.dreier.mytargets.shared.models.db.Shot;
import de.dreier.mytargets.shared.models.db.StandardRound;
import de.dreier.mytargets.shared.models.db.Training;
import de.dreier.mytargets.shared.utils.SharedUtils;

import static de.dreier.mytargets.shared.SharedApplicationInstance.get;
import static de.dreier.mytargets.shared.models.db.End.getSortedScoreDistribution;
import static de.dreier.mytargets.shared.targets.scoringstyle.ScoringStyle.MISS_SYMBOL;

public class HtmlUtils {

    public static final String BR = "<br>";
    private static final String CSS = "<style type=\"text/css\">\n" + "body{font-family: Roboto, Sans-serif;}\n"
            + ".myTable { border-collapse:collapse; width:100%; }\n"
            + ".myTable td, .myTable th { padding:5px; border:1px solid #000; }\n"
            + ".align_left td {text-align: left; }\n" + ".align_center td {text-align: center; }\n"
            + ".circle {border-radius: 50%; width: 20px; height: 20px; padding: 5px; text-align: center; margin: auto; position: relative;}\n"
            + ".circle_arrow { border-radius: 50%; width: 13px; height: 13px; \n"
            + "  padding: 2px; font-size: 11px; text-align: center; \n"
            + "  vertical-align: center; background: black; color: white;\n"
            + "  position: absolute; bottom: -4px; right: -4px; }" + "</style>";

    public static String getScoreboard(long trainingId, long roundId, ScoreboardConfiguration configuration) {
        // Query information from database
        Training training = Training.get(trainingId);
        List<Round> rounds;
        if (roundId == -1) {
            rounds = training.getRounds();
        } else {
            rounds = Collections.singletonList(Round.get(roundId));
        }

        // Initialize html Strings
        String html = "<html>" + CSS;

        if (configuration.showTitle) {
            html += "<h3>" + training.title + "</h3>";
        }

        boolean[] equals = new boolean[2];
        if (configuration.showProperties) {
            html += getTrainingInfoHTML(training, rounds, equals, true) + BR;
        }

        if (configuration.showTable) {
            for (Round round : rounds) {
                html += BR + bold(get(R.string.round) + " " + (round.index + 1));
                if (configuration.showProperties) {
                    html += BR + getRoundInfo(round, equals);
                }
                html += getRoundTable(configuration, round);
            }
        }

        if (configuration.showStatistics) {
            html += getStatistics(rounds);
        }

        if (configuration.showComments) {
            html += getComments(rounds);
        }

        if (configuration.showSignature) {
            html += getSignature();
        }

        html += "</html>";
        return html;
    }

    private static String getRoundTable(ScoreboardConfiguration configuration, Round round) {
        String html = "<table class=\"myTable\">";
        html += getTableHeader(round.shotsPerEnd);
        int carry = 0;
        for (End end : round.getEnds()) {
            html += "<tr class=\"align_center\">";
            html += "<td>" + (end.index + 1) + "</td>";
            int sum = 0;
            for (Shot shot : end.getSortedShotList()) {
                html += "<td>";
                html += getPoints(configuration, shot, round.getTarget());
                html += "</td>";
                int points = round.getTarget().getScoreByZone(shot.scoringRing, shot.index);
                sum += points;
                carry += points;
            }
            html += "<td>" + sum + "</td>";
            html += "<td>" + carry + "</td>";
            html += "</tr>";
        }
        html += "</table>";
        return html;
    }

    @NonNull
    private static String getPoints(ScoreboardConfiguration configuration, Shot shot, Target target) {
        final String points = target.zoneToString(shot.scoringRing, shot.index);
        if (configuration.showPointsColored) {
            int fillColor = target.getModel().getZone(shot.scoringRing).getFillColor();
            int color = target.getModel().getZone(shot.scoringRing).getTextColor();
            final String pointsDiv = String.format(
                    "<div class=\"circle\" style='background: #%06X; color: #%06X'>%s", fillColor & 0xFFFFFF,
                    color & 0xFFFFFF, points);
            final String arrowDiv = shot.arrowNumber == null ? ""
                    : String.format("<div class=\"circle_arrow\">%s</div>", shot.arrowNumber);
            return pointsDiv + arrowDiv + "</div>";
        } else {
            return points;
        }
    }

    private static String getTableHeader(int ppp) {
        String html = "<tr class=\"align_center\">" + "<th rowspan=\"2\">" + get(R.string.passe) + "</th>"
                + "<th colspan=\"" + ppp + "\">" + get(R.string.arrows) + "</th>" + "<th rowspan=\"2\">"
                + get(R.string.sum) + "</th>" + "<th rowspan=\"2\">" + get(R.string.carry) + "</th>"
                + "</tr><tr class=\"align_center\">";
        for (int i = 1; i <= ppp; i++) {
            html += "<th>" + i + "</th>";
        }
        html += "</tr>";
        return html;
    }

    private static String getComments(List<Round> rounds) {
        String comments = "<table class=\"myTable\" style=\"margin-top:5px;\"><tr class=\"align_center\">" + "<th>"
                + get(R.string.round) + "</th>" + "<th>" + get(R.string.passe) + "</th>" + "<th>"
                + get(R.string.points) + "</th>" + "<th>" + get(R.string.comment) + "</th></tr>";
        int commentsCount = 0;

        int j = 0;
        for (Round round : rounds) {
            int i = 1;
            List<End> ends = round.getEnds();
            for (End end : ends) {
                for (int s = 0; s < end.getShots().size(); s++) {
                    Shot shot = end.getShots().get(s);
                    if (!TextUtils.isEmpty(shot.comment)) {
                        comments += "<tr class=\"align_center\"><td>" + j + "</td>" + "<td>" + i + "</td>" + "<td>"
                                + round.getTarget().zoneToString(shot.scoringRing, s) + "</td>" + "<td>"
                                + TextUtils.htmlEncode(shot.comment).replace("\n", "<br />") + "</td></tr>";
                        commentsCount++;
                    }
                }
                i++;
            }
            j++;
        }

        // If a minimum of one comment is present show comments table
        String html = "";
        if (commentsCount > 0) {
            html = comments + "</table>";
        }
        return html;
    }

    public static String getRoundInfo(Round round, boolean[] equals) {
        HtmlInfoBuilder info = new HtmlInfoBuilder();
        if (!equals[0]) {
            info.addLine(R.string.distance, round.distance);
        }
        if (!equals[1]) {
            info.addLine(R.string.target_face, round.getTarget());
        }
        if (!round.comment.isEmpty()) {
            info.addLine(R.string.comment, round.comment);
        }
        return info.toString();
    }

    @NonNull
    private static String getStatistics(List<Round> rounds) {
        if (rounds.size() == 0) {
            return "";
        } else if (rounds.size() == 1) {
            return getStatisticsForRound(rounds);
        } else {
            String html = "";
            for (Round round : rounds) {
                html += BR + bold(get(R.string.round) + " " + (round.index + 1));
                html += getStatisticsForRound(Collections.singletonList(round));
            }
            html += BR + bold(get(R.string.training));
            return html + getStatisticsForRound(rounds);
        }
    }

    @NonNull
    private static String bold(String text) {
        return "<b>" + text + "</b>";
    }

    @NonNull
    private static String getStatisticsForRound(List<Round> rounds) {
        String html = BR + "<table class=\"myTable\" style=\"margin-top:5px;\"><tr>";
        List<Map.Entry<SelectableZone, Integer>> scoreDistribution = getSortedScoreDistribution(rounds);
        int hits = 0;
        int total = 0;
        for (Map.Entry<SelectableZone, Integer> score : scoreDistribution) {
            if (!score.getKey().text.equals(MISS_SYMBOL)) {
                hits += score.getValue();
            }
            total += score.getValue();
        }

        List<Pair<String, Integer>> topScores = End.getTopScoreDistribution(scoreDistribution);
        for (Pair<String, Integer> topScore : topScores) {
            html += "<th>" + topScore.first + "</th>";
        }
        html += "<th>" + get(R.string.hits) + "</th>";
        html += "<th>" + get(R.string.average) + "</th>";
        html += "</tr><tr class=\"align_center\">";

        for (Pair<String, Integer> topScore : topScores) {
            html += "<td>" + topScore.second + "</td>";
        }
        html += "<td>" + hits + "/" + total + "</td>";
        html += "<td>" + getAverageScore(scoreDistribution) + "</td>";
        return html + "</tr></table>";
    }

    private static String getAverageScore(List<Map.Entry<SelectableZone, Integer>> scoreDistribution) {
        int sum = 0;
        int count = 0;
        for (Map.Entry<SelectableZone, Integer> entry : scoreDistribution) {
            sum += entry.getValue() * entry.getKey().points;
            count += entry.getValue();
        }
        if (count == 0) {
            return "-";
        } else {
            return String.format(Locale.getDefault(), "%.2f", sum * 1.0f / count);
        }
    }

    public static String getTrainingInfoHTML(Training training, List<Round> rounds, boolean[] equals,
            boolean scoreboard) {
        HtmlInfoBuilder info = new HtmlInfoBuilder();
        addStaticTrainingHeaderInfo(info, training, rounds, scoreboard);
        addDynamicTrainingHeaderInfo(rounds, equals, info);
        return info.toString();
    }

    private static void addStaticTrainingHeaderInfo(HtmlInfoBuilder info, Training training, List<Round> rounds,
            boolean scoreboard) {
        if (scoreboard) {
            getScoreboardOnlyHeaderInfo(info, training, rounds);
        }

        if (training.indoor) {
            info.addLine(R.string.environment, get(R.string.indoor));
        } else {
            info.addLine(R.string.weather, training.getEnvironment().weather.getName());
            info.addLine(R.string.wind, training.getEnvironment().getWindSpeed(ApplicationInstance.getContext()));
            if (!TextUtils.isEmpty(training.getEnvironment().location)) {
                info.addLine(R.string.location, training.getEnvironment().location);
            }
        }

        Bow bow = Bow.get(training.bowId);
        if (bow != null) {
            info.addLine(R.string.bow, bow.name);
            if (scoreboard) {
                info.addLine(R.string.bow_type, bow.type);
            }
        }

        Arrow arrow = Arrow.get(training.arrowId);
        if (arrow != null) {
            info.addLine(R.string.arrow, arrow.name);
        }

        if (training.standardRoundId != null) {
            StandardRound standardRound = StandardRound.get(training.standardRoundId);
            info.addLine(R.string.standard_round, standardRound.name);
        }
    }

    private static void addDynamicTrainingHeaderInfo(List<Round> rounds, boolean[] equals, HtmlInfoBuilder info) {
        if (rounds.size() > 0) {
            getEqualValues(rounds, equals);
            Round round = rounds.get(0);
            if (equals[0]) {
                info.addLine(R.string.distance, round.distance);
            }
            if (equals[1]) {
                info.addLine(R.string.target_face, round.getTarget());
            }
        }
    }

    private static void getEqualValues(List<Round> rounds, boolean[] equals) {
        // Aggregate round information
        equals[0] = true;
        equals[1] = true;
        Round round = rounds.get(0);
        for (Round r : rounds) {
            equals[0] = SharedUtils.equals(r.distance, round.distance) && equals[0];
            equals[1] = r.getTarget().equals(round.getTarget()) && equals[1];
        }
    }

    private static void getScoreboardOnlyHeaderInfo(HtmlInfoBuilder info, Training training, List<Round> rounds) {
        final String fullName = SettingsManager.getProfileFullName();
        if (!fullName.trim().isEmpty()) {
            info.addLine(R.string.name, fullName);
        }
        final int age = SettingsManager.getProfileAge();
        if (age > 0 && age < 18) {
            info.addLine(R.string.age, age);
        }
        final String club = SettingsManager.getProfileClub();
        if (!club.isEmpty()) {
            info.addLine(R.string.club, club);
        }
        if (rounds.size() > 1) {
            info.addLine(R.string.points, training.getReachedScore().format(true));
        }
        info.addLine(R.string.date, training.getFormattedDate());
    }

    private static String getSignature() {
        return "<div style=\"border-top: 2px solid black; width: 30%;margin-right: 5%;margin-top: 100px;float:left;\">"
                + get(R.string.witness) + "</div>"
                + "<div style=\"border-top: 2px solid black; width: 30%;float:left; margin-top: 100px;\">"
                + get(R.string.archer) + "</div>";
    }

}