/*
 * Copyright 2008 Google Inc.
 * 
 * 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
 * 
 * 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 com.google.gwt.user.client.ui;

import com.google.gwt.aria.client.Roles;
import com.google.gwt.dom.client.Element;
import com.google.gwt.i18n.client.LocaleInfo;
import com.google.gwt.user.client.DOM;

/**
 * <p>
 * A {@link SimplePanel} that wraps its contents in stylized boxes, which can be
 * used to add rounded corners to a {@link Widget}.
 * </p>
 * <p>
 * This widget will <em>only</em> work in quirks mode in most cases.
 * Specifically, setting the height or width of the DecoratorPanel will result
 * in rendering issues.
 * </p>
 * <p>
 * Wrapping a {@link Widget} in a "9-box" allows users to specify images in each
 * of the corners and along the four borders. This method allows the content
 * within the {@link DecoratorPanel} to resize without disrupting the look of
 * the border. In addition, rounded corners can generally be combined into a
 * single image file, which reduces the number of downloaded files at startup.
 * This class also simplifies the process of using AlphaImageLoaders to support
 * 8-bit transparencies (anti-aliasing and shadows) in ie6, which does not
 * support them normally.
 * </p>
 * <h3>Setting the Size:</h3>
 * <p>
 * If you set the width or height of the {@link DecoratorPanel}, you need to
 * set the height and width of the middleCenter cell to 100% so that the
 * middleCenter cell takes up all of the available space. If you do not set the
 * width and height of the {@link DecoratorPanel}, it will wrap its contents
 * tightly.
 * </p>
 * 
 * <pre>
 * .gwt-DecoratorPanel .middleCenter {
 *   height: 100%;
 *   width: 100%;
 * }
 * </pre>
 * 
 * <h3>CSS Style Rules</h3>
 * <ul class='css'>
 * <li>.gwt-DecoratorPanel { the panel }</li>
 * <li>.gwt-DecoratorPanel .top { the top row }</li>
 * <li>.gwt-DecoratorPanel .topLeft { the top left cell }</li>
 * <li>.gwt-DecoratorPanel .topLeftInner { the inner element of the cell }</li>
 * <li>.gwt-DecoratorPanel .topCenter { the top center cell }</li>
 * <li>.gwt-DecoratorPanel .topCenterInner { the inner element of the cell }</li>
 * <li>.gwt-DecoratorPanel .topRight { the top right cell }</li>
 * <li>.gwt-DecoratorPanel .topRightInner { the inner element of the cell }</li>
 * <li>.gwt-DecoratorPanel .middle { the middle row }</li>
 * <li>.gwt-DecoratorPanel .middleLeft { the middle left cell }</li>
 * <li>.gwt-DecoratorPanel .middleLeftInner { the inner element of the cell }</li>
 * <li>.gwt-DecoratorPanel .middleCenter { the middle center cell }</li>
 * <li>.gwt-DecoratorPanel .middleCenterInner { the inner element of the cell }</li>
 * <li>.gwt-DecoratorPanel .middleRight { the middle right cell }</li>
 * <li>.gwt-DecoratorPanel .middleRightInner { the inner element of the cell }</li>
 * <li>.gwt-DecoratorPanel .bottom { the bottom row }</li>
 * <li>.gwt-DecoratorPanel .bottomLeft { the bottom left cell }</li>
 * <li>.gwt-DecoratorPanel .bottomLeftInner { the inner element of the cell }</li>
 * <li>.gwt-DecoratorPanel .bottomCenter { the bottom center cell }</li>
 * <li>.gwt-DecoratorPanel .bottomCenterInner { the inner element of the cell }</li>
 * <li>.gwt-DecoratorPanel .bottomRight { the bottom right cell }</li>
 * <li>.gwt-DecoratorPanel .bottomRightInner { the inner element of the cell }</li>
 * </ul>
 */
public class DecoratorPanel extends SimplePanel {
  /**
   * The default style name.
   */
  private static final String DEFAULT_STYLENAME = "gwt-DecoratorPanel";

  /**
   * The default styles applied to each row.
   */
  private static final String[] DEFAULT_ROW_STYLENAMES = {
      "top", "middle", "bottom"};

  /**
   * Create a new row with a specific style name. The row will contain three
   * cells (Left, Center, and Right), each prefixed with the specified style
   * name.
   * 
   * This method allows Widgets to reuse the code on a DOM level, without
   * creating a DecoratorPanel Widget.
   * 
   * @param styleName the style name
   * @return the new row {@link Element}
   */
  static Element createTR(String styleName) {
    Element trElem = DOM.createTR();
    setStyleName(trElem, styleName);
    if (LocaleInfo.getCurrentLocale().isRTL()) {
      DOM.appendChild(trElem, createTD(styleName + "Right"));
      DOM.appendChild(trElem, createTD(styleName + "Center"));
      DOM.appendChild(trElem, createTD(styleName + "Left"));
    } else {
      DOM.appendChild(trElem, createTD(styleName + "Left"));
      DOM.appendChild(trElem, createTD(styleName + "Center"));
      DOM.appendChild(trElem, createTD(styleName + "Right"));
    }
    return trElem;
  }

  /**
   * Create a new table cell with a specific style name.
   * 
   * @param styleName the style name
   * @return the new cell {@link Element}
   */
  private static Element createTD(String styleName) {
    Element tdElem = DOM.createTD();
    Element inner = DOM.createDiv();
    DOM.appendChild(tdElem, inner);
    setStyleName(tdElem, styleName);
    setStyleName(inner, styleName + "Inner");
    return tdElem;
  }

  /**
   * The container element at the center of the panel.
   */
  private Element containerElem;

  /**
   * The table body element.
   */
  private Element tbody;

  /**
   * Create a new {@link DecoratorPanel}.
   */
  public DecoratorPanel() {
    this(DEFAULT_ROW_STYLENAMES, 1);
  }

  /**
   * Creates a new panel using the specified style names to apply to each row.
   * Each row will contain three cells (Left, Center, and Right). The Center
   * cell in the containerIndex row will contain the {@link Widget}.
   * 
   * @param rowStyles an array of style names to apply to each row
   * @param containerIndex the index of the container row
   */
  DecoratorPanel(String[] rowStyles, int containerIndex) {
    super(DOM.createTable());

    // Add a tbody
    Element table = getElement();
    // aria role to indicate it is a plain layout table
    Roles.getPresentationRole().set(table);
    
    tbody = DOM.createTBody();
    DOM.appendChild(table, tbody);
    table.setPropertyInt("cellSpacing", 0);
    table.setPropertyInt("cellPadding", 0);

    // Add each row
    for (int i = 0; i < rowStyles.length; i++) {
      Element row = createTR(rowStyles[i]);
      DOM.appendChild(tbody, row);
      if (i == containerIndex) {
        containerElem = DOM.getFirstChild(DOM.getChild(row, 1));
      }
    }

    // Set the overall style name
    setStyleName(DEFAULT_STYLENAME);
  }

  /**
   * Get a specific Element from the panel.
   * 
   * @param row the row index
   * @param cell the cell index
   * @return the Element at the given row and cell
   */
  protected com.google.gwt.user.client.Element getCellElement(int row, int cell) {
    Element tr = DOM.getChild(tbody, row);
    Element td = DOM.getChild(tr, cell);
    return DOM.asOld(DOM.getFirstChild(td));
  }

  @Override
  protected com.google.gwt.user.client.Element getContainerElement() {
    return DOM.asOld(containerElem);
  }
}
