/*
 * 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.
 */

/* $Id$ */

package org.apache.fop.layoutmgr;

import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import java.util.Stack;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.apache.fop.area.Area;
import org.apache.fop.area.BlockParent;
import org.apache.fop.fo.pagination.Flow;
import org.apache.fop.util.ListUtil;

/**
 * LayoutManager for an fo:flow object.
 * Its parent LM is the PageSequenceLayoutManager.
 * This LM is responsible for getting columns of the appropriate size
 * and filling them with block-level areas generated by its children.
 * TODO Reintroduce emergency counter (generate error to avoid endless loop)
 */
public class FlowLayoutManager extends BlockStackingLayoutManager {

    /**
     * logging instance
     */
    private static Log log = LogFactory.getLog(FlowLayoutManager.class);

    /** Array of areas currently being filled stored by area class */
    private final BlockParent[] currentAreas = new BlockParent[Area.CLASS_MAX];

    private boolean handlingFloat;

    /**
     * This is the top level layout manager.
     * It is created by the PageSequence FO.
     * @param pslm parent PageSequenceLayoutManager object
     * @param node Flow object
     */
    public FlowLayoutManager(PageSequenceLayoutManager pslm, Flow node) {
        super(node);
        setGeneratesBlockArea(true);
        setParent(pslm);
    }

    /** {@inheritDoc} */
    @Override
    public List getNextKnuthElements(LayoutContext context, int alignment) {
        return getNextKnuthElements(context, alignment, null, null);
    }

    /**
     * Get a sequence of KnuthElements representing the content
     * of the node assigned to the LM.
     * @param context   the LayoutContext used to store layout information
     * @param alignment the desired text alignment
     * @param restartPosition   {@link Position} to restart from
     * @param restartLM {@link LayoutManager} to restart from
     * @return the list of KnuthElements
     * @see LayoutManager#getNextKnuthElements(LayoutContext,int)
     */
    List getNextKnuthElements(LayoutContext context, int alignment,
            Position restartPosition, LayoutManager restartLM) {

        List<ListElement> elements = new LinkedList<ListElement>();

        boolean isRestart = (restartPosition != null);
        // always reset in case of restart (exception: see below)
        boolean doReset = isRestart;
        LayoutManager currentChildLM;
        Stack<LayoutManager> lmStack = new Stack<LayoutManager>();
        if (isRestart) {
            currentChildLM = restartPosition.getLM();
            if (currentChildLM == null) {
                throw new IllegalStateException("Cannot find layout manager to restart from");
            }
            if (restartLM != null && restartLM.getParent() == this) {
                currentChildLM = restartLM;
            } else {
                while (currentChildLM.getParent() != this) {
                    lmStack.push(currentChildLM);
                    currentChildLM = currentChildLM.getParent();
                }
                doReset = false;
            }
            setCurrentChildLM(currentChildLM);
        } else {
            currentChildLM = getChildLM();
        }

        while (currentChildLM != null) {
            if (!isRestart || doReset) {
                if (doReset) {
                    currentChildLM.reset(); // TODO won't work with forced breaks
                }
                if (addChildElements(elements, currentChildLM, context, alignment,
                        null, null, null) != null) {
                    return elements;
                }
            } else {
                if (addChildElements(elements, currentChildLM, context, alignment, lmStack,
                        restartPosition, restartLM) != null) {
                    return elements;
                }
                // restarted; force reset as of next child
                doReset = true;
            }
            currentChildLM = getChildLM();
        }

        SpaceResolver.resolveElementList(elements);
        setFinished(true);

        assert !elements.isEmpty();
        return elements;
    }

    private List<ListElement> addChildElements(List<ListElement> elements,
            LayoutManager childLM, LayoutContext context, int alignment,
            Stack<LayoutManager> lmStack, Position position, LayoutManager restartAtLM) {
        if (handleSpanChange(childLM, context)) {
            SpaceResolver.resolveElementList(elements);
            return elements;
        }

        LayoutContext childLC = makeChildLayoutContext(context);
        List<ListElement> childElements
                = getNextChildElements(childLM, context, childLC, alignment, lmStack,
                    position, restartAtLM);
        if (elements.isEmpty()) {
            context.updateKeepWithPreviousPending(childLC.getKeepWithPreviousPending());
        }
        if (!elements.isEmpty()
                && !ElementListUtils.startsWithForcedBreak(childElements)) {
            addInBetweenBreak(elements, context, childLC);
        }
        context.updateKeepWithNextPending(childLC.getKeepWithNextPending());

        elements.addAll(childElements);

        if (ElementListUtils.endsWithForcedBreak(elements)) {
            // a descendant of this flow has break-before or break-after
            if (childLM.isFinished() && !hasNextChildLM()) {
                setFinished(true);
            }
            SpaceResolver.resolveElementList(elements);
            return elements;
        }
        return null;
    }

    private boolean handleSpanChange(LayoutManager childLM, LayoutContext context) {
        int span = EN_NONE;
        int disableColumnBalancing = EN_FALSE;
        if (childLM instanceof BlockLayoutManager) {
            span = ((BlockLayoutManager)childLM).getBlockFO().getSpan();
            disableColumnBalancing = ((BlockLayoutManager) childLM).getBlockFO()
                    .getDisableColumnBalancing();
        } else if (childLM instanceof BlockContainerLayoutManager) {
            span = ((BlockContainerLayoutManager)childLM).getBlockContainerFO().getSpan();
            disableColumnBalancing = ((BlockContainerLayoutManager) childLM).getBlockContainerFO()
                    .getDisableColumnBalancing();
        }

        int currentSpan = context.getCurrentSpan();
        if (currentSpan != span) {
            if (span == EN_ALL) {
                context.setDisableColumnBalancing(disableColumnBalancing);
            }
            log.debug("span change from " + currentSpan + " to " + span);
            context.signalSpanChange(span);
            return true;
        } else {
            return false;
        }
    }

    /**
     * Overridden to take into account the current page-master's
     * writing-mode
     * {@inheritDoc}
     */
    @Override
    protected LayoutContext makeChildLayoutContext(LayoutContext context) {
        LayoutContext childLC = LayoutContext.newInstance();
        childLC.setStackLimitBP(context.getStackLimitBP());
        childLC.setRefIPD(context.getRefIPD());
        childLC.setWritingMode(getCurrentPage().getSimplePageMaster().getWritingMode());
        return childLC;
    }

    /**
     * Overridden to wrap the child positions before returning the list
     * {@inheritDoc}
     */
    @Override
    protected List<ListElement> getNextChildElements(LayoutManager childLM, LayoutContext context,
            LayoutContext childLC, int alignment, Stack<LayoutManager> lmStack,
            Position restartPosition, LayoutManager restartLM) {

        List<ListElement> childElements;
        if (lmStack == null) {
            childElements = childLM.getNextKnuthElements(childLC, alignment);
        } else {
            childElements = childLM.getNextKnuthElements(childLC, alignment,
                    lmStack, restartPosition, restartLM);
        }
        assert !childElements.isEmpty();

        // "wrap" the Position inside each element
        List tempList = childElements;
        childElements = new LinkedList<ListElement>();
        wrapPositionElements(tempList, childElements);
        return childElements;
    }

    /** {@inheritDoc} */
    @Override
    public int negotiateBPDAdjustment(int adj, KnuthElement lastElement) {
        log.debug(" FLM.negotiateBPDAdjustment> " + adj);

        Position lastPosition = lastElement.getPosition();
        if (lastPosition instanceof NonLeafPosition) {
            // this element was not created by this FlowLM
            NonLeafPosition savedPos = (NonLeafPosition) lastPosition;
            lastElement.setPosition(savedPos.getPosition());
            int returnValue = ((BlockLevelLayoutManager)lastElement.getLayoutManager())
                    .negotiateBPDAdjustment(adj, lastElement);
            lastElement.setPosition(savedPos);
            log.debug(" FLM.negotiateBPDAdjustment> result " + returnValue);
            return returnValue;
        } else {
            return 0;
        }
    }

    /** {@inheritDoc} */
    @Override
    public void discardSpace(KnuthGlue spaceGlue) {
        log.debug(" FLM.discardSpace> ");

        Position gluePosition = spaceGlue.getPosition();
        if (gluePosition instanceof NonLeafPosition) {
            // this element was not created by this FlowLM
            NonLeafPosition savedPos = (NonLeafPosition) gluePosition;
            spaceGlue.setPosition(savedPos.getPosition());
            ((BlockLevelLayoutManager) spaceGlue.getLayoutManager()).discardSpace(spaceGlue);
            spaceGlue.setPosition(savedPos);
        }
    }

    /** {@inheritDoc} */
    @Override
    public Keep getKeepTogether() {
        return Keep.KEEP_AUTO;
    }

    /** {@inheritDoc} */
    @Override
    public Keep getKeepWithNext() {
        return Keep.KEEP_AUTO;
    }

    /** {@inheritDoc} */
    @Override
    public Keep getKeepWithPrevious() {
        return Keep.KEEP_AUTO;
    }

    /** {@inheritDoc} */
    @Override
    public List<KnuthElement> getChangedKnuthElements(List oldList, int alignment) {
        ListIterator<KnuthElement> oldListIterator = oldList.listIterator();
        KnuthElement returnedElement;
        List<KnuthElement> returnedList = new LinkedList<KnuthElement>();
        List<KnuthElement> returnList = new LinkedList<KnuthElement>();
        KnuthElement prevElement = null;
        KnuthElement currElement = null;
        int fromIndex = 0;

        // "unwrap" the Positions stored in the elements
        KnuthElement oldElement;
        while (oldListIterator.hasNext()) {
            oldElement = oldListIterator.next();
            if (oldElement.getPosition() instanceof NonLeafPosition) {
                // oldElement was created by a descendant of this FlowLM
                oldElement.setPosition((oldElement.getPosition()).getPosition());
            } else {
                // thisElement was created by this FlowLM, remove it
                oldListIterator.remove();
            }
        }
        // reset the iterator
        oldListIterator = oldList.listIterator();


        while (oldListIterator.hasNext()) {
            currElement = oldListIterator.next();
            if (prevElement != null
                && prevElement.getLayoutManager() != currElement.getLayoutManager()) {
                // prevElement is the last element generated by the same LM
                BlockLevelLayoutManager prevLM = (BlockLevelLayoutManager)
                                                 prevElement.getLayoutManager();
                BlockLevelLayoutManager currLM = (BlockLevelLayoutManager)
                                                 currElement.getLayoutManager();
                returnedList.addAll(prevLM.getChangedKnuthElements(
                        oldList.subList(fromIndex, oldListIterator.previousIndex()), alignment));
                fromIndex = oldListIterator.previousIndex();

                // there is another block after this one
                if (prevLM.mustKeepWithNext()
                    || currLM.mustKeepWithPrevious()) {
                    // add an infinite penalty to forbid a break between blocks
                    returnedList.add(new KnuthPenalty(0, KnuthElement.INFINITE, false,
                            new Position(this), false));
                } else if (!ListUtil.getLast(returnedList).isGlue()) {
                    // add a null penalty to allow a break between blocks
                    returnedList.add(new KnuthPenalty(0, 0, false, new Position(this), false));
                }
            }
            prevElement = currElement;
        }
        if (currElement != null) {
            BlockLevelLayoutManager currLM = (BlockLevelLayoutManager)
                                             currElement.getLayoutManager();
            returnedList.addAll(currLM.getChangedKnuthElements(
                    oldList.subList(fromIndex, oldList.size()), alignment));
        }

        // "wrap" the Position stored in each element of returnedList
        // and add elements to returnList
        for (KnuthElement aReturnedList : returnedList) {
            returnedElement = aReturnedList;
            if (returnedElement.getLayoutManager() != this) {
                returnedElement.setPosition(
                        new NonLeafPosition(this, returnedElement.getPosition()));
            }
            returnList.add(returnedElement);
        }

        return returnList;
    }

    /** {@inheritDoc} */
    @Override
    public void addAreas(PositionIterator parentIter, LayoutContext layoutContext) {
        AreaAdditionUtil.addAreas(this, parentIter, layoutContext);
        flush();
    }

    /**
     * Add child area to a the correct container, depending on its
     * area class. A Flow can fill at most one area container of any class
     * at any one time. The actual work is done by BlockStackingLM.
     *
     * @param childArea the area to add
     */
    @Override
    public void addChildArea(Area childArea) {
        if (childArea instanceof BlockParent && handlingFloat()) {
            BlockParent bp = (BlockParent) childArea;
            bp.setXOffset(getPSLM().getStartIntrusionAdjustment());
        }
        getParentArea(childArea);
        addChildToArea(childArea,
                          this.currentAreas[childArea.getAreaClass()]);
    }

    /** {@inheritDoc} */
    @Override
    public Area getParentArea(Area childArea) {
        BlockParent parentArea = null;
        int aclass = childArea.getAreaClass();

        if (aclass == Area.CLASS_NORMAL || aclass == Area.CLASS_SIDE_FLOAT) {
            parentArea = getCurrentPV().getCurrentFlow();
        } else if (aclass == Area.CLASS_BEFORE_FLOAT) {
            parentArea = getCurrentPV().getBodyRegion().getBeforeFloat();
        } else if (aclass == Area.CLASS_FOOTNOTE) {
            parentArea = getCurrentPV().getBodyRegion().getFootnote();
        } else {
            throw new IllegalStateException("(internal error) Invalid "
                    + "area class (" + aclass + ") requested.");
        }

        this.currentAreas[aclass] = parentArea;
        setCurrentArea(parentArea);
        return parentArea;
    }

    /**
     * Returns the IPD of the content area
     * @return the IPD of the content area
     */
    @Override
    public int getContentAreaIPD() {
        int flowIPD = getPSLM().getCurrentColumnWidth();
        return flowIPD;
    }

    /**
     * Returns the BPD of the content area
     * @return the BPD of the content area
     */
    @Override
    public int getContentAreaBPD() {
        return getCurrentPV().getBodyRegion().getBPD();
    }

    /** {@inheritDoc} */
    @Override
    public boolean isRestartable() {
        return true;
    }

    public void handleFloatOn() {
        handlingFloat = true;
    }

    public void handleFloatOff() {
        handlingFloat = false;
    }

    public boolean handlingFloat() {
        return handlingFloat;
    }
}

