com.github.fauu.natrank.service.MatchDataImportServiceImpl.java Source code

Java tutorial

Introduction

Here is the source code for com.github.fauu.natrank.service.MatchDataImportServiceImpl.java

Source

/*
 * Copyright (C) 2014 natrank Developers (http://github.com/fauu/natrank)
 *
 * This software is licensed under the GNU General Public License
 * (version 3 or later). See the COPYING file in this distribution.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this software. If not, see <http://www.gnu.org/licenses/>.
 *
 * Authored by: Piotr Grabowski <fau999@gmail.com>
 */

package com.github.fauu.natrank.service;

import com.github.fauu.natrank.model.CountryTeamMerge;
import com.github.fauu.natrank.model.MatchDataError;
import com.github.fauu.natrank.model.ParsedRawMatchDatum;
import com.github.fauu.natrank.model.ProcessedMatchData;
import com.github.fauu.natrank.model.entity.*;
import com.github.fauu.natrank.repository.*;
import com.google.common.base.Strings;
import org.joda.time.LocalDate;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;

import javax.transaction.Transactional;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.StringReader;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Service
public class MatchDataImportServiceImpl implements MatchDataImportService {

    @Autowired
    private CityRepository cityRepository;

    @Autowired
    private CountryCodeRepository countryCodeRepository;

    @Autowired
    private CountryRepository countryRepository;

    @Autowired
    private FlagRepository flagRepository;

    @Autowired
    private MatchRepository matchRepository;

    @Autowired
    private MatchTypeRepository matchTypeRepository;

    @Autowired
    private TeamRepository teamRepository;

    @Autowired
    private CountryService countryService;

    @Override
    public ProcessedMatchData processMatchData(String rawMatchData) {
        ProcessedMatchData matchData = new ProcessedMatchData();
        DateTimeFormatter dateTimeFormatter = DateTimeFormat.forPattern("dd/MM/yyyy");

        int lineNo = 1;
        BufferedReader reader = new BufferedReader(new StringReader(rawMatchData));
        try {
            String line;
            while ((line = reader.readLine()) != null) {
                String[] splitLine = line.split(";");
                int numFields = splitLine.length;

                if (numFields == 6) {
                    for (int i = 0; i < numFields; i++) {
                        if (splitLine[i] == null || splitLine[i].trim().length() == 0) {
                            MatchDataError error = new MatchDataError(lineNo, line,
                                    MatchDataError.Type.ERROR_MISSING_FIELD);

                            matchData.getErrors().add(error);
                        }
                    }

                    ParsedRawMatchDatum match = new ParsedRawMatchDatum();
                    LocalDate matchDate;
                    try {
                        matchDate = dateTimeFormatter.parseLocalDate(splitLine[0]);
                    } catch (IllegalArgumentException e) {
                        MatchDataError error = new MatchDataError(lineNo, line,
                                MatchDataError.Type.ERROR_INCORRECT_DATE_FORMAT);
                        matchData.getErrors().add(error);
                        e.printStackTrace();

                        matchDate = null;
                    }

                    String matchType = splitLine[1];
                    String matchCity = splitLine[2];
                    String matchTeam1 = splitLine[3];
                    String matchTeam2 = splitLine[4];
                    String matchResult = splitLine[5];

                    Country team1Country = countryRepository.findByName(matchTeam1);
                    Country team2Country = countryRepository.findByName(matchTeam2);
                    if ((team1Country != null) && (team2Country != null)) {
                        List<Match> duplicates = matchRepository.findByDateAndTeam1AndTeam2(matchDate,
                                team1Country.getTeam(), team2Country.getTeam());
                        if (duplicates.size() > 0) {
                            continue;
                        }
                    }

                    match.setDate(matchDate);
                    match.setType(matchType);
                    match.setCity(matchCity);
                    match.setTeam1(matchTeam1);
                    match.setTeam2(matchTeam2);
                    match.setResult(matchResult);

                    matchData.getMatches().add(match);
                } else {
                    MatchDataError error = new MatchDataError(lineNo, line,
                            MatchDataError.Type.ERROR_INCORRECT_LINE_FORMAT);

                    matchData.getErrors().add(error);
                }

                lineNo++;
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                reader.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        if (matchData.getErrors().size() == 0) {
            List<String> existingCountryNames = countryRepository.findAllNames();
            Set<String> processedNewCountryNames = new HashSet<>();
            List<String> existingCityNames = cityRepository.findAllNames();
            Set<String> processedNewCityNames = new HashSet<>();
            List<String> existingMatchTypesFifaNames = matchTypeRepository.findAllFifaNames();
            Set<String> processedNewMatchTypeFifaNames = new HashSet<>();

            List<String> countryNamesTemp = new LinkedList<>();

            for (ParsedRawMatchDatum parsedRawMatchDatum : matchData.getMatches()) {
                String matchTypeFifaName = parsedRawMatchDatum.getType();
                if (!processedNewMatchTypeFifaNames.contains(matchTypeFifaName)
                        && !existingMatchTypesFifaNames.contains(matchTypeFifaName)) {
                    MatchType newType = new MatchType();
                    newType.setFifaName(matchTypeFifaName);

                    processedNewMatchTypeFifaNames.add(matchTypeFifaName);
                    matchData.getTypes().add(newType);
                }

                countryNamesTemp.add(parsedRawMatchDatum.getTeam1());
                countryNamesTemp.add(parsedRawMatchDatum.getTeam2());
                for (String countryName : countryNamesTemp) {
                    if (!processedNewCountryNames.contains(countryName)
                            && !existingCountryNames.contains(countryName)) {
                        Country newCountry = new Country();
                        newCountry.setName(countryName);
                        newCountry.setPeriod(new Period());
                        newCountry.getPeriod().setFromDate(parsedRawMatchDatum.getDate());
                        List<CountryCode> matchingCountryCodes = countryCodeRepository
                                .findByCountryName(newCountry.getName());
                        String inferredCountryCode = "";
                        if (matchingCountryCodes.size() > 0) {
                            inferredCountryCode = matchingCountryCodes.get(0).getCode();
                        }
                        newCountry.setCode(inferredCountryCode);

                        processedNewCountryNames.add(newCountry.getName());
                        matchData.getCountries().add(newCountry);
                    }
                }
                countryNamesTemp.clear();

                String cityName = parsedRawMatchDatum.getCity();
                if (!processedNewCityNames.contains(cityName) && !existingCityNames.contains(cityName)) {
                    City newCity = new City();
                    newCity.setName(cityName);

                    CityCountryAssoc cityCountryAssoc = new CityCountryAssoc();
                    cityCountryAssoc.setCity(newCity);
                    cityCountryAssoc.setPeriod(new Period());
                    cityCountryAssoc.getPeriod().setFromDate(parsedRawMatchDatum.getDate());

                    newCity.getCityCountryAssocs().add(cityCountryAssoc);

                    processedNewCityNames.add(cityName);
                    matchData.getCities().add(newCity);
                    matchData.getCitiesInferredCountryNames().add(parsedRawMatchDatum.getTeam1());
                }

            }
        }

        return matchData;
    }

    @Override
    public List<Team> findAllTeams() throws DataAccessException {
        return teamRepository.findAll();
    }

    @Override
    public List<Country> findAllCountriesSortedByName() throws DataAccessException {
        return countryRepository.findAll(new Sort(Sort.Direction.ASC, "name"));
    }

    @Override
    @Transactional
    public void addCountries(List<Country> countries) throws DataAccessException {
        List<Country> countriesWithPredecessors = new LinkedList<>();

        for (Country country : countries) {
            // TODO: Perhaps do this in a DB trigger/JPA event listener?
            String oldTeamName = country.getTeam().getCurrentName();
            if (oldTeamName != null) {
                Country oldTeamCountry = countryRepository.findByName(oldTeamName);
                oldTeamCountry.getPeriod().setToDate(country.getPeriod().getFromDate().minusDays(1));

                countryRepository.save(oldTeamCountry);
            }

            if (!Strings.isNullOrEmpty(country.getPredecessorName())) {
                countriesWithPredecessors.add(country);
            }

            Flag countryFlag = new Flag();
            countryFlag.setCountry(country);
            countryFlag.setCode(country.getCode() + country.getPeriod().getFromDate().getYear());
            countryFlag.setPeriod(new Period());
            countryFlag.getPeriod().setFromDate(country.getPeriod().getFromDate());

            country.getFlags().add(countryFlag);
        }

        countryRepository.save(countries);

        for (Country country : countriesWithPredecessors) {
            countryService.mergeTeams(
                    new CountryTeamMerge(country, countryRepository.findByName(country.getPredecessorName())));
        }
    }

    @Override
    @Transactional
    public void addCities(List<City> cities) throws DataAccessException {
        for (City city : cities) {
            Country firstCountry = city.getCountries().get(0);

            if (firstCountry.getPeriod().getToDate() == null) {
                continue;
            }

            city.getCityCountryAssocs().get(0).getPeriod().setToDate(firstCountry.getPeriod().getToDate());

            Team teamOfFirstCountry = firstCountry.getTeam();

            if (teamOfFirstCountry.getCountries().size() == 1) {
                continue;
            }

            List<Country> newCityCountries = teamOfFirstCountry.getCountries().subList(1,
                    teamOfFirstCountry.getCountries().size());

            for (Country country : newCityCountries) {
                CityCountryAssoc cityCountryAssoc = new CityCountryAssoc();
                cityCountryAssoc.setCity(city);
                cityCountryAssoc.setCountry(country);
                Period period = new Period();
                period.setFromDate(country.getPeriod().getFromDate());
                period.setToDate(country.getPeriod().getToDate());
                cityCountryAssoc.setPeriod(period);

                city.getCityCountryAssocs().add(cityCountryAssoc);
            }
        }

        cityRepository.save(cities);
    }

    @Override
    public void addMatchTypes(List<MatchType> types) throws DataAccessException {
        matchTypeRepository.save(types);
    }

    @Override
    public List<Match> createMatches(ProcessedMatchData matchData) throws DataAccessException {
        List<Match> newMatches = new LinkedList<>();

        List<MatchType> types = matchTypeRepository.findAll();
        List<City> cities = cityRepository.findAll();
        List<Country> countries = countryRepository.findAll();

        StringBuilder resultExtraBuilder = new StringBuilder(30);

        for (ParsedRawMatchDatum intMatch : matchData.getMatches()) {
            Match newMatch = new Match();

            newMatch.setDate(intMatch.getDate());

            for (MatchType type : types) {
                if (type.getFifaName().equals(intMatch.getType())) {
                    newMatch.setType(type);
                    break;
                }
            }

            for (City city : cities) {
                if (city.getName().equals(intMatch.getCity())) {
                    newMatch.setCity(city);
                    break;
                }
            }

            for (Country country : countries) {
                if (country.getName().equals(intMatch.getTeam1())) {
                    newMatch.setTeam1(country.getTeam());
                } else if (country.getName().equals(intMatch.getTeam2())) {
                    newMatch.setTeam2(country.getTeam());
                }

                if ((newMatch.getTeam1() != null) && (newMatch.getTeam2() != null)) {
                    break;
                }
            }

            String fullResult = intMatch.getResult();
            Pattern resultPattern = Pattern
                    .compile("(\\d+):(\\d+)(?:\\s(a\\.e\\.t\\.))?(?:\\s(\\(\\d+:\\d+(?:,\\s\\d+:\\d+)?\\)))?"
                            + "(?:\\s(\\d+):(\\d+)\\sPSO)?");
            Matcher resultMatcher = resultPattern.matcher(fullResult);
            int team1Goals = 0;
            int team2Goals = 0;
            boolean extraTime = false;
            String resultsOnGameBreaks = null;
            int penTeam1Goals = 0;
            int penTeam2Goals = 0;
            if (resultMatcher.matches()) {
                if ((resultMatcher.group(1) != null) && (resultMatcher.group(2) != null)) {
                    team1Goals = Integer.parseInt(resultMatcher.group(1));
                    team2Goals = Integer.parseInt(resultMatcher.group(2));
                } else {
                    // TODO: Should not happen, log this
                }
                extraTime = (resultMatcher.group(3) != null) ? true : false;
                resultsOnGameBreaks = resultMatcher.group(4);
                if ((resultMatcher.group(5) != null) && (resultMatcher.group(6) != null)) {
                    penTeam1Goals = Integer.parseInt(resultMatcher.group(5));
                    penTeam2Goals = Integer.parseInt(resultMatcher.group(6));
                }
            } else {
                // TODO: Should not happen, log this
            }

            newMatch.setTeam1Goals(team1Goals);
            newMatch.setTeam2Goals(team2Goals);

            if (newMatch.getTeam1().isCityHomeForDate(newMatch.getCity(), newMatch.getDate())) {
                newMatch.setHomeTeam(newMatch.getTeam1());
            } else if (newMatch.getTeam2().isCityHomeForDate(newMatch.getCity(), newMatch.getDate())) {
                newMatch.setHomeTeam(newMatch.getTeam2());
            } else {
                // TODO: Should not happen, log this
            }

            resultExtraBuilder.delete(0, resultExtraBuilder.length());
            if (extraTime) {
                resultExtraBuilder.append("AET");
                resultExtraBuilder.append(' ');
            }
            if (resultsOnGameBreaks != null) {
                resultExtraBuilder.append(resultsOnGameBreaks);
                resultExtraBuilder.append(' ');
            }
            if (penTeam1Goals > 0 || penTeam2Goals > 0) {
                resultExtraBuilder.append(' ');
                resultExtraBuilder.append(penTeam1Goals);
                resultExtraBuilder.append(':');
                resultExtraBuilder.append(penTeam2Goals);
                resultExtraBuilder.append(" PEN");
                newMatch.setPenaltyShootout(true);
            } else {
                newMatch.setPenaltyShootout(false);
            }

            if (!newMatch.isPenaltyShootout()) {
                if (team1Goals > team2Goals) {
                    newMatch.setWinnerTeam(newMatch.getTeam1());
                } else if (team1Goals < team2Goals) {
                    newMatch.setWinnerTeam(newMatch.getTeam2());
                } else {
                    newMatch.setWinnerTeam(null);
                }
            } else {
                if (penTeam1Goals > penTeam2Goals) {
                    newMatch.setWinnerTeam(newMatch.getTeam1());
                } else {
                    newMatch.setWinnerTeam(newMatch.getTeam2());
                }
            }

            newMatch.setResultExtra(resultExtraBuilder.toString());

            newMatches.add(newMatch);
        }

        return newMatches;
    }

    @Override
    public void addMatches(List<Match> matches) {
        matchRepository.save(matches);
    }

}