/************************************************************************
 *
 *  MathmlConverter.java
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library 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.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *  Copyright: 2002-2007 by Henrik Just
 *
 *  All Rights Reserved.
 * 
 *  Version 0.4.2 (2007-04-02)
 *
 */

package writer2latex.latex;

import java.util.Hashtable;

import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import writer2latex.latex.i18n.I18n;
import writer2latex.office.MIMETypes;
import writer2latex.office.OfficeReader;
import writer2latex.office.XMLString;
import writer2latex.util.Config;
import writer2latex.util.Misc;
import writer2latex.xmerge.EmbeddedObject;
import writer2latex.xmerge.EmbeddedXMLObject;

/**
 *  <p>This class converts mathml nodes to LaTeX.
 *  (Actually it only converts the starmath annotation currently, if available).</p>
 */
public final class MathmlConverter extends ConverterHelper {
    
    private StarMathConverter smc;
	
    private boolean bContainsFormulas = false;
	
    public MathmlConverter(OfficeReader ofr,Config config, ConverterPalette palette) {
        super(ofr,config,palette);
        smc = new StarMathConverter(palette.getI18n(),config);
    }

    public void appendDeclarations(LaTeXDocumentPortion pack, LaTeXDocumentPortion decl) {
        if (bContainsFormulas) {
            if (config.useOoomath()) {
                pack.append("\\usepackage{ooomath}").nl();
            }
            else {
                smc.appendDeclarations(pack,decl);
            }
            //decl.append("\\everymath{\\displaystyle}").nl();
        }
    }
	
    public String convert(Node settings, Node formula) {
        // TODO: Use settings to determine display mode/text mode
        // formula must be a math:math node
        // First try to find a StarMath annotation
        Node semantics = Misc.getChildByTagName(formula,XMLString.MATH_SEMANTICS);
		if (semantics!=null) {
            Node annotation = Misc.getChildByTagName(semantics,XMLString.MATH_ANNOTATION);
            if (annotation!=null) {
                String sStarMath = "";
                if (annotation.hasChildNodes()) {
                    NodeList anl = annotation.getChildNodes();
                    int nLen = anl.getLength();
                    for (int i=0; i<nLen; i++) {
                        if (anl.item(i).getNodeType() == Node.TEXT_NODE) {
                            sStarMath+=anl.item(i).getNodeValue();
                        }
                    }
                    bContainsFormulas = true;      
                    return smc.convert(sStarMath);
                }
            }
        }
        // No annotation was found. In this case we should convert the mathml,
        // but currently we ignore the problem.
        // TODO: Investigate if Vasil I. Yaroshevich's MathML->LaTeX
        // XSL transformation could be used here. (Potential problem:
        // OOo uses MathML 1.01, not MathML 2)
        return "\\text{Warning: No StarMath annotation}";
    }
	
    /**<p>Try to convert a paragraph as a display equation</p>
     * <p>Currently a display equation is a paragraph which contains only
     * whitespace + a single math object</p>
     * @param node the paragraph
     * @param ldp the LaTeXDocumentPortion to contain the converted equation
     * @return true if the conversion was succesful, false if the paragraph
     * did not contain a display equation
     */
    public boolean handleDisplayEquation(Node node, LaTeXDocumentPortion ldp) {
        if (parseDisplayFormula(node,0)==1) {
            ldp.append("\\[").append(convert(null,theFormula)).append("\\]").nl();
            return true;
        }
        else {
            return false;
        }
    }
	
    private Node theFormula = null; // only used by handleDisplayEquation
	
    private int parseDisplayFormula(Node node, int nParserStatus) {
        // nParserStatus = 0 : before equation
        // nParserStatus = 1 : after equation
        // nParserStatus = 2 : after illegal content
        Node child = node.getFirstChild();
        while (child!=null) {
            Node formula = getFormula(child);
            if (formula!=null) {
                theFormula = formula;
                nParserStatus++;
            }
            else if (Misc.isElement(child,XMLString.TEXT_SPAN)) {
                nParserStatus = parseDisplayFormula(child,nParserStatus);
            }
            else if (Misc.isElement(child)) {
                if (Misc.isElement(child,XMLString.TEXT_S)) {
                    // Spaces are allowed
                }
                else if (Misc.isElement(child,XMLString.TEXT_TAB)) {
                    // Tab stops are allowed
                }
                else if (Misc.isElement(child,XMLString.TEXT_TAB_STOP)) { // old
                    // Tab stops are allowed
                }
                else if (Misc.isElement(child)) {
                    // Other elements are illegal
                    nParserStatus = 2;
                }
            }
            else if (Misc.isText(child)) {
                if (!ofr.isWhitespace(child.getNodeValue())) { nParserStatus = 2; }
            }

            if (nParserStatus>=2) { return 2; }

            child = child.getNextSibling();
        }
        return nParserStatus;
    }
	
    // TODO: Extend OfficeReader to handle frames
    private Node getFormula(Node node) {
        if (Misc.isElement(node,XMLString.DRAW_FRAME)) {
            node=Misc.getFirstChildElement(node);
        }

        String sHref = Misc.getAttribute(node,XMLString.XLINK_HREF);
		
        if (sHref!=null) { // Embedded object in package or linked object
            if (ofr.isInPackage(sHref)) { // Embedded object in package
                if (sHref.startsWith("#")) { sHref=sHref.substring(1); }
                if (sHref.startsWith("./")) { sHref=sHref.substring(2); }
                EmbeddedObject object = palette.getEmbeddedObject(sHref); 
                if (object!=null) {
                    if (MIMETypes.MATH.equals(object.getType()) || MIMETypes.ODF.equals(object.getType())) { // Formula!
                        try {
                            Document formuladoc = ((EmbeddedXMLObject) object).getContentDOM();
                            return Misc.getChildByTagName(formuladoc,XMLString.MATH_MATH);
                        }
                        catch (org.xml.sax.SAXException e) {
                            e.printStackTrace();
                        }
                        catch (java.io.IOException e) {
                            e.printStackTrace();
                        }
	                }
                }
            }
        }
        else { // flat xml, object is contained in node
            return Misc.getChildByTagName(node,XMLString.MATH_MATH);
        }
        return null;
    }
	


}