package org.openstreetmap.josm.plugins.rasterfilters.preferences;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.StringReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.URLConnection;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.json.Json;
import javax.json.JsonArray;
import javax.json.JsonObject;
import javax.json.JsonReader;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.openstreetmap.josm.Main;
/**
* This class is responsible for downloading jars which contains
* filters implementations, for loading meta from the
* <a href="https://josm.openstreetmap.de/wiki/ImageFilters">filter's page</a>.
* Also it stores the downloaded information for creating filter's GUI and etc.
*
* @author Nipel-Crumple
*/
public class FiltersDownloader implements ActionListener {
private static volatile String pluginDir;
public static Set<JsonObject> filtersMeta = new HashSet<>();
public static Set<String> filterTitles = new TreeSet<>();
public static Set<URL> binariesLocalUrls = new HashSet<>();
public static ClassLoader loader;
public static Map<String, String> urlsMap = new HashMap<>();
private static Set<JsonObject> filtersMetaToLoad = new HashSet<>();
static List<FilterInfo> filtersInfoList = new ArrayList<>();
public static List<FilterInfo> downloadFiltersInfoList() {
// JsonObject jsonRequest = Json
// .createObjectBuilder()
// .add("id", new Random().nextInt())
// .add("method", "wiki.getPageHTML")
// .add("params",
// Json.createArrayBuilder().add("ImageFilters").build())
// .build();
// String jsonRequestString = jsonRequest.toString();
// URL wikiApi;
// HttpURLConnection wikiConnection;
try {
// wikiApi = new URL("https://josm.openstreetmap.de/wiki/ImageFilters");
// wikiConnection = (HttpURLConnection) wikiApi.openConnection();
// wikiConnection.setDoOutput(true);
// wikiConnection.setDoInput(true);
//
// wikiConnection.setRequestProperty("Content-Type",
// "application/json");
// wikiConnection.setRequestProperty("Method", "POST");
// wikiConnection.connect();
// OutputStream os = wikiConnection.getOutputStream();
// os.write(jsonRequestString.getBytes("UTF-8"));
// os.close();
// int HttpResult = wikiConnection.getResponseCode();
// if (HttpResult == HttpURLConnection.HTTP_OK) {
// JsonReader jsonStream = Json
// .createReader(new InputStreamReader(wikiConnection
// .getInputStream(), "utf-8"));
// BufferedReader inReader = new BufferedReader(new InputStreamReader(wikiConnection.getInputStream()));
// JsonObject jsonResponse = jsonStream.readObject();
// jsonStream.close();
Document doc = Jsoup.connect("https://josm.openstreetmap.de/wiki/ImageFilters").get();
Elements trTagElems = doc.getElementsByTag("tr");
// Elements trTagElems = Jsoup.parse(
// jsonResponse.getString("result"))
// .getElementsByTag("tr");
for (Element element : trTagElems) {
Elements elems = element.getElementsByTag("td");
if (!elems.isEmpty()) {
String name = elems.get(0).text();
String owner = elems.get(1).text();
String description = elems.get(2).text();
String link = elems.get(0).getElementsByTag("a")
.attr("href");
JsonObject meta = loadMeta(link);
if (meta != null) {
String paramName = "rasterfilters."
+ meta.getString("name");
boolean needToLoad = Main.pref.getBoolean(paramName);
if (needToLoad) {
JsonArray binaries = meta.getJsonArray("binaries");
filterTitles.add(meta.getString("title"));
for (int i = 0; i < binaries.size(); i++) {
filtersMetaToLoad.add(meta);
loadBinaryToFile(binaries.getString(i));
}
}
FilterInfo newFilterInfo = new FilterInfo(name,
description, meta, needToLoad);
newFilterInfo.setOwner(owner);
if (!filtersInfoList.contains(newFilterInfo)) {
filtersInfoList.add(newFilterInfo);
}
}
}
}
// } else {
// Main.debug("Error happenned while requesting for the list of filters");
// }
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
loadBinariesFromMeta(filtersMetaToLoad);
return filtersInfoList;
}
public static JsonObject loadMeta(String link) {
Pattern p = Pattern.compile("ImageFilters/\\w.*");
Matcher m = p.matcher(link);
if (m.find()) {
link = link.substring(m.start());
}
// JsonObject jsonRequest = Json.createObjectBuilder()
// .add("id", new Random().nextInt())
// .add("method", "wiki.getPageHTML")
// .add("params", Json.createArrayBuilder().add(link).build())
// .build();
// String jsonStringRequest = jsonRequest.toString();
URL wikiApi;
HttpURLConnection wikiConnection;
JsonObject meta = null;
try {
// wikiApi = new URL("https://josm.openstreetmap.de/jsonrpc");
// wikiConnection = (HttpURLConnection) wikiApi.openConnection();
// wikiConnection.setDoOutput(true);
// wikiConnection.setDoInput(true);
//
// wikiConnection.setRequestProperty("Content-Type",
// "application/json");
// wikiConnection.setRequestProperty("Method", "POST");
// wikiConnection.connect();
//
// OutputStream os = wikiConnection.getOutputStream();
// os.write(jsonStringRequest.getBytes("UTF-8"));
// os.close();
//
// int HttpResult = wikiConnection.getResponseCode();
// if (HttpResult == HttpURLConnection.HTTP_OK) {
// JsonReader jsonStream = Json
// .createReader(new InputStreamReader(wikiConnection
// .getInputStream(), "UTF-8"));
// JsonObject jsonResponse = jsonStream.readObject();
// jsonStream.close();
// String jsonPage = jsonResponse.getString("result");
Document doc = Jsoup.connect("https://josm.openstreetmap.de/wiki/" + link).get();
String json = doc.getElementsByTag("pre").first().text();
JsonReader reader = Json.createReader(new StringReader(json));
meta = reader.readObject();
reader.close();
// } else {
// Main.debug(wikiConnection.getResponseMessage());
// }
} catch (IOException e1) {
e1.printStackTrace();
}
filtersMeta.add(meta);
return meta;
}
public static void initFilters() {
File file = new File(pluginDir, "urls.map");
Main.debug("EXIST FILE? " + file.exists());
try (BufferedReader br = Files.newBufferedReader(file.toPath(), StandardCharsets.UTF_8)) {
String temp;
while ((temp = br.readLine()) != null) {
String[] mapEntry = temp.split("\\t");
File fileUrl = new File(mapEntry[1]);
if (fileUrl.exists()) {
URL url;
try {
url = new URL("jar", "", fileUrl.toURI().toURL() + "!/");
Main.debug("binaryUrl: " + url.toString());
binariesLocalUrls.add(url);
} catch (MalformedURLException e) {
Main.debug("Initializing filters with unknown protocol. \n"
+ e.getMessage());
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
Main.debug("BinariesLocal : " + binariesLocalUrls.toString());
loader = new URLClassLoader(
binariesLocalUrls.toArray(new URL[binariesLocalUrls.size()]),
FiltersDownloader.class.getClassLoader());
}
public static void destroyFilters() {
filterTitles.clear();
binariesLocalUrls.clear();
FiltersDownloader.filtersMeta.clear();
}
@Override
public void actionPerformed(ActionEvent e) {
for (FilterInfo temp : filtersInfoList) {
if (temp.isNeedToDownload()) {
if (!filtersMetaToLoad.contains(temp.getMeta())) {
filtersMetaToLoad.add(temp.getMeta());
}
filterTitles.add(temp.getMeta().getString("title"));
} else {
filterTitles.remove(temp.getMeta().getString("title"));
}
}
loadBinariesFromMeta(filtersMetaToLoad);
filtersMetaToLoad.clear();
}
public static void loadBinariesFromMeta(Set<JsonObject> metaList) {
File file = new File(pluginDir, "urls.map");
Main.debug("pluginDir and urls map" + file.getAbsoluteFile());
try (BufferedWriter writer = Files.newBufferedWriter(file.toPath(), StandardCharsets.UTF_8)) {
for (JsonObject temp : metaList) {
JsonArray binaries = temp.getJsonArray("binaries");
for (int i = 0; i < binaries.size(); i++) {
String localFile = loadBinaryToFile(binaries.getString(i));
try {
writer.append(binaries.getString(i));
writer.append("\t");
writer.append(localFile);
writer.append("\n");
} catch (IOException e) {
e.printStackTrace();
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static void setPluginDir(String dir) {
pluginDir = dir;
}
public static String loadBinaryToFile(String fromUrl) {
// Main.debug("Need to load binary from " + fromUrl);
URL url = null;
URLConnection con = null;
Pattern p = Pattern.compile("\\w.*/");
Matcher m = p.matcher(fromUrl);
String localFile = null;
File plugin = new File(pluginDir);
Main.debug("plugin dir" + plugin.getAbsolutePath());
if (m.find()) {
if (plugin.exists()) {
localFile = fromUrl.substring(m.end());
Main.debug("localFile: " + localFile);
}
}
try {
url = new URL(fromUrl);
con = url.openConnection();
String plugDir = plugin.getAbsolutePath();
File file = new File(plugDir, localFile);
Main.debug("Binary file: " + file.getAbsolutePath());
if (file.exists()) {
Main.debug("File " + localFile + " already exists");
return file.getAbsolutePath();
} else {
BufferedInputStream in = new BufferedInputStream(
con.getInputStream());
BufferedOutputStream out = new BufferedOutputStream(
new FileOutputStream(file));
int i;
while ((i = in.read()) != -1) {
out.write(i);
}
out.flush();
out.close();
in.close();
return localFile;
}
} catch (MalformedURLException e1) {
e1.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}