/************************************************************************
 *
 *  CaptionConverter.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.5 (2007-06-14)
 *
 */
 
package writer2latex.latex;

import org.w3c.dom.Element;
import org.w3c.dom.Node;

import writer2latex.latex.util.Context;
import writer2latex.office.OfficeReader;
import writer2latex.office.XMLString;
import writer2latex.util.Config;

/**
 *  <p>This class converts captions (for figures and tables) to LaTeX.</p>
 *  <p>Packages:
 *  <ul><li>caption.sty is used implement non-floating captions</li></ul>
 *  <p>Options:
 *  <ul><li>use_caption is a boolean option to determine whether or not
 *  to use caption.sty. If this option is set to false, a simple definition of
 *  \captionof (borrowed from capt-of.sty) is inserted in the preamble</li></ul>
 *  <p>TODO: Implement formatting of captions using the features of caption.sty
 *  (only if formatting>=CONVERT_BASIC)
 */
public class CaptionConverter extends ConverterHelper {

    private boolean bNeedCaptionOf = false;
	
    private Element seqField = null; // the sequence field within the current caption

    public CaptionConverter(OfficeReader ofr, Config config, ConverterPalette palette) {
        super(ofr,config,palette);
    }

    public void appendDeclarations(LaTeXDocumentPortion pack, LaTeXDocumentPortion decl) {
        if (bNeedCaptionOf) {
            if (config.useCaption()) {
                pack.append("\\usepackage{caption}").nl();
            }
            else { // use definition borrowed from capt-of.sty
                decl.append("% Non-floating captions").nl()
                    .append("\\makeatletter").nl()
                    .append("\\newcommand\\captionof[1]{\\def\\@captype{#1}\\caption}").nl()
                    .append("\\makeatother").nl();
            }
        }
    }
	
    /**
     * <p> Process content of a text:p tag as a caption body (inluding label)</p>
     *  @param <code>node</code> The text:p element node containing the caption
     *  @param <code>ldp</code> The <code>LaTeXDocumentPortion</code> to add LaTeX code to
     *  @param <code>oc</code> The current context
     *  @param <code>bIsCaptionOf</code> true if this is caption uses captionof 
     */
    public void handleCaptionBody(Element node,LaTeXDocumentPortion ldp, Context oc, boolean bIsCaptionOf) {
        bNeedCaptionOf|=bIsCaptionOf;

        // Get rid of the caption label before converting
        removeCaptionLabel(node,0);
        Element label = seqField;
        seqField = null;

        // Get the stylename of the paragraph and push the font used
        String sStyleName = node.getAttribute(XMLString.TEXT_STYLE_NAME);
        palette.getI18n().pushSpecialTable(palette.getCharSc().getFontName(ofr.getParStyle(sStyleName)));
		
        if (palette.getHeadingCv().containsElements(node)) {
            ldp.append("[");
            palette.getInlineCv().traversePlainInlineText(node,ldp,oc);
            ldp.append("]");
        }
        // Update context before traversing text
        Context ic = (Context) oc.clone();
        ldp.append("{");
        palette.getInlineCv().traverseInlineText(node,ldp,ic,false);
        ldp.append("}").nl();

        // Insert label
        palette.getFieldCv().handleSequence(label,ldp,oc);

        // Flush any index marks
        palette.getIndexCv().flushIndexMarks(ldp,oc);

        // pop the font name
        palette.getI18n().popSpecialTable();

    }
	
    // In OpenDocument a caption is an ordinary paragraph with a text:seqence
    // element. For example
    // Table <text:sequence>3</text:sequence>: Caption text
    // The first part is the caption label which is autogenerated by LaTeX.
    // Before converting, we remove this in 3 steps:
    //   nStep = 0: Remove all text before the text:sequence
    //   nStep = 1: Remove all text up to the first alphanumeric character
    //              after the text:sequence
    //   nStep = 2: Finished!
    private int removeCaptionLabel(Element node, int nStep) {
        if (nStep==2) { return 2; }

        Node removeMe = null;

        Node child = node.getFirstChild();
        while (child!=null) {
            if (child.getNodeType()==Node.ELEMENT_NODE) {
                if (nStep==0 && child.getNodeName().equals(XMLString.TEXT_SEQUENCE)) {
                    removeMe = child; 
                    seqField = (Element) child; // remember me...
                    nStep = 1;
                }
                else if (nStep<2 && !ofr.isDrawElement(child)) {
                    // draw elements (frames) should not be touched..
                    nStep = removeCaptionLabel((Element)child,nStep);
                }
            }
            else if (child.getNodeType()==Node.TEXT_NODE) {
                if (nStep==0) {
                    child.setNodeValue("");
                }
                else if (nStep==1) {
                    String s = child.getNodeValue();
                    int n = s.length();
                    for (int j=0; j<n; j++) {
                        if (Character.isLetterOrDigit(s.charAt(j))) {
                            child.setNodeValue(s.substring(j));
                            nStep = 2;
                            break;
                        }
	                }
                }
            }
            child = child.getNextSibling();
        }

        if (removeMe!=null) { node.removeChild(removeMe); }
        return nStep;
    }
	

}