/* ====================================================================
   Licensed to the Apache Software Foundation (ASF) under one or more
   contributor license agreements.  See the NOTICE file distributed with
   this work for additional information regarding copyright ownership.
   The ASF licenses this file to You under the Apache License, Version 2.0
   (the "License"); you may not use this file except in compliance with
   the License.  You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
==================================================================== */
package org.apache.poi.xwpf.usermodel;


import javax.xml.namespace.QName;

import org.apache.xmlbeans.XmlCursor;
import org.apache.xmlbeans.XmlCursor.TokenType;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTSdtContentCell;


/**
 * Experimental class to offer rudimentary read-only processing of
 * of the XWPFSDTCellContent.
 * <p>
 * WARNING - APIs expected to change rapidly
 */
public class XWPFSDTContentCell implements ISDTContent {

    //A full implementation would grab the icells
    //that a content cell can contain.  This would require
    //significant changes, including changing the notion that the
    //parent of a cell can be not just a row, but an sdt.
    //For now we are just grabbing the text out of the text tokentypes.

    //private List<ICell> cells = new ArrayList<ICell>().

    private final CTSdtContentCell sdtContentCell;
    private String text;

    public XWPFSDTContentCell(CTSdtContentCell sdtContentCell,
                              XWPFTableRow xwpfTableRow, IBody part) {
        super();
        this.sdtContentCell = sdtContentCell;
    }

    private String extractTextFromSdtContentCell() {
        //sdtContentCell is allowed to be null:  minOccurs="0" maxOccurs="1"
        if (sdtContentCell == null) {
            return "";
        }
        StringBuilder sb = new StringBuilder();
        try (final XmlCursor cursor = sdtContentCell.newCursor()) {
            //keep track of the following,
            //and add "\n" only before the start of a body
            //element if it is not the first body element.

            //index of cell in row
            int tcCnt = 0;
            //count of body objects
            int iBodyCnt = 0;
            int depth = 1;

            while (cursor.hasNextToken() && depth > 0) {
                TokenType t = cursor.toNextToken();
                if (t.isText()) {
                    sb.append(cursor.getTextValue());
                } else if (isStartToken(cursor, "tr")) {
                    tcCnt = 0;
                    iBodyCnt = 0;
                } else if (isStartToken(cursor, "tc")) {
                    if (tcCnt++ > 0) {
                        sb.append("\t");
                    }
                    iBodyCnt = 0;
                } else if (isStartToken(cursor, "p") ||
                        isStartToken(cursor, "tbl") ||
                        isStartToken(cursor, "sdt")) {
                    if (iBodyCnt > 0) {
                        sb.append("\n");
                    }
                    iBodyCnt++;
                }
                if (cursor.isStart()) {
                    depth++;
                } else if (cursor.isEnd()) {
                    depth--;
                }
            }
            return sb.toString();
        }
    }

    private boolean isStartToken(XmlCursor cursor, String string) {
        if (!cursor.isStart()) {
            return false;
        }
        QName qName = cursor.getName();
        if (qName != null && qName.getLocalPart() != null &&
                qName.getLocalPart().equals(string)) {
            return true;
        }
        return false;
    }

    @Override
    public String getText() {
        if (text == null) {
            text = extractTextFromSdtContentCell();
        }
        return text;
    }

    @Override
    public String toString() {
        return getText();
    }

    /**
     * Return the underlying XML bean.
     * @return the underlying CTSdtContentCell bean.
     * @since POI 5.5.0
     */
    public CTSdtContentCell getCTSdtContentCell() {
        return sdtContentCell;
    }
}
