byku.traindroid.DataFacade.java Source code

Java tutorial

Introduction

Here is the source code for byku.traindroid.DataFacade.java

Source

/*******************************************************************************
 * Copyright (C) 2010-2011 Dmitriy Nesterov
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 ******************************************************************************/

package byku.traindroid;

import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;

import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/*
 * Static class that processes saved data. 
 */
public final class DataFacade {
    /*
     * Timetables and stations.
     */
    private static ArrayList<TimeTable> _timeTables = new ArrayList<TimeTable>();
    private static ArrayList<Station> _stations = new ArrayList<Station>();

    /*
     * Sources addresses.
     */
    private static final String TUTU_ADRESS = "http://www.tutu.ru/rasp.php?st1=%s&st2=%s&date=%s&print=yes";
    private static final String YANDEX_ADRESS = "http://www.rasp.yandex.ru/search/?from%s=%s&to%s=%s&dateForward=%s";

    /*
     * Regular expressions.
     */
    private static final String TIME_REGEXP = "\\d\\d:\\d\\d";
    public static String TUTU_REGEXP = "";
    public static String YANDEX_REGEXP = "";

    public static void Init() {
        if (TUTU_REGEXP.equals(""))
            TUTU_REGEXP = ">\\d\\d:\\d\\d</a";
        if (YANDEX_REGEXP.equals(""))
            YANDEX_REGEXP = "(>|\\s)\\d\\d:\\d\\d<";

        if (_stations.size() == 0) {
            Station station;
            station = new Station("", "80710", "");
            _stations.add(station);
            station = new Station("?", "79310", "?");
            _stations.add(station);
            station = new Station("?-?", "79610",
                    "?-?");
            _stations.add(station);

            //         station = new Station("??", "81310", "??");
            //         _stations.add(station);
            //         station = new Station("", "81010", "");
            //         _stations.add(station);
            //         station = new Station("?", "81710", "?");
            //         _stations.add(station);
            //         station = new Station("", "81110", "");
            //         _stations.add(station);
            //         station = new Station("??", "79410", "??");
            //         _stations.add(station);
            //         station = new Station("?", "79510", "?");
            //         _stations.add(station);
            //         station = new Station("?", "79910", "?");
            //         _stations.add(station);
        }
    }

    public static ArrayList<TimeTable> GetTimeTables() {
        return _timeTables;
    }

    public static ArrayList<TimeTable> GetTimeTables(String date) {
        ArrayList<TimeTable> timeTables = new ArrayList<TimeTable>();

        for (TimeTable timeTable : _timeTables) {
            if (timeTable.getDate().equals(date)) {
                timeTables.add(timeTable);
            }
        }

        return timeTables;
    }

    public static ArrayList<Station> GetStations() {
        return _stations;
    }

    public static String[] GetStationNames() {
        String[] result = new String[_stations.size()];
        for (int i = 0; i < _stations.size(); ++i) {
            result[i] = _stations.get(i).getName();
        }

        return result;
    }

    public static Station FindStation(String name) {
        for (int i = 0; i < _stations.size(); ++i) {
            if (_stations.get(i).getName().equals(name)) {
                return _stations.get(i);
            }
        }

        return null;
    }

    public static ArrayList<TimeTable> GetTimeTables(String date, Station stationFrom, Station stationTo) {
        ArrayList<TimeTable> timeTables = new ArrayList<TimeTable>();

        for (TimeTable timeTable : _timeTables) {
            if (timeTable.getDate().equals(date) && timeTable.getStationFrom().equals(stationFrom)
                    && timeTable.getStationTo().equals(stationTo)) {
                timeTables.add(timeTable);
            }
        }

        return timeTables;
    }

    public static void Serialize(FileOutputStream stream) throws IOException {
        ByteUtils.WriteInt(stream, _stations.size());
        for (Station station : _stations) {
            station.Serialize(stream);
        }

        ByteUtils.WriteInt(stream, _timeTables.size());
        for (TimeTable timeTable : _timeTables) {
            timeTable.Serialize(stream);
        }

        ByteUtils.WriteString(stream, TUTU_REGEXP);
        ByteUtils.WriteString(stream, YANDEX_REGEXP);
    }

    public static void Deserialize(FileInputStream stream) throws IOException {
        int size = ByteUtils.ReadInt(stream);
        _stations.clear();
        for (int i = 0; i < size; ++i) {
            _stations.add(new Station(stream));
        }

        size = ByteUtils.ReadInt(stream);
        _timeTables.clear();
        for (int i = 0; i < size; ++i) {
            _timeTables.add(new TimeTable(stream));
        }

        TUTU_REGEXP = ByteUtils.ReadString(stream);
        YANDEX_REGEXP = ByteUtils.ReadString(stream);
    }

    /*
     * Gets new timetables for specified sources, stations, dates and saves it locally.
     * @return Error description if it occurred.
     */
    public static String UpdateTimeTable(Station from, Station to, int dayFrom, int daysCount, Boolean updateYandex,
            Boolean updateTutu) {
        String result = "";
        Calendar calendar = Calendar.getInstance();
        int day = calendar.get(Calendar.DATE) + dayFrom;
        int month = calendar.get(Calendar.MONTH) + 1;
        int year = calendar.get(Calendar.YEAR);

        for (int i = 0; i < daysCount; ++i) {
            // Yes, it should be something like date.addDays(1) but it already tested and I'm lazy.
            if (day > calendar.getActualMaximum(Calendar.DAY_OF_MONTH)) {
                day -= calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
                ++month;
                if (month > 12) {
                    month = 1;
                    ++year;
                }
            }
            String date = Utils.DateToString(day, month, year);

            if (updateTutu) {
                String url = String.format(TUTU_ADRESS, from.getTutuId(), to.getTutuId(), date);
                String message = processSource(url, from, to, date, TUTU_REGEXP, "tutu");
                result += (message != "") ? "\n" + message : "";
            }

            if (updateYandex) {
                String fromType = getYandexStationType(from.getYandexId());
                String toType = getYandexStationType(to.getYandexId());
                String url = String.format(YANDEX_ADRESS, fromType, from.getYandexId(), toType, to.getYandexId(),
                        date);
                String message = processSource(url, from, to, date, YANDEX_REGEXP, "yandex");
                result += (message != "") ? "\n" + message : "";
            }

            ++day;
        }

        return result;
    }

    public static void ClearTimeTable(Boolean all) {
        if (all) {
            _timeTables.clear();
            return;
        }

        Date today = Utils.Today();

        for (int i = 0; i < _timeTables.size(); ++i) {
            Date date = Utils.StringToDate(_timeTables.get(i).getDate(), true);
            if (date.before(today)) {
                _timeTables.remove(i);
                --i;
            }
        }
    }

    /*
     * Process request for new timetable for one source.
     * @return Error description if it occurred.
     */
    private static String processSource(String url, Station from, Station to, String date, String regexp,
            String sourceName) {
        ArrayList<Pair<String, String>> times = new ArrayList<Pair<String, String>>();
        HttpClient client = new DefaultHttpClient();
        HttpGet request = new HttpGet(url.replaceAll(" ", "+"));
        HttpResponse response;

        try {
            response = client.execute(request);
            ByteArrayOutputStream buffer = new ByteArrayOutputStream();
            response.getEntity().writeTo(buffer);

            String message = parsePage(new String(buffer.toByteArray()), regexp, times);
            if (!message.equals("")) {
                _timeTables.add(new TimeTable(from, to, date + "*", sourceName, times));
                return message;
            }

            removeTimeTableIfExists(from.getName(), to.getName(), date, sourceName);

            _timeTables.add(new TimeTable(from, to, date, sourceName, times));
        } catch (Exception e) {
            return e.getMessage();
        }

        return "";
    }

    /*
     * Parses page content using regexp and fill array with times of trains.
     * @return Error description if it occurred. 
     */
    private static String parsePage(String page, String regexp, ArrayList<Pair<String, String>> times) {
        ArrayList<String> matches = new ArrayList<String>();

        Pattern pattern = Pattern.compile(regexp);
        Matcher matcher = pattern.matcher(page);

        Pattern timePattern = Pattern.compile(TIME_REGEXP);
        Matcher timeMatcher = timePattern.matcher("");

        while (matcher.find()) {
            matches.add(matcher.group());
        }

        if (matches.size() == 0) {
            return "Trains data not found. Maybe server changes it's format.";
        }

        for (int i = 0; i < matches.size(); i += 2) {
            if (i + 1 == matches.size()) {
                return "Incorrect times count.";
            }

            if (matches.get(i).equals(matches.get(i + 1))) {
                continue;
            }

            timeMatcher.reset(matches.get(i));
            String timeFrom = timeMatcher.find() ? timeMatcher.group() : "error";

            timeMatcher.reset(matches.get(i + 1));
            String timeTo = timeMatcher.find() ? timeMatcher.group() : "error";

            times.add(new Pair<String, String>(timeFrom, timeTo));
        }

        return "";
    }

    private static void removeTimeTableIfExists(String from, String to, String date, String sourceName) {
        for (int i = 0; i < _timeTables.size(); ++i) {
            TimeTable timeTable = _timeTables.get(i);
            if (timeTable.getStationFrom().getName().equals(from) && timeTable.getStationTo().getName().equals(to)
                    && timeTable.getDate().equals(date) && timeTable.getSource().equals(sourceName)) {
                _timeTables.remove(i);
            }
        }
    }

    private static String getYandexStationType(String station) {
        if (station.charAt(0) == 's' || station.charAt(0) == 'S') {
            return "Id";
        }
        return "Name";
    }
}