/************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
 * 
 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
 * Copyright 2009 IBM. All rights reserved.
 * 
 * Use is subject to license terms.
 * 
 * Licensed 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. You can also
 * obtain a copy of the License at http://odftoolkit.org/docs/license.txt
 * 
 * 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.odftoolkit.odfdom.doc.element.table;

import org.odftoolkit.odfdom.doc.OdfFileDom;
import org.odftoolkit.odfdom.dom.element.table.OdfCoveredTableCellElement;
import org.odftoolkit.odfdom.dom.element.table.OdfTableRowElement;
import org.odftoolkit.odfdom.dom.type.OdfPositiveInteger;
import org.odftoolkit.odfdom.dom.util.DomNodeList;

import org.w3c.dom.DOMException;
import org.w3c.dom.Node;

public class OdfTableRow extends OdfTableRowElement {


	private static final long serialVersionUID = -786721372779697783L;
	private int mCurrentNumberOfColumns = 0;

    /** Creates a new instance of this class */
    public OdfTableRow(OdfFileDom ownerDoc) {
        super(ownerDoc);
    }

    //@Override
    public OdfTable getTable() {
        return getAncestorAs(OdfTable.class);
    }

    public Node removeCell(Node remChild) throws DOMException {
        if (remChild instanceof OdfTableCell) {
            OdfTableCell td = (OdfTableCell) remChild;
            int nColSpan = td.getNumberColumnsSpanned().intValue();
            int nColRepeat = td.getNumberColumnsRepeated().intValue();
            int nColVanish = Math.max(nColSpan, nColRepeat);
            mCurrentNumberOfColumns -= nColVanish;
        }
        return super.removeChild(remChild);
    }

    public Node appendCell(Node newChild) throws DOMException {

        // If a covered cell is inserted which is not auto generated,
        // then we have to check whether this replaces an auto generated
        // covered cell that is been inserted previously
        // covered cells have been inserted automatically. We have to
        // replace the first auto generated node we find, but have to stop the
        // (backward) search whenever we find a non auto generated cell.
        OdfCoveredTableCell aOldCoveredCell = null;
        if (newChild instanceof OdfCoveredTableCell &&
                !((OdfCoveredTableCell) newChild).isAutoGenerated()) {
            Node aTestNode = super.getLastChild();
            while (aTestNode != null) {
                if (aTestNode instanceof OdfCoveredTableCell) {
                    if (((OdfCoveredTableCell) aTestNode).isAutoGenerated()) {
                        aOldCoveredCell = (OdfCoveredTableCell) aTestNode;
                    } else {
                        break;
                    }
                } else if (aTestNode instanceof OdfTableCell) {
                    break;
                }
                aTestNode = aTestNode.getPreviousSibling();
            }
        }

        Node aNode = null;
        if (aOldCoveredCell != null) {
            ((OdfCoveredTableCell) newChild).setNumberRowsSpanned(aOldCoveredCell.getNumberRowsSpanned());
            ((OdfCoveredTableCell) newChild).setNumberColumnsSpanned(aOldCoveredCell.getNumberColumnsSpanned());
            aNode = newChild;
            Node nextCovered = aOldCoveredCell.getNextSibling();
            replaceChild(newChild, aOldCoveredCell);

            // in case the table cell is repeated, we have to remove up to repeat autogenerated
            // covered cells:
            int repeated = ((OdfCoveredTableCell)newChild).getNumberColumnsRepeated().intValue();
            while (repeated > 1 && nextCovered != null && nextCovered instanceof OdfCoveredTableCell &&
                    ((OdfCoveredTableCell) nextCovered).isAutoGenerated()) {
                Node removeNode = nextCovered;
                nextCovered = nextCovered.getNextSibling();
                removeChild(removeNode);
                --repeated;
                --mCurrentNumberOfColumns;
            }
        } else {
            aNode = super.appendChild(newChild);
        }

        if (aNode instanceof OdfTableCell) {
            OdfTableCell td = (OdfTableCell) aNode;
            int nColSpan = td.getNumberColumnsSpanned().intValue();
            int nColRepeat = td.getNumberColumnsRepeated().intValue();
            int nStartCol = mCurrentNumberOfColumns; // optimization
            //int nStartCol = td.getColumnIndex();
            int nColAdd = Math.max(nColSpan, nColRepeat);
            int nEndCol = nStartCol + nColAdd;

            // take care of table columns
            // if there is no table column forthis element create new
            // table columns
            OdfTable table = getTable();
            if (table != null) {
                int count = table.getTableColumnCount(); // table.getCurrentNumberOfColumns(); => member;
                if (count < nEndCol) {
                    if(nColRepeat > 1){
                        table.addTableColumn(nEndCol - count); // sets member at table!
                    }else{
                        for(int i = 0; i < nEndCol - count; ++i){
                            table.addTableColumn(1); // sets member at table!
                        }
                    }
                }
            }

            mCurrentNumberOfColumns += nColAdd;

            if (nColSpan > 1) {
                appendCoveredCells(nColSpan - 1, td.getNumberRowsSpanned().intValue(), aNode);
            }
            inheritSpannedCells(nEndCol);
        }
        return aNode;
    }

    private void appendCoveredCells(int nColSpan, int nRowSpan, Node aNode) {
        while (nColSpan > 0) {
            OdfCoveredTableCell aCTC =
                    (OdfCoveredTableCell) getOwnerDocument().createElementNS(
                    OdfCoveredTableCellElement.ELEMENT_NAME.getUri(),
                    OdfCoveredTableCellElement.ELEMENT_NAME.getQName());
            aCTC.setNumberColumnsSpanned(new OdfPositiveInteger(nColSpan));
            aCTC.setNumberRowsSpanned(new OdfPositiveInteger(nRowSpan));
            aCTC.setAutoGenerated();
            appendChild(aCTC);

            --nColSpan;
        }
    }

    public void inheritSpannedCells(int nCol) {
        OdfTableRow aPrevRow = getPreviousRow();
        if (aPrevRow == null) {
            return;
        }

        Node aUpperNode = aPrevRow.getCellAt(nCol);
        if (aUpperNode == null) {
            return;
        }

        int nCoveredCellsToAdd = 0;
        int nUpperRowSpan = 1;
        if (aUpperNode instanceof OdfTableCell) {
            OdfTableCell aUpperCell = (OdfTableCell) aUpperNode;
            nUpperRowSpan = aUpperCell.getNumberRowsSpanned().intValue();
            if (nUpperRowSpan > 1) {
                nCoveredCellsToAdd = aUpperCell.getNumberColumnsSpanned().intValue();
            }
        }
        if (aUpperNode instanceof OdfCoveredTableCell) {
            OdfCoveredTableCell aUpperCell = (OdfCoveredTableCell) aUpperNode;
            nUpperRowSpan = aUpperCell.getNumberRowsSpanned().intValue();
            if (nUpperRowSpan > 1) {

                nCoveredCellsToAdd = aUpperCell.getNumberColumnsSpanned().intValue();
            }
        }
        if (nCoveredCellsToAdd == 0) {
            return;
        }

        mCurrentNumberOfColumns += nCoveredCellsToAdd;
        appendCoveredCells(nCoveredCellsToAdd, nUpperRowSpan - 1, null);

    }

    public OdfTableRow getPreviousRow() {
        Node aPrevNode = getPreviousSibling();
        while (aPrevNode != null) {
            if (aPrevNode instanceof OdfTableRow) {
                return (OdfTableRow) aPrevNode;
            }
            /*if( aPrevNode instanceof OdfTableHeaderRows )
            {
            OdfTableHeaderRows aRows = (OdfTableHeaderRows)aPrevNode;
            return aRows.getPreviousRow();
            }*/
            aPrevNode = aPrevNode.getPreviousSibling();
        }
        /*if( aPrevNode == null )
        {
        Node aParentNode = getParentNode();
        if( aParentNode != null && aParentNode instanceof OdfTableRowContainer )
        {
        OdfTableRowContainer aRows = (OdfTableRowContainer)aParentNode;
        return aRows.getPreviousRow();
        }
        }*/

        return null;
    }

    public Node getCellAt(int nCol) {
        for (Node n : new DomNodeList(getChildNodes())) {
            if (n instanceof OdfTableCell ||
                    n instanceof OdfCoveredTableCell) {
                if (nCol == 0) {
                    return n;
                } else {
                    nCol = nCol - ((OdfTableCellBase) n).getNumberColumnsRepeated().intValue();
                }
            }
        }

        return null;
    }
}
