pl.umk.mat.zawodyweb.www.ranking.RankingACM.java Source code

Java tutorial

Introduction

Here is the source code for pl.umk.mat.zawodyweb.www.ranking.RankingACM.java

Source

/*
 * Copyright (c) 2009-2014, ZawodyWeb Team
 * All rights reserved.
 *
 * This file is distributable under the Simplified BSD license. See the terms
 * of the Simplified BSD license in the documentation provided with this file.
 */
package pl.umk.mat.zawodyweb.www.ranking;

import java.sql.Timestamp;
import java.util.*;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import pl.umk.mat.zawodyweb.database.*;
import pl.umk.mat.zawodyweb.database.hibernate.HibernateUtil;
import pl.umk.mat.zawodyweb.database.pojo.*;

/**
 * @author <a href="mailto:faramir@mat.umk.pl">Marek Nowicki</a>
 * @version $Rev$ $Date: 2010-10-10 02:53:49 +0200 (N, 10 pa 2010)$
 */
public class RankingACM implements RankingInterface {

    private final ResourceBundle messages = ResourceBundle.getBundle("pl.umk.mat.zawodyweb.www.Messages");

    private class SolutionACM implements Comparable {

        String abbrev;
        long date;
        long time;
        long time_from_bombs;
        int bombs;
        String name;
        boolean frozen;

        public SolutionACM(String abbrev, long date, long time, long time_from_bombs, int bombs, String name,
                boolean frozen) {
            this.abbrev = abbrev;
            this.date = date;
            this.time = time;
            this.time_from_bombs = time_from_bombs;
            this.bombs = bombs;
            this.name = name;
            this.frozen = frozen;
        }

        @Override
        public int compareTo(Object o) {
            if (this.date < ((SolutionACM) o).date) {
                return -1;
            }
            if (this.date > ((SolutionACM) o).date) {
                return 1;
            }
            return 0;
        }
    }

    private class UserACM implements Comparable {

        String login;
        String firstname;
        String lastname;
        boolean loginOnly;
        int id_user;
        int points;
        long totalTime;
        List<SolutionACM> solutions;

        public UserACM(int id_user, Users users) {
            this.id_user = id_user;
            this.points = 0;
            this.totalTime = 0;
            this.solutions = new ArrayList<>();

            this.login = users.getLogin();
            this.firstname = users.getFirstname();
            this.lastname = users.getLastname();
            this.loginOnly = users.getOnlylogin();
        }

        void add(int points, SolutionACM solutionACM) {
            this.points += points;
            this.totalTime += solutionACM.time + solutionACM.time_from_bombs;
            this.solutions.add(solutionACM);
        }

        String getSolutionsForRanking() {
            String r = "";
            String text;
            Collections.sort(this.solutions);

            for (SolutionACM solutionACM : solutions) {
                text = solutionACM.abbrev;
                if (solutionACM.bombs >= 4) {
                    text += "(" + solutionACM.bombs + ")";
                } else {
                    for (int i = 0; i < solutionACM.bombs; ++i) {
                        text += "*";
                    }
                }
                r += RankingUtils.formatText(text, solutionACM.name + " [" + parseTime(solutionACM.time)
                        + (solutionACM.time_from_bombs == 0 ? "" : "+" + parseTime(solutionACM.time_from_bombs))
                        + "]", solutionACM.frozen ? "frozen" : null) + " ";
            }
            return r.trim();
        }

        @Override
        public int compareTo(Object o) {
            UserACM u2 = (UserACM) o;
            if (this.points < u2.points) {
                return 1;
            }
            if (this.points > u2.points) {
                return -1;
            }
            if (this.totalTime > u2.totalTime) {
                return 1;
            }
            if (this.totalTime < u2.totalTime) {
                return -1;
            }

            int r;
            r = RankingUtils.compareStrings(this.lastname, u2.lastname);
            if (r != 0) {
                return r;
            }

            r = RankingUtils.compareStrings(this.firstname, u2.firstname);
            if (r != 0) {
                return r;
            }

            return RankingUtils.compareStrings(this.login, u2.login);
        }
    }

    private String parseTime(long time) {
        long d, h, m, s;
        d = time / (24 * 60 * 60);
        time %= (24 * 60 * 60);
        h = time / (60 * 60);
        time %= (60 * 60);
        m = time / 60;
        time %= 60;
        s = time;

        if (d > 0) {
            return String.format("%dd %02d:%02d:%02d", d, h, m, s);
        } else if (h > 0) {
            return String.format("%d:%02d:%02d", h, m, s);
        } else {
            return String.format("%d:%02d", m, s);
        }
    }

    private RankingTable getRankingACM(int contest_id, Timestamp checkDate, boolean admin, Integer series_id) {
        Session hibernateSession = HibernateUtil.getSessionFactory().getCurrentSession();

        Timestamp checkTimestamp;
        Timestamp visibleTimestamp;

        UsersDAO usersDAO = DAOFactory.DEFAULT.buildUsersDAO();
        SeriesDAO seriesDAO = DAOFactory.DEFAULT.buildSeriesDAO();
        ProblemsDAO problemsDAO = DAOFactory.DEFAULT.buildProblemsDAO();
        Map<Integer, UserACM> mapUserACM = new HashMap<>();

        boolean allTests;
        boolean frozenRanking = false;
        boolean frozenSeria;

        long lCheckDate = checkDate.getTime();

        for (Series series : seriesDAO.findByContestsid(contest_id)) {

            if ((series_id == null && series.getVisibleinranking() == false)
                    || (series_id != null && series_id.equals(series.getId()) == false)) {
                continue;
            }

            if (series.getStartdate().getTime() > lCheckDate) {
                continue;
            }

            frozenSeria = false;
            checkTimestamp = checkDate;
            allTests = admin;

            if (!admin && series.getFreezedate() != null) {
                if (lCheckDate > series.getFreezedate().getTime()
                        && (series.getUnfreezedate() == null || lCheckDate < series.getUnfreezedate().getTime())) {
                    checkTimestamp = new Timestamp(series.getFreezedate().getTime());
                    if (series.getUnfreezedate() != null) {
                        frozenRanking = true;
                    }
                    frozenSeria = true;
                }
            }

            if (checkTimestamp.before(series.getStartdate())) {
                visibleTimestamp = new Timestamp(0);
            } else {
                visibleTimestamp = new Timestamp(series.getStartdate().getTime());
            }

            if (series.getUnfreezedate() != null) {
                if (checkDate.after(series.getUnfreezedate())) {
                    allTests = true;
                }
            }

            for (Problems problems : problemsDAO.findBySeriesid(series.getId())) {
                if (problems.getVisibleinranking() == false) {
                    continue;
                }

                // select sum(maxpoints) from tests where problemsid='7' and visibility=1
                Number maxPoints;
                Number testCount;
                if (allTests) {
                    Object[] o = (Object[]) hibernateSession.createCriteria(Tests.class)
                            .setProjection(Projections.projectionList().add(Projections.sum("maxpoints"))
                                    .add(Projections.rowCount()))
                            .add(Restrictions.eq("problems.id", problems.getId())).uniqueResult();
                    maxPoints = (Number) o[0];
                    testCount = (Number) o[1];
                } else {
                    Object[] o = (Object[]) hibernateSession.createCriteria(Tests.class)
                            .setProjection(Projections.projectionList().add(Projections.sum("maxpoints"))
                                    .add(Projections.rowCount()))
                            .add(Restrictions.and(Restrictions.eq("problems.id", problems.getId()),
                                    Restrictions.eq("visibility", 1)))
                            .uniqueResult();
                    maxPoints = (Number) o[0];
                    testCount = (Number) o[1];
                }
                if (maxPoints == null) {
                    maxPoints = 0; // To nie powinno si nigdy zdarzy ;).. chyba, e nie ma testu przy zadaniu?
                }
                if (testCount == null) {
                    testCount = 0; // To nie powinno si zdarzy nigdy.
                }

                Query query;
                if (allTests == true) {
                    query = hibernateSession.createSQLQuery("" + "select usersid, min(sdate) sdate " // zapytanie zewntrzne znajduj minimaln dat wysania poprawnego rozwizania dla kadego usera
                            + "from submits " + "where id in (" + "    select submits.id " // zapytanie wewntrzne znajduje wszystkie id, ktre zdobyy maksa punktw
                            + "    from submits,results,tests " + "    where submits.problemsid = :problemsId "
                            + "      and submits.id=results.submitsid " + "        and tests.id = results.testsid "
                            + "      and results.status = :statusAcc " + "      and submits.state = :stateDone "
                            + "      and sdate <= :currentTimestamp " + "      and sdate >= :visibleTimestamp "
                            + "      and visibleInRanking=true"
                            //+ "      and tests.visibility=1 "
                            + "    group by submits.id,usersid,sdate " + "    having sum(points) = :maxPoints "
                            + "      and count(points) = :testCount " + "  ) " + "group by usersid")
                            .setInteger("problemsId", problems.getId())
                            .setInteger("statusAcc", ResultsStatusEnum.ACC.getCode())
                            .setInteger("stateDone", SubmitsStateEnum.DONE.getCode())
                            .setInteger("maxPoints", maxPoints.intValue())
                            .setInteger("testCount", testCount.intValue())
                            .setTimestamp("currentTimestamp", checkTimestamp)
                            .setTimestamp("visibleTimestamp", visibleTimestamp);
                } else {
                    query = hibernateSession.createSQLQuery("" + "select usersid, min(sdate) sdate "
                            + "from submits " + "where id in (" + "    select submits.id "
                            + "    from submits,results,tests " + "    where submits.problemsid = :problemsId "
                            + "      and submits.id=results.submitsid " + "        and tests.id = results.testsid "
                            + "      and results.status = :statusAcc " + "      and submits.state = :stateDone "
                            + "      and sdate <= :currentTimestamp " + "      and sdate >= :visibleTimestamp "
                            + "      and visibleInRanking=true" + "        and tests.visibility=1 " // FIXME: should be ok
                            + "    group by submits.id,usersid,sdate " + "    having sum(points) = :maxPoints "
                            + "      and count(points) = :testCount " + "  ) " + "group by usersid")
                            .setInteger("problemsId", problems.getId())
                            .setInteger("statusAcc", ResultsStatusEnum.ACC.getCode())
                            .setInteger("stateDone", SubmitsStateEnum.DONE.getCode())
                            .setInteger("maxPoints", maxPoints.intValue())
                            .setInteger("testCount", testCount.intValue())
                            .setTimestamp("currentTimestamp", checkTimestamp)
                            .setTimestamp("visibleTimestamp", visibleTimestamp);
                }

                for (Object list : query.list()) { // tu jest zwrcona lista "zaakceptowanych" w danym momencie rozwiza zadania
                    Object[] o = (Object[]) list;

                    Number bombs = (Number) hibernateSession.createCriteria(Submits.class)
                            .setProjection(Projections.rowCount())
                            .add(Restrictions.eq("problems.id", (Number) problems.getId()))
                            .add(Restrictions.eq("users.id", (Number) o[0]))
                            .add(Restrictions.lt("sdate", (Timestamp) o[1])).uniqueResult();

                    if (bombs == null) {
                        bombs = 0;
                    }

                    UserACM user = mapUserACM.get((Integer) o[0]);
                    if (user == null) {
                        Integer user_id = (Integer) o[0];
                        Users users = usersDAO.getById(user_id);

                        user = new UserACM(user_id, users);
                        mapUserACM.put((Integer) o[0], user);
                    }

                    user.add(maxPoints.intValue(), new SolutionACM(problems.getAbbrev(),
                            ((Timestamp) o[1]).getTime(),
                            (maxPoints.equals(0) ? 0
                                    : ((Timestamp) o[1]).getTime() - series.getStartdate().getTime()) / 1000,
                            series.getPenaltytime() * bombs.intValue(), bombs.intValue(), problems.getName(),
                            frozenSeria));
                }
            }

        }

        /*
         * Tworzenie rankingu z danych
         */
        List<UserACM> cre = new ArrayList<>();
        cre.addAll(mapUserACM.values());
        Collections.sort(cre);

        /*
         * nazwy kolumn
         */
        List<String> columnsCaptions = new ArrayList<>();
        columnsCaptions.add(messages.getString("points"));
        columnsCaptions.add(messages.getString("time"));
        columnsCaptions.add(messages.getString("solutions"));

        /*
         * nazwy klas css-owych dla kolumn
         */
        List<String> columnsCSS = new ArrayList<>();
        columnsCSS.add("small"); // points
        columnsCSS.add("nowrap small"); // time
        columnsCSS.add("big left"); // solutions

        /*
         * tabelka z rankingiem
         */
        List<RankingEntry> vectorRankingEntry = new ArrayList<>();
        int place = 0;
        long totalTime = -1;
        int points = Integer.MAX_VALUE;
        for (UserACM user : cre) {
            if (points > user.points || (points == user.points && totalTime < user.totalTime)) {
                ++place;
                points = user.points;
                totalTime = user.totalTime;
            }
            List<String> v = new ArrayList<>();
            v.add(Integer.toString(user.points));
            v.add(parseTime(user.totalTime));
            v.add(user.getSolutionsForRanking());

            vectorRankingEntry
                    .add(new RankingEntry(place, user.firstname, user.lastname, user.login, user.loginOnly, v));
        }

        return new RankingTable(columnsCaptions, columnsCSS, vectorRankingEntry, frozenRanking);
    }

    @Override
    public RankingTable getRanking(int contest_id, Timestamp checkDate, boolean admin) {
        return getRankingACM(contest_id, checkDate, admin, null);
    }

    @Override
    public RankingTable getRankingForSeries(int contest_id, int series_id, Timestamp checkDate, boolean admin) {
        return getRankingACM(contest_id, checkDate, admin, series_id);
    }

    @Override
    public List<Integer> getRankingSolutions(int contest_id, Integer series_id, Timestamp checkDate,
            boolean admin) {
        Session hibernateSession = HibernateUtil.getSessionFactory().getCurrentSession();

        Timestamp checkTimestamp;
        Timestamp visibleTimestamp;

        SeriesDAO seriesDAO = DAOFactory.DEFAULT.buildSeriesDAO();
        ProblemsDAO problemsDAO = DAOFactory.DEFAULT.buildProblemsDAO();

        List<Integer> submits = new ArrayList<>();

        boolean allTests;

        long lCheckDate = checkDate.getTime();

        for (Series series : seriesDAO.findByContestsid(contest_id)) {

            if ((series_id == null && series.getVisibleinranking() == false)
                    || (series_id != null && series_id.equals(series.getId()) == false)) {
                continue;
            }

            if (series.getStartdate().getTime() > lCheckDate) {
                continue;
            }

            checkTimestamp = checkDate;
            allTests = admin;

            if (!admin && series.getFreezedate() != null) {
                if (lCheckDate > series.getFreezedate().getTime()
                        && (series.getUnfreezedate() == null || lCheckDate < series.getUnfreezedate().getTime())) {
                    checkTimestamp = new Timestamp(series.getFreezedate().getTime());
                }
            }

            if (checkTimestamp.before(series.getStartdate())) {
                visibleTimestamp = new Timestamp(0);
            } else {
                visibleTimestamp = new Timestamp(series.getStartdate().getTime());
            }

            if (series.getUnfreezedate() != null) {
                if (checkDate.after(series.getUnfreezedate())) {
                    allTests = true;
                }
            }

            for (Problems problems : problemsDAO.findBySeriesid(series.getId())) {
                if (problems.getVisibleinranking() == false) {
                    continue;
                }

                // select sum(maxpoints) from tests where problemsid='7' and visibility=1
                Number maxPoints;
                Number testCount;
                if (allTests) {
                    Object[] o = (Object[]) hibernateSession.createCriteria(Tests.class)
                            .setProjection(Projections.projectionList().add(Projections.sum("maxpoints"))
                                    .add(Projections.rowCount()))
                            .add(Restrictions.eq("problems.id", problems.getId())).uniqueResult();
                    maxPoints = (Number) o[0];
                    testCount = (Number) o[1];
                } else {
                    Object[] o = (Object[]) hibernateSession.createCriteria(Tests.class)
                            .setProjection(Projections.projectionList().add(Projections.sum("maxpoints"))
                                    .add(Projections.rowCount()))
                            .add(Restrictions.and(Restrictions.eq("problems.id", problems.getId()),
                                    Restrictions.eq("visibility", 1)))
                            .uniqueResult();
                    maxPoints = (Number) o[0];
                    testCount = (Number) o[1];
                }
                if (maxPoints == null) {
                    maxPoints = 0; // To nie powinno si nigdy zdarzy ;).. chyba, e nie ma testu przy zadaniu?
                }
                if (testCount == null) {
                    testCount = 0; // To nie powinno si zdarzy nigdy.
                }

                Query query;
                if (allTests == true) {
                    query = hibernateSession.createSQLQuery("" + "select min(id) sid " // zapytanie zewntrzne znajduj minimaln dat wysania poprawnego rozwizania dla kadego usera
                            + "from submits " + "where id in (" + "    select submits.id " // zapytanie wewntrzne znajduje wszystkie id, ktre zdobyy maksa punktw
                            + "    from submits,results,tests " + "    where submits.problemsid = :problemsId "
                            + "      and submits.id = results.submitsid "
                            + "        and tests.id = results.testsid " + "      and results.status = :statusAcc "
                            + "      and submits.state = :stateDone " + "      and sdate <= :currentTimestamp "
                            + "      and sdate >= :visibleTimestamp " + "      and visibleInRanking=true"
                            //+ "      and tests.visibility=1 "
                            + "    group by submits.id,usersid,sdate " + "    having sum(points) = :maxPoints "
                            + "      and count(points) = :testsCount " + "  ) " + "group by usersid")
                            .setInteger("problemsId", problems.getId())
                            .setInteger("statusAcc", ResultsStatusEnum.ACC.getCode())
                            .setInteger("stateDone", SubmitsStateEnum.DONE.getCode())
                            .setInteger("maxPoints", maxPoints.intValue())
                            .setInteger("testCount", testCount.intValue())
                            .setTimestamp("currentTimestamp", checkTimestamp)
                            .setTimestamp("visibleTimestamp", visibleTimestamp);
                } else {
                    query = hibernateSession.createSQLQuery("" + "select min(id) sid " + "from submits "
                            + "where id in (" + "    select submits.id " + "    from submits,results,tests "
                            + "    where submits.problemsid = :problemsId "
                            + "      and submits.id = results.submitsid "
                            + "        and tests.id = results.testsid " + "      and results.status = :statusAcc "
                            + "      and submits.state = :stateDone " + "      and sdate <= :currentTimestamp "
                            + "      and sdate >= :visibleTimestamp " + "      and visibleInRanking=true"
                            + "        and tests.visibility=1 " // FIXME: should be ok
                            + "    group by submits.id,usersid,sdate " + "    having sum(points) = :maxPoints "
                            + "      and count(points) = :testCount " + "  ) " + "group by usersid")
                            .setInteger("problemsId", problems.getId())
                            .setInteger("statusAcc", ResultsStatusEnum.ACC.getCode())
                            .setInteger("stateDone", SubmitsStateEnum.DONE.getCode())
                            .setInteger("maxPoints", maxPoints.intValue())
                            .setInteger("testCount", testCount.intValue())
                            .setTimestamp("currentTimestamp", checkTimestamp)
                            .setTimestamp("visibleTimestamp", visibleTimestamp);
                }

                for (Object id : query.list()) { // tu jest zwrcona lista "zaakceptowanych" w danym momencie rozwiza zadania
                    submits.add((Integer) id);
                }
            }
        }

        return submits;
    }
}