content: import com.google.common.cache.Cache;
  import com.google.common.cache.CacheBuilder;
  import com.google.common.util.concurrent.ThreadFactoryBuilder;
  import com.google.gson.Gson;
  import com.mojang.authlib.GameProfile;
  import eu.the5zig.mod.MinecraftFactory;
  import eu.the5zig.mod.gui.ingame.resource.CapeResource;
  import eu.the5zig.mod.gui.ingame.resource.IResourceManager;
  import eu.the5zig.mod.gui.ingame.resource.PlayerResource;
  import eu.the5zig.util.Utils;
  import org.apache.commons.codec.binary.Base64;
  import org.apache.commons.io.IOUtils;
  
  import javax.imageio.ImageIO;
  import java.awt.image.BufferedImage;
  import java.io.BufferedReader;
  import java.io.ByteArrayInputStream;
  import java.io.InputStreamReader;
  import java.net.HttpURLConnection;
  import java.net.URL;
  import java.util.UUID;
  import java.util.concurrent.ExecutorService;
  import java.util.concurrent.Executors;
  import java.util.concurrent.TimeUnit;
  
  public class ResourceManager implements IResourceManager {
  
  	private static final int PLAYER_RESOURCE_VERSION = 1;
  
  	private static final ExecutorService EXECUTOR_SERVICE = Executors.newSingleThreadExecutor(new ThreadFactoryBuilder().setNameFormat("5zig Texture Downloader #%d").setDaemon(true)
  			.build());
  	private static final String BASE_URL = "http://textures.5zig.net/";
  	private static final Gson gson = new Gson();
  
  	private final GameProfile playerProfile;
  	private PlayerResource ownPlayerResource;
  	private final Cache<UUID, PlayerResource> playerResources = CacheBuilder.newBuilder().expireAfterAccess(3, TimeUnit.MINUTES).build();
  
  	public ResourceManager(GameProfile playerProfile) {
  		this.playerProfile = playerProfile;
  	}
  
  	public void loadPlayerTextures(final GameProfile gameProfile) {
  		if (gameProfile == null || gameProfile.getId() == null) {
  			return;
  		}
  		PlayerResource playerResource;
  		if (playerProfile.getName().equals(gameProfile.getName())) {
  			if (ownPlayerResource == null) {
  				ownPlayerResource = loadPlayerResource(playerProfile);
  			}
  		} else {
  			playerResource = playerResources.getIfPresent(gameProfile.getId());
  			if (playerResource != null) {
  				MinecraftFactory.getClassProxyCallback().getLogger().debug("Loaded player resource textures from cache for player " + gameProfile.getName());
  			} else {
  				playerResources.put(gameProfile.getId(), loadPlayerResource(gameProfile));
  			}
  		}
  	}
  
  	private PlayerResource loadPlayerResource(final GameProfile gameProfile) {
  		final String url = BASE_URL + "textures/" + PLAYER_RESOURCE_VERSION + "/" + Utils.getUUIDWithoutDashes(gameProfile.getId());
  		final PlayerResource playerResource = new PlayerResource();
  
  		final ResourceLocation capeLocation = new ResourceLocation("the5zigmod", "capes/" + gameProfile.getId());
  		final SimpleTickingTexture capeTexture;
  		bqh texture = ((Variables) MinecraftFactory.getVars()).getTextureManager().b(capeLocation);
  		if (texture instanceof SimpleTickingTexture) {
  			capeTexture = (SimpleTickingTexture) texture;
  			capeTexture.setBufferedImage(null);
  		} else {
  			capeTexture = new SimpleTickingTexture(capeLocation);
  			((Variables) MinecraftFactory.getVars()).getTextureManager().a(capeLocation, capeTexture);
  		}
  
  		EXECUTOR_SERVICE.execute(new Runnable() {
  			@Override
  			public void run() {
  				MinecraftFactory.getClassProxyCallback().getLogger().debug("Loading player resource textures from {} for player {}", url, gameProfile.getName());
  
  				HttpURLConnection connection = null;
  				BufferedReader reader = null;
  				try {
  					connection = (HttpURLConnection) (new URL(url)).openConnection(MinecraftFactory.getVars().getProxy());
  					connection.setDoInput(true);
  					connection.setDoOutput(false);
  					connection.connect();
  
  					if (connection.getResponseCode() != 200) {
  						return;
  					}
  					reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
  					String line = reader.readLine();
  
  					TextureData data = gson.fromJson(line, TextureData.class);
  					if (data.animatedCape != null && !data.animatedCape.isEmpty()) {
  						try {
  							BufferedImage cape = ImageIO.read(new ByteArrayInputStream(Base64.decodeBase64(data.animatedCape)));
  							capeTexture.setBufferedImage(cape);
  
  							playerResource.setCapeResource(new CapeResource(capeLocation, capeTexture));
  						} catch (Exception e) {
  							MinecraftFactory.getClassProxyCallback().getLogger().error("Could not parse cape for " + gameProfile.getId(), e);
  						}
  					} else if (data.cape != null && !data.cape.isEmpty()) {
  						try {
  							BufferedImage cape = ImageIO.read(new ByteArrayInputStream(Base64.decodeBase64(data.cape)));
  							capeTexture.setBufferedImage(cape);
  
  							playerResource.setCapeResource(new CapeResource(capeLocation, capeTexture));
  						} catch (Exception e) {
  							MinecraftFactory.getClassProxyCallback().getLogger().error("Could not parse cape for " + gameProfile.getId(), e);
  						}
  					}
  				} catch (Exception e) {
  					MinecraftFactory.getClassProxyCallback().getLogger().error("Couldn\'t download http texture", e);
  				} finally {
  					IOUtils.closeQuietly(reader);
  					if (connection != null) {
  						connection.disconnect();
  					}
  				}
  			}
  		});
  
  		return playerResource;
  	}
  
  	@Override
  	public void cleanupTextures() {
  		MinecraftFactory.getClassProxyCallback().getLogger().debug("Cleaning up player textures...");
  		for (PlayerResource playerResource : playerResources.asMap().values()) {
  			if (playerResource.getCapeResource() != null) {
  				((SimpleTickingTexture) playerResource.getCapeResource().getSimpleTexture()).setBufferedImage(null);
  			}
  		}
  		playerResources.invalidateAll();
  		ownPlayerResource = null;
  	}
  
  	@Override
  	public Object getCapeLocation(Object player) {
  		GameProfile profile = ((blg) player).bJ();
  		if (playerProfile.getName().equals(profile.getName())) {
  			return getCapeLocation(ownPlayerResource);
  		} else {
  			return getCapeLocation(playerResources.getIfPresent(profile.getId()));
  		}
  	}
  
  	@Override
  	public Object getOwnCapeLocation() {
  		return getCapeLocation(ownPlayerResource);
  	}
  
  	private Object getCapeLocation(PlayerResource playerResource) {
  		if (playerResource != null && playerResource.getCapeResource() != null) {
  			CapeResource capeResource = playerResource.getCapeResource();
  			return ((SimpleTickingTexture) capeResource.getSimpleTexture()).getCurrentResource();
  		}
  		return null;
  	}
  
  	@Override
  	public void updateOwnPlayerTextures() {
  		ownPlayerResource = null;
  		loadPlayerTextures(MinecraftFactory.getVars().getGameProfile());
  	}
  }
  