/**
 * Copyright (C) 2010 Orbeon, Inc.
 *
 * This program is free software; you can redistribute it and/or modify it under the terms of the
 * GNU Lesser General Public License as published by the Free Software Foundation; either version
 * 2.1 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU Lesser General Public License for more details.
 *
 * The full text of the license is available at http://www.gnu.org/copyleft/lesser.html
 */
package org.orbeon.oxf.xforms.function.xxforms;

import org.orbeon.oxf.pipeline.api.PipelineContext;
import org.orbeon.oxf.processor.transformer.TransformerURIResolver;
import org.orbeon.oxf.xforms.function.XFormsFunction;
import org.orbeon.oxf.xml.XMLParsing;
import org.orbeon.oxf.xml.XMLReceiverAdapter;
import org.orbeon.saxon.expr.ExpressionVisitor;
import org.orbeon.saxon.expr.StaticContext;
import org.orbeon.saxon.expr.XPathContext;
import org.orbeon.saxon.om.Item;
import org.orbeon.saxon.trans.XPathException;
import org.orbeon.saxon.value.BooleanValue;
import org.orbeon.saxon.value.StringValue;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;

import javax.xml.transform.sax.SAXSource;

/*
 * NOTE: this class inspired by Saxon's UnparsedText.java.
 */
public class XXFormsDocBase64 extends XFormsFunction {

    private String expressionBaseURI;

    public static final int DOC_BASE64 = 0;
    public static final int DOC_BASE64_AVAILABLE = 1;

    @Override
    public void checkArguments(ExpressionVisitor visitor) throws XPathException {
        if (expressionBaseURI == null) {
            final StaticContext env = visitor.getStaticContext();
            super.checkArguments(visitor);
            expressionBaseURI = env.getBaseURI();
        }
    }

    @Override
    public Item evaluateItem(XPathContext context) throws XPathException {
        final StringValue result;
        try {
            final StringValue url = (StringValue) argument[0].evaluateItem(context);
            if (url == null) {
                return null;
            }

            result = new StringValue(readFile(url.getStringValue(), expressionBaseURI));
        } catch (XPathException e) {
            if (operation == DOC_BASE64_AVAILABLE) {
                return BooleanValue.FALSE;
            } else {
                throw e;
            }
        }
        if (operation == DOC_BASE64_AVAILABLE) {
            return BooleanValue.TRUE;
        } else {
            return result;
        }
    }

    private CharSequence readFile(String href, String baseURI) throws XPathException {
        try {

            // Use resolver as it does a series of tasks for us, and use "binary" mode
            final TransformerURIResolver resolver = new TransformerURIResolver(null, PipelineContext.get(), null, XMLParsing.ParserConfiguration.PLAIN, "binary");

            final StringBuilder sb = new StringBuilder(1024);

            // Get SAX source using crazy SAX API
            // Source produces a binary document (content Base64-encoded)
            final SAXSource source = (SAXSource) resolver.resolve(href, baseURI);
            final XMLReader xmlReader = source.getXMLReader();
            xmlReader.setContentHandler(new XMLReceiverAdapter() {
                public void characters(char ch[], int start, int length) throws SAXException {
                    // Append Base64-encoded text only
                    sb.append(ch, start, length);
                }
            });
            xmlReader.parse(source.getInputSource());

            // Return content formatted as Base64
            return sb.toString();
        } catch (Exception e) {
            throw new XPathException(e);
        }
    }
}
