package de.geeksfactory.opacclient.apis;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.message.BasicNameValuePair;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import org.json.JSONException;
import org.json.JSONObject;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import de.geeksfactory.opacclient.apis.OpacApi.MultiStepResult.Status;
import de.geeksfactory.opacclient.i18n.StringProvider;
import de.geeksfactory.opacclient.networking.HttpClientFactory;
import de.geeksfactory.opacclient.networking.HttpUtils;
import de.geeksfactory.opacclient.networking.NotReachableException;
import de.geeksfactory.opacclient.networking.SSLSecurityException;
import de.geeksfactory.opacclient.objects.Account;
import de.geeksfactory.opacclient.objects.AccountData;
import de.geeksfactory.opacclient.objects.Copy;
import de.geeksfactory.opacclient.objects.Detail;
import de.geeksfactory.opacclient.objects.DetailedItem;
import de.geeksfactory.opacclient.objects.Filter;
import de.geeksfactory.opacclient.objects.Filter.Option;
import de.geeksfactory.opacclient.objects.LentItem;
import de.geeksfactory.opacclient.objects.Library;
import de.geeksfactory.opacclient.objects.ReservedItem;
import de.geeksfactory.opacclient.objects.SearchRequestResult;
import de.geeksfactory.opacclient.objects.SearchResult;
import de.geeksfactory.opacclient.objects.SearchResult.MediaType;
import de.geeksfactory.opacclient.searchfields.DropdownSearchField;
import de.geeksfactory.opacclient.searchfields.SearchField;
import de.geeksfactory.opacclient.searchfields.SearchQuery;
import de.geeksfactory.opacclient.searchfields.TextSearchField;
public class Adis extends BaseApi implements OpacApi {
protected static HashMap<String, MediaType> types = new HashMap<>();
protected static HashSet<String> ignoredFieldNames = new HashSet<>();
static {
types.put("Buch", MediaType.BOOK);
types.put("Band", MediaType.BOOK);
types.put("DVD-ROM", MediaType.CD_SOFTWARE);
types.put("CD-ROM", MediaType.CD_SOFTWARE);
types.put("Medienkombination", MediaType.PACKAGE);
types.put("DVD-Video", MediaType.DVD);
types.put("Noten", MediaType.SCORE_MUSIC);
types.put("Konsolenspiel", MediaType.GAME_CONSOLE);
types.put("Spielkonsole", MediaType.GAME_CONSOLE);
types.put("CD", MediaType.CD);
types.put("Zeitschrift", MediaType.MAGAZINE);
types.put("Zeitschriftenheft", MediaType.MAGAZINE);
types.put("Zeitung", MediaType.NEWSPAPER);
types.put("Beitrag E-Book", MediaType.EBOOK);
types.put("Elektronische Ressource", MediaType.EBOOK);
types.put("E-Book", MediaType.EBOOK);
types.put("Karte", MediaType.MAP);
types.put("E-Ressource", MediaType.EBOOK);
types.put("Munzinger", MediaType.EBOOK);
types.put("E-Audio", MediaType.EAUDIO);
types.put("Blu-Ray", MediaType.BLURAY);
// TODO: The following fields from Berlin make no sense and don't work
// when they are displayed alone.
// We can only include them if we automatically deselect the "Verbund"
// checkbox
// when one of these dropdowns has a value other than "".
ignoredFieldNames.add("oder Bezirk");
ignoredFieldNames.add("oder Bibliothek");
}
protected String opac_url = "";
protected JSONObject data;
protected Library library;
protected int s_requestCount = 0;
protected String s_service;
protected String s_sid;
protected String s_exts;
protected String s_alink;
protected List<NameValuePair> s_pageform;
protected int s_lastpage;
protected Document s_reusedoc;
public static Map<String, List<String>> getQueryParams(String url) {
try {
Map<String, List<String>> params = new HashMap<>();
String[] urlParts = url.split("\\?");
if (urlParts.length > 1) {
String query = urlParts[1];
for (String param : query.split("&")) {
String[] pair = param.split("=");
String key = URLDecoder.decode(pair[0], "UTF-8");
String value = "";
if (pair.length > 1) {
value = URLDecoder.decode(pair[1], "UTF-8");
}
List<String> values = params.get(key);
if (values == null) {
values = new ArrayList<>();
params.put(key, values);
}
values.add(value);
}
}
return params;
} catch (UnsupportedEncodingException ex) {
throw new AssertionError(ex);
}
}
public Document htmlGet(String url) throws
IOException {
if (!url.contains("requestCount") && s_requestCount >= 0) {
url = url + (url.contains("?") ? "&" : "?") + "requestCount="
+ s_requestCount;
}
HttpGet httpget = new HttpGet(cleanUrl(url));
HttpResponse response;
try {
response = http_client.execute(httpget);
} catch (javax.net.ssl.SSLPeerUnverifiedException e) {
throw new SSLSecurityException(e.getMessage());
} catch (javax.net.ssl.SSLException e) {
// Can be "Not trusted server certificate" or can be a
// aborted/interrupted handshake/connection
if (e.getMessage().contains("timed out")
|| e.getMessage().contains("reset by")) {
e.printStackTrace();
throw new NotReachableException(e.getMessage());
} else {
throw new SSLSecurityException(e.getMessage());
}
} catch (InterruptedIOException e) {
e.printStackTrace();
throw new NotReachableException(e.getMessage());
} catch (IOException e) {
if (e.getMessage() != null && e.getMessage().contains("Request aborted")) {
e.printStackTrace();
throw new NotReachableException(e.getMessage());
} else {
throw e;
}
}
if (response.getStatusLine().getStatusCode() >= 400) {
throw new NotReachableException(response.getStatusLine().getReasonPhrase());
}
String html = convertStreamToString(response.getEntity().getContent(),
getDefaultEncoding());
HttpUtils.consume(response.getEntity());
Document doc = Jsoup.parse(html);
Pattern patRequestCount = Pattern.compile("requestCount=([0-9]+)");
for (Element a : doc.select("a")) {
Matcher objid_matcher = patRequestCount.matcher(a.attr("href"));
if (objid_matcher.matches()) {
s_requestCount = Integer.parseInt(objid_matcher.group(1));
}
}
doc.setBaseUri(url);
return doc;
}
public Document htmlPost(String url, List<NameValuePair> data)
throws IOException {
HttpPost httppost = new HttpPost(cleanUrl(url));
boolean rcf = false;
for (NameValuePair nv : data) {
if (nv.getName().equals("requestCount")) {
rcf = true;
break;
}
}
if (!rcf) {
data.add(new BasicNameValuePair("requestCount", s_requestCount + ""));
}
httppost.setEntity(new UrlEncodedFormEntity(data, getDefaultEncoding()));
HttpResponse response;
try {
response = http_client.execute(httppost);
} catch (javax.net.ssl.SSLPeerUnverifiedException e) {
throw new SSLSecurityException(e.getMessage());
} catch (javax.net.ssl.SSLException e) {
// Can be "Not trusted server certificate" or can be a
// aborted/interrupted handshake/connection
if (e.getMessage().contains("timed out")
|| e.getMessage().contains("reset by")) {
e.printStackTrace();
throw new NotReachableException(e.getMessage());
} else {
throw new SSLSecurityException(e.getMessage());
}
} catch (InterruptedIOException e) {
e.printStackTrace();
throw new NotReachableException(e.getMessage());
} catch (IOException e) {
if (e.getMessage() != null && e.getMessage().contains("Request aborted")) {
e.printStackTrace();
throw new NotReachableException(e.getMessage());
} else {
throw e;
}
}
if (response.getStatusLine().getStatusCode() >= 400) {
throw new NotReachableException(response.getStatusLine().getReasonPhrase());
}
String html = convertStreamToString(response.getEntity().getContent(),
getDefaultEncoding());
HttpUtils.consume(response.getEntity());
Document doc = Jsoup.parse(html);
Pattern patRequestCount = Pattern
.compile(".*requestCount=([0-9]+)[^0-9].*");
for (Element a : doc.select("a")) {
Matcher objid_matcher = patRequestCount.matcher(a.attr("href"));
if (objid_matcher.matches()) {
s_requestCount = Integer.parseInt(objid_matcher.group(1));
}
}
doc.setBaseUri(url);
return doc;
}
@Override
public void start() throws IOException {
try {
s_requestCount = -1;
Document doc = htmlGet(opac_url + "?"
+ data.getString("startparams"));
Pattern padSid = Pattern
.compile(".*;jsessionid=([0-9A-Fa-f]+)[^0-9A-Fa-f].*");
for (Element navitem : doc.select("#unav li a, .tree_ul li a")) {
// Düsseldorf uses a custom layout where the navbar is .tree_ul
if (navitem.attr("href").contains("service=")) {
s_service = getQueryParams(navitem.attr("href")).get(
"service").get(0);
}
if (navitem.text().contains("Erweiterte Suche")) {
s_exts = getQueryParams(navitem.attr("href")).get("sp")
.get(0);
}
Matcher objid_matcher = padSid.matcher(navitem.attr("href"));
if (objid_matcher.matches()) {
s_sid = objid_matcher.group(1);
}
}
if (s_exts == null) {
s_exts = "SS6";
}
} catch (JSONException e) {
throw new RuntimeException(e);
}
super.start();
}
@Override
protected String getDefaultEncoding() {
return "UTF-8";
}
@Override
public SearchRequestResult search(List<SearchQuery> queries)
throws IOException, OpacErrorException {
start();
// TODO: There are also libraries with a different search form,
// s_exts=SS2 instead of s_exts=SS6
// e.g. munich. Treat them differently!
Document doc = htmlGet(opac_url + ";jsessionid=" + s_sid + "?service="
+ s_service + "&sp=" + s_exts);
int dropdownTextCount = 0;
int totalCount = 0;
List<NameValuePair> nvpairs = new ArrayList<>();
for (SearchQuery query : queries) {
if (!query.getValue().equals("")) {
totalCount++;
if (query.getSearchField() instanceof DropdownSearchField) {
doc.select("select#" + query.getKey())
.val(query.getValue());
continue;
}
if (query.getSearchField() instanceof TextSearchField &&
query.getSearchField().getData() != null &&
!query.getSearchField().getData().optBoolean("selectable", true) &&
doc.select("#" + query.getKey()).size() > 0) {
doc.select("#" + query.getKey())
.val(query.getValue());
continue;
}
dropdownTextCount++;
if (s_exts.equals("SS2")
|| (query.getSearchField().getData() != null && !query
.getSearchField().getData()
.optBoolean("selectable", true))) {
doc.select("input#" + query.getKey()).val(query.getValue());
} else {
if (doc.select("select#SUCH01_1").size() == 0 &&
doc.select("input[fld=FELD01_" + dropdownTextCount + "]").size() > 0) {
// Hack needed for Nürnberg
doc.select("input[fld=FELD01_" + dropdownTextCount + "]").first()
.previousElementSibling().val(query.getKey());
doc.select("input[fld=FELD01_" + dropdownTextCount + "]")
.val(query.getValue());
} else {
doc.select("select#SUCH01_" + dropdownTextCount).val(query.getKey());
doc.select("input#FELD01_" + dropdownTextCount).val(query.getValue());
}
}
if (dropdownTextCount > 4) {
throw new OpacErrorException(stringProvider.getQuantityString(
StringProvider.LIMITED_NUM_OF_CRITERIA, 4, 4));
}
}
}
for (Element input : doc.select("input, select")) {
if (!"image".equals(input.attr("type"))
&& !"submit".equals(input.attr("type"))
&& !"".equals(input.attr("name"))) {
nvpairs.add(new BasicNameValuePair(input.attr("name"), input
.attr("value")));
}
}
nvpairs.add(new BasicNameValuePair("$Toolbar_0.x", "1"));
nvpairs.add(new BasicNameValuePair("$Toolbar_0.y", "1"));
if (totalCount == 0) {
throw new OpacErrorException(
stringProvider.getString(StringProvider.NO_CRITERIA_INPUT));
}
Document docresults = htmlPost(opac_url + ";jsessionid=" + s_sid,
nvpairs);
return parse_search_wrapped(docresults, 1);
}
public class SingleResultFound extends Exception {
}
protected SearchRequestResult parse_search_wrapped(Document doc, int page) throws IOException, OpacErrorException {
try {
return parse_search(doc, page);
} catch (SingleResultFound e) {
// Zurück zur Trefferliste
List<NameValuePair> nvpairs = new ArrayList<>();
for (Element input : doc.select("input, select")) {
if (!"image".equals(input.attr("type"))
&& !"submit".equals(input.attr("type"))
&& !"".equals(input.attr("name"))) {
nvpairs.add(new BasicNameValuePair(input.attr("name"), input
.attr("value")));
}
}
nvpairs.add(new BasicNameValuePair("$Toolbar_1.x", "1"));
nvpairs.add(new BasicNameValuePair("$Toolbar_1.y", "1"));
doc = htmlPost(opac_url + ";jsessionid=" + s_sid, nvpairs);
try {
return parse_search(doc, page);
} catch (SingleResultFound e1) {
throw new NotReachableException();
}
}
}
private SearchRequestResult parse_search(Document doc, int page)
throws OpacErrorException, SingleResultFound {
if (doc.select(".message h1").size() > 0
&& doc.select("#right #R06").size() == 0) {
throw new OpacErrorException(doc.select(".message h1").text());
}
if (doc.select("#OPACLI").text().contains("nicht gefunden")) {
throw new OpacErrorException(
stringProvider.getString(StringProvider.NO_RESULTS));
}
int total_result_count = -1;
List<SearchResult> results = new ArrayList<>();
if (doc.select("#R06").size() > 0) {
Pattern patNum = Pattern
.compile(".*Treffer: .* von ([0-9]+)[^0-9]*");
Matcher matcher = patNum.matcher(doc.select("#R06").text()
.trim());
if (matcher.matches()) {
total_result_count = Integer.parseInt(matcher.group(1));
} else if (doc.select("#R06").text().trim().endsWith("Treffer: 1")) {
total_result_count = 1;
}
}
if (doc.select("#R03").size() == 1
&& doc.select("#R03").text().trim()
.endsWith("Treffer: 1")) {
throw new SingleResultFound();
}
Pattern patId = Pattern
.compile("javascript:.*htmlOnLink\\('([0-9A-Za-z]+)'\\)");
int nr = 1;
String selector_row, selector_link, selector_img, selector_num, selector_text;
if (doc.select("table.rTable_table tbody").size() > 0) {
selector_row = "table.rTable_table tbody tr";
selector_link = ".rTable_td_text a";
selector_text = ".rList_name";
selector_img = ".rTable_td_img img, .rTable_td_text img";
selector_num = "tr td:first-child";
} else {
// New version, e.g. Berlin
selector_row = ".rList li.rList_li_even, .rList li.rList_li_odd";
selector_link = ".rList_titel a";
selector_text = ".rList_name";
selector_img = ".rlist_icon img, .rList_titel img, .rList_medium .icon, .rList_availability .icon, .rList_img img";
selector_num = ".rList_num";
}
for (Element tr : doc.select(selector_row)) {
SearchResult res = new SearchResult();
Element innerele = tr.select(selector_link).first();
innerele.select("img").remove();
String descr = innerele.html();
for (Element n : tr.select(selector_text)) {
String t = n.text().replace("\u00a0", " ").trim();
if (t.length() > 0) {
descr += "<br />" + t.trim();
}
}
res.setInnerhtml(descr);
try {
res.setNr(Integer.parseInt(tr.select(selector_num).text().trim()));
} catch (NumberFormatException e) {
res.setNr(nr);
}
Matcher matcher = patId.matcher(tr.select(selector_link).first().attr("href"));
if (matcher.matches()) {
res.setId(matcher.group(1));
}
for (Element img : tr.select(selector_img)) {
String ttext = img.attr("title");
String src = img.attr("abs:src");
if (types.containsKey(ttext)) {
res.setType(types.get(ttext));
} else if (ttext.contains("+")
&& types.containsKey(ttext.split("\\+")[0].trim())) {
res.setType(types.get(ttext.split("\\+")[0].trim()));
} else if (ttext.matches(".*ist verf.+gbar") ||
ttext.contains("is available") ||
img.attr("href").contains("verfu_ja")) {
res.setStatus(SearchResult.Status.GREEN);
} else if (ttext.matches(".*nicht verf.+gbar") ||
ttext.contains("not available") ||
img.attr("href").contains("verfu_nein")) {
res.setStatus(SearchResult.Status.RED);
}
}
results.add(res);
nr++;
}
updatePageform(doc);
s_lastpage = page;
return new SearchRequestResult(results, total_result_count, page);
}
@Override
public void init(Library library, HttpClientFactory httpClientFactory) {
super.init(library, httpClientFactory);
this.library = library;
this.data = library.getData();
try {
this.opac_url = data.getString("baseurl");
} catch (JSONException e) {
throw new RuntimeException(e);
}
}
@Override
public SearchRequestResult filterResults(Filter filter, Option option)
throws IOException {
throw new UnsupportedOperationException();
}
@Override
public SearchRequestResult searchGetPage(int page) throws IOException,
OpacErrorException {
SearchRequestResult res = null;
while (page != s_lastpage) {
List<NameValuePair> nvpairs = s_pageform;
int i = 0;
List<Integer> indexes = new ArrayList<>();
for (NameValuePair np : nvpairs) {
if (np.getName().contains("$Toolbar_")) {
indexes.add(i);
}
i++;
}
for (int j = indexes.size() - 1; j >= 0; j--) {
nvpairs.remove((int) indexes.get(j));
}
int p;
if (page > s_lastpage) {
nvpairs.add(new BasicNameValuePair("$Toolbar_5.x", "1"));
nvpairs.add(new BasicNameValuePair("$Toolbar_5.y", "1"));
p = s_lastpage + 1;
} else {
nvpairs.add(new BasicNameValuePair("$Toolbar_4.x", "1"));
nvpairs.add(new BasicNameValuePair("$Toolbar_4.y", "1"));
p = s_lastpage - 1;
}
Document docresults = htmlPost(opac_url + ";jsessionid=" + s_sid,
nvpairs);
res = parse_search_wrapped(docresults, p);
}
return res;
}
@Override
public DetailedItem getResultById(String id, String homebranch)
throws IOException, OpacErrorException {
Document doc;
List<NameValuePair> nvpairs;
if (id == null && s_reusedoc != null) {
doc = s_reusedoc;
} else {
nvpairs = s_pageform;
int i = 0;
List<Integer> indexes = new ArrayList<>();
for (NameValuePair np : nvpairs) {
if (np.getName().contains("$Toolbar_")
|| np.getName().contains("selected")) {
indexes.add(i);
}
i++;
}
for (int j = indexes.size() - 1; j >= 0; j--) {
nvpairs.remove((int) indexes.get(j));
}
nvpairs.add(new BasicNameValuePair("selected", "ZTEXT " + id));
doc = htmlPost(opac_url + ";jsessionid=" + s_sid, nvpairs);
List<NameValuePair> form = new ArrayList<>();
for (Element input : doc.select("input, select")) {
if (!"image".equals(input.attr("type"))
&& !"submit".equals(input.attr("type"))
&& !"checkbox".equals(input.attr("type"))
&& !"".equals(input.attr("name"))
&& !"selected".equals(input.attr("name"))) {
form.add(new BasicNameValuePair(input.attr("name"), input
.attr("value")));
}
}
form.add(new BasicNameValuePair("selected", "ZTEXT " + id));
doc = htmlPost(opac_url + ";jsessionid=" + s_sid, form);
// Yep, two times.
}
// Reset
updatePageform(doc);
nvpairs = s_pageform;
nvpairs.add(new BasicNameValuePair("$Toolbar_1.x", "1"));
nvpairs.add(new BasicNameValuePair("$Toolbar_1.y", "1"));
parse_search_wrapped(htmlPost(opac_url + ";jsessionid=" + s_sid, nvpairs), 1);
nvpairs = s_pageform;
nvpairs.add(new BasicNameValuePair("$Toolbar_3.x", "1"));
nvpairs.add(new BasicNameValuePair("$Toolbar_3.y", "1"));
parse_search_wrapped(htmlPost(opac_url + ";jsessionid=" + s_sid, nvpairs), 1);
return parseResult(id, doc);
}
DetailedItem parseResult(String id, Document doc)
throws IOException, OpacErrorException {
List<NameValuePair> nvpairs;
DetailedItem res = new DetailedItem();
if (doc.select("#R001 img").size() == 1) {
String cover_url = doc.select("#R001 img").first().absUrl("src");
if (!cover_url.endsWith("erne.gif")) {
// If there is no cover, the first image usually is the "n Stars" rating badge
res.setCover(cover_url);
}
}
for (Element tr : doc.select("#R06 .aDISListe table tbody tr")) {
if (tr.children().size() < 2) {
continue;
}
String title = tr.child(0).text().trim();
String value = tr.child(1).text().trim();
if (value.contains("hier klicken") || value.startsWith("zur ") ||
title.contains("URL")) {
res.addDetail(new Detail(title, tr.child(1).select("a").first().absUrl("href")));
} else {
res.addDetail(new Detail(title, value));
}
if (title.contains("Titel") && res.getTitle() == null) {
res.setTitle(value.split("[:/;]")[0].trim());
}
}
if (res.getTitle() == null) {
for (Detail d : res.getDetails()) {
if (d.getDesc().contains("Gesamtwerk")) {
res.setTitle(d.getContent());
break;
}
}
}
if (doc.select("input[value*=Reservieren], input[value*=Vormerken]")
.size() > 0 && id != null) {
res.setReservable(true);
res.setReservation_info(id);
}
DateTimeFormatter fmt = DateTimeFormat.forPattern("dd.MM.yyyy").withLocale(Locale.GERMAN);
if (doc.select("#R08 table.rTable_table, #R09 table.rTable_table").size() > 0) {
Element table = doc.select("#R08 table.rTable_table, #R09 table.rTable_table").first();
Map<Integer, String> colmap = new HashMap<>();
int i = 0;
for (Element th : table.select("thead tr th")) {
String head = th.text().trim();
if (head.contains("Bibliothek") || head.contains("Library")) {
colmap.put(i, "branch");
} else if (head.contains("Standort") || head.contains("Location")) {
colmap.put(i, "location");
} else if (head.contains("Signatur") || head.contains("Call number")) {
colmap.put(i, "signature");
} else if (head.contains("URL")) {
colmap.put(i, "url");
} else if (head.contains("Status") || head.contains("Hinweis")
|| head.contains("Leihfrist") || head.matches(".*Verf.+gbarkeit.*")) {
colmap.put(i, "status");
}
i++;
}
for (Element tr : table.select("tbody tr")) {
Copy copy = new Copy();
for (Entry<Integer, String> entry : colmap.entrySet()) {
if (entry.getValue().equals("status")) {
String status = tr.child(entry.getKey()).text().trim();
String currentStatus =
copy.getStatus() != null ? copy.getStatus() + " - " : "";
if (status.contains(" am: ")) {
copy.setStatus(currentStatus + status.split("-")[0]);
try {
copy.setReturnDate(fmt.parseLocalDate(status.split(": ")[1]));
} catch (IllegalArgumentException e) {
e.printStackTrace();
}
} else {
copy.setStatus(currentStatus + status);
}
} else {
copy.set(entry.getValue(), tr.child(entry.getKey()).text().trim());
}
}
res.addCopy(copy);
}
}
res.setId(""); // null would be overridden by the UI, because there _is_
// an id,< we just can not use it.
return res;
}
@Override
public DetailedItem getResult(int position) throws IOException,
OpacErrorException {
if (s_reusedoc != null) {
return getResultById(null, null);
}
throw new UnsupportedOperationException();
}
@Override
public ReservationResult reservation(DetailedItem item, Account account,
int useraction, String selection) throws IOException {
Document doc;
List<NameValuePair> nvpairs;
ReservationResult res = null;
if (selection != null && selection.equals("")) {
selection = null;
}
if (s_pageform == null) {
return new ReservationResult(Status.ERROR);
}
// Load details
nvpairs = s_pageform;
int i = 0;
List<Integer> indexes = new ArrayList<>();
for (NameValuePair np : nvpairs) {
if (np.getName().contains("$Toolbar_")
|| np.getName().contains("selected")) {
indexes.add(i);
}
i++;
}
for (int j = indexes.size() - 1; j >= 0; j--) {
nvpairs.remove((int) indexes.get(j));
}
nvpairs.add(new BasicNameValuePair("selected", "ZTEXT "
+ item.getReservation_info()));
htmlPost(opac_url + ";jsessionid=" + s_sid, nvpairs);
doc = htmlPost(opac_url + ";jsessionid=" + s_sid, nvpairs); // Yep, two
// times.
List<NameValuePair> form = new ArrayList<>();
for (Element input : doc.select("input, select")) {
if (!"image".equals(input.attr("type"))
&& (!"submit".equals(input.attr("type"))
|| input.val().contains("Reservieren") || input
.val().contains("Vormerken"))
&& !"checkbox".equals(input.attr("type"))
&& !"".equals(input.attr("name"))) {
form.add(new BasicNameValuePair(input.attr("name"), input
.attr("value")));
}
}
doc = htmlPost(opac_url + ";jsessionid=" + s_sid, form);
if (doc.select(".message h1").size() > 0) {
String msg = doc.select(".message h1").text().trim();
res = new ReservationResult(MultiStepResult.Status.ERROR, msg);
form = new ArrayList<>();
for (Element input : doc.select("input")) {
if (!"image".equals(input.attr("type"))
&& !"checkbox".equals(input.attr("type"))
&& !"".equals(input.attr("name"))) {
form.add(new BasicNameValuePair(input.attr("name"), input
.attr("value")));
}
}
doc = htmlPost(opac_url + ";jsessionid=" + s_sid, form);
} else {
try {
doc = handleLoginForm(doc, account);
} catch (OpacErrorException e1) {
return new ReservationResult(MultiStepResult.Status.ERROR,
e1.getMessage());
}
if (useraction == 0 && selection == null) {
res = new ReservationResult(
MultiStepResult.Status.CONFIRMATION_NEEDED);
List<String[]> details = new ArrayList<>();
details.add(new String[]{doc.select("#F23").text()});
res.setDetails(details);
} else if (doc.select("#AUSGAB_1").size() > 0 && (selection == null || "confirmed".equals(selection))) {
List<Map<String, String>> sel = new ArrayList<>();
for (Element opt : doc.select("#AUSGAB_1 option")) {
if (opt.text().trim().length() > 0) {
Map<String, String> selopt = new HashMap<>();
selopt.put("key", opt.val());
selopt.put("value", opt.text());
sel.add(selopt);
}
}
res = new ReservationResult(
MultiStepResult.Status.SELECTION_NEEDED, doc.select(
"#AUSGAB_1").first().parent().select("span").text());
res.setSelection(sel);
} else if (doc.select("#FSET01 select[name=select$0]").size() > 0 &&
(selection == null || !selection.contains("_SEP_"))) {
// Munich: "Benachrichtigung mit E-Mail"
List<Map<String, String>> sel = new ArrayList<>();
for (Element opt : doc.select("select[name=select$0] option")) {
if (opt.text().trim().length() > 0) {
Map<String, String> selopt = new HashMap<>();
selopt.put("value", opt.text());
if (selection != null) {
selopt.put("key", opt.val() + "_SEP_" + selection);
} else {
selopt.put("key", opt.val());
}
sel.add(selopt);
}
}
res = new ReservationResult(
MultiStepResult.Status.SELECTION_NEEDED, doc.select(
"#FSET01 select[name=select$0]").first().parent().select("span").text());
res.setSelection(sel);
} else if (selection != null || doc.select("#AUSGAB_1").size() == 0) {
if (doc.select("#AUSGAB_1").size() > 0 && selection != null) {
if (selection.contains("_SEP_")) {
doc.select("#AUSGAB_1").attr("value", selection.split("_SEP_")[1]);
} else {
doc.select("#AUSGAB_1").attr("value", selection);
}
}
if (doc.select("#FSET01 select[name=select$0]").size() > 0 && selection != null) {
if (selection.contains("_SEP_")) {
doc.select("#FSET01 select[name=select$0]")
.attr("value", selection.split("_SEP_")[0]);
} else {
doc.select("#FSET01 select[name=select$0]").attr("value", selection);
}
}
if (doc.select("#BENJN_1").size() > 0) {
// Notification not requested because some libraries notify by snail mail
// and take a fee for it (Example: Stuttgart_Uni)
doc.select("#BENJN_1").attr("value", "Nein");
}
if (doc.select(".message h1").size() > 0) {
String msg = doc.select(".message h1").text().trim();
form = new ArrayList<>();
for (Element input : doc.select("input")) {
if (!"image".equals(input.attr("type"))
&& !"checkbox".equals(input.attr("type"))
&& !"".equals(input.attr("name"))) {
form.add(new BasicNameValuePair(input.attr("name"),
input.attr("value")));
}
}
doc = htmlPost(opac_url + ";jsessionid=" + s_sid, form);
if (!msg.contains("Reservation ist erfolgt")) {
res = new ReservationResult(
MultiStepResult.Status.ERROR, msg);
} else {
res = new ReservationResult(MultiStepResult.Status.OK,
msg);
}
} else {
form = new ArrayList<>();
for (Element input : doc.select("input, select")) {
if (!"image".equals(input.attr("type"))
&& !"submit".equals(input.attr("type"))
&& !"checkbox".equals(input.attr("type"))
&& !"".equals(input.attr("name"))) {
form.add(new BasicNameValuePair(input.attr("name"),
input.attr("value")));
}
}
form.add(new BasicNameValuePair("textButton",
"Reservation abschicken"));
res = new ReservationResult(MultiStepResult.Status.OK);
doc = htmlPost(opac_url + ";jsessionid=" + s_sid, form);
if (doc.select("input[name=textButton]").attr("value")
.contains("kostenpflichtig bestellen")) {
// Munich
form = new ArrayList<>();
for (Element input : doc.select("input, select")) {
if (!"image".equals(input.attr("type"))
&& !"submit".equals(input.attr("type"))
&& !"checkbox".equals(input.attr("type"))
&& !"".equals(input.attr("name"))) {
form.add(new BasicNameValuePair(input.attr("name"),
input.attr("value")));
}
}
form.add(new BasicNameValuePair("textButton",
doc.select("input[name=textButton]").first().attr("value")));
doc = htmlPost(opac_url + ";jsessionid=" + s_sid, form);
}
if (doc.select(".message h1").size() > 0) {
String msg = doc.select(".message h1").text().trim();
form = new ArrayList<>();
for (Element input : doc.select("input")) {
if (!"image".equals(input.attr("type"))
&& !"checkbox".equals(input.attr("type"))
&& !"".equals(input.attr("name"))) {
form.add(new BasicNameValuePair(input
.attr("name"), input.attr("value")));
}
}
doc = htmlPost(opac_url + ";jsessionid=" + s_sid, form);
if (!msg.contains("Reservation ist erfolgt")) {
res = new ReservationResult(
MultiStepResult.Status.ERROR, msg);
} else {
res = new ReservationResult(
MultiStepResult.Status.OK, msg);
}
} else if (doc.select("#R01").text()
.contains("Informationen zu Ihrer Reservation")) {
String msg = doc.select("#OPACLI").text().trim();
form = new ArrayList<>();
for (Element input : doc.select("input")) {
if (!"image".equals(input.attr("type"))
&& !"checkbox".equals(input.attr("type"))
&& !"".equals(input.attr("name"))) {
form.add(new BasicNameValuePair(input
.attr("name"), input.attr("value")));
}
}
doc = htmlPost(opac_url + ";jsessionid=" + s_sid, form);
if (!msg.contains("Reservation ist erfolgt")) {
res = new ReservationResult(
MultiStepResult.Status.ERROR, msg);
} else {
res = new ReservationResult(
MultiStepResult.Status.OK, msg);
}
}
}
}
}
if (res == null
|| res.getStatus() == MultiStepResult.Status.SELECTION_NEEDED
|| res.getStatus() == MultiStepResult.Status.CONFIRMATION_NEEDED) {
form = new ArrayList<>();
for (Element input : doc.select("input, select")) {
if (!"image".equals(input.attr("type"))
&& !"submit".equals(input.attr("type"))
&& !"checkbox".equals(input.attr("type"))
&& !"".equals(input.attr("name"))) {
form.add(new BasicNameValuePair(input.attr("name"), input
.attr("value")));
}
}
Element button = doc.select("input[value=Abbrechen], input[value=Zurück]").first();
form.add(new BasicNameValuePair(button.attr("name"), button.attr("value")));
doc = htmlPost(opac_url + ";jsessionid=" + s_sid, form);
}
// Reset
updatePageform(doc);
try {
nvpairs = s_pageform;
nvpairs.add(new BasicNameValuePair("$Toolbar_1.x", "1"));
nvpairs.add(new BasicNameValuePair("$Toolbar_1.y", "1"));
parse_search_wrapped(htmlPost(opac_url + ";jsessionid=" + s_sid, nvpairs),
1);
nvpairs = s_pageform;
nvpairs.add(new BasicNameValuePair("$Toolbar_3.x", "1"));
nvpairs.add(new BasicNameValuePair("$Toolbar_3.y", "1"));
parse_search_wrapped(htmlPost(opac_url + ";jsessionid=" + s_sid, nvpairs),
1);
} catch (OpacErrorException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return res;
}
void updatePageform(Document doc) {
s_pageform = new ArrayList<>();
for (Element input : doc.select("input, select")) {
if (!"image".equals(input.attr("type"))
&& !"submit".equals(input.attr("type"))
&& !"checkbox".equals(input.attr("type"))
&& !"".equals(input.attr("name"))) {
s_pageform.add(new BasicNameValuePair(input.attr("name"), input
.attr("value")));
}
}
}
@Override
public ProlongResult prolong(String media, Account account, int useraction,
String selection) throws IOException {
String alink = null;
Document doc;
start();
doc = htmlGet(opac_url + ";jsessionid=" + s_sid + "?service="
+ s_service + "&sp=SBK");
try {
doc = handleLoginForm(doc, account);
} catch (OpacErrorException e) {
return new ProlongResult(Status.ERROR, e.getMessage());
}
for (Element tr : doc.select(".rTable_div tr")) {
if (tr.select("a").size() == 1) {
if (tr.select("a").first().absUrl("href")
.contains("sp=SZA")) {
alink = tr.select("a").first().absUrl("href");
}
}
}
if (alink == null) {
return new ProlongResult(Status.ERROR);
}
doc = htmlGet(alink);
List<NameValuePair> form = new ArrayList<>();
for (Element input : doc.select("input, select")) {
if (!"image".equals(input.attr("type"))
&& !"submit".equals(input.attr("type"))
&& !"checkbox".equals(input.attr("type"))
&& !"".equals(input.attr("name"))) {
form.add(new BasicNameValuePair(input.attr("name"), input
.attr("value")));
}
}
for (Element tr : doc.select(".rTable_div tr")) {
if (tr.select("input").attr("name").equals(media.split("\\|")[0])
&& tr.select("input").hasAttr("disabled")) {
form.add(new BasicNameValuePair("$Toolbar_0.x", "1"));
form.add(new BasicNameValuePair("$Toolbar_0.y", "1"));
htmlPost(opac_url + ";jsessionid=" + s_sid, form);
return new ProlongResult(Status.ERROR, tr.child(4).text()
.trim());
}
}
form.add(new BasicNameValuePair(media.split("\\|")[0], "on"));
form.add(new BasicNameValuePair("textButton$1",
"Markierte Titel verlängern"));
doc = htmlPost(opac_url + ";jsessionid=" + s_sid, form);
form = new ArrayList<>();
for (Element input : doc.select("input, select")) {
if (!"image".equals(input.attr("type"))
&& !"submit".equals(input.attr("type"))
&& !"checkbox".equals(input.attr("type"))
&& !"".equals(input.attr("name"))) {
form.add(new BasicNameValuePair(input.attr("name"), input
.attr("value")));
}
}
form.add(new BasicNameValuePair("$Toolbar_0.x", "1"));
form.add(new BasicNameValuePair("$Toolbar_0.y", "1"));
htmlPost(opac_url + ";jsessionid=" + s_sid, form);
return new ProlongResult(Status.OK);
}
@Override
public ProlongAllResult prolongAll(Account account, int useraction,
String selection) throws IOException {
String alink = null;
Document doc;
start();
doc = htmlGet(opac_url + ";jsessionid=" + s_sid + "?service="
+ s_service + "&sp=SBK");
try {
doc = handleLoginForm(doc, account);
} catch (OpacErrorException e) {
return new ProlongAllResult(Status.ERROR, e.getMessage());
}
for (Element tr : doc.select(".rTable_div tr")) {
if (tr.select("a").size() == 1) {
if (tr.select("a").first().absUrl("href")
.contains("sp=SZA")) {
alink = tr.select("a").first().absUrl("href");
}
}
}
if (alink == null) {
return new ProlongAllResult(Status.ERROR);
}
doc = htmlGet(alink);
List<NameValuePair> form = new ArrayList<>();
for (Element input : doc.select("input, select")) {
if (!"image".equals(input.attr("type"))
&& !"submit".equals(input.attr("type"))
&& !"checkbox".equals(input.attr("type"))
&& !"".equals(input.attr("name"))) {
form.add(new BasicNameValuePair(input.attr("name"), input
.attr("value")));
}
if ("checkbox".equals(input.attr("type"))
&& !input.hasAttr("disabled")) {
form.add(new BasicNameValuePair(input.attr("name"), "on"));
}
}
form.add(new BasicNameValuePair("textButton$1",
"Markierte Titel verlängern"));
doc = htmlPost(opac_url + ";jsessionid=" + s_sid, form);
List<Map<String, String>> result = new ArrayList<>();
for (Element tr : doc.select(".rTable_div tbody tr")) {
Map<String, String> line = new HashMap<>();
line.put(ProlongAllResult.KEY_LINE_TITLE,
tr.child(3).text().split("[:/;]")[0].trim());
line.put(ProlongAllResult.KEY_LINE_NEW_RETURNDATE, tr.child(1)
.text());
line.put(ProlongAllResult.KEY_LINE_MESSAGE, tr.child(4).text());
result.add(line);
}
form = new ArrayList<>();
for (Element input : doc.select("input, select")) {
if (!"image".equals(input.attr("type"))
&& !"submit".equals(input.attr("type"))
&& !"checkbox".equals(input.attr("type"))
&& !"".equals(input.attr("name"))) {
form.add(new BasicNameValuePair(input.attr("name"), input
.attr("value")));
}
}
form.add(new BasicNameValuePair("$Toolbar_0.x", "1"));
form.add(new BasicNameValuePair("$Toolbar_0.y", "1"));
htmlPost(opac_url + ";jsessionid=" + s_sid, form);
return new ProlongAllResult(Status.OK, result);
}
@Override
public CancelResult cancel(String media, Account account, int useraction,
String selection) throws IOException, OpacErrorException {
String rlink = null;
Document doc;
rlink = media.split("\\|")[1].replace("requestCount=", "fooo=");
start();
doc = htmlGet(opac_url + ";jsessionid=" + s_sid + "?service="
+ s_service + "&sp=SBK");
try {
doc = handleLoginForm(doc, account);
} catch (OpacErrorException e) {
return new CancelResult(Status.ERROR, e.getMessage());
}
for (Element tr : doc.select(".rTable_div tr")) {
String url = media.split("\\|")[1].toUpperCase(Locale.GERMAN);
String sp = "SZM";
if (url.contains("SP=")) {
Map<String, String> qp = getQueryParamsFirst(url);
if (qp.containsKey("SP")) {
sp = qp.get("SP");
}
}
if (tr.select("a").size() == 1) {
if ((tr.text().contains("Reservationen") || tr.text().contains("Vormerkung") ||
tr.text().contains("Bestellung"))
&& !tr.child(0).text().trim().equals("")
&& tr.select("a").first().attr("href")
.toUpperCase(Locale.GERMAN)
.contains("SP=" + sp)) {
rlink = tr.select("a").first().absUrl("href");
}
}
}
if (rlink == null) {
return new CancelResult(Status.ERROR);
}
doc = htmlGet(rlink);
List<NameValuePair> form = new ArrayList<>();
for (Element input : doc.select("input, select")) {
if (!"image".equals(input.attr("type"))
&& !"submit".equals(input.attr("type"))
&& !"checkbox".equals(input.attr("type"))
&& !"".equals(input.attr("name"))) {
form.add(new BasicNameValuePair(input.attr("name"), input
.attr("value")));
}
}
form.add(new BasicNameValuePair(media.split("\\|")[0], "on"));
form.add(new BasicNameValuePair("textButton$0",
"Markierte Titel löschen"));
doc = htmlPost(opac_url + ";jsessionid=" + s_sid, form);
form = new ArrayList<>();
for (Element input : doc.select("input, select")) {
if (!"image".equals(input.attr("type"))
&& !"submit".equals(input.attr("type"))
&& !"checkbox".equals(input.attr("type"))
&& !"".equals(input.attr("name"))) {
form.add(new BasicNameValuePair(input.attr("name"), input
.attr("value")));
}
}
form.add(new BasicNameValuePair("$Toolbar_0.x", "1"));
form.add(new BasicNameValuePair("$Toolbar_0.y", "1"));
htmlPost(opac_url + ";jsessionid=" + s_sid, form);
return new CancelResult(Status.OK);
}
@Override
public AccountData account(Account account) throws IOException,
JSONException, OpacErrorException {
start();
Document doc = htmlGet(opac_url + ";jsessionid=" + s_sid + "?service="
+ s_service + "&sp=SBK");
doc = handleLoginForm(doc, account);
boolean split_title_author = true;
if (doc.head().html().contains("VOEBB")) {
split_title_author = false;
}
AccountData adata = new AccountData(account.getId());
for (Element tr : doc.select(".aDISListe tr")) {
if (tr.child(0).text().matches(".*F.+llige Geb.+hren.*")) {
adata.setPendingFees(tr.child(1).text().trim());
}
if (tr.child(0).text().matches(".*Ausweis g.+ltig bis.*")) {
adata.setValidUntil(tr.child(1).text().trim());
}
}
DateTimeFormatter fmt = DateTimeFormat.forPattern("dd.MM.yyyy").withLocale(Locale.GERMAN);
// Ausleihen
String alink = null;
int anum = 0;
List<LentItem> lent = new ArrayList<>();
for (Element tr : doc.select(".rTable_div tr")) {
if (tr.select("a").size() == 1) {
if (tr.select("a").first().absUrl("href").contains("sp=SZA")) {
alink = tr.select("a").first().absUrl("href");
anum = Integer.parseInt(tr.child(0).text().trim());
}
}
}
if (alink != null) {
Document adoc = htmlGet(alink);
s_alink = alink;
List<NameValuePair> form = new ArrayList<>();
String prolongTest = null;
for (Element input : adoc.select("input, select")) {
if (!"image".equals(input.attr("type"))
&& !"submit".equals(input.attr("type"))
&& !"".equals(input.attr("name"))) {
if (input.attr("type").equals("checkbox")
&& !input.hasAttr("value")) {
input.val("on");
}
form.add(new BasicNameValuePair(input.attr("name"), input
.attr("value")));
} else if (input.val().matches(".+verl.+ngerbar.+")) {
prolongTest = input.attr("name");
}
}
if (prolongTest != null) {
form.add(new BasicNameValuePair(prolongTest,
"Markierte Titel verlängerbar?"));
Document adoc_new = htmlPost(opac_url + ";jsessionid=" + s_sid, form);
if (adoc_new.select(".message h1").size() == 0) {
adoc = adoc_new;
}
}
for (Element tr : adoc.select(".rTable_div tbody tr")) {
LentItem item = new LentItem();
String text = Jsoup.parse(tr.child(3).html().replaceAll("(?i)<br[^>]*>", "#"))
.text();
if (text.contains(" / ")) {
// Format "Titel / Autor #Sig#Nr", z.B. normale Ausleihe in Berlin
String[] split = text.split("[/#\n]");
String title = split[0];
//Is always the last one...
String id = split[split.length-1];
item.setId(id);
if (split_title_author) {
title = title.replaceFirst("([^:;\n]+)[:;\n](.*)$", "$1");
}
item.setTitle(title.trim());
if (split.length > 1) {
item.setAuthor(split[1].replaceFirst("([^:;\n]+)[:;\n](.*)$", "$1").trim());
}
} else {
// Format "Autor: Titel - Verlag - ISBN:... #Nummer", z.B. Fernleihe in Berlin
String[] split = text.split("#");
String[] aut_tit = split[0].split(": ");
item.setAuthor(aut_tit[0].replaceFirst("([^:;\n]+)[:;\n](.*)$", "$1").trim());
if (aut_tit.length > 1) {
item.setTitle(
aut_tit[1].replaceFirst("([^:;\n]+)[:;\n](.*)$", "$1").trim());
}
//Is always the last one...
String id = split[split.length-1];
item.setId(id);
}
String date = tr.child(1).text().trim();
if (date.contains("-")) {
// Nürnberg: "29.03.2016 - 26.04.2016"
// for beginning and end date in one field
date = date.split("-")[1].trim();
}
try {
item.setDeadline(fmt.parseLocalDate(date));
} catch (IllegalArgumentException e) {
e.printStackTrace();
}
item.setHomeBranch(tr.child(2).text().trim());
if (tr.select("input[type=checkbox]").hasAttr("disabled")) {
item.setRenewable(false);
} else {
item.setProlongData(
tr.select("input[type=checkbox]").attr("name") + "|" + alink);
}
// item.setRenewable(tr.child(4).text().matches(".*nicht verl.+ngerbar.*"));
lent.add(item);
}
assert (lent.size() == anum);
form = new ArrayList<>();
for (Element input : adoc.select("input, select")) {
if (!"image".equals(input.attr("type"))
&& !"submit".equals(input.attr("type"))
&& !"checkbox".equals(input.attr("type"))
&& !"".equals(input.attr("name"))) {
form.add(new BasicNameValuePair(input.attr("name"), input
.attr("value")));
}
}
form.add(new BasicNameValuePair("$Toolbar_0.x", "1"));
form.add(new BasicNameValuePair("$Toolbar_0.y", "1"));
doc = htmlPost(opac_url + ";jsessionid=" + s_sid, form);
} else {
assert (anum == 0);
}
adata.setLent(lent);
List<String[]> rlinks = new ArrayList<>();
int rnum = 0;
List<ReservedItem> res = new ArrayList<>();
for (Element tr : doc.select(".rTable_div tr")) {
if (tr.select("a").size() == 1) {
if ((tr.text().contains("Reservationen")
|| tr.text().contains("Vormerkung")
|| tr.text().contains("Fernleihbestellung")
|| tr.text().contains("Bereitstellung")
|| tr.text().contains("Bestellw")
|| tr.text().contains("Magazin"))
&& !tr.child(0).text().trim().equals("")) {
rlinks.add(new String[]{
tr.select("a").text(),
tr.select("a").first().absUrl("href"),
});
rnum += Integer.parseInt(tr.child(0).text().trim());
}
}
}
for (String[] rlink : rlinks) {
Document rdoc = htmlGet(rlink[1]);
boolean error = false;
boolean interlib = rdoc.html().contains("Ihre Fernleih-Bestellung");
boolean stacks = rdoc.html().contains("aus dem Magazin");
boolean provision = rdoc.html().contains("Ihre Bereitstellung");
Map<String, Integer> colmap = new HashMap<>();
colmap.put("title", 2);
colmap.put("branch", 1);
colmap.put("expirationdate", 0);
int i = 0;
for (Element th : rdoc.select(".rTable_div thead tr th")) {
if (th.text().contains("Bis")) {
colmap.put("expirationdate", i);
}
if (th.text().contains("Ausgabeort")) {
colmap.put("branch", i);
}
if (th.text().contains("Titel")) {
colmap.put("title", i);
}
if (th.text().contains("Hinweis")) {
colmap.put("status", i);
}
i++;
}
for (Element tr : rdoc.select(".rTable_div tbody tr")) {
if (tr.children().size() >= colmap.size()) {
ReservedItem item = new ReservedItem();
String text = tr.child(colmap.get("title")).html();
text = Jsoup.parse(text.replaceAll("(?i)<br[^>]*>", ";")).text();
if (split_title_author) {
String[] split = text.split("[:/;\n]");
item.setTitle(split[0].replaceFirst("([^:;\n]+)[:;\n](.*)$", "$1").trim());
if (split.length > 1) {
item.setAuthor(
split[1].replaceFirst("([^:;\n]+)[:;\n](.*)$", "$1").trim());
}
} else {
item.setTitle(text);
}
String branch = tr.child(colmap.get("branch")).text().trim();
if (interlib) {
branch = stringProvider
.getFormattedString(StringProvider.INTERLIB_BRANCH, branch);
} else if (stacks) {
branch = stringProvider
.getFormattedString(StringProvider.STACKS_BRANCH, branch);
} else if (provision) {
branch = stringProvider
.getFormattedString(StringProvider.PROVISION_BRANCH, branch);
}
item.setBranch(branch);
if (rlink[0].contains("Abholbereit")) {
// Abholbereite Bestellungen
item.setStatus("bereit");
if (tr.child(0).text().trim().length() >= 10) {
item.setExpirationDate(fmt.parseLocalDate(
tr.child(colmap.get("expirationdate")).text().trim()
.substring(0, 10)));
}
} else {
// Nicht abholbereite
if (tr.select("input[type=checkbox]").size() > 0
&& (rlink[1].toUpperCase(Locale.GERMAN).contains(
"SP=SZM") || rlink[1].toUpperCase(
Locale.GERMAN).contains("SP=SZW") || rlink[1].toUpperCase(
Locale.GERMAN).contains("SP=SZB"))) {
item.setCancelData(
tr.select("input[type=checkbox]").attr("name") + "|" +
rlink[1]);
}
}
res.add(item);
} else {
// This is a strange bug where sometimes there is only three
// columns
error = true;
}
}
if (error) {
// Maybe we should send a bug report here, but using ACRA breaks
// the unit tests
adata.setWarning("Beim Abrufen der Reservationen ist ein Problem aufgetreten");
}
List<NameValuePair> form = new ArrayList<>();
for (Element input : rdoc.select("input, select")) {
if (!"image".equals(input.attr("type"))
&& !"submit".equals(input.attr("type"))
&& !"checkbox".equals(input.attr("type"))
&& !"".equals(input.attr("name"))) {
form.add(new BasicNameValuePair(input.attr("name"), input
.attr("value")));
}
}
form.add(new BasicNameValuePair("$Toolbar_0.x", "1"));
form.add(new BasicNameValuePair("$Toolbar_0.y", "1"));
htmlPost(opac_url + ";jsessionid=" + s_sid, form);
}
assert (res.size() == rnum);
adata.setReservations(res);
return adata;
}
protected Document handleLoginForm(Document doc, Account account)
throws IOException, OpacErrorException {
if (doc.select("#LPASSW_1").size() == 0) {
return doc;
}
doc.select("#LPASSW_1").val(account.getPassword());
List<NameValuePair> form = new ArrayList<>();
for (Element input : doc.select("input, select")) {
if (!"image".equals(input.attr("type"))
&& !"checkbox".equals(input.attr("type"))
&& !"submit".equals(input.attr("type"))
&& !"".equals(input.attr("name"))) {
if (input.attr("id").equals("L#AUSW_1")
|| input.attr("fld").equals("L#AUSW_1")
|| input.attr("id").equals("IDENT_1")
|| input.attr("id").equals("LMATNR_1")) {
input.attr("value", account.getName());
}
form.add(new BasicNameValuePair(input.attr("name"), input
.attr("value")));
}
}
Element inputSend = doc.select("input[type=submit]").first();
form.add(new BasicNameValuePair(inputSend.attr("name"), inputSend
.attr("value")));
doc = htmlPost(opac_url + ";jsessionid=" + s_sid, form);
if (doc.select(".message h1").size() > 0) {
String msg = doc.select(".message h1").text().trim();
form = new ArrayList<>();
for (Element input : doc.select("input")) {
if (!"image".equals(input.attr("type"))
&& !"checkbox".equals(input.attr("type"))
&& !"".equals(input.attr("name"))) {
form.add(new BasicNameValuePair(input.attr("name"), input
.attr("value")));
}
}
doc = htmlPost(opac_url + ";jsessionid=" + s_sid, form);
if (!msg.contains("Sie sind angemeldet") && !msg.contains("jetzt angemeldet")) {
throw new OpacErrorException(msg);
}
return doc;
} else {
return doc;
}
}
@Override
public List<SearchField> parseSearchFields() throws IOException,
JSONException {
if (!initialised) {
start();
}
Document doc = htmlGet(opac_url + ";jsessionid=" + s_sid + "?service="
+ s_service + "&sp=" + s_exts);
List<SearchField> fields = new ArrayList<>();
// dropdown to select which field you want to search in
Elements searchoptions = doc.select("#SUCH01_1 option");
if (searchoptions.size() == 0 && doc.select("input[fld=FELD01_1]").size() > 0) {
// Hack is needed in Nuernberg
searchoptions = doc.select("input[fld=FELD01_1]").first().previousElementSibling()
.select("option");
}
for (Element opt : searchoptions) {
TextSearchField field = new TextSearchField();
field.setId(opt.attr("value"));
field.setDisplayName(opt.text());
field.setHint("");
fields.add(field);
}
// Save data so that the search() function knows that this
// is not a selectable search field
JSONObject selectableData = new JSONObject();
selectableData.put("selectable", false);
for (Element row : doc.select("div[id~=F\\d+]")) {
if (row.select("input[type=text]").size() == 1
&& row.select("input, select").first().tagName()
.equals("input")) {
// A single text search field
Element input = row.select("input[type=text]").first();
TextSearchField field = new TextSearchField();
field.setId(input.attr("id"));
field.setDisplayName(row.select("label").first().text());
field.setHint("");
field.setData(selectableData);
fields.add(field);
} else if (row.select("select").size() == 1
&& row.select("input[type=text]").size() == 0) {
// Things like language, media type, etc.
Element select = row.select("select").first();
DropdownSearchField field = new DropdownSearchField();
field.setId(select.id());
field.setDisplayName(row.select("label").first().text());
List<Map<String, String>> values = new ArrayList<>();
for (Element opt : select.select("option")) {
field.addDropdownValue(opt.attr("value"), opt.text());
}
fields.add(field);
} else if (row.select("select").size() == 0
&& row.select("input[type=text]").size() == 3
&& row.select("label").size() == 3) {
// Three text inputs.
// Year single/from/to or things like Band-/Heft-/Satznummer
String name1 = row.select("label").get(0).text();
String name2 = row.select("label").get(1).text();
String name3 = row.select("label").get(2).text();
Element input1 = row.select("input[type=text]").get(0);
Element input2 = row.select("input[type=text]").get(1);
Element input3 = row.select("input[type=text]").get(2);
if (name2.contains("von") && name3.contains("bis")) {
TextSearchField field1 = new TextSearchField();
field1.setId(input1.id());
field1.setDisplayName(name1);
field1.setHint("");
field1.setData(selectableData);
fields.add(field1);
TextSearchField field2 = new TextSearchField();
field2.setId(input2.id());
field2.setDisplayName(name2.replace("von", "").trim());
field2.setHint("von");
field2.setData(selectableData);
fields.add(field2);
TextSearchField field3 = new TextSearchField();
field3.setId(input3.id());
field3.setDisplayName(name3.replace("bis", "").trim());
field3.setHint("bis");
field3.setHalfWidth(true);
field3.setData(selectableData);
fields.add(field3);
} else {
TextSearchField field1 = new TextSearchField();
field1.setId(input1.id());
field1.setDisplayName(name1);
field1.setHint("");
field1.setData(selectableData);
fields.add(field1);
TextSearchField field2 = new TextSearchField();
field2.setId(input2.id());
field2.setDisplayName(name2);
field2.setHint("");
field2.setData(selectableData);
fields.add(field2);
TextSearchField field3 = new TextSearchField();
field3.setId(input3.id());
field3.setDisplayName(name3);
field3.setHint("");
field3.setData(selectableData);
fields.add(field3);
}
}
}
for (Iterator<SearchField> iterator = fields.iterator(); iterator
.hasNext(); ) {
SearchField field = iterator.next();
if (ignoredFieldNames.contains(field.getDisplayName())) {
iterator.remove();
}
}
return fields;
}
@Override
public String getShareUrl(String id, String title) {
// TODO Auto-generated method stub
return null;
}
@Override
public int getSupportFlags() {
return SUPPORT_FLAG_ACCOUNT_PROLONG_ALL
| SUPPORT_FLAG_ENDLESS_SCROLLING | SUPPORT_FLAG_WARN_RESERVATION_FEES;
}
@Override
public void checkAccountData(Account account) throws IOException,
JSONException, OpacErrorException {
start();
Document doc = htmlGet(opac_url + ";jsessionid=" + s_sid + "?service="
+ s_service + "&sp=SBK");
handleLoginForm(doc, account);
}
@Override
public void setLanguage(String language) {
// TODO Auto-generated method stub
}
@Override
public Set<String> getSupportedLanguages() throws IOException {
// TODO Auto-generated method stub
return null;
}
}