/*
* Copyright Michael Keppler
*
* 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 util.tvdataservice;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.Icon;
import util.io.IOUtilities;
import util.misc.ChangeTrackingProperties;
import util.misc.SoftReferenceCache;
import util.ui.LazyImageIcon;
import com.l2fprod.util.StringUtils;
import devplugin.AbstractTvDataService;
/**
* A class that loads for Channels from a server.
*/
public class IconLoader {
private static final Logger mLog = Logger.getLogger(IconLoader.class.getName());
private File mIconDir;
private File mIconIndexFile;
private String mChannelGroup;
private ChangeTrackingProperties mProperties;
private AbstractTvDataService mDataService;
/**
* A cache for icons.
*/
private static final SoftReferenceCache<String, File> ICON_CACHE = new SoftReferenceCache<String, File>();
/**
* A list with servers that don't respond on last access.
*/
private static final ArrayList<String> BLOCKED_SERVERS = new ArrayList<String>(0);
public IconLoader(final AbstractTvDataService service, final String channelGroup, final File dir) throws IOException {
mDataService = service;
mChannelGroup = channelGroup;
mIconDir = new File(dir + "/icons_" + mChannelGroup);
if (!mIconDir.exists()) {
mIconDir.mkdirs();
}
mIconIndexFile = new File(mIconDir, "index.txt");
mProperties = new ChangeTrackingProperties();
if (mIconIndexFile.exists()) {
BufferedInputStream in = new BufferedInputStream(new FileInputStream(
mIconIndexFile), 0x1000);
mProperties.load(in);
in.close();
} else {
mLog.warning("no icons known for channel group " + channelGroup);
}
}
public Icon getIcon(final String channelId, final String url) throws IOException {
String key = new StringBuilder("icons_").append(mChannelGroup).append("_")
.append(channelId).toString();
String prevUrl = (String) mProperties.get(key);
Icon icon = null;
File iconFile = new File(mIconDir, escapedName(channelId));
if (url.equals(prevUrl)) {
// the url hasn't changed; we should have the icon locally
icon = getIconFromFile(iconFile);
return icon;
} else {
mLog.warning("iconUrl is not in cache for channelId " + channelId
+ ". prevUrl=" + prevUrl + ". currentUrl=" + url);
}
if (ICON_CACHE.containsKey(url)) {
try {
File iconCacheFile = ICON_CACHE.get(url);
if (iconCacheFile != null && !iconCacheFile.equals(iconFile)) {
IOUtilities.copy(ICON_CACHE.get(url), iconFile);
icon = getIconFromFile(iconFile);
}
} catch (Exception e) {
mLog.log(Level.SEVERE, "Problem while copying File from Cache", e);
}
}
if (icon == null && mDataService.hasRightToDownloadIcons()
&& !BLOCKED_SERVERS.contains(url)) {
// download the icon
try {
util.io.IOUtilities.download(new URL(url), iconFile);
icon = getIconFromFile(iconFile);
ICON_CACHE.put(url, iconFile);
} catch (IOException e) {
BLOCKED_SERVERS.add(url);
mLog.warning("channel " + channelId + ": could not download icon from " + url);
} catch (Exception e) {
mLog.severe("Could not extract icon file");
}
}
if (icon != null) {
mProperties.setProperty(key, url);
}
return icon;
}
private String escapedName(final String channelId) {
return StringUtils.replace(channelId, ".", "_");
}
private String unescape(final String fileName) {
return StringUtils.replace(fileName, "_", ".");
}
private Icon getIconFromFile(final File iconFile) {
// rename old icon files on the fly to avoid file names ending in
// ".com" which is reserved for executables on Microsoft platforms
if (!iconFile.exists()) {
String namePart = iconFile.getName();
String unescapedPath = iconFile.getAbsolutePath().replace(namePart,
unescape(namePart));
File unescapedFile = new File(unescapedPath);
if (unescapedFile.exists()) {
unescapedFile.renameTo(iconFile);
}
}
// now load the (renamed) image
try {
return new LazyImageIcon(iconFile.toURI().toURL());
} catch (MalformedURLException e) {
e.printStackTrace();
}
return null;
}
public void close() throws IOException {
FileOutputStream out = new FileOutputStream(mIconIndexFile);
out.getChannel().lock();
mProperties.store(out, null);
out.close();
}
}