package parsers;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import com.gargoylesoftware.htmlunit.FailingHttpStatusCodeException;
import com.gargoylesoftware.htmlunit.Page;
import com.gargoylesoftware.htmlunit.WebClient;
import com.gargoylesoftware.htmlunit.html.DomElement;
import com.gargoylesoftware.htmlunit.html.DomNodeList;
import com.gargoylesoftware.htmlunit.html.HtmlDivision;
import com.gargoylesoftware.htmlunit.html.HtmlElement;
import com.gargoylesoftware.htmlunit.html.HtmlHeading1;
import com.gargoylesoftware.htmlunit.html.HtmlPage;
import com.gargoylesoftware.htmlunit.html.HtmlSpan;
import com.gargoylesoftware.htmlunit.html.HtmlTable;
import com.gargoylesoftware.htmlunit.html.HtmlTableCell;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;

import controllers.DatabaseController;
import controllers.MainController;

public class TravsportParser implements Parser {

    private static final TravsportParser instance = new TravsportParser();
    private final DatabaseController databaseController;

    private TravsportParser() {
        databaseController = DatabaseController.getInstance();
    };

    public static TravsportParser getInstance() {
        return instance;
    }

    /**
     * Förklaringar tid - 'a' betyder "autoStart" vilket get snabbare tid tid - 'g'
     * betyder "gallopp" vilker ger långsammare tid tid - 'd' betyder "Diskad" två
     * galopper eller gallopp över mållinje eller längre än 150 meter tid - 'it'
     * betyder "Ingen tid" kan vara fel på banans tidtagning eller liknande så det
     * finns ingen tid.
     *
     * @param horseId
     */
    public void getHorseStats(String raceType, String horseId) {
        final WebClient webclient = MyWebClient.getInstance().getWebclient();
        HtmlPage page;
        try {
            page = webclient.getPage("https://sportapp.travsport.se/sportinfo/horse/" + horseId + "/results");
            webclient.waitForBackgroundJavaScript(3000);
            webclient.waitForBackgroundJavaScriptStartingBefore(3000);
            // Hitta div med data-testid="sportinfo-horse-details" för häst info

            final HtmlDivision detailsDiv
                    = (HtmlDivision) page.getBody().getByXPath("//div[@data-testid='sportinfo-horse-details']").get(0);

            final HtmlHeading1 nameHeader = (HtmlHeading1) detailsDiv.getByXPath("//h1").get(0);
            final String horseName = nameHeader.getTextContent().trim();
            // Hitta div med data-testid="sportinfo-horse-results" för årliga resultat är
            // första tabellen, andra tabellen är lopp resultat
            final HtmlDivision resultsDiv
                    = (HtmlDivision) page.getBody().getByXPath("//div[@data-testid='sportinfo-horse-results']").get(0);
            final ArrayList<DomElement> resultsDivs = Lists.newArrayList(resultsDiv.getChildElements());

            final HtmlDivision raceResults = (HtmlDivision) resultsDivs.get(4);

            final HtmlTable raceTable = (HtmlTable) raceResults.getFirstChild();

            final List<HtmlTableCell> tableHeader = raceTable.getRow(0).getCells();

            int trackPos = -1;
            int datePos = -1;
            int lanePos = -1;
            int distancePos = -1;
            int resultPos = -1;
            int timePos = -1;
            int shoePos = -1;
            int sulkyPos = -1;
            int driverPos = -1;
            int trainerPos = -1;
            int oddsPos = -1;
            int pos = 0;
            for (final HtmlTableCell th : tableHeader) {
                final HtmlSpan span = (HtmlSpan) th.getFirstChild();
                final String text = span.getTextContent().toLowerCase();
                if (text.equals("bana")) {
                    trackPos = pos;
                } else if (text.equals("datum")) {
                    datePos = pos;
                } else if (text.equals("spår")) {
                    lanePos = pos;
                } else if (text.equals("dist.")) {
                    distancePos = pos;
                } else if (text.equals("res.")) {
                    resultPos = pos;
                } else if (text.equals("tid")) {
                    timePos = pos;
                } else if (text.equals("skor")) {
                    shoePos = pos;
                } else if (text.equals("vagn")) {
                    sulkyPos = pos;
                } else if (text.equals("kusk")) {
                    driverPos = pos;
                } else if (text.equals("tränare")) {
                    trainerPos = pos;
                } else if (text.equals("odds")) {
                    oddsPos = pos;
                } else if (text.equals("kategori")) {
                    //
                } else if (text.equals("vinstsumma")) {
                    //
                } else {
                    System.err.println("What should I do with " + text);
                }

                pos++;
            }

            for (int i = 1; i < raceTable.getRowCount(); i++) {
                final List<HtmlTableCell> cells = raceTable.getRow(i).getCells();
                final String timeCell = cells.get(6).getTextContent();
                final float time;
                final String timeModifier;

                time = getTimeFromTimeCellValue(timeCell);

                timeModifier = getTimeModifierFromTimeCellValue(timeCell);

                final String trackShortCode = cells.get(trackPos).getTextContent();
                final String date = cells.get(datePos).getTextContent().split("-")[0];
                final int raceNumber = Integer.valueOf(cells.get(datePos).getTextContent().split("-")[1]);
                final int startLine = Strings.isNullOrEmpty(cells.get(lanePos).getTextContent()) ? -1
                        : Integer.valueOf(cells.get(lanePos).getTextContent());
                final int distance = Integer.valueOf(cells.get(distancePos).getTextContent().replaceAll("\\D", ""));
                final int result = Strings.isNullOrEmpty(cells.get(resultPos).getTextContent().replaceAll("\\D", "")) ? -1
                        : Integer.valueOf(cells.get(resultPos).getTextContent().replaceAll("\\D", ""));
                final int shooes;
                final DomNodeList<HtmlElement> shoeSpans = cells.get(shoePos).getElementsByTagName("span");
                if (shoeSpans.getLength() == 0) { // NO SHOES
                    shooes = 0;
                } else {
                    // show title possible values {"Barfota fram", "Skor runt om", "barfota bak",
                    // "barfota runt om"}
                    final String shoeTitle = shoeSpans.get(0).getAttribute("title").toLowerCase();
                    if (shoeTitle.equals("barfota fram")) {
                        shooes = 1;
                    } else if (shoeTitle.equals("skor runt om")) {
                        shooes = 2;
                    } else if (shoeTitle.equals("barfota runt om")) {
                        shooes = 0;
                    } else if (shoeTitle.equals("barfota bak")) {
                        shooes = 3;
                    } else {
                        shooes = -1;
                        System.err.println("Dont know the value of " + shoeTitle);
                    }
                }

                final String driverName = cells.get(driverPos).getTextContent();
                final String trainerName = cells.get(trainerPos).getTextContent();

                DatabaseController.getInstance().insertResult(trackShortCode,
                        date,
                        raceNumber,
                        startLine,
                        distance,
                        result,
                        time,
                        timeModifier,
                        shooes,
                        -1,
                        driverName,
                        trainerName,
                        horseName,
                        0,
                        0,
                        0,
                        raceType,
                        -1);
            }

        } catch (final ClassCastException e) {
            System.out.println("Failed to cast " + e.getMessage());
            throw new RuntimeException(e.getMessage(), e);
        } catch (FailingHttpStatusCodeException | IOException e) {
            throw new RuntimeException(e.getMessage(), e);
        } catch (final Exception e) {
            System.err.println("Failed with exception " + e.getMessage() + " Horse id " + horseId);
        }
        webclient.close();
    }

    public void getRaceResults(String startOfMonth, String endOfMonth) {
        final String calendarUrl = "https://api.travsport.se/webapi/raceinfo/organisation/TROT/sourceofdata/BOTH?fromracedate="
                + startOfMonth + "&tosubmissiondate=" + endOfMonth + "&toracedate=" + endOfMonth;
        final String url = "https://api.travsport.se/webapi/raceinfo/results/organisation/TROT/sourceofdata/SPORT/racedayid/";

        final ArrayList<JsonObject> outerJsonObjects = getJsonObjects(calendarUrl);

        final List<JsonObject> withStartlist
                = outerJsonObjects.stream().filter(j -> j.get("trackProgramExists").getAsBoolean()).collect(Collectors.toList());

        for (final JsonObject outerJo : withStartlist) {
            final int raceDayId = outerJo.get("raceDayId").getAsInt();
            final String trackName = outerJo.get("trackName").getAsString();
            final String trackCode = databaseController.getTrackShortCodeByName(trackName);

            try {
                final Page page = MyWebClient.getInstance().getJsonWebClient().getPage(url + raceDayId);
                final String content = new String(page.getWebResponse().getContentAsString()); // .getBytes("ISO-8859-1"),
                                                                                               // "UTF-8");
                final Gson gson = new Gson();
                final JsonObject jo = gson.fromJson(content, JsonObject.class);

                final ArrayList<JsonObject> jsonObjects = Lists.newArrayList();
                final JsonArray results = jo.get("racesWithReadyResult").getAsJsonArray();
                results.forEach(j -> jsonObjects.add(j.getAsJsonObject()));

                for (final JsonObject json : jsonObjects) {
                    final JsonObject generalInfo = json.get("generalInfo").getAsJsonObject();
                    final int raceNumber = generalInfo.get("raceNumber").getAsInt();

                    final String startTime = generalInfo.get("startTime").getAsString();
                    final Pattern pattern = Pattern.compile("\\d{4}-\\d{2}-\\d{2}");
                    final Matcher matcher = pattern.matcher(startTime);
                    String raceDate;
                    if (matcher.find()) {
                        raceDate = matcher.group();
                    } else {
                        throw new RuntimeException("Could not find date from " + startTime);
                    }

                    try {
                        final JsonArray raceResultRows = json.get("raceResultRows").getAsJsonArray();
                        for (int i = 0; i < raceResultRows.size(); i++) {
                            final JsonObject res = raceResultRows.get(i).getAsJsonObject();
                            final int result = res.get("placementNumber").getAsInt();
                            final JsonObject horse = res.get("horse").getAsJsonObject();
                            final int horseTravsportId = horse.get("id").getAsInt();
                            final String horseName = horse.get("name").getAsString();

                            final JsonObject driver = res.get("driver").getAsJsonObject();
                            final int driverTravsportId = driver.get("id").getAsInt();
                            final String driverName = driver.get("name").getAsString();

                            final JsonObject trainer = res.get("trainer").getAsJsonObject();
                            final int trainerTravsportId = trainer.get("id").getAsInt();
                            final String trainerName = trainer.get("name").getAsString();
                            int shoeInfo = 0;
                            try {
                                shoeInfo = res.get("shoeInfo").getAsJsonObject().get("sortValue").getAsInt();
                            } catch (final NullPointerException e) {
                                // ignore
                            }

                            final String timeString = res.get("time").getAsString();
                            final float time = getTimeFromTimeCellValue(timeString);
                            final String timeModifier = getTimeModifierFromTimeCellValue(timeString);

                            final String[] startPosAndDistance = res.get("startPositionAndDistance").getAsString().split("/");
                            final int lane = res.get("programNumber").getAsInt();
                            final int distance = Integer.valueOf(startPosAndDistance[1]);

                            DatabaseController.getInstance().insertResult(trackCode,
                                    raceDate,
                                    raceNumber,
                                    lane,
                                    distance,
                                    result,
                                    time,
                                    timeModifier,
                                    shoeInfo,
                                    0,
                                    driverName,
                                    trainerName,
                                    horseName,
                                    horseTravsportId,
                                    trainerTravsportId,
                                    driverTravsportId,
                                    "",
                                    raceDayId);
                        }
                    } catch (final NullPointerException e) {
                        System.out.println(url + raceDayId);
                        System.out.println("ERROR WITH MESSAGE: " + e.getMessage() + e.getCause());
                        continue;
                    }
                }
            } catch (FailingHttpStatusCodeException | IOException e) {
                throw new RuntimeException(e.getMessage(), e);
            }
        }
    }

    // Get raceDayResultsJSon
    // https://api.travsport.se/webapi/raceinfo/results/organisation/TROT/sourceofdata/SPORT/racedayid/590412
    public void getRaceCalendar(String date, boolean getFullStats) {
        // JSON för race dagen
        // https://api.travsport.se/webapi/raceinfo/startlists/organisation/TROT/sourceofdata/SPORT/racedayid/590412
        // JSON för calendern
        // https://api.travsport.se/webapi/raceinfo/organisation/TROT/sourceofdata/BOTH?fromracedate=2021-02-01&tosubmissiondate=2021-02-28&toracedate=2021-02-28
        final String calendarUrl;
        if (date == null) {
            calendarUrl = "https://api.travsport.se/webapi/raceinfo/organisation/TROT/sourceofdata/BOTH?fromracedate="
                    + getTodaysDate() + "&tosubmissiondate=" + getLastDayOfMonth() + "&toracedate=" + getLastDayOfMonth();
        } else {
            calendarUrl = "https://api.travsport.se/webapi/raceinfo/organisation/TROT/sourceofdata/BOTH?fromracedate=" + date
                    + "&tosubmissiondate=" + date + "&toracedate=" + date;
        }
        final String raceUrl
                = "https://api.travsport.se/webapi/raceinfo/startlists/organisation/TROT/sourceofdata/SPORT/racedayid/";

        final ArrayList<JsonObject> jsonObjects = getJsonObjects(calendarUrl);

        final List<JsonObject> withStartlist
                = jsonObjects.stream().filter(j -> j.get("trackProgramExists").getAsBoolean()).collect(Collectors.toList());

        int i = 1;
        for (final JsonObject jo : withStartlist) {
            final int raceDayId = jo.get("raceDayId").getAsInt();
            final String raceDate = jo.get("raceDayDate").getAsString();
            final String trackName = jo.get("trackName").getAsString();
            final String trackCode = databaseController.getTrackShortCodeByName(trackName);

            System.out.println("Updating raceCalendar day " + raceDate + " " + i++ + "/" + withStartlist.size() + " tackcode "
                    + trackCode + " trackName " + trackName);

            final ArrayList<JsonObject> raceJsonObjects = Lists.newArrayList();
            try {
                final Page page = MyWebClient.getInstance().getJsonWebClient().getPage(raceUrl + raceDayId);
                final String content = new String(page.getWebResponse().getContentAsString()); // .getBytes("ISO-8859-1"),
                                                                                               // "UTF-8");
                // final String content = page.getWebResponse().getContentAsString();
                final Gson gson = new Gson();
                final JsonObject raceObject = gson.fromJson(content, JsonObject.class);
                final JsonArray raceListData = raceObject.get("raceList").getAsJsonArray();
                raceListData.forEach(e -> raceJsonObjects.add(e.getAsJsonObject()));

                for (final JsonObject race : raceJsonObjects) {
                    final int raceNumber = race.get("raceNumber").getAsInt();
                    // final int raceId = race.get("raceId").getAsInt();
                    final int distance = race.get("distance").getAsInt();
                    final String raceStartType = ""; // race.get("raceType").getAsJsonObject().get("code").getAsString();
                    final JsonArray horses = race.get("horses").getAsJsonArray();
                    final ArrayList<JsonObject> horseData = Lists.newArrayList();

                    horses.forEach(h -> horseData.add(h.getAsJsonObject()));
                    for (final JsonObject horse : horseData) {
                        final int horseTravsportId = horse.get("id").getAsInt();
                        final String horseName = horse.get("name").getAsString();
                        final JsonObject driverObject = horse.get("driver").getAsJsonObject();
                        final String driverName = driverObject.get("name").getAsString();
                        final int driverId = driverObject.get("licenseId").getAsInt();
                        final JsonObject trainerObject = horse.get("trainer").getAsJsonObject();
                        final String trainerName
                                = trainerObject.get("name") != null ? trainerObject.get("name").getAsString() : "";
                        final int trainerId
                                = trainerObject.get("licenseId") != null ? trainerObject.get("licenseId").getAsInt() : -1;

                        final JsonObject ownerObject = horse.get("owner").getAsJsonObject();
                        String ownerName;
                        int ownerId;
                        try {
                            ownerName = ownerObject.get("name").getAsString();
                            ownerId = ownerObject.get("licenseId").getAsInt();
                        } catch (final NullPointerException e) {
                            ownerName = "";
                            ownerId = -1;
                        }
                        final int lane = horse.get("startPosition").getAsInt();
                        final int actualDistance = horse.get("actualDistance").getAsInt();
                        final int shoe = horse.get("shoeOption").getAsJsonObject().get("code").getAsInt();

                        databaseController.insertResult(trackCode,
                                raceDate,
                                raceNumber,
                                lane,
                                actualDistance,
                                -2,
                                -1,
                                raceStartType,
                                shoe,
                                -1,
                                driverName,
                                trainerName,
                                horseName,
                                horseTravsportId,
                                trainerId,
                                driverId,
                                "",
                                raceDayId);
                        final int horseIdByName = databaseController.getHorseId(horseName, horseTravsportId);
                        if (horseIdByName > -1 && shouldUpdateFullStats(getFullStats, "horse", horseTravsportId)) {
                            getHorseStatByIdJson(horseTravsportId, horseName, "", -1);
                        }

                        final int driverIdByName = databaseController.getDriverId(driverName, driverId);
                        if (driverIdByName > -1 && shouldUpdateFullStats(getFullStats, "driver", driverId)) {
                            getDriverStatById(driverId, driverName, -1);
                        }
                    }
                }
            } catch (final NullPointerException e) {
                System.out.println("Failed to get results");
                // throw new RuntimeException(e.getMessage(), e);
            } catch (FailingHttpStatusCodeException | IOException e1) {
                System.out.println("EXCEPTION while getting raceCalendar at date " + date);
                // throw new RuntimeException(e1.getMessage(), e1);
            }

        }

        // Xpath data-testid = racecalendar-button-startlist

    }

    private boolean shouldUpdateFullStats(boolean getFullStats, String who, int travsportId) {
        final String collected = DatabaseController.getInstance().getFullStatsCollected(who, travsportId);

        return getFullStats && (Strings.isNullOrEmpty(collected) || collected.equalsIgnoreCase("null"));
    }

    public int getHorseIdByName(String horseName) {
        /*
         * Uppdatera med detta anrop, kommer tillbaka en JSON sträng som man kan ta utan
         * css och allt.
         * https://api.travsport.se/webapi/horses/results/organisation/TROT/sourceofdata
         * /SPORT/horseid/781845
         *
         */
        /*
         * Search String
         * https://api.travsport.se/webapi/horses/search/organisation/TROT?age=0&gender=
         * BOTH&horseName=molly&trotBreed=ALL&autoSuffixWildcard=true
         *
         * Svarar med lista ex.
         * [{"organisation":"TROT","sourceOfData":"SPORT","horseId":58291,
         * "name":"GINA II","yearOfBirth":"1945","horseGender":{"code":"S","text":"sto"}
         * ,"horseBreed":{"code":"K","text":"kallblodig travare"}},
         * {"organisation":"TROT","sourceOfData":"SPORT","horseId":58264,"name":"GINA",
         * "yearOfBirth":"1935","horseGender":{"code":"S","text":"sto"},"horseBreed":{
         * "code":"K","text":"kallblodig travare"}}]
         */

        int horseId = DatabaseController.getInstance().getHorseTravsportId(horseName);
        if (horseId <= 0) {
            System.out.println("Getting horse id from travsport");
            final String url = "https://api.travsport.se/webapi/horses/search/organisation/TROT?age=0&gender=BOTH&horseName="
                    + horseName + "&trotBreed=ALL&autoSuffixWildcard=false";

            final WebClient webclient = MyWebClient.getInstance().getWebclient();
            try {

                final Page page = webclient.getPage(url);

                final String content = page.getWebResponse().getContentAsString();
                final Gson gson = new Gson();
                final JsonArray fromJson = gson.fromJson(content, JsonArray.class);
                final ArrayList<JsonObject> jsonObjects = Lists.newArrayList();
                fromJson.forEach(e -> jsonObjects.add(e.getAsJsonObject()));

                Collections.sort(jsonObjects, new Comparator<JsonObject>() {

                    @Override
                    public int compare(JsonObject o1, JsonObject o2) {
                        return o2.get("horseId").getAsString().compareTo(o1.get("horseId").getAsString());
                    }

                });
                horseId = jsonObjects.get(0).get("horseId").getAsInt();
                DatabaseController.getInstance().setHorseTravsportId(Integer.valueOf(horseId), horseName);
            } catch (FailingHttpStatusCodeException | IOException e) {
                throw new RuntimeException(e.getMessage(), e);
            } catch (final IndexOutOfBoundsException e) {
                System.out.println("Horse with name " + horseName + " not found at travsport");
            }

        }
        return horseId;
    }

    private ArrayList<JsonObject> getJsonObjects(String url) {
        final ArrayList<JsonObject> jsonObjects = Lists.newArrayList();
        try (WebClient wc = MyWebClient.getInstance().getJsonWebClient();) {

            final Page page = wc.getPage(url);
            final String content = page.getWebResponse().getContentAsString();
            final Gson gson = new Gson();
            final JsonArray fromJson = gson.fromJson(content, JsonArray.class);
            fromJson.forEach(e -> jsonObjects.add(e.getAsJsonObject()));
        } catch (FailingHttpStatusCodeException | IOException e) {
            throw new RuntimeException(e.getMessage(), e);
        }
        return jsonObjects;
    }

    public void getHorseStatByIdJson(int horseTravsportId, String horseName, String raceType, int raceId) {
        final String url = "https://api.travsport.se/webapi/horses/results/organisation/TROT/sourceofdata/SPORT/horseid/"
                + horseTravsportId;

        final ArrayList<JsonObject> jsonObjects = getJsonObjects(url);
        final int i = 0;
        final int rows = jsonObjects.size();
        System.out.println("Updating horse " + horseName + " " + rows + " results");
        for (final JsonObject jo : jsonObjects) {
            final String trackCode = jo.get("trackCode").getAsString();

            final JsonObject raceInfo = jo.get("raceInformation").getAsJsonObject();
            final String raceDate = raceInfo.get("date").getAsString();
            final int raceNumber = raceInfo.get("raceNumber").getAsInt();

            int lane;
            try {
                lane = Integer.valueOf(jo.get("startPosition").getAsJsonObject().get("displayValue").getAsString());
            } catch (final NumberFormatException e) {
                lane = -1;
            }

            final int distance = Integer.valueOf(jo.get("distance").getAsJsonObject().get("displayValue").getAsString());

            final String timeValue = jo.get("kilometerTime").getAsJsonObject().get("displayValue").getAsString();

            final float time = getTimeFromTimeCellValue(timeValue);
            final String timeModifier = getTimeModifierFromTimeCellValue(timeValue);

            if (jo.get("shoeInfo") != null) {
                final JsonObject shoeInfo = jo.get("shoeInfo").getAsJsonObject();
                final boolean frontShoe = shoeInfo.get("front").getAsBoolean();
                final boolean backShoe = shoeInfo.get("back").getAsBoolean();
                // konvertera till värdet som det ska vara...
            }

            final JsonObject placementInfo = jo.get("placement").getAsJsonObject();
            final String resultString = placementInfo.get("displayValue").getAsString();
            final int result = Strings.isNullOrEmpty(resultString.replaceAll("\\D", "")) ? -1
                    : Integer.valueOf(resultString.replaceAll("\\D", ""));

            final JsonObject driverInfo = jo.get("driver").getAsJsonObject();
            final int driverId = driverInfo.get("id").getAsInt();
            final String driverName = driverInfo.get("name").getAsString();

            final JsonObject trainerInfo = jo.get("trainer").getAsJsonObject();
            final int trainerId = trainerInfo.get("id").getAsInt();
            final String trainerName = trainerInfo.get("name").getAsString();

            // final String sulkyString =
            // jo.get("suklyOptions").getAsJsonObject().get("description").getAsString();

            DatabaseController.getInstance().insertResult(trackCode,
                    raceDate,
                    raceNumber,
                    lane,
                    distance,
                    result,
                    time,
                    timeModifier,
                    -1,
                    -1,
                    driverName,
                    trainerName,
                    horseName,
                    horseTravsportId,
                    trainerId,
                    driverId,
                    raceType,
                    raceId);

        }
        databaseController
                .setfullStatsCollected("horse", horseTravsportId, MainController.DATE_FORMAT.format(new Date()).toString());
    }

    public void getDriverStatById(int driverTravsportId, String driverName, int raceId) {
        // https://api.travsport.se/webapi/licenseholder/drivers/results/organisation/TROT/sourceofdata/SPORT/driverid/70381
        // JSON resultat

        final String url
                = "https://api.travsport.se/webapi/licenseholder/drivers/results/organisation/TROT/sourceofdata/SPORT/driverid/"
                        + driverTravsportId;
        final WebClient wc = MyWebClient.getInstance().getJsonWebClient();

        try {
            final Page page = wc.getPage(url);

            final String content = page.getWebResponse().getContentAsString();
            final Gson gson = new Gson();
            final JsonArray fromJson = gson.fromJson(content, JsonArray.class);
            final ArrayList<JsonObject> jsonObjects = Lists.newArrayList();
            fromJson.forEach(e -> jsonObjects.add(e.getAsJsonObject()));

            final int i = 0;
            final int rows = jsonObjects.size();
            System.out.println("Updating driver " + driverName + " " + rows + " results");
            for (final JsonObject jo : jsonObjects) {

                final String trackCode = jo.get("trackCode").getAsString();

                final JsonObject raceInfo = jo.get("raceInformation").getAsJsonObject();
                final String raceDate = raceInfo.get("date").getAsString();
                final int raceNumber = raceInfo.get("raceNumber").getAsInt();
                int lane;
                try {
                    lane = Integer.valueOf(jo.get("startPosition").getAsJsonObject().get("displayValue").getAsString());
                } catch (final NumberFormatException e) {
                    lane = -1;
                }
                final int distance = Integer.valueOf(jo.get("distance").getAsJsonObject().get("displayValue").getAsString());

                final String timeValue = jo.get("kilometerTime").getAsJsonObject().get("displayValue").getAsString();
                final float time = getTimeFromTimeCellValue(timeValue);
                final String timeModifier = getTimeModifierFromTimeCellValue(timeValue);

                final String resultString = jo.get("placement").getAsJsonObject().get("displayValue").getAsString();
                final int result = Strings.isNullOrEmpty(resultString.replaceAll("\\D", "")) ? -1
                        : Integer.valueOf(resultString.replaceAll("\\D", ""));

                final JsonObject horseObject = jo.get("horse").getAsJsonObject();
                final String horseName = horseObject.get("name").getAsString();
                final int travsportIdHorse = horseObject.get("id").getAsInt();
                String trainerName = "";
                int trainerId = -1;
                if (jo.get("trainer") != null) {
                    final JsonObject trainerObject = jo.get("trainer").getAsJsonObject();
                    trainerName = trainerObject.get("name").getAsString();
                    trainerId = trainerObject.get("id").getAsInt();
                }

                DatabaseController.getInstance().insertResult(trackCode,
                        raceDate,
                        raceNumber,
                        lane,
                        distance,
                        result,
                        time,
                        timeModifier,
                        -1,
                        -1,
                        driverName,
                        trainerName,
                        horseName,
                        travsportIdHorse,
                        trainerId,
                        driverTravsportId,
                        "",
                        raceId);

            }

            databaseController
                    .setfullStatsCollected("driver", driverTravsportId, MainController.DATE_FORMAT.format(new Date()).toString());

        } catch (FailingHttpStatusCodeException | IOException e) {
            throw new RuntimeException(e.getMessage(), e);
        }
    }

    public int getDriverIdByName(String firstName, String lastName) {
        System.out.println("Getting driver id from travsport by name " + firstName + " " + lastName);
        final String url = "https://api.travsport.se/webapi/licenseholder/search/organisation/TROT?firstName=" + firstName
                + "&lastName=" + lastName + "&showAll=false";
        int driverId = 0;
        final WebClient webclient = MyWebClient.getInstance().getJsonWebClient();
        try {

            final Page page = webclient.getPage(url);

            final String content = page.getWebResponse().getContentAsString();
            final Gson gson = new Gson();
            final JsonArray fromJson = gson.fromJson(content, JsonArray.class);
            final ArrayList<JsonObject> jsonObjects = Lists.newArrayList();
            fromJson.forEach(e -> jsonObjects.add(e.getAsJsonObject()));

            Collections.sort(jsonObjects, new Comparator<JsonObject>() {

                @Override
                public int compare(JsonObject o1, JsonObject o2) {
                    return o2.get("id").getAsString().compareTo(o1.get("id").getAsString());
                }

            });
            driverId = jsonObjects.get(0).get("id").getAsInt();
            DatabaseController.getInstance().setDriverTravsportId(driverId, firstName, lastName);

        } catch (FailingHttpStatusCodeException | IOException e) {
            throw new RuntimeException(e.getMessage(), e);
        } catch (final IndexOutOfBoundsException e) {
            System.out.println("Driver with name " + firstName + " " + lastName + " not found at travsport");
        }
        return driverId;
    }

    public void updateRaceResults(int raceId) {
        // https://api.travsport.se/webapi/raceinfo/results/organisation/TROT/sourceofdata/SPORT/racedayid/<raceId>
        final String url
                = "https://api.travsport.se/webapi/raceinfo/results/organisation/TROT/sourceofdata/SPORT/racedayid/" + raceId;

        try {
            final Page page = MyWebClient.getInstance().getJsonWebClient().getPage(url);
            final String content = new String(page.getWebResponse().getContentAsString()); // .getBytes("ISO-8859-1"), "UTF-8");
            final Gson gson = new Gson();
            final JsonObject jo = gson.fromJson(content, JsonObject.class);

            final ArrayList<JsonObject> jsonObjects = Lists.newArrayList();
            final JsonArray results = jo.get("racesWithReadyResult").getAsJsonArray();
            results.forEach(j -> jsonObjects.add(j.getAsJsonObject()));

            for (final JsonObject json : jsonObjects) {
                final JsonObject generalInfo = json.get("generalInfo").getAsJsonObject();
                final int raceNumber = generalInfo.get("raceNumber").getAsInt();
                Matcher matcher;
                String startTime;
                try {
                    startTime = generalInfo.get("startTime").getAsString();
                    final Pattern pattern = Pattern.compile("\\d{4}-\\d{2}-\\d{2}");
                    matcher = pattern.matcher(startTime);
                } catch (final NullPointerException e) {
                    continue;
                }
                String raceDate;
                if (matcher.find()) {
                    raceDate = matcher.group();
                } else {
                    throw new RuntimeException("Could not find date from " + startTime);
                }

                try {
                    final JsonArray raceResultRows = json.get("raceResultRows").getAsJsonArray();

                    for (int i = 0; i < raceResultRows.size(); i++) {
                        final JsonObject res = raceResultRows.get(i).getAsJsonObject();
                        final int result = res.get("placementNumber").getAsInt();
                        final JsonObject horse = res.get("horse").getAsJsonObject();
                        final int horseTravsportId = horse.get("id").getAsInt();
                        final String horseName = horse.get("name").getAsString();

                        final JsonObject driver = res.get("driver").getAsJsonObject();
                        final int driverTravsportId = driver.get("id").getAsInt();
                        final String driverName = driver.get("name").getAsString();

                        final JsonObject trainer = res.get("trainer").getAsJsonObject();
                        final int trainerTravsportId = trainer.get("id").getAsInt();
                        final String trainerName = trainer.get("name").getAsString();
                        int shoeInfo = 0;
                        try {
                            shoeInfo = res.get("shoeInfo").getAsJsonObject().get("sortValue").getAsInt();
                        } catch (final NullPointerException e) {
                            // ignore
                        }

                        final String timeString = res.get("time").getAsString();
                        final float time = getTimeFromTimeCellValue(timeString);
                        final String timeModifier = getTimeModifierFromTimeCellValue(timeString);

                        final String[] startPosAndDistance = res.get("startPositionAndDistance").getAsString().split("/");
                        // final int lane = Integer.valueOf(startPosAndDistance[0]);
                        final int lane = res.get("programNumber").getAsInt();
                        final int distance = Integer.valueOf(startPosAndDistance[1]);

                        DatabaseController.getInstance().updateFromRaceResults(raceId,
                                result,
                                time,
                                timeModifier,
                                lane,
                                distance,
                                horseTravsportId,
                                driverTravsportId,
                                raceDate,
                                raceNumber);
                        System.out.println("Updated raceId " + raceId + " horse " + horseName + "(" + horseTravsportId
                                + ") driver " + driverName + "(" + driverTravsportId + ") at date " + raceDate + " with result "
                                + result + " time " + time + " time mod " + timeModifier + " race number: " + raceNumber);
                    }
                } catch (final NullPointerException e) {
                    System.out.println("ERROR WITH MESSAGE: " + e.getMessage());
                    continue;
                }
            }
        } catch (FailingHttpStatusCodeException | IOException e) {
            throw new RuntimeException(e.getMessage(), e);
        }
    }

}
