// Copyright (C) 2013 The Android Open Source Project
//
// 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.gerrit.client.api;

import com.google.gwt.core.client.JavaScriptObject;
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.dom.client.StyleInjector;
import com.google.gwt.user.client.DOM;
import com.google.gwtexpui.safehtml.client.SafeHtmlBuilder;

final class HtmlTemplate {
  static native void init() /*-{
    var ElementSet = function(r,e) {
      this.root = r;
      this.elements = e;
    };
    ElementSet.prototype = {
      clear: function() {
        this.root = null;
        this.elements = null;
      },
    };

    $wnd.Gerrit.css = @com.google.gerrit.client.api.HtmlTemplate::css(Ljava/lang/String;);
    $wnd.Gerrit.html = function(h,r,w) {
      var i = {};
      if (r) {
        h = h.replace(
          /\sid=['"]\{([a-z_][a-z0-9_]*)\}['"]|\{([a-z0-9._-]+)\}/gi,
          function(m,a,b) {
            if (a)
              return @com.google.gerrit.client.api.HtmlTemplate::id(
                  Lcom/google/gerrit/client/api/HtmlTemplate$IdMap;
                  Ljava/lang/String;)
                (i,a);
            return @com.google.gerrit.client.api.HtmlTemplate::html(
                Lcom/google/gerrit/client/api/HtmlTemplate$ReplacementMap;
                Ljava/lang/String;)
              (r,b);
          });
      }
      var e = @com.google.gerrit.client.api.HtmlTemplate::parseHtml(
          Ljava/lang/String;Lcom/google/gerrit/client/api/HtmlTemplate$IdMap;
          Lcom/google/gerrit/client/api/HtmlTemplate$ReplacementMap;
          Z)
        (h,i,r,!!w);
      return w ? new ElementSet(e,i) : e;
    };
  }-*/;

  private static final String css(String css) {
    String name = DOM.createUniqueId();
    StyleInjector.inject("." + name + "{" + css + "}");
    return name;
  }

  private static final String id(IdMap idMap, String key) {
    String id = DOM.createUniqueId();
    idMap.put(id, key);
    return " id='" + id + "'";
  }

  private static final String html(ReplacementMap opts, String id) {
    int d = id.indexOf('.');
    if (0 < d) {
      String name = id.substring(0, d);
      String rest = id.substring(d + 1);
      return html(opts.map(name), rest);
    }
    return new SafeHtmlBuilder().append(opts.str(id)).asString();
  }

  private static final Node parseHtml(
      String html,
      IdMap ids,
      ReplacementMap opts,
      boolean wantElements) {
    Element div = Document.get().createDivElement();
    div.setInnerHTML(html);
    if (!ids.isEmpty()) {
      attachHandlers(div, ids, opts, wantElements);
    }
    if (div.getChildCount() == 1) {
      return div.getFirstChild();
    }
    return div;
  }

  private static void attachHandlers(
      Element e,
      IdMap ids,
      ReplacementMap opts,
      boolean wantElements) {
    if (e.getId() != null) {
      String key = ids.get(e.getId());
      if (key != null) {
        ids.remove(e.getId());
        if (wantElements) {
          ids.put(key, e);
        }
        e.setId(null);
        opts.map(key).attachHandlers(e);
      }
    }
    for (Element c = e.getFirstChildElement(); c != null;) {
      attachHandlers(c, ids, opts, wantElements);
      c = c.getNextSiblingElement();
    }
  }

  private static class ReplacementMap extends JavaScriptObject {
    final native ReplacementMap map(String n) /*-{ return this[n] }-*/;
    final native String str(String n) /*-{ return ''+this[n] }-*/;
    final native void attachHandlers(Element e) /*-{
      for (var k in this) {
        var f = this[k];
        if (k.substring(0, 2) == 'on' && typeof f == 'function')
          e[k] = f;
      }
    }-*/;

    protected ReplacementMap() {
    }
  }

  private static class IdMap extends JavaScriptObject {
    final native String get(String i) /*-{ return this[i] }-*/;
    final native void remove(String i) /*-{ delete this[i] }-*/;
    final native void put(String i, String k) /*-{ this[i] = k }-*/;
    final native void put(String k, Element e) /*-{ this[k] = e }-*/;
    final native boolean isEmpty() /*-{
      for (var i in this)
        return false;
      return true;
    }-*/;

    protected IdMap() {
    }
  }

  private HtmlTemplate() {
  }
}
