/*
 * 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.uibinder.client;

import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.Node;
import com.google.gwt.safehtml.shared.annotations.IsSafeHtml;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.UIObject;

/**
 * Static helper methods used by UiBinder. These methods are likely to move,
 * so please don't use them for non-UiBinder code.
 */
public class UiBinderUtil {

  /**
   * Temporary attachment record that keeps track of where an element was
   * before attachment.  Use the detach method to put things back.
   *
   */
  public static class TempAttachment {
    private final Element element;
    private final Element origParent;
    private final Element origSibling;

    private TempAttachment(Element origParent, Element origSibling,
        Element element) {
      this.origParent = origParent;
      this.origSibling = origSibling;
      this.element = element;
    }

    /**
     * Restore to previous DOM state before attachment.
     */
    public void detach() {
      // Put the panel's element back where it was.
      if (origParent != null) {
        origParent.insertBefore(element, origSibling);
      } else {
        orphan(element);
      }
    }
  }

  private static Element hiddenDiv;

  /**
   * Attaches the element to the dom temporarily.  Keeps track of where it is
   * attached so that things can be put back latter.
   *
   * @return attachment record which can be used for reverting back to previous
   *         DOM state
   */
  public static TempAttachment attachToDom(Element element) {
    // TODO(rjrjr) This is copied from HTMLPanel. Reconcile
    ensureHiddenDiv();

    // Hang on to the panel's original parent and sibling elements so that it
    // can be replaced.
    Element origParent = element.getParentElement();
    Element origSibling = element.getNextSiblingElement();

    // Attach the panel's element to the hidden div.
    hiddenDiv.appendChild(element);

    return new TempAttachment(origParent, origSibling, element);
  }

  public static Element fromHtml(@IsSafeHtml String html) {
    ensureHiddenDiv();
    hiddenDiv.setInnerHTML(html);
    Element newbie = hiddenDiv.getFirstChildElement();
    orphan(newbie);
    return newbie;
  }

  private static void ensureHiddenDiv() {
    // If the hidden DIV has not been created, create it.
    if (hiddenDiv == null) {
      hiddenDiv = Document.get().createDivElement();
      UIObject.setVisible(hiddenDiv, false);
      RootPanel.getBodyElement().appendChild(hiddenDiv);
    }
  }

  private static void orphan(Node node) {
    node.getParentNode().removeChild(node);
  }

  /**
   * Not to be instantiated.
   */
  private UiBinderUtil() { }
}
