/*
 * 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.render.rtf;

import java.awt.Color;

import org.apache.fop.apps.FOPException;
import org.apache.fop.fo.Constants;
import org.apache.fop.fo.flow.table.Table;
import org.apache.fop.fo.flow.table.TableCell;
import org.apache.fop.fo.flow.table.TableHeader;
import org.apache.fop.fo.flow.table.TablePart;
import org.apache.fop.fo.flow.table.TableRow;
import org.apache.fop.fo.properties.CommonBorderPaddingBackground;
import org.apache.fop.render.rtf.rtflib.rtfdoc.ITableAttributes;
import org.apache.fop.render.rtf.rtflib.rtfdoc.RtfAttributes;

/**
 * <p>Table attributes converter.</p>
 *
 * <p>This work was authored by Roberto Marra (roberto@link-u.com),
 * Boris Poudérous (boris.pouderous@eads-telecom.com),
 * Normand Massé, and
 * Peter Herweg (pherweg@web.de).</p>
 *
 * This class was originally developed for the JFOR project and
 * is now integrated into FOP.
-----------------------------------------------------------------------------*/

/**
 * Provides methods to convert the attributes to RtfAttributes.
 */

public final class TableAttributesConverter {

    //////////////////////////////////////////////////
    // @@ Construction
    //////////////////////////////////////////////////

    /**
     * Constructor is private, because it's just a utility class.
     */
    private TableAttributesConverter() {
    }

    //////////////////////////////////////////////////
    // @@ Static converter methods
    //////////////////////////////////////////////////
    /**
     * Converts table-only attributes to rtf attributes.
     *
     * @param fobj the table for which the attributes are converted
     * @return All valid rtf attributes together
     * @throws ConverterException On convertion error
     */
    static RtfAttributes convertTableAttributes(Table fobj)
            throws FOPException {
        FOPRtfAttributes attrib = new FOPRtfAttributes();
        attrib.setTwips(ITableAttributes.ATTR_ROW_LEFT_INDENT,
                fobj.getCommonMarginBlock().marginLeft);
        return attrib;
    }

    /**
     * Converts table-only attributes to rtf attributes.
     *
     * @param part the table part for which the attributes are converted
     * @return All valid rtf attributes together
     * @throws ConverterException On convertion error
     */
    static RtfAttributes convertTablePartAttributes(TablePart part)
            throws FOPException {
        FOPRtfAttributes attrib = new FOPRtfAttributes();
        return attrib;
    }

    /**
     * Converts cell attributes to rtf attributes.
     * @param fobj FObj whose properties are to be converted
     *
     * @return All valid rtf attributes together
     *
     * @throws ConverterException On conversion error
     */
    static RtfAttributes convertCellAttributes(TableCell fobj)
    throws FOPException {

        //Property p;
        //RtfColorTable colorTable = RtfColorTable.getInstance();

        FOPRtfAttributes attrib = new FOPRtfAttributes();

        //boolean isBorderPresent = false;
        CommonBorderPaddingBackground border = fobj.getCommonBorderPaddingBackground();

        // Cell background color
        Color color = border.backgroundColor;
        if (color == null) {
            //If there is no background-color specified for the cell,
            //then try to read it from table-row or table-header.
            CommonBorderPaddingBackground brd = null;

            if (fobj.getParent() instanceof TableRow) {
                TableRow parentRow = (TableRow)fobj.getParent();
                brd = parentRow.getCommonBorderPaddingBackground();
                color = brd.backgroundColor;
            } else if (fobj.getParent() instanceof TableHeader) {
                TableHeader parentHeader = (TableHeader)fobj.getParent();
                brd = parentHeader.getCommonBorderPaddingBackground();
                color = brd.backgroundColor;
            }

            if (color == null
                    && fobj.getParent() != null
                    && fobj.getParent().getParent() != null
                    && fobj.getParent().getParent().getParent() instanceof Table) {

                Table table = (Table)fobj.getParent().getParent().getParent();
                brd = table.getCommonBorderPaddingBackground();
                color = brd.backgroundColor;
            }


        }
        if ((color != null)
                && (color.getAlpha() != 0
                        || color.getRed() != 0
                        || color.getGreen() != 0
                        || color.getBlue() != 0)) {
            attrib.set(ITableAttributes.CELL_COLOR_BACKGROUND, color);
        }

        BorderAttributesConverter.makeBorder(border, CommonBorderPaddingBackground.BEFORE,
                attrib, ITableAttributes.CELL_BORDER_TOP);
        BorderAttributesConverter.makeBorder(border, CommonBorderPaddingBackground.AFTER,
                attrib, ITableAttributes.CELL_BORDER_BOTTOM);
        BorderAttributesConverter.makeBorder(border, CommonBorderPaddingBackground.START,
                attrib, ITableAttributes.CELL_BORDER_LEFT);
        BorderAttributesConverter.makeBorder(border, CommonBorderPaddingBackground.END,
                attrib,  ITableAttributes.CELL_BORDER_RIGHT);

        int padding;
        boolean reproduceMSWordBug = true;
        //TODO Make this configurable
        if (reproduceMSWordBug) {
            //MS Word has a bug where padding left and top are exchanged
            padding = border.getPaddingStart(false, null); // TODO do we need a real context here?
            if (padding != 0) {
                attrib.setTwips(ITableAttributes.ATTR_CELL_PADDING_TOP, padding);
                attrib.set(ITableAttributes.ATTR_CELL_U_PADDING_TOP, 3 /*=twips*/);
            }
            padding = border.getPaddingBefore(false, null); // TODO do we need a real context here?
            if (padding != 0) {
                attrib.setTwips(ITableAttributes.ATTR_CELL_PADDING_LEFT, padding);
                attrib.set(ITableAttributes.ATTR_CELL_U_PADDING_LEFT, 3 /*=twips*/);
            }
        } else {
            padding = border.getPaddingStart(false, null); // TODO do we need a real context here?
            if (padding != 0) {
                attrib.setTwips(ITableAttributes.ATTR_CELL_PADDING_LEFT, padding);
                attrib.set(ITableAttributes.ATTR_CELL_U_PADDING_LEFT, 3 /*=twips*/);
            }
            padding = border.getPaddingBefore(false, null); // TODO do we need a real context here?
            if (padding != 0) {
                attrib.setTwips(ITableAttributes.ATTR_CELL_PADDING_TOP, padding);
                attrib.set(ITableAttributes.ATTR_CELL_U_PADDING_TOP, 3 /*=twips*/);
            }
        }
        padding = border.getPaddingEnd(false, null);  // TODO do we need a real context here?
        if (padding != 0) {
            attrib.setTwips(ITableAttributes.ATTR_CELL_PADDING_RIGHT, padding);
            attrib.set(ITableAttributes.ATTR_CELL_U_PADDING_RIGHT, 3 /*=twips*/);
        }
        padding = border.getPaddingAfter(false, null); // TODO do we need a real context here?
        if (padding != 0) {
            attrib.setTwips(ITableAttributes.ATTR_CELL_PADDING_BOTTOM, padding);
            attrib.set(ITableAttributes.ATTR_CELL_U_PADDING_BOTTOM, 3 /*=twips*/);
        }

        int n = fobj.getNumberColumnsSpanned();
        // Column spanning :
        if (n > 1) {
            attrib.set(ITableAttributes.COLUMN_SPAN, n);
        }

        switch (fobj.getDisplayAlign()) {
        case Constants.EN_BEFORE:
            attrib.set(ITableAttributes.ATTR_CELL_VERT_ALIGN_TOP);
            break;
        case Constants.EN_CENTER:
            attrib.set(ITableAttributes.ATTR_CELL_VERT_ALIGN_CENTER);
            break;
        case Constants.EN_AFTER:
            attrib.set(ITableAttributes.ATTR_CELL_VERT_ALIGN_BOTTOM);
            break;
        default: //nop
        }

        return attrib;
    }


    /**
     * Converts table and row attributes to rtf attributes.
     *
     * @param fobj FObj to be converted
     * @return All valid rtf attributes together
     * @throws ConverterException On converion error
     */
    static RtfAttributes convertRowAttributes(TableRow fobj,
            RtfAttributes rtfatts)
    throws FOPException {

        //Property p;
        //RtfColorTable colorTable = RtfColorTable.getInstance();

        RtfAttributes attrib = null;

        if (rtfatts == null) {
            attrib = new RtfAttributes();
        } else {
            attrib = rtfatts;
        }

        //String attrValue;
        //boolean isBorderPresent = false;
        //need to set a default width

        //check for keep-together row attribute

        if (fobj.getKeepTogether().getWithinPage().getEnum() == Constants.EN_ALWAYS) {
            attrib.set(ITableAttributes.ROW_KEEP_TOGETHER);
        }

        //Check for keep-with-next row attribute.
        if (fobj.getKeepWithNext().getWithinPage().getEnum() == Constants.EN_ALWAYS) {
            attrib.set(ITableAttributes.ROW_KEEP_WITH_NEXT);
        }

        //Check for keep-with-previous row attribute.
        if (fobj.getKeepWithPrevious().getWithinPage().getEnum() == Constants.EN_ALWAYS) {
            attrib.set(ITableAttributes.ROW_KEEP_WITH_PREVIOUS);
        }

        //Check for height row attribute.
        if (fobj.getHeight().getEnum() != Constants.EN_AUTO) {
            attrib.set(ITableAttributes.ROW_HEIGHT, fobj.getHeight().getValue() / (1000 / 20));
        }

        /* to write a border to a side of a cell one must write the directional
         * side (ie. left, right) and the inside value if one needs to be taken
         * out ie if the cell lies on the edge of a table or not, the offending
         * value will be taken out by RtfTableRow.  This is because you can't
         * say BORDER_TOP and BORDER_HORIZONTAL if the cell lies at the top of
         * the table.  Similarly using BORDER_BOTTOM and BORDER_HORIZONTAL will
         * not work if the cell lies at th bottom of the table.  The same rules
         * apply for left right and vertical.

         * Also, the border type must be written after every control word.  Thus
         * it is implemented that the border type is the value of the border
         * place.
         */
        CommonBorderPaddingBackground border = fobj.getCommonBorderPaddingBackground();
        BorderAttributesConverter.makeBorder(border, CommonBorderPaddingBackground.BEFORE,
                attrib, ITableAttributes.CELL_BORDER_TOP);
        BorderAttributesConverter.makeBorder(border, CommonBorderPaddingBackground.AFTER,
                attrib, ITableAttributes.CELL_BORDER_BOTTOM);
        BorderAttributesConverter.makeBorder(border, CommonBorderPaddingBackground.START,
                attrib, ITableAttributes.CELL_BORDER_LEFT);
        BorderAttributesConverter.makeBorder(border, CommonBorderPaddingBackground.END,
                attrib, ITableAttributes.CELL_BORDER_RIGHT);

/*
        ep = (EnumProperty)fobj.getProperty(Constants.PR_BORDER_TOP_STYLE);
        if (ep != null && ep.getEnum() != Constants.EN_NONE) {
            attrib.set(ITableAttributes.ROW_BORDER_TOP,       "\\"
                       + convertAttributetoRtf(ep.getEnum()));
            attrib.set(ITableAttributes.ROW_BORDER_HORIZONTAL, "\\"
                       + convertAttributetoRtf(ep.getEnum()));
            isBorderPresent = true;
        }
        ep = (EnumProperty)fobj.getProperty(Constants.PR_BORDER_BOTTOM_STYLE);
        if (ep != null && ep.getEnum() != Constants.EN_NONE) {
            attrib.set(ITableAttributes.ROW_BORDER_BOTTOM,    "\\"
                       + convertAttributetoRtf(ep.getEnum()));
            attrib.set(ITableAttributes.ROW_BORDER_HORIZONTAL, "\\"
                       + convertAttributetoRtf(ep.getEnum()));
            isBorderPresent = true;
        }
        ep = (EnumProperty)fobj.getProperty(Constants.PR_BORDER_LEFT_STYLE);
        if (ep != null && ep.getEnum() != Constants.EN_NONE) {
            attrib.set(ITableAttributes.ROW_BORDER_LEFT,     "\\"
                       + convertAttributetoRtf(ep.getEnum()));
            attrib.set(ITableAttributes.ROW_BORDER_VERTICAL, "\\"
                       + convertAttributetoRtf(ep.getEnum()));
            isBorderPresent = true;
        }
        ep = (EnumProperty)fobj.getProperty(Constants.PR_BORDER_RIGHT_STYLE);
        if (ep != null && ep.getEnum() != Constants.EN_NONE) {
            attrib.set(ITableAttributes.ROW_BORDER_RIGHT,    "\\"
                       + convertAttributetoRtf(ep.getEnum()));
            attrib.set(ITableAttributes.ROW_BORDER_VERTICAL, "\\"
                       + convertAttributetoRtf(ep.getEnum()));
            isBorderPresent = true;
        }

        //Currently there is only one border width supported in each cell.
        p = fobj.getProperty(Constants.PR_BORDER_LEFT_WIDTH);
        if(p == null) {
            p = fobj.getProperty(Constants.PR_BORDER_RIGHT_WIDTH);
        }
        if(p == null) {
            p = fobj.getProperty(Constants.PR_BORDER_TOP_WIDTH);
        }
        if(p == null) {
            p = fobj.getProperty(Constants.PR_BORDER_BOTTOM_WIDTH);
        }
        if (p != null) {
            LengthProperty lengthprop = (LengthProperty)p;

            Float f = new Float(lengthprop.getLength().getValue() / 1000f);
            String sValue = f.toString() + FixedLength.POINT;

            attrib.set(BorderAttributesConverter.BORDER_WIDTH,
                       (int)FoUnitsConverter.getInstance().convertToTwips(sValue));
        } else if (isBorderPresent) {
            //if not defined, set default border width
            //note 20 twips = 1 point
            attrib.set(BorderAttributesConverter.BORDER_WIDTH,
                       (int)FoUnitsConverter.getInstance().convertToTwips("1pt"));
        }
*/
        return attrib;
    }

}
