All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.moviejukebox.plugin.DefaultImagePlugin Maven / Gradle / Ivy

There is a newer version: 2.9
Show newest version
/*
 *      Copyright (c) 2004-2012 YAMJ Members
 *      http://code.google.com/p/moviejukebox/people/list
 *
 *      Web: http://code.google.com/p/moviejukebox/
 *
 *      This software is licensed under a Creative Commons License
 *      See this page: http://code.google.com/p/moviejukebox/wiki/License
 *
 *      For any reuse or distribution, you must make clear to others the
 *      license terms of this work.
 */
package com.moviejukebox.plugin;

import com.moviejukebox.fanarttv.model.FTArtworkType;
import com.moviejukebox.model.*;
import com.moviejukebox.model.Comparator.ValueComparator;
import com.moviejukebox.tools.GraphicTools;
import com.moviejukebox.tools.PropertiesUtil;
import static com.moviejukebox.tools.PropertiesUtil.FALSE;
import static com.moviejukebox.tools.PropertiesUtil.TRUE;
import com.moviejukebox.tools.StringTools;
import com.moviejukebox.tools.SystemTools;
import java.awt.*;
import java.awt.geom.RoundRectangle2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import org.apache.commons.configuration.HierarchicalConfiguration;
import org.apache.commons.configuration.XMLConfiguration;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.apache.sanselan.ImageReadException;

public class DefaultImagePlugin implements MovieImagePlugin {

    private static final String BANNER = "banners";
    private static final String POSTER = "posters";
    private static final String VIDEOIMAGE = "videoimages";
    private static final String THUMBNAIL = "thumbnails";
    private static final String FOOTER = "footer";
    private static final String CLEARART = FTArtworkType.CLEARART.toString().toLowerCase();
    private static final String CLEARLOGO = FTArtworkType.CLEARLOGO.toString().toLowerCase();
    private static final String SEASONTHUMB = FTArtworkType.SEASONTHUMB.toString().toLowerCase();
    private static final String TVTHUMB = FTArtworkType.TVTHUMB.toString().toLowerCase();
    private static final String CHARACTERART = FTArtworkType.CHARACTERART.toString().toLowerCase();
    private static final String MOVIEART = FTArtworkType.MOVIEART.toString().toLowerCase();
    private static final String MOVIEDISC = FTArtworkType.MOVIEDISC.toString().toLowerCase();
    private static final String MOVIELOGO = FTArtworkType.MOVIELOGO.toString().toLowerCase();
    private static final List validImageTypes = Collections.synchronizedList(new ArrayList());
    private static final Logger logger = Logger.getLogger(DefaultImagePlugin.class);
    private String overlayRoot;
    private String overlayResources;
    // Literals
    private static final String LEFT = "left";
    private static final String RIGHT = "right";
    private static final String BLOCK = "block";
    private static final String DEFAULT = "default";
    private static final String COLOUR_WHITE = "255/255/255";
    private static final String VIDEOSOURCE = "videosource";
    private static final String LANGUAGE = "language";
    private static final String ACODEC = "acodec";
    private static final String ALANG = "alang";
    private static final String AUDIOCODEC = "audiocodec";
    private static final String AUDIOLANG = "audiolang";
    private static final String AUDIOCHANNELS = "audiochannels";
    private static final String CHANNELS = "channels";
    private static final String CONTAINER = "container";
    private static final String CERTIFICATION = "certification";
    private static final String KEYWORDS = "keywords";
    private static final String COUNTRY = "country";
    private static final String COMPANY = "company";
    private static final String AWARD = "award";
    private static final String EQUAL = "equal";
    private static final String AUTO = "auto";
    private static final String TOP = "top";
    private static final String D_PLUS = "\\d+";
    private static final String MSG_VALID = ", please ensure it is valid";
    private static final String MSG_RESOURCES = " is in the resources directory.";
    //stretch images
    private boolean addHDLogo;
    private boolean addTVLogo;
    private boolean addSetLogo;
    private boolean addSubTitle;
    private boolean blockSubTitle;
    private boolean addLanguage;
    private boolean blockLanguage;
    private boolean highdefDiff;
    private boolean addTextSetSize;
    private String textAlignment;
    private String textFont;
    private int textFontSize;
    private String textFontColor;
    private String textFontShadow;
    private int textOffset;
    private String imageType;
    private boolean roundCorners;
    private int cornerRadius;
    // cornerQuality/rcqfactor to improve roundCorner Quality
    private float rcqFactor;
    private int frameSize;
    private String frameColorHD;
    private String frameColor720;
    private String frameColor1080;
    private String frameColorSD;
    private String overlaySource;
    // Issue 1937: Overlay configuration XML
    private List overlayLayers = new ArrayList();
    private boolean xmlOverlay;
    private boolean addRating;
    private boolean realRating;
    private boolean addVideoSource;
    private boolean addVideoOut;
    private boolean addVideoCodec;
    private boolean addAudioCodec;
    private boolean blockAudioCodec;
    private boolean addAudioChannels;
    private boolean blockAudioChannels;
    private boolean addAudioLang;
    private boolean blockAudioLang;
    private boolean addContainer;
    private boolean addAspectRatio;
    private boolean addFPS;
    private boolean addCertification;
    private boolean addWatched;
    private boolean blockWatched;
    private boolean addTop250;
    private boolean addKeywords;
    private boolean addCountry;
    private boolean blockCountry;
    private boolean addCompany;
    private boolean blockCompany;
    private boolean countSetLogo;
    private boolean addAward;
    private boolean awardEventName;
    private boolean blockAward;
    private boolean countAward;
    private boolean blockClones;
    private boolean addEpisode;
    private boolean blockEpisode;
    private Map> keywordsRating = new HashMap>();
    private Map> keywordsVideoSource = new HashMap>();
    private Map> keywordsVideoOut = new HashMap>();
    private Map> keywordsVideoCodec = new HashMap>();
    private Map> keywordsAudioCodec = new HashMap>();
    private Map> keywordsAudioChannels = new HashMap>();
    private Map> keywordsAudioLang = new HashMap>();
    private Map> keywordsContainer = new HashMap>();
    private Map> keywordsAspectRatio = new HashMap>();
    private Map> keywordsFPS = new HashMap>();
    private Map> keywordsCertification = new HashMap>();
    private Map> keywordsKeywords = new HashMap>();
    private Map> keywordsCountry = new HashMap>();
    private Map> keywordsCompany = new HashMap>();
    private Map> keywordsAward = new HashMap>();
    private Map overlayBlocks = new HashMap();
    private int viIndex;

    public DefaultImagePlugin() {
        // Generic properties
        String skinHome = PropertiesUtil.getProperty("mjb.skin.dir", "./skins/default");
        boolean skinRoot = PropertiesUtil.getBooleanProperty("mjb.overlay.skinroot", TRUE);
        overlayRoot = PropertiesUtil.getProperty("mjb.overlay.dir", Movie.UNKNOWN);
        overlayRoot = (skinRoot ? (skinHome + File.separator) : "") + (StringTools.isValidString(overlayRoot) ? (overlayRoot + File.separator) : "");
        overlayResources = overlayRoot + PropertiesUtil.getProperty("mjb.overlay.resources", "resources") + File.separator;
        highdefDiff = PropertiesUtil.getBooleanProperty("highdef.differentiate", FALSE);

        synchronized (validImageTypes) {
            if (validImageTypes.isEmpty()) {
                validImageTypes.add(BANNER);
                validImageTypes.add(POSTER);
                validImageTypes.add(VIDEOIMAGE);
                validImageTypes.add(THUMBNAIL);
                validImageTypes.add(FOOTER);
                validImageTypes.add(CLEARART);
                validImageTypes.add(CLEARLOGO);
                validImageTypes.add(SEASONTHUMB);
                validImageTypes.add(TVTHUMB);
                validImageTypes.add(CHARACTERART);
                validImageTypes.add(MOVIEART);
                validImageTypes.add(MOVIEDISC);
                validImageTypes.add(MOVIELOGO);
            }
        }
    }

    @Override
    public BufferedImage generate(Movie movie, BufferedImage imageGraphic, String gImageType, String perspectiveDirection) {
        boolean addReflectionEffect = PropertiesUtil.getBooleanProperty(imageType + ".reflection", FALSE);
        boolean addPerspective = PropertiesUtil.getBooleanProperty(imageType + ".perspective", FALSE);
        boolean imageNormalize = PropertiesUtil.getBooleanProperty(imageType + ".normalize", FALSE);
        boolean imageStretch = PropertiesUtil.getBooleanProperty(imageType + ".stretch", FALSE);
        boolean addOverlay = PropertiesUtil.getBooleanProperty(imageType + ".overlay", FALSE);

        boolean isFooter = false;

        imageType = gImageType.toLowerCase();

        viIndex = 0;
        if (imageType.indexOf(FOOTER) == 0) {
            isFooter = true;
            imageType = imageType.replaceFirst(FOOTER, "");
        } else if (imageType.indexOf(VIDEOIMAGE) == 0 && !imageType.equals(VIDEOIMAGE)) {
            viIndex = Integer.parseInt(imageType.replaceFirst(VIDEOIMAGE, ""));
            viIndex = (viIndex > 0 && viIndex <= movie.getFiles().size()) ? (viIndex - 1) : 0;
            imageType = VIDEOIMAGE;
        } else if (!validImageTypes.contains(imageType)) {
            // This is an error with the calling function
            logger.error("YAMJ Error with calling function in DefaultImagePlugin.java");
            logger.error("The image type '" + imageType + "' cannot be found");
            return imageGraphic;
        }

        // Specific Properties (dependent upon the imageType)
        int imageWidth = PropertiesUtil.getIntProperty(imageType + ".width", "400");
        int imageHeight = PropertiesUtil.getIntProperty(imageType + ".height", "600");
        addHDLogo = PropertiesUtil.getBooleanProperty(imageType + ".logoHD", FALSE);
        addTVLogo = PropertiesUtil.getBooleanProperty(imageType + ".logoTV", FALSE);

        String tmpSubTitle = PropertiesUtil.getProperty(imageType + ".logoSubTitle", FALSE);
        blockSubTitle = tmpSubTitle.equalsIgnoreCase(BLOCK);
        addSubTitle = tmpSubTitle.equalsIgnoreCase(TRUE) || blockSubTitle;

        String tmpLanguage = PropertiesUtil.getProperty(imageType + ".language", FALSE);
        blockLanguage = tmpLanguage.equalsIgnoreCase(BLOCK);
        addLanguage = tmpLanguage.equalsIgnoreCase(TRUE) || blockLanguage;

        String tmpSetLogo = PropertiesUtil.getProperty(imageType + ".logoSet", FALSE);
        countSetLogo = tmpSetLogo.equalsIgnoreCase("count");
        addSetLogo = tmpSetLogo.equalsIgnoreCase(TRUE) || countSetLogo; // Note: This should only be for thumbnails

        boolean addTextTitle = PropertiesUtil.getBooleanProperty(imageType + ".addText.title", FALSE);
        boolean addTextSeason = PropertiesUtil.getBooleanProperty(imageType + ".addText.season", FALSE);
        addTextSetSize = PropertiesUtil.getBooleanProperty(imageType + ".addText.setSize", FALSE); // Note: This should only be for thumbnails
        textAlignment = PropertiesUtil.getProperty(imageType + ".addText.alignment", LEFT);
        textFont = PropertiesUtil.getProperty(imageType + ".addText.font", "Helvetica");
        textFontSize = PropertiesUtil.getIntProperty(imageType + ".addText.fontSize", "36");
        textFontColor = PropertiesUtil.getProperty(imageType + ".addText.fontColor", "LIGHT_GRAY");
        textFontShadow = PropertiesUtil.getProperty(imageType + ".addText.fontShadow", "DARK_GRAY");
        textOffset = PropertiesUtil.getIntProperty(imageType + ".addText.offset", "10");
        roundCorners = PropertiesUtil.getBooleanProperty(imageType + ".roundCorners", FALSE);
        cornerRadius = PropertiesUtil.getIntProperty(imageType + ".cornerRadius", "25");
        int cornerQuality = PropertiesUtil.getIntProperty(imageType + ".cornerQuality", "0");

        int overlayOffsetX = PropertiesUtil.getIntProperty(imageType + ".overlay.offsetX", "0");
        int overlayOffsetY = PropertiesUtil.getIntProperty(imageType + ".overlay.offsetY", "0");
        overlaySource = PropertiesUtil.getProperty(imageType + ".overlay.source", DEFAULT);

        boolean addFrame = PropertiesUtil.getBooleanProperty(imageType + ".addFrame", FALSE);
        frameSize = PropertiesUtil.getIntProperty(imageType + ".frame.size", "5");
        frameColorSD = PropertiesUtil.getProperty(imageType + ".frame.colorSD", COLOUR_WHITE);
        frameColorHD = PropertiesUtil.getProperty(imageType + ".frame.colorHD", COLOUR_WHITE);
        frameColor720 = PropertiesUtil.getProperty(imageType + ".frame.color720", COLOUR_WHITE);
        frameColor1080 = PropertiesUtil.getProperty(imageType + ".frame.color1080", COLOUR_WHITE);

        // Issue 1937: Overlay configuration XML
        String tmpRating = PropertiesUtil.getProperty(imageType + ".rating", FALSE);
        realRating = tmpRating.equalsIgnoreCase("real");
        addRating = tmpRating.equalsIgnoreCase(TRUE) || realRating;

        String tmpAudioCodec = PropertiesUtil.getProperty(imageType + ".audiocodec", FALSE);
        blockAudioCodec = tmpAudioCodec.equalsIgnoreCase(BLOCK);
        addAudioCodec = tmpAudioCodec.equalsIgnoreCase(TRUE) || blockAudioCodec;

        String tmpAudioChannels = PropertiesUtil.getProperty(imageType + ".audiochannels", FALSE);
        blockAudioChannels = tmpAudioChannels.equalsIgnoreCase(BLOCK);
        addAudioChannels = tmpAudioChannels.equalsIgnoreCase(TRUE) || blockAudioChannels;

        String tmpAudioLang = PropertiesUtil.getProperty(imageType + ".audiolang", FALSE);
        blockAudioLang = tmpAudioCodec.equalsIgnoreCase(BLOCK);
        addAudioLang = tmpAudioLang.equalsIgnoreCase(TRUE) || blockAudioLang;

        addVideoSource = PropertiesUtil.getBooleanProperty(imageType + ".videosource", FALSE);
        addVideoOut = PropertiesUtil.getBooleanProperty(imageType + ".videoout", FALSE);
        addVideoCodec = PropertiesUtil.getBooleanProperty(imageType + ".videocodec", FALSE);
        addContainer = PropertiesUtil.getBooleanProperty(imageType + ".container", FALSE);
        addAspectRatio = PropertiesUtil.getBooleanProperty(imageType + ".aspect", FALSE);
        addFPS = PropertiesUtil.getBooleanProperty(imageType + ".fps", FALSE);
        addCertification = PropertiesUtil.getBooleanProperty(imageType + ".certification", FALSE);

        String tmpWatched = PropertiesUtil.getProperty(imageType + ".watched", FALSE);
        blockWatched = tmpWatched.equalsIgnoreCase(BLOCK);
        addWatched = tmpWatched.equalsIgnoreCase(TRUE) || blockWatched;

        String tmpEpisode = PropertiesUtil.getProperty(imageType + ".episode", FALSE);
        blockEpisode = tmpEpisode.equalsIgnoreCase(BLOCK);
        addEpisode = tmpEpisode.equalsIgnoreCase(TRUE) || blockEpisode;

        addTop250 = PropertiesUtil.getBooleanProperty(imageType + ".top250", FALSE);
        addKeywords = PropertiesUtil.getBooleanProperty(imageType + ".keywords", FALSE);
        blockClones = PropertiesUtil.getBooleanProperty(imageType + ".clones", FALSE);

        String tmpCountry = PropertiesUtil.getProperty(imageType + ".country", FALSE);
        blockCountry = tmpCountry.equalsIgnoreCase(BLOCK);
        addCountry = tmpCountry.equalsIgnoreCase(TRUE) || blockCountry;

        String tmpCompany = PropertiesUtil.getProperty(imageType + ".company", FALSE);
        blockCompany = tmpCompany.equalsIgnoreCase(BLOCK);
        addCompany = tmpCompany.equalsIgnoreCase(TRUE) || blockCompany;

        String tmpAward = PropertiesUtil.getProperty(imageType + ".award", FALSE);
        blockAward = tmpAward.equalsIgnoreCase(BLOCK);
        countAward = tmpAward.equalsIgnoreCase("count");
        addAward = tmpAward.equalsIgnoreCase(TRUE) || blockAward || countAward;
        awardEventName = PropertiesUtil.getBooleanProperty(imageType + ".award.useEventName", FALSE);

        xmlOverlay = PropertiesUtil.getBooleanProperty(imageType + ".xmlOverlay", FALSE);
        if (xmlOverlay) {
            String tmp = PropertiesUtil.getProperty("overlay.keywords.rating", "");
            fillOverlayKeywords(keywordsRating, tmp);
            tmp = PropertiesUtil.getProperty("overlay.keywords.videosource", "");
            fillOverlayKeywords(keywordsVideoSource, tmp);
            tmp = PropertiesUtil.getProperty("overlay.keywords.videoout", "");
            fillOverlayKeywords(keywordsVideoOut, tmp);
            tmp = PropertiesUtil.getProperty("overlay.keywords.videocodec", "");
            fillOverlayKeywords(keywordsVideoCodec, tmp);
            tmp = PropertiesUtil.getProperty("overlay.keywords.audiocodec", "");
            fillOverlayKeywords(keywordsAudioCodec, tmp);
            tmp = PropertiesUtil.getProperty("overlay.keywords.audiochannels", "");
            fillOverlayKeywords(keywordsAudioChannels, tmp);
            tmp = PropertiesUtil.getProperty("overlay.keywords.audiolang", "");
            fillOverlayKeywords(keywordsAudioLang, tmp);
            tmp = PropertiesUtil.getProperty("overlay.keywords.container", "");
            fillOverlayKeywords(keywordsContainer, tmp);
            tmp = PropertiesUtil.getProperty("overlay.keywords.aspect", "");
            fillOverlayKeywords(keywordsAspectRatio, tmp);
            tmp = PropertiesUtil.getProperty("overlay.keywords.fps", "");
            fillOverlayKeywords(keywordsFPS, tmp);
            tmp = PropertiesUtil.getProperty("overlay.keywords.certification", "");
            fillOverlayKeywords(keywordsCertification, tmp);
            tmp = PropertiesUtil.getProperty("overlay.keywords.keywords", "");
            fillOverlayKeywords(keywordsKeywords, tmp);
            tmp = PropertiesUtil.getProperty("overlay.keywords.country", "");
            fillOverlayKeywords(keywordsCountry, tmp);
            tmp = PropertiesUtil.getProperty("overlay.keywords.company", "");
            fillOverlayKeywords(keywordsCompany, tmp);
            tmp = PropertiesUtil.getProperty("overlay.keywords.award", "");
            fillOverlayKeywords(keywordsAward, tmp);
            fillOverlayParams(PropertiesUtil.getProperty(imageType + ".xmlOverlayFile", "overlay-default.xml"));
        }

        float ratio = (float) imageWidth / (float) imageHeight;

        if (roundCorners) {
            rcqFactor = (float) cornerQuality / 10 + 1;
        } else {
            rcqFactor = 1;
        }

        BufferedImage bi = imageGraphic;

        if (imageGraphic != null) {
            int origWidth = imageGraphic.getWidth();
            int origHeight = imageGraphic.getHeight();
            boolean skipResize = false;
            if (origWidth < imageWidth && origHeight < imageHeight && !addHDLogo && !addLanguage) {
                //Perhaps better: if (origWidth == imageWidth && origHeight == imageHeight && !addHDLogo && !addLanguage) {
                skipResize = true;
            }

            if (imageNormalize) {
                if (skipResize) {
                    bi = GraphicTools.scaleToSizeNormalized((int) (origHeight * rcqFactor * ratio), (int) (origHeight * rcqFactor), bi);
                } else {
                    bi = GraphicTools.scaleToSizeNormalized((int) (imageWidth * rcqFactor), (int) (imageHeight * rcqFactor), bi);
                }
            } else if (imageStretch) {
                bi = GraphicTools.scaleToSizeStretch((int) (imageWidth * rcqFactor), (int) (imageHeight * rcqFactor), bi);

            } else if (!skipResize) {
                bi = GraphicTools.scaleToSize((int) (imageWidth * rcqFactor), (int) (imageHeight * rcqFactor), bi);
            }

            // addFrame before rounding the corners see Issue 1825
            if (addFrame) {
                bi = drawFrame(movie, bi);
            }

            // roundCornders after addFrame see Issue 1825
            if (roundCorners) {
                if (!addFrame) {
                    bi = drawRoundCorners(bi);
                }

                // Don't resize if the factor is the same
                if (rcqFactor > 1.00f) {
                    //roundCorner quality resizing
                    bi = GraphicTools.scaleToSizeStretch((int) imageWidth, (int) imageHeight, bi);
                }
            }

            if (imageType.equalsIgnoreCase(BANNER)) {
                if (addTextTitle) {
                    bi = drawText(bi, movie.getTitle(), true);
                }

                if (addTextSeason && movie.isTVShow()) {
                    bi = drawText(bi, "Season " + movie.getSeason(), false);
                }
            }

            bi = drawLogos(movie, bi, isFooter ? FOOTER : imageType, true);

            if (addOverlay) {
                bi = drawOverlay(movie, bi, overlayOffsetX, overlayOffsetY);
            }

            bi = drawLogos(movie, bi, isFooter ? FOOTER : imageType, false);

            if (addReflectionEffect) {
                bi = GraphicTools.createReflectedPicture(bi, isFooter ? FOOTER : imageType);
            }

            if (addPerspective) {
                String perspDir;
                if (perspectiveDirection == null) { // make sure the perspectiveDirection is populated {
                    perspDir = PropertiesUtil.getProperty(imageType + ".perspectiveDirection", RIGHT);
                } else {
                    perspDir = perspectiveDirection;
                }

                bi = GraphicTools.create3DPicture(bi, isFooter ? FOOTER : imageType, perspDir);
            }
        }

        return bi;
    }

    /**
     * Draw a frame around the image; color depends on resolution if wanted
     *
     * @param movie
     * @param bi
     * @return
     */
    private BufferedImage drawFrame(Movie movie, BufferedImage bi) {
        BufferedImage newImg = new BufferedImage(bi.getWidth(), bi.getHeight(), BufferedImage.TYPE_INT_ARGB);
        Graphics2D newGraphics = newImg.createGraphics();
        newGraphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        int cornerRadius2 = 0;

        if (!movie.isHD()) {
            String[] colorSD = frameColorSD.split("/");
            int lengthSD[] = new int[colorSD.length];
            for (int i = 0; i < colorSD.length; i++) {
                lengthSD[i] = Integer.parseInt(colorSD[i]);
            }
            newGraphics.setPaint(new Color(lengthSD[0], lengthSD[1], lengthSD[2]));
        } else if (highdefDiff) {
            if (movie.isHD()) {
                // Otherwise use the 720p
                String[] color720 = frameColor720.split("/");
                int length720[] = new int[color720.length];
                for (int i = 0; i < color720.length; i++) {
                    length720[i] = Integer.parseInt(color720[i]);
                }
                newGraphics.setPaint(new Color(length720[0], length720[1], length720[2]));
            }

            if (movie.isHD1080()) {
                String[] color1080 = frameColor1080.split("/");
                int length1080[] = new int[color1080.length];
                for (int i = 0; i < color1080.length; i++) {
                    length1080[i] = Integer.parseInt(color1080[i]);
                }
                newGraphics.setPaint(new Color(length1080[0], length1080[1], length1080[2]));
            }
        } else {
            // We don't care, so use the default HD logo.
            String[] colorHD = frameColorHD.split("/");
            int lengthHD[] = new int[colorHD.length];
            for (int i = 0; i < colorHD.length; i++) {
                lengthHD[i] = Integer.parseInt(colorHD[i]);
            }
            newGraphics.setPaint(new Color(lengthHD[0], lengthHD[1], lengthHD[2]));
        }

        if (roundCorners) {
            cornerRadius2 = cornerRadius;
        }

        RoundRectangle2D.Double rect = new RoundRectangle2D.Double(0, 0, bi.getWidth(), bi.getHeight(), rcqFactor * cornerRadius2, rcqFactor * cornerRadius2);
        newGraphics.setClip(rect);

        // image fitted into border
        newGraphics.drawImage(bi, (int) (rcqFactor * frameSize - 1), (int) (rcqFactor * frameSize - 1), (int) (bi.getWidth() - (rcqFactor * frameSize * 2) + 2), (int) (bi.getHeight() - (rcqFactor * frameSize * 2) + 2), null);

        BasicStroke s4 = new BasicStroke(rcqFactor * frameSize * 2);

        newGraphics.setStroke(s4);
        newGraphics.draw(rect);
        newGraphics.dispose();

        return newImg;
    }

    /**
     * Draw rounded corners on the image
     *
     * @param bi
     * @return
     */
    protected BufferedImage drawRoundCorners(BufferedImage bi) {
        BufferedImage newImg = new BufferedImage(bi.getWidth(), bi.getHeight(), BufferedImage.TYPE_INT_ARGB);
        Graphics2D newGraphics = newImg.createGraphics();
        newGraphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

        RoundRectangle2D.Double rect = new RoundRectangle2D.Double(0, 0, bi.getWidth(), bi.getHeight(), rcqFactor * cornerRadius, rcqFactor * cornerRadius);
        newGraphics.setClip(rect);
        newGraphics.drawImage(bi, 0, 0, null);

        newGraphics.dispose();
        return newImg;
    }

    /**
     * Draw the TV and HD logos onto the image
     *
     * @param movie The source movie
     * @param newBi The image to draw on
     * @return The new image with the added logos
     */
    protected BufferedImage drawLogos(Movie movie, BufferedImage bi, String imageType, boolean beforeMainOverlay) {
        BufferedImage newBi = bi;

        // Issue 1937: Overlay configuration XML
        if (xmlOverlay) {
            for (LogoOverlay layer : overlayLayers) {
                if (layer.before != beforeMainOverlay) {
                    continue;
                }
                boolean flag = false;
                List states = new ArrayList();
                for (String name : layer.names) {
                    String value = Movie.UNKNOWN;
                    if (checkLogoEnabled(name)) {
                        if (name.equalsIgnoreCase("set")) {
                            value = ((imageType.equalsIgnoreCase(THUMBNAIL) || imageType.equalsIgnoreCase(BANNER) || imageType.equalsIgnoreCase(FOOTER)) && movie.isSetMaster()) ? countSetLogo ? Integer.toString(movie.getSetSize()) : TRUE : countSetLogo ? "0" : FALSE;
                        } else if (name.equalsIgnoreCase("TV")) {
                            value = movie.isTVShow() ? TRUE : FALSE;
                        } else if (name.equalsIgnoreCase("HD")) {
                            value = movie.isHD() ? highdefDiff ? movie.isHD1080() ? "hd1080" : "hd720" : "hd" : FALSE;
                        } else if (name.equalsIgnoreCase("subtitle") || name.equalsIgnoreCase("ST")) {
                            value = (StringTools.isNotValidString(movie.getSubtitles()) || movie.getSubtitles().equalsIgnoreCase("NO")) ? FALSE : (blockSubTitle ? movie.getSubtitles() : TRUE);
                        } else if (name.equalsIgnoreCase(LANGUAGE)) {
                            value = movie.getLanguage();
                        } else if (name.equalsIgnoreCase("rating")) {
                            value = ((!movie.isTVShow() && !movie.isSetMaster()) || (movie.isTVShow() && movie.isSetMaster())) ? Integer.toString(realRating ? movie.getRating() : (movie.getRating() / 10) * 10) : Movie.UNKNOWN;
                        } else if (name.equalsIgnoreCase(VIDEOSOURCE) || name.equalsIgnoreCase("source") || name.equalsIgnoreCase("VS")) {
                            value = movie.getVideoSource();
                        } else if (name.equalsIgnoreCase("videoout") || name.equalsIgnoreCase("out") || name.equalsIgnoreCase("VO")) {
                            value = movie.getVideoOutput();
                        } else if (name.equalsIgnoreCase("videocodec") || name.equalsIgnoreCase("vcodec") || name.equalsIgnoreCase("VC")) {
                            value = movie.getVideoCodec();
                        } else if (name.equalsIgnoreCase(AUDIOCODEC) || name.equalsIgnoreCase(ACODEC) || name.equalsIgnoreCase("AC")) {
                            value = movie.getAudioCodec();
                            if (!blockAudioCodec) {
                                int pos = value.indexOf(Movie.SPACE_SLASH_SPACE);
                                if (pos > -1) {
                                    value = value.substring(0, pos);
                                }
                                pos = value.indexOf(" (");
                                if (pos > -1) {
                                    value = value.substring(0, pos);
                                }
                            } else {
                                while (value.contains(" (") && value.indexOf(" (") < value.indexOf(')')) {
                                    value = value.substring(0, value.indexOf(" (")) + value.substring(value.indexOf(')') + 1);
                                }
                            }
                        } else if (name.equalsIgnoreCase(AUDIOLANG) || name.equalsIgnoreCase(ALANG) || name.equalsIgnoreCase("AL")) {
                            value = "";
                            for (String tmp : movie.getAudioCodec().split(Movie.SPACE_SLASH_SPACE)) {
                                if (tmp.contains(" (") && tmp.indexOf(" (") < tmp.indexOf(")")) {
                                    tmp = tmp.substring(tmp.indexOf(" (") + 2, tmp.indexOf(")"));
                                } else {
                                    tmp = Movie.UNKNOWN;
                                }
                                if (!blockAudioLang) {
                                    value = tmp;
                                    break;
                                }
                                if (StringUtils.isNotBlank(value)) {
                                    value += Movie.SPACE_SLASH_SPACE;
                                }
                                value += tmp;
                            }
                            if (value.equals("")) {
                                value = Movie.UNKNOWN;
                            }
                        } else if (name.equalsIgnoreCase(AUDIOCHANNELS) || name.equalsIgnoreCase(CHANNELS)) {
                            value = movie.getAudioChannels();
                            if (!blockAudioChannels) {
                                int pos = value.indexOf(Movie.SPACE_SLASH_SPACE);
                                if (pos > -1) {
                                    value = value.substring(0, pos);
                                }
                            }
                        } else if (name.equalsIgnoreCase(CONTAINER)) {
                            value = movie.getContainer();
                        } else if (name.equalsIgnoreCase("aspect")) {
                            value = movie.getAspectRatio();
                        } else if (name.equalsIgnoreCase("fps")) {
                            value = Float.toString(movie.getFps());
                        } else if (name.equalsIgnoreCase(CERTIFICATION)) {
                            value = movie.getCertification();
                        } else if (name.equalsIgnoreCase("watched")) {
                            if (imageType.equalsIgnoreCase(VIDEOIMAGE)) {
                                value = movie.getFiles().toArray(new MovieFile[movie.getFiles().size()])[viIndex].isWatched() ? TRUE : FALSE;
                            } else if (movie.isTVShow() && blockWatched) {
                                StringBuilder sbWatched = new StringBuilder();
                                boolean first = true;
                                for (MovieFile mf : movie.getFiles()) {
                                    if (first) {
                                        first = false;
                                    } else {
                                        sbWatched.append(Movie.SPACE_SLASH_SPACE);
                                    }
                                    sbWatched.append(mf.isWatched() ? TRUE : FALSE);
                                }
                                value = sbWatched.toString();
                            } else {
                                value = movie.isWatched() ? TRUE : FALSE;
                            }
                        } else if (name.equalsIgnoreCase("episode")) {
                            if (movie.isTVShow()) {
                                if (blockEpisode) {
                                    StringBuilder sbEpisode = new StringBuilder();
                                    boolean first = true;
                                    int firstPart, lastPart;
                                    for (MovieFile mf : movie.getFiles()) {
                                        firstPart = mf.getFirstPart();
                                        lastPart = mf.getLastPart();
                                        for (int part = firstPart; part <= lastPart; part++) {
                                            if (first) {
                                                first = false;
                                            } else {
                                                sbEpisode.append(Movie.SPACE_SLASH_SPACE);
                                            }
                                            sbEpisode.append(part);
                                        }
                                    }
                                    value = sbEpisode.toString();
                                } else {
                                    value = Integer.toString(movie.getFiles().size());
                                }
                            }
                        } else if (name.equalsIgnoreCase("top250")) {
                            value = movie.getTop250() > 0 ? TRUE : FALSE;
                        } else if (name.equalsIgnoreCase(KEYWORDS)) {
                            value = movie.getBaseFilename().toLowerCase();
                        } else if (name.equalsIgnoreCase(COUNTRY)) {
                            value = movie.getCountry();
                            if (!blockCountry) {
                                int pos = value.indexOf(Movie.SPACE_SLASH_SPACE);
                                if (pos > -1) {
                                    value = value.substring(0, pos);
                                }
                            }
                        } else if (name.equalsIgnoreCase(COMPANY)) {
                            value = movie.getCompany();
                            if (!blockCompany) {
                                int pos = value.indexOf(Movie.SPACE_SLASH_SPACE);
                                if (pos > -1) {
                                    value = value.substring(0, pos);
                                }
                            }
                        } else if (name.equalsIgnoreCase(AWARD)) {
                            value = "";
                            int awardCount = 0;
                            HashMap awards = new HashMap();
                            if (!movie.isSetMaster()) {
                                for (AwardEvent awardEvent : movie.getAwards()) {
                                    for (Award award : awardEvent.getAwards()) {
                                        if (award.getWon() > 0) {
                                            if (blockAward) {
                                                awards.put((awardEventName ? (awardEvent.getName() + " - ") : "") + award.getName(), award.getWon());
                                            } else if (countAward) {
                                                awardCount++;
                                            } else {
                                                value = TRUE;
                                                break;
                                            }
                                        }
                                    }
                                    if (!blockAward && !countAward && StringTools.isValidString(value)) {
                                        break;
                                    }
                                }
                            }

                            if (blockAward) {
                                ValueComparator bvc = new ValueComparator(awards);
                                TreeMap sortedAwards = new TreeMap(bvc);
                                sortedAwards.putAll(awards);

                                StringBuilder sbAwards = new StringBuilder();
                                boolean first = value.isEmpty();   // Append the separator only if the "value" is not empty

                                for (String award : sortedAwards.keySet()) {
                                    if (first) {
                                        first = false;
                                    } else {
                                        sbAwards.append(Movie.SPACE_SLASH_SPACE);
                                    }
                                    sbAwards.append(award);
                                }
                                value += sbAwards.toString();
                            }
                            value = (StringTools.isNotValidString(value) && !countAward) ? blockAward ? Movie.UNKNOWN : FALSE : countAward ? Integer.toString(awardCount) : value;
                        } else {
                            value = PropertiesUtil.getProperty(name, Movie.UNKNOWN);
                        }
                    }
                    StateOverlay state = new StateOverlay(layer.left, layer.top, layer.align, layer.valign, layer.width, layer.height, value);
                    states.add(state);
                }

                for (int inx = 0; inx < layer.names.size(); inx++) {
                    String name = layer.names.get(inx);
                    String value = states.get(inx).value;
                    String filename = Movie.UNKNOWN;
                    if (checkLogoEnabled(name)) {
                        if (!blockLanguage && name.equalsIgnoreCase(LANGUAGE) && StringTools.isValidString(value)) {
                            filename = "languages/English.png";
                        }
                        String[] values = value.split(Movie.SPACE_SLASH_SPACE);
                        for (int j = 0; j < values.length; j++) {
                            value = values[j];
                            for (ImageOverlay img : layer.images) {
                                if (img.name.equalsIgnoreCase(name)) {
                                    boolean accept = false;
                                    if (img.values.size() == 1 && cmpOverlayValue(name, img.value, value)) {
                                        accept = true;
                                    } else if (img.values.size() > 1) {
                                        accept = true;
                                        for (int i = 0; i < layer.names.size(); i++) {
                                            accept = accept && cmpOverlayValue(layer.names.get(i), img.values.get(i), states.get(i).value);
                                            if (!accept) {
                                                break;
                                            }
                                        }
                                    }
                                    if (!accept) {
                                        continue;
                                    }
                                    File imageFile = new File(overlayResources + img.filename);
                                    if (imageFile.exists()) {
                                        if (StringTools.isNotValidString(filename)) {
                                            filename = img.filename;
                                        } else {
                                            filename += Movie.SPACE_SLASH_SPACE + img.filename;
                                        }
                                    }
                                    break;
                                }
                            }
                        }
                        flag = flag || StringTools.isValidString(filename);
                    }
                    states.get(inx).filename = filename;
                }

                if (!flag) {
                    continue;
                }

                if (layer.positions.size() > 0) {
                    for (ConditionOverlay cond : layer.positions) {
                        flag = true;
                        for (int i = 0; i < layer.names.size(); i++) {
                            String name = layer.names.get(i);
                            String condition = cond.values.get(i);
                            String value = states.get(i).value;
                            flag = flag && cmpOverlayValue(name, condition, value);
                            if (!flag) {
                                break;
                            }
                        }
                        if (flag) {
                            for (int i = 0; i < layer.names.size(); i++) {
                                PositionOverlay pos = cond.positions.get(i);
                                states.get(i).left = pos.left;
                                states.get(i).top = pos.top;
                                states.get(i).align = pos.align;
                                states.get(i).valign = pos.valign;
                            }
                            break;
                        }
                    }
                }

                for (int i = 0; i < layer.names.size(); i++) {
                    StateOverlay state = states.get(i);
                    String name = layer.names.get(i);
                    if (!blockLanguage && name.equalsIgnoreCase(LANGUAGE)) {
                        newBi = drawLanguage(movie, newBi, getOverlayX(newBi.getWidth(), 62, state.left, state.align), getOverlayY(newBi.getHeight(), 40, state.top, state.valign));
                        continue;
                    }

                    String filename = state.filename;
                    if (StringTools.isNotValidString(filename)) {
                        continue;
                    }

                    if (((blockAudioCodec && ((name.equalsIgnoreCase(AUDIOCODEC) || name.equalsIgnoreCase(ACODEC) || name.equalsIgnoreCase("AC"))))
                            || (blockAudioChannels && (name.equalsIgnoreCase(AUDIOCHANNELS) || name.equalsIgnoreCase(CHANNELS)))
                            || (blockAudioLang && (name.equalsIgnoreCase(AUDIOLANG) || name.equalsIgnoreCase(ALANG) || name.equalsIgnoreCase("AL")))
                            || (blockCountry && name.equalsIgnoreCase(COUNTRY))
                            || (blockCompany && name.equalsIgnoreCase(COMPANY))
                            || (blockAward && name.equalsIgnoreCase(AWARD))
                            || (blockWatched && name.equalsIgnoreCase("watched"))
                            || (blockEpisode && name.equalsIgnoreCase("episode"))
                            || (blockSubTitle && name.equalsIgnoreCase("subtitle"))
                            || (blockLanguage && name.equalsIgnoreCase(LANGUAGE)))
                            && (overlayBlocks.get(name) != null)) {
                        newBi = drawBlock(movie, newBi, name, filename, state.left, state.align, state.width, state.top, state.valign, state.height);
                        continue;
                    }

                    try {
                        BufferedImage biSet = GraphicTools.loadJPEGImage(overlayResources + filename);

                        Graphics2D g2d = newBi.createGraphics();
                        g2d.drawImage(biSet, getOverlayX(newBi.getWidth(), biSet.getWidth(), state.left, state.align), getOverlayY(newBi.getHeight(), biSet.getHeight(), state.top, state.valign), state.width.matches(D_PLUS) ? Integer.parseInt(state.width) : biSet.getWidth(), state.height.matches(D_PLUS) ? Integer.parseInt(state.height) : biSet.getHeight(), null);
                        g2d.dispose();
                    } catch (ImageReadException ex) {
                        logger.warn("Failed to read " + overlayResources + filename + MSG_VALID);
                    } catch (IOException ex) {
                        logger.warn("Failed drawing overlay to image file: Please check that " + filename + MSG_RESOURCES);
                    }

                    if (name.equalsIgnoreCase("set")) {
                        newBi = drawSetSize(movie, newBi);
                        continue;
                    }
                }
            }
        } else if (beforeMainOverlay) {
            if (addHDLogo) {
                newBi = drawLogoHD(movie, newBi, addTVLogo);
            }

            if (addTVLogo) {
                newBi = drawLogoTV(movie, newBi, addHDLogo);
            }

            if (addLanguage) {
                newBi = drawLanguage(movie, newBi, 1, 1);
            }

            if (addSubTitle) {
                newBi = drawSubTitle(movie, newBi);
            }

            // Should only really happen on set's thumbnails.
            if (imageType.equalsIgnoreCase(THUMBNAIL) && movie.isSetMaster()) {
                // Draw the set logo if requested.
                if (addSetLogo) {
                    newBi = drawSet(movie, newBi);
                    logger.debug("Drew set logo on " + movie.getTitle());
                }
                newBi = drawSetSize(movie, newBi);
            }
        }

        return newBi;
    }

    /**
     * Draw the SubTitle logo on the image
     *
     * @param movie
     * @param bi
     * @return
     */
    private BufferedImage drawSubTitle(Movie movie, BufferedImage bi) {
        // If the doesn't have subtitles, then quit
        if (StringTools.isNotValidString(movie.getSubtitles()) || movie.getSubtitles().equalsIgnoreCase("NO")) {
            return bi;
        }

        String logoFilename = "subtitle.png";
        File logoFile = new File(getResourcesPath() + logoFilename);

        if (!logoFile.exists()) {
            logger.debug("Missing SubTitle logo (" + logoFilename + ") unable to draw logo");
            return bi;
        }

        try {
            BufferedImage biSubTitle = GraphicTools.loadJPEGImage(logoFile);
            Graphics2D g2d = bi.createGraphics();
            g2d.drawImage(biSubTitle, bi.getWidth() - biSubTitle.getWidth() - 5, 5, null);
            g2d.dispose();
        } catch (ImageReadException ex) {
            logger.warn("Failed to read " + logoFilename + MSG_VALID);
        } catch (IOException error) {
            logger.warn("Failed drawing SubTitle logo to thumbnail file: Please check that " + logoFilename + MSG_RESOURCES);
        }

        return bi;
    }

    /**
     * Draw the appropriate HD logo onto the image file
     *
     * @param movie The source movie
     * @param bi The original image
     * @param addOtherLogo Do we need to draw the TV logo as well?
     * @return The new image file
     */
    private BufferedImage drawLogoHD(Movie movie, BufferedImage bi, Boolean addOtherLogo) {
        // If the movie isn't high definition, then quit
        if (!movie.isHD()) {
            return bi;
        }

        String logoFilename;
        File logoFile;

        // Determine which logo to use.
        if (highdefDiff) {
            if (movie.isHD1080()) {
                // Use the 1080p logo
                logoFilename = "hd-1080.png";
            } else {
                // Otherwise use the 720p
                logoFilename = "hd-720.png";
            }
        } else {
            // We don't care, so use the default HD logo.
            logoFilename = "hd.png";
        }

        logoFile = new File(getResourcesPath() + logoFilename);
        if (!logoFile.exists()) {
            logger.debug("Missing HD logo (" + logoFilename + ") using default hd.png");
            logoFilename = "hd.png";
        }

        try {
            BufferedImage biHd = GraphicTools.loadJPEGImage(getResourcesPath() + logoFilename);
            Graphics2D g2d = bi.createGraphics();

            if (addOtherLogo && (movie.isTVShow())) {
                // Both logos are required, so put the HD logo on the LEFT
                g2d.drawImage(biHd, 5, bi.getHeight() - biHd.getHeight() - 5, null);
                logger.debug("Drew HD logo (" + logoFilename + ") on the left");
            } else {
                // Only the HD logo is required so set it in the centre
                g2d.drawImage(biHd, bi.getWidth() / 2 - biHd.getWidth() / 2, bi.getHeight() - biHd.getHeight() - 5, null);
                logger.debug("Drew HD logo (" + logoFilename + ") in the middle");
            }

            g2d.dispose();
        } catch (ImageReadException ex) {
            logger.warn("Failed to read " + logoFilename + MSG_VALID);
        } catch (IOException error) {
            logger.warn("Failed drawing HD logo to thumbnail file: Please check that " + logoFilename + MSG_RESOURCES);
        }

        return bi;
    }

    /**
     * Draw the TV logo onto the image file
     *
     * @param movie The source movie
     * @param bi The original image
     * @param addOtherLogo Do we need to draw the HD logo as well?
     * @return The new image file
     */
    private BufferedImage drawLogoTV(Movie movie, BufferedImage bi, Boolean addOtherLogo) {
        String logoFilename = "tv.png";

        if (movie.isTVShow()) {
            try {
                BufferedImage biTV = GraphicTools.loadJPEGImage(getResourcesPath() + logoFilename);
                Graphics2D g2d = bi.createGraphics();

                if (addOtherLogo && movie.isHD()) {
                    // Both logos are required, so put the TV logo on the RIGHT
                    g2d.drawImage(biTV, bi.getWidth() - biTV.getWidth() - 5, bi.getHeight() - biTV.getHeight() - 5, null);
                    logger.debug("Drew TV logo on the right");
                } else {
                    // Only the TV logo is required so set it in the centre
                    g2d.drawImage(biTV, bi.getWidth() / 2 - biTV.getWidth() / 2, bi.getHeight() - biTV.getHeight() - 5, null);
                    logger.debug("Drew TV logo in the middle");
                }

                g2d.dispose();
            } catch (ImageReadException ex) {
                logger.warn("Failed to read " + logoFilename + MSG_VALID);
            } catch (IOException error) {
                logger.warn("Failed drawing TV logo to thumbnail file: Please check that " + logoFilename + MSG_RESOURCES);
                logger.error(SystemTools.getStackTrace(error));
            }
        }

        return bi;
    }

    /**
     * Draw an overlay on the image, such as a box cover specific for videosource, container, certification if wanted
     *
     * @param movie
     * @param bi
     * @param offsetY
     * @param offsetX
     * @return
     */
    private BufferedImage drawOverlay(Movie movie, BufferedImage bi, int offsetX, int offsetY) {

        String source;
        if (overlaySource.equalsIgnoreCase(VIDEOSOURCE)) {
            source = movie.getVideoSource();
        } else if (overlaySource.equalsIgnoreCase(CERTIFICATION)) {
            source = movie.getCertification();
        } else if (overlaySource.equalsIgnoreCase(CONTAINER)) {
            source = movie.getContainer();
        } else {
            source = DEFAULT;
        }

        // Make sure the source is formatted correctly
        source = source.toLowerCase().trim();

        // Check for a blank or an UNKNOWN source and correct it
        if (StringTools.isNotValidString(source)) {
            source = DEFAULT;
        }

        String overlayFilename = source + "_overlay_" + imageType + ".png";

        try {
            BufferedImage biOverlay = GraphicTools.loadJPEGImage(getResourcesPath() + overlayFilename);

            BufferedImage returnBI = new BufferedImage(biOverlay.getWidth(), biOverlay.getHeight(), BufferedImage.TYPE_INT_ARGB);
            Graphics2D g2BI = returnBI.createGraphics();
            g2BI.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

            g2BI.drawImage(bi,
                    offsetX, offsetY, offsetX + bi.getWidth(), offsetY + bi.getHeight(),
                    0, 0, bi.getWidth(), bi.getHeight(),
                    null);
            g2BI.drawImage(biOverlay, 0, 0, null);

            g2BI.dispose();

            return returnBI;
        } catch (ImageReadException ex) {
            logger.warn("Failed to read " + overlayFilename + MSG_VALID);
        } catch (IOException ex) {
            logger.warn("Failed drawing overlay to " + movie.getBaseName() + ". Please check that " + overlayFilename + MSG_RESOURCES);
        }

        return bi;
    }

    /**
     * Draw the language logo to the image
     *
     * @param movie Movie file, used to determine the language
     * @param bi The image file to draw on
     * @return The new image file with the language flag on it
     */
    private BufferedImage drawLanguage(IMovieBasicInformation movie, BufferedImage bi, int left, int top) {
        String lang = movie.getLanguage();

        if (StringTools.isValidString(lang)) {
            String[] languages = lang.split("/");

            StringBuilder fullLanguage = new StringBuilder();
            for (String language : languages) {
                // CHeck the language is valid before adding it
                if (StringTools.isValidString(language)) {
                    if (fullLanguage.length() > 0) {
                        fullLanguage.append("_");
                    }
                    fullLanguage.append(language.trim());
                }
            }

            // If there isn't a valid language, quit
            if (StringTools.isNotValidString(fullLanguage.toString())) {
                return bi;
            }

            String languageFilename = "languages" + File.separator + fullLanguage + ".png";

            try {
                Graphics2D g2d = bi.createGraphics();
                File imageFile = new File(getResourcesPath() + languageFilename);
                if (imageFile.exists()) {
                    BufferedImage biLang = GraphicTools.loadJPEGImage(imageFile);
                    g2d.drawImage(biLang, 1, 1, null);
                } else {
                    if (languages.length == 1) {
                        logger.warn("Failed drawing Language logo to thumbnail file: " + movie.getBaseName());
                        logger.warn("Please check that language specific graphic (" + fullLanguage + ".png) is in the resources/languages directory.");
                    } else {
                        logger.debug("Unable to find multiple language image (" + fullLanguage + ".png) in the resources/languages directory, generating it from single one.");
                        int width = -1;
                        int height = -1;
                        int nbCols = (int) Math.sqrt(languages.length);
                        int nbRows = languages.length / nbCols;

                        BufferedImage[] imageFiles = new BufferedImage[languages.length];
                        // Looking for image file
                        for (int i = 0; i < languages.length; i++) {
                            String language = languages[i].trim();
                            languageFilename = "languages" + File.separator + language + ".png";
                            imageFile = new File(getResourcesPath() + languageFilename);
                            if (imageFile.exists()) {

                                BufferedImage biLang = GraphicTools.loadJPEGImage(imageFile);
                                imageFiles[i] = biLang;

                                // Determine image size.
                                if (width == -1) {

                                    width = biLang.getWidth() / nbCols;
                                    height = biLang.getHeight() / nbRows;
                                }
                            } else {
                                logger.warn("Failed drawing Language logo to thumbnail file: " + movie.getBaseName());
                                logger.warn("Please check that language specific graphic (" + languageFilename + ") is in the resources/languages directory.");
                            }
                        }

                        for (int i = 0; i < imageFiles.length; i++) {
                            int indexCol = (i) % nbCols;
                            int indexRow = (i / nbCols);
                            g2d.drawImage(imageFiles[i], left + (width * indexCol), top + (height * indexRow), width, height, null);
                        }
                    }
                }

                g2d.dispose();
            } catch (ImageReadException ex) {
                logger.warn("Failed to read " + languageFilename + MSG_VALID);
            } catch (IOException ex) {
                logger.warn("Exception drawing Language logo to thumbnail file '" + movie.getBaseName() + "': " + ex.getMessage());
                logger.warn("Please check that language specific graphic (" + languageFilename + ") is in the resources/languages directory.");
            }
        }

        return bi;
    }

    private BufferedImage drawBlock(IMovieBasicInformation movie, BufferedImage bi, String name, String files, int left, String align, String width, int top, String valign, String height) {

        int currentFilenameNumber = 0;

        if (StringTools.isValidString(files)) {
            String[] filenames = files.split(Movie.SPACE_SLASH_SPACE);
            try {
                Graphics2D g2d = bi.createGraphics();
                BufferedImage biSet = GraphicTools.loadJPEGImage(overlayResources + filenames[currentFilenameNumber]);
                List uniqueFiles = new ArrayList();
                uniqueFiles.add(filenames[0]);
                int lWidth = width.matches(D_PLUS) ? Integer.parseInt(width) : biSet.getWidth();
                int lHeight = height.matches(D_PLUS) ? Integer.parseInt(height) : biSet.getHeight();
                LogosBlock block = overlayBlocks.get(name);
                int cols = block.cols;
                int rows = block.rows;
                boolean clones = block.clones;
                if (filenames.length > 1) {
                    if (cols == 0 && rows == 0) {
                        cols = (int) Math.sqrt(filenames.length);
                        rows = (int) (filenames.length / cols);
                    } else if (cols == 0) {
                        cols = (int) (filenames.length / rows);
                    } else if (rows == 0) {
                        rows = (int) (filenames.length / cols);
                    }
                    if (block.size) {
                        lWidth = (int) (lWidth / cols);
                        lHeight = (int) (lHeight / rows);
                    }
                }
                int maxWidth = lWidth;
                int maxHeight = lHeight;
                g2d.drawImage(biSet, getOverlayX(bi.getWidth(), lWidth, left, align), getOverlayY(bi.getHeight(), lHeight, top, valign), lWidth, lHeight, null);
                if ((filenames.length > 1) && (block != null)) {
                    int col = 0;
                    int row = 0;
                    int offsetX = block.dir ? lWidth : 0;
                    int offsetY = block.dir ? 0 : lHeight;
                    for (int i = 1; i < filenames.length; i++) {
                        if (!clones) {
                            if (uniqueFiles.contains(filenames[i])) {
                                continue;
                            } else {
                                uniqueFiles.add(filenames[i]);
                            }
                        }
                        if (block.dir) {
                            col++;
                            if (block.cols > 0 && col >= cols) {
                                col = 0;
                                row++;
                                if (block.rows > 0 && row >= rows) {
                                    break;
                                }
                            }
                        } else {
                            row++;
                            if (block.rows > 0 && row >= rows) {
                                row = 0;
                                col++;
                                if (block.cols > 0 && col >= cols) {
                                    break;
                                }
                            }
                        }

                        currentFilenameNumber = i;
                        biSet = GraphicTools.loadJPEGImage(overlayResources + filenames[currentFilenameNumber]);
                        if (block.size || width.equalsIgnoreCase(EQUAL) || width.matches(D_PLUS)) {
                            offsetX = (left > 0 ? 1 : -1) * col * (lWidth + block.hmargin);
                        } else if (width.equalsIgnoreCase(AUTO)) {
                            lWidth = biSet.getWidth();
                            offsetX = block.dir ? col == 0 ? 0 : offsetX : row == 0 ? (offsetX + maxWidth) : offsetX;
                        }
                        if (block.size || height.equalsIgnoreCase(EQUAL) || height.matches(D_PLUS)) {
                            offsetY = (top > 0 ? 1 : -1) * row * (lHeight + block.vmargin);
                        } else if (height.equalsIgnoreCase(AUTO)) {
                            lHeight = biSet.getHeight();
                            offsetY = block.dir ? col == 0 ? (offsetY + maxHeight) : offsetY : row == 0 ? 0 : offsetY;
                        }
                        g2d.drawImage(biSet, getOverlayX(bi.getWidth(), lWidth, left + offsetX, align),
                                getOverlayY(bi.getHeight(), lHeight, top + offsetY, valign),
                                lWidth, lHeight, null);
                        if (!block.size && width.equalsIgnoreCase(AUTO)) {
                            if (block.dir) {
                                offsetX += (left > 0 ? 1 : -1) * lWidth;
                            } else {
                                maxWidth = (maxWidth < lWidth || row == 0) ? lWidth : maxWidth;
                            }
                        }
                        if (!block.size && height.equalsIgnoreCase(AUTO)) {
                            if (block.dir) {
                                maxHeight = (maxHeight < lHeight || col == 0) ? lHeight : maxHeight;
                            } else {
                                offsetY += (top > 0 ? 1 : -1) * lHeight;
                            }
                        }
                    }
                }
                g2d.dispose();
            } catch (ImageReadException ex) {
                logger.warn("Failed to read " + filenames[currentFilenameNumber] + MSG_VALID);
            } catch (IOException e) {
                logger.warn("Failed drawing overlay block logo (" + filenames[currentFilenameNumber] + ") to thumbnail file: " + movie.getBaseName());
            }
        }
        return bi;
    }

    /**
     * Draw the set logo onto a poster
     *
     * @param movie the movie to check
     * @param bi the image to draw on
     * @return the new buffered image
     */
    private BufferedImage drawSet(Movie movie, BufferedImage bi) {
        String setFilename = "set.png";
        try {
            BufferedImage biSet = GraphicTools.loadJPEGImage(getResourcesPath() + setFilename);

            Graphics2D g2d = bi.createGraphics();
            g2d.drawImage(biSet, bi.getWidth() - biSet.getWidth() - 5, 1, null);
            g2d.dispose();
        } catch (ImageReadException ex) {
            logger.warn("Failed to read " + setFilename + MSG_VALID);
        } catch (IOException error) {
            logger.warn("Failed drawing set logo to thumbnail for " + movie.getBaseFilename());
            logger.warn("Please check that set graphic (set.png) is in the resources directory. " + error.getMessage());
        }

        return bi;
    }

    private BufferedImage drawSetSize(Movie movie, BufferedImage bi) {
        // Let's draw the set's size (at bottom) if requested.
        final int size = movie.getSetSize();
        if (addTextSetSize && size > 0) {
            String text;
            // Let's draw not more than 9...
            if (size > 9) {
                text = "9+";
            } else {
                text = Integer.toString(size);
            }
            logger.debug("Size (" + movie.getSetSize() + ") of set [" + movie.getTitle() + "] was drawn");
            return drawText(bi, text, false);
        }

        return bi;
    }

    /**
     * Calculate the path to the resources (skin path)
     *
     * @return path to the resource directory
     */
    protected String getResourcesPath() {
        return overlayResources;
    }

    protected BufferedImage drawPerspective(Identifiable movie, BufferedImage bi) {
        return bi;
    }

    private BufferedImage drawText(BufferedImage bi, String outputText, boolean verticalAlign) {
        Graphics2D g2d = bi.createGraphics();
        g2d.setFont(new Font(textFont, Font.BOLD, textFontSize));
        FontMetrics fm = g2d.getFontMetrics();
        int textWidth = fm.stringWidth(outputText);
        int imageWidth = bi.getWidth();
        int imageHeight = bi.getHeight();
        int leftAlignment;
        int topAlignment;

        if (textAlignment.equalsIgnoreCase(LEFT)) {
            leftAlignment = textOffset;
        } else if (textAlignment.equalsIgnoreCase(RIGHT)) {
            leftAlignment = imageWidth - textWidth - textOffset;
        } else {
            leftAlignment = (imageWidth / 2) - (textWidth / 2);
        }

        if (verticalAlign) {
            // Align the text to the top
            topAlignment = fm.getHeight() - 10;
        } else {
            // Align the text to the bottom
            topAlignment = imageHeight - 10;
        }

        // Create the drop shadow
        if (!textFontShadow.equalsIgnoreCase("")) {
            g2d.setColor(getColor(textFontShadow, Color.DARK_GRAY));
            g2d.drawString(outputText, leftAlignment + 2, topAlignment + 2);
        }

        // Create the text itself
        g2d.setColor(getColor(textFontColor, Color.LIGHT_GRAY));
        g2d.drawString(outputText, leftAlignment, topAlignment);

        g2d.dispose();
        return bi;
    }

    private static Color getColor(String color, Color defaultColor) {
        Color returnColor = MyColor.get(color);
        if (returnColor == null) {
            return defaultColor;
        }
        return returnColor;
    }

    enum MyColor {

        white(Color.white), WHITE(Color.WHITE),
        lightGray(Color.lightGray), LIGHT_GRAY(Color.LIGHT_GRAY),
        gray(Color.gray), GRAY(Color.GRAY),
        darkGray(Color.darkGray), DARK_GRAY(Color.DARK_GRAY),
        black(Color.black), BLACK(Color.BLACK),
        red(Color.red), RED(Color.RED),
        pink(Color.pink), PINK(Color.PINK),
        orange(Color.orange), ORANGE(Color.ORANGE),
        yellow(Color.yellow), YELLOW(Color.YELLOW),
        green(Color.green), GREEN(Color.GREEN),
        magenta(Color.magenta), MAGENTA(Color.MAGENTA),
        cyan(Color.cyan), CYAN(Color.CYAN),
        blue(Color.blue), BLUE(Color.BLUE);
        private final Color color;

        // Constructor
        MyColor(Color color) {
            this.color = color;
        }

        public static Color get(String name) {
            for (MyColor aColor : MyColor.values()) {
                if (aColor.toString().equalsIgnoreCase(name)) {
                    return aColor.color;
                }
            }
            return null;
        }
    }

    // Issue 1937: Overlay configuration XML
    private class PositionOverlay {

        protected Integer left = 0;
        protected Integer top = 0;
        protected String align = LEFT;
        protected String valign = TOP;
        protected String width = EQUAL;
        protected String height = EQUAL;

        public PositionOverlay() {
        }

        public PositionOverlay(Integer left, Integer top, String align, String valign, String width, String height) {
            this.left = left;
            this.top = top;
            this.align = align;
            this.valign = valign;
            this.width = width;
            this.height = height;
        }
    }

    private class ImageOverlay {

        private String name;
        private String value;
        private List values = new ArrayList();
        private String filename;

        public ImageOverlay(String name, String value, String filename, List values) {
            this.name = name;
            this.value = value;
            this.filename = filename;
            this.values = values;
        }
    }

    private class ConditionOverlay {

        private List values = new ArrayList();
        private List positions = new ArrayList();
    }

    private class LogoOverlay extends PositionOverlay {

        private boolean before = true;
        private List names = new ArrayList();
        private List images = new ArrayList();
        private List positions = new ArrayList();
    }

    private class StateOverlay extends PositionOverlay {

        private String value = Movie.UNKNOWN;
        private String filename = Movie.UNKNOWN;

        public StateOverlay(Integer left, Integer top, String align, String valign, String width, String height, String value) {
            this.left = left;
            this.top = top;
            this.align = align;
            this.valign = valign;
            this.width = width;
            this.height = height;
            this.value = value;
        }
    }

    private class LogosBlock {

        private boolean dir = false;         // true - vertical, false - horizontal,
        private boolean size = false;        // true - static, false - auto
        private boolean clones = false;      // true - enabled clones
        private Integer cols = 1;            // 0 - auto count
        private Integer rows = 0;            // 0 - auto count
        private Integer hmargin = 0;
        private Integer vmargin = 0;

        public LogosBlock(boolean dir, boolean size, String cols, String rows, String hmargin, String vmargin, boolean clones) {
            this.dir = dir;
            this.size = size;
            this.clones = clones;
            this.cols = cols.equalsIgnoreCase(AUTO) ? 0 : Integer.parseInt(cols);
            this.rows = rows.equalsIgnoreCase(AUTO) ? 0 : Integer.parseInt(rows);
            this.hmargin = Integer.parseInt(hmargin);
            this.vmargin = Integer.parseInt(vmargin);
        }
    }

    private void fillOverlayParams(String xmlOverlayFilename) {
        if (!xmlOverlayFilename.toUpperCase().endsWith("XML")) {
            return;
        }
        File xmlOverlayFile = new File(overlayRoot + xmlOverlayFilename);
        if (xmlOverlayFile.exists() && xmlOverlayFile.isFile()) {
            try {
                XMLConfiguration c = new XMLConfiguration(xmlOverlayFile);
                List layers = c.configurationsAt("layer");
                overlayLayers.clear();
                int index = 0;
                for (HierarchicalConfiguration layer : layers) {
                    String name = layer.getString("name");
                    if (StringTools.isNotValidString(name)) {
                        continue;
                    }
                    LogoOverlay overlay = new LogoOverlay();

                    String after = layer.getString("[@after]");
                    if (StringTools.isValidString(after) && after.equalsIgnoreCase(TRUE)) {
                        overlay.before = false;
                    }

                    String left = layer.getString(LEFT);
                    String top = layer.getString(TOP);
                    String align = layer.getString("align");
                    String valign = layer.getString("valign");
                    String width = layer.getString("width");
                    String height = layer.getString("height");

                    overlay.names = Arrays.asList(name.split("/"));
                    if (StringTools.isValidString(left)) {
                        try {
                            overlay.left = Integer.parseInt(left);
                        } catch (Exception ignore) {
                        }
                    }
                    if (StringTools.isValidString(top)) {
                        try {
                            overlay.top = Integer.parseInt(top);
                        } catch (Exception ignore) {
                        }
                    }
                    if (StringTools.isValidString(align) && (align.equalsIgnoreCase(LEFT) || align.equalsIgnoreCase("center") || align.equalsIgnoreCase(RIGHT))) {
                        overlay.align = align;
                    }
                    if (StringTools.isValidString(valign) && (valign.equalsIgnoreCase(TOP) || valign.equalsIgnoreCase("center") || valign.equalsIgnoreCase("bottom"))) {
                        overlay.valign = valign;
                    }
                    if (StringTools.isValidString(width) && (width.equalsIgnoreCase(EQUAL) || width.equalsIgnoreCase(AUTO) || width.matches(D_PLUS))) {
                        overlay.width = width;
                    }
                    if (StringTools.isValidString(height) && (height.equalsIgnoreCase(EQUAL) || height.equalsIgnoreCase(AUTO) || height.matches(D_PLUS))) {
                        overlay.height = height;
                    }

                    List images = c.configurationsAt("layer(" + index + ").images.image");
                    for (HierarchicalConfiguration image : images) {
                        name = image.getString("[@name]");
                        String value = image.getString("[@value]");
                        String filename = image.getString("[@filename]");

                        if (StringTools.isNotValidString(name)) {
                            name = overlay.names.get(0);
                        }
                        if (!overlay.names.contains(name) || StringTools.isNotValidString(value) || StringTools.isNotValidString(filename)) {
                            continue;
                        }

                        ImageOverlay img = new ImageOverlay(name, value, filename, Arrays.asList(value.split("/")));
                        if (img.values.size() > 1) {
                            for (int i = 0; i < overlay.names.size(); i++) {
                                if (img.values.size() <= i) {
                                    img.values.add(Movie.UNKNOWN);
                                } else if (StringTools.isNotValidString(img.values.get(i))) {
                                    img.values.set(i, Movie.UNKNOWN);
                                }
                            }
                        }
                        overlay.images.add(img);
                    }

                    if (overlay.names.size() > 1) {
                        List positions = c.configurationsAt("layer(" + index + ").positions.position");
                        for (HierarchicalConfiguration position : positions) {
                            String value = position.getString("[@value]");
                            left = position.getString("[@left]");
                            top = position.getString("[@top]");
                            align = position.getString("[@align]");
                            valign = position.getString("[@valign]");
                            width = position.getString("[@width]");
                            height = position.getString("[@height]");

                            if (StringTools.isNotValidString(value)) {
                                continue;
                            }
                            ConditionOverlay condition = new ConditionOverlay();
                            condition.values = Arrays.asList(value.split("/"));
                            if (StringTools.isNotValidString(left)) {
                                left = Integer.toString(overlay.left);
                            }
                            if (StringTools.isNotValidString(top)) {
                                top = Integer.toString(overlay.top);
                            }
                            if (StringTools.isNotValidString(align)) {
                                align = overlay.align;
                            }
                            if (StringTools.isNotValidString(valign)) {
                                valign = overlay.valign;
                            }
                            if (StringTools.isNotValidString(width)) {
                                width = overlay.width;
                            }
                            if (StringTools.isNotValidString(height)) {
                                height = overlay.height;
                            }
                            List lefts = Arrays.asList(left.split("/"));
                            List tops = Arrays.asList(top.split("/"));
                            List aligns = Arrays.asList(align.split("/"));
                            List valigns = Arrays.asList(valign.split("/"));
                            List widths = Arrays.asList(width.split("/"));
                            List heights = Arrays.asList(height.split("/"));
                            for (int i = 0; i < overlay.names.size(); i++) {
                                if (StringTools.isNotValidString(condition.values.get(i))) {
                                    condition.values.set(i, Movie.UNKNOWN);
                                }
                                PositionOverlay p = new PositionOverlay((lefts.size() <= i || StringTools.isNotValidString(lefts.get(i))) ? overlay.left : Integer.parseInt(lefts.get(i)),
                                        (tops.size() <= i || StringTools.isNotValidString(tops.get(i))) ? overlay.top : Integer.parseInt(tops.get(i)),
                                        (aligns.size() <= i || StringTools.isNotValidString(aligns.get(i))) ? overlay.align : aligns.get(i),
                                        (valigns.size() <= i || StringTools.isNotValidString(valigns.get(i))) ? overlay.valign : valigns.get(i),
                                        (widths.size() <= i || StringTools.isNotValidString(widths.get(i))) ? overlay.width : widths.get(i),
                                        (heights.size() <= i || StringTools.isNotValidString(heights.get(i))) ? overlay.height : heights.get(i));
                                condition.positions.add(p);
                            }
                            overlay.positions.add(condition);
                        }
                    }
                    overlayLayers.add(overlay);
                    index++;
                }

                List blocks = c.configurationsAt(BLOCK);
                overlayBlocks.clear();
                for (HierarchicalConfiguration block : blocks) {
                    String name = block.getString("name");
                    if (StringTools.isNotValidString(name)) {
                        continue;
                    }
                    String dir = block.getString("dir");
                    dir = StringTools.isNotValidString(dir) ? "horizontal" : dir;
                    String size = block.getString("size");
                    size = StringTools.isNotValidString(size) ? AUTO : size;
                    String cols = block.getString("cols");
                    cols = StringTools.isNotValidString(cols) ? AUTO : cols;
                    String rows = block.getString("rows");
                    rows = StringTools.isNotValidString(rows) ? AUTO : rows;
                    String hmargin = block.getString("hmargin");
                    hmargin = StringTools.isNotValidString(hmargin) ? "0" : hmargin;
                    String vmargin = block.getString("vmargin");
                    vmargin = StringTools.isNotValidString(vmargin) ? "0" : vmargin;
                    String clones = block.getString("clones");
                    overlayBlocks.put(name, new LogosBlock(dir.equalsIgnoreCase("horizontal"),
                            size.equalsIgnoreCase("static"),
                            cols, rows, hmargin, vmargin, StringTools.isNotValidString(clones) ? blockClones : (clones.equalsIgnoreCase(TRUE) ? true : (clones.equalsIgnoreCase(FALSE) ? false : blockClones))));
                }
            } catch (Exception error) {
                logger.error("Failed parsing moviejukebox overlay configuration file: " + xmlOverlayFile.getName());
                logger.error(SystemTools.getStackTrace(error));
            }
        } else {
            logger.error("The moviejukebox overlay configuration file you specified is invalid: " + xmlOverlayFile.getName());
        }
    }

    protected boolean checkLogoEnabled(String name) {
        if (name.equalsIgnoreCase(LANGUAGE)) {
            return addLanguage;
        } else if (name.equalsIgnoreCase("subtitle")) {
            return addSubTitle;
        } else if (name.equalsIgnoreCase("set")) {
            return addSetLogo;
        } else if (name.equalsIgnoreCase("TV")) {
            return addTVLogo;
        } else if (name.equalsIgnoreCase("HD")) {
            return addHDLogo;
        } else if (name.equalsIgnoreCase("rating")) {
            return addRating;
        } else if (name.equalsIgnoreCase(VIDEOSOURCE) || name.equalsIgnoreCase("source") || name.equalsIgnoreCase("VS")) {
            return addVideoSource;
        } else if (name.equalsIgnoreCase("videoout") || name.equalsIgnoreCase("out") || name.equalsIgnoreCase("VO")) {
            return addVideoOut;
        } else if (name.equalsIgnoreCase("videocodec") || name.equalsIgnoreCase("vcodec") || name.equalsIgnoreCase("VC")) {
            return addVideoCodec;
        } else if (name.equalsIgnoreCase(AUDIOCODEC) || name.equalsIgnoreCase(ACODEC) || name.equalsIgnoreCase("AC")) {
            return addAudioCodec;
        } else if (name.equalsIgnoreCase(AUDIOCHANNELS) || name.equalsIgnoreCase(CHANNELS)) {
            return addAudioChannels;
        } else if (name.equalsIgnoreCase(AUDIOLANG) || name.equalsIgnoreCase(ALANG) || name.equalsIgnoreCase("AL")) {
            return addAudioLang;
        } else if (name.equalsIgnoreCase(CONTAINER)) {
            return addContainer;
        } else if (name.equalsIgnoreCase("aspect")) {
            return addAspectRatio;
        } else if (name.equalsIgnoreCase("fps")) {
            return addFPS;
        } else if (name.equalsIgnoreCase(CERTIFICATION)) {
            return addCertification;
        } else if (name.equalsIgnoreCase("watched")) {
            return addWatched;
        } else if (name.equalsIgnoreCase("episode")) {
            return addEpisode;
        } else if (name.equalsIgnoreCase("top250")) {
            return addTop250;
        } else if (name.equalsIgnoreCase(KEYWORDS)) {
            return addKeywords;
        } else if (name.equalsIgnoreCase(COUNTRY)) {
            return addCountry;
        } else if (name.equalsIgnoreCase(COMPANY)) {
            return addCompany;
        } else if (name.equalsIgnoreCase(AWARD)) {
            return addAward;
        }
        return !PropertiesUtil.getProperty(name, Movie.UNKNOWN).equals(Movie.UNKNOWN);
    }

    protected int getOverlayX(int fieldWidth, int itemWidth, Integer left, String align) {
        if (align.equalsIgnoreCase(LEFT)) {
            return (int) (left >= 0 ? left : fieldWidth + left);
        } else if (align.equalsIgnoreCase(RIGHT)) {
            return (int) (left >= 0 ? fieldWidth - left - itemWidth : -left - itemWidth);
        } else {
            return (int) (left == 0 ? ((fieldWidth - itemWidth) / 2) : left > 0 ? (fieldWidth / 2 + left) : (fieldWidth / 2 + left - itemWidth));
        }
    }

    protected int getOverlayY(int fieldHeight, int itemHeight, Integer top, String align) {
        if (align.equalsIgnoreCase(TOP)) {
            return (int) (top >= 0 ? top : fieldHeight + top);
        } else if (align.equalsIgnoreCase("bottom")) {
            return (int) (top >= 0 ? fieldHeight - top - itemHeight : -top - itemHeight);
        } else {
            return (int) (top == 0 ? ((fieldHeight - itemHeight) / 2) : top > 0 ? (fieldHeight / 2 + top) : (fieldHeight / 2 + top - itemHeight));
        }
    }

    protected void fillOverlayKeywords(Map> data, String value) {
        data.clear();
        if (StringTools.isValidString(value)) {
            String[] temp = value.split(" ; ");
            for (int i = 0; i < temp.length; i++) {
                String[] values = temp[i].split(Movie.SPACE_SLASH_SPACE);
                if (values.length > 1) {
                    ArrayList arr = new ArrayList(Arrays.asList(values));
                    data.put(values[0], arr);
                }
            }
        }
    }

    protected boolean cmpOverlayValue(String name, String condition, String value) {
        boolean result = ((name.equalsIgnoreCase(KEYWORDS) && value.indexOf(condition.toLowerCase()) > -1)
                || condition.equalsIgnoreCase(value)
                || condition.equalsIgnoreCase(DEFAULT));
        if (!result) {
            Map> data;
            if (name.equalsIgnoreCase("rating")) {
                data = keywordsRating;
            } else if (name.equalsIgnoreCase(VIDEOSOURCE) || name.equalsIgnoreCase("source") || name.equalsIgnoreCase("VS")) {
                data = keywordsVideoSource;
            } else if (name.equalsIgnoreCase("videoout") || name.equalsIgnoreCase("out") || name.equalsIgnoreCase("VO")) {
                data = keywordsVideoOut;
            } else if (name.equalsIgnoreCase("videocodec") || name.equalsIgnoreCase("vcodec") || name.equalsIgnoreCase("VC")) {
                data = keywordsVideoCodec;
            } else if (name.equalsIgnoreCase(AUDIOCODEC) || name.equalsIgnoreCase(ACODEC) || name.equalsIgnoreCase("AC")) {
                data = keywordsAudioCodec;
            } else if (name.equalsIgnoreCase(AUDIOCHANNELS) || name.equalsIgnoreCase(CHANNELS)) {
                data = keywordsAudioChannels;
            } else if (name.equalsIgnoreCase(AUDIOLANG) || name.equalsIgnoreCase(ALANG) || name.equalsIgnoreCase("AL")) {
                data = keywordsAudioLang;
            } else if (name.equalsIgnoreCase(CONTAINER)) {
                data = keywordsContainer;
            } else if (name.equalsIgnoreCase("aspect")) {
                data = keywordsAspectRatio;
            } else if (name.equalsIgnoreCase("fps")) {
                data = keywordsFPS;
            } else if (name.equalsIgnoreCase(CERTIFICATION)) {
                data = keywordsCertification;
            } else if (name.equalsIgnoreCase(KEYWORDS)) {
                data = keywordsKeywords;
            } else if (name.equalsIgnoreCase(COUNTRY)) {
                data = keywordsCountry;
            } else if (name.equalsIgnoreCase(COMPANY)) {
                data = keywordsCompany;
            } else if (name.equalsIgnoreCase(AWARD)) {
                data = keywordsAward;
            } else {
                return false;
            }
            ArrayList arr = data.get(condition);
            if (arr != null) {
                for (int loop = 0; loop < arr.size(); loop++) {
                    if (name.equalsIgnoreCase(KEYWORDS)) {
                        result = value.indexOf(arr.get(loop).toLowerCase()) > -1;
                    } else {
                        result = arr.get(loop).equalsIgnoreCase(value);
                    }
                    if (result) {
                        break;
                    }
                }
            }
        }
        return result;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy