package com.brilliance.isc.doc.handle.impl.common;

import org.slf4j.LoggerFactory;
import org.slf4j.Logger;
import com.lowagie.text.BadElementException;
import com.lowagie.text.Image;
import org.bouncycastle.util.encoders.Base64;
import org.w3c.dom.Element;
import org.xhtmlrenderer.extend.FSImage;
import org.xhtmlrenderer.extend.ReplacedElement;
import org.xhtmlrenderer.extend.ReplacedElementFactory;
import org.xhtmlrenderer.extend.UserAgentCallback;
import org.xhtmlrenderer.layout.LayoutContext;
import org.xhtmlrenderer.pdf.ITextFSImage;
import org.xhtmlrenderer.pdf.ITextImageElement;
import org.xhtmlrenderer.render.BlockBox;
import org.xhtmlrenderer.simple.extend.DefaultFormSubmissionListener;
import org.xhtmlrenderer.simple.extend.FormSubmissionListener;

import java.io.IOException;
import java.util.Map;

public class Base64ImgReplacedElementFactory implements ReplacedElementFactory {

    private final Logger logger = LoggerFactory.getLogger(Base64ImgReplacedElementFactory.class);

    private Map<String,String> imgMap;

    public Base64ImgReplacedElementFactory(Map<String,String> imgMap){
        this.imgMap = imgMap;
    }

    /**
     * <b>NOTE:</b> Only block equivalent elements can be replaced.
     *
     * @param c
     * @param box
     * @param uac
     * @param cssWidth  The CSS width of the element in dots (or <code>-1</code> if
     *                  width is <code>auto</code>)
     * @param cssHeight The CSS height of the element in dots (or <code>-1</code>
     *                  if the height should be treated as <code>auto</code>)
     * @return The <code>ReplacedElement</code> or <code>null</code> if no
     * <code>ReplacedElement</code> applies
     */
    @Override
    public ReplacedElement createReplacedElement(LayoutContext c, BlockBox box, UserAgentCallback uac, int cssWidth, int cssHeight) {
        Element e = box.getElement();
        if(e == null){
            return null;
        }
        String nodeName = e.getNodeName();
        if(nodeName.equalsIgnoreCase("img")){
            String attribute = e.getAttribute("src");
            FSImage fsImage;
            try{
                fsImage = buildImage(attribute,uac);
            } catch (BadElementException ex) {
                logger.warn("base64转image失败:{}",ex);
                fsImage = null;
            } catch (IOException ex) {
                logger.warn("base64转image失败:{}",ex);
                fsImage = null;
            }
            if(fsImage != null){
                if(cssWidth != -1 || cssHeight !=-1){
                    fsImage.scale(cssWidth,cssHeight);
                }
                return new ITextImageElement(fsImage);
            }
        }
        return null;
    }

    protected FSImage buildImage(String srcAttr,UserAgentCallback uac) throws IOException, BadElementException {
        FSImage fsImage;
        if(srcAttr.startsWith("data:image/")){
            String key = srcAttr.substring("data:image/".length());
            if(imgMap.containsKey(key)){
                srcAttr = imgMap.get(key);
            }
            String b64encoded = srcAttr.substring(srcAttr.indexOf("base64,")+"base64,".length());
            byte[] decodeBytes = Base64.decode(b64encoded);
            fsImage = new ITextFSImage(Image.getInstance(decodeBytes));
        }else{
            fsImage = uac.getImageResource(srcAttr).getImage();
        }
        return fsImage;
    }

    /**
     * Instructs the <code>ReplacedElementFactory</code> to discard any cached
     * data (typically because a new page is about to be loaded).
     */
    @Override
    public void reset() {

    }

    /**
     * Removes any reference to <code>Element</code> <code>e</code>.
     *
     * @param e
     */
    @Override
    public void remove(Element e) {

    }

    /**
     * Identifies the FSL which will be used for callbacks when a form submit action is executed; you can use a
     * {@link DefaultFormSubmissionListener} if you don't want any action to be taken.
     *
     * @param listener the listener instance to receive callbacks on form submission.
     */
    @Override
    public void setFormSubmissionListener(FormSubmissionListener listener) {

    }
}
