/*
 * Copyright 2013 The Polymer Authors. All rights reserved.
 * Use of this source code is governed by a BSD-style
 * license that can be found in the LICENSE file.
 */

(function(){
  
var HTMLElementElement = function(inElement) {
  inElement.register = HTMLElementElement.prototype.register;
  parseElementElement(inElement);
  return inElement;
};

HTMLElementElement.prototype = {
  register: function(inMore) {
    if (inMore) {
      this.options.lifecycle = inMore.lifecycle;
      if (inMore.prototype) {
        mixin(this.options.prototype, inMore.prototype);
      }
    }
  }
};

function parseElementElement(inElement) {
  // options to glean from inElement attributes
  var options = {
    name: '',
    extends: null
  };
  // glean them
  takeAttributes(inElement, options);
  // default base
  var base = HTMLElement.prototype;
  // optional specified base
  if (options.extends) {
    // build an instance of options.extends
    var archetype = document.createElement(options.extends);
    // acquire the prototype
    // TODO(sjmiles): __proto__ may be hinted by the custom element
    // system on platforms that don't support native __proto__
    // on those platforms the API is mixed into archetype and the
    // effective base is not archetype's real prototype
    base = archetype.__proto__ || Object.getPrototypeOf(archetype);
  }
  // extend base
  options.prototype = Object.create(base);
  // install options
  inElement.options = options;
  // locate user script
  var script = inElement.querySelector('script,scripts');
  if (script) {
    // execute user script in 'inElement' context
    executeComponentScript(script.textContent, inElement, options.name);
  };
  // register our new element
  var ctor = document.register(options.name, options);
  inElement.ctor = ctor;
  // store optional constructor reference
  var refName = inElement.getAttribute('constructor');
  if (refName) {
    window[refName] = ctor;
  }
}
  
// each property in inDictionary takes a value
// from the matching attribute in inElement, if any
function takeAttributes(inElement, inDictionary) {
  for (var n in inDictionary) {
    var a = inElement.attributes[n];
    if (a) {
      inDictionary[n] = a.value;
    }
  }
}

// invoke inScript in inContext scope
function executeComponentScript(inScript, inContext, inName) {
  // set (highlander) context
  context = inContext;
  // source location
  var owner = context.ownerDocument;
  var url = (owner._URL || owner.URL || owner.impl 
      && (owner.impl._URL || owner.impl.URL));
  // ensure the component has a unique source map so it can be debugged
  // if the name matches the filename part of the owning document's url,
  // use this, otherwise, add ":<name>" to the document url.
  var match = url.match(/.*\/([^.]*)[.]?.*$/);
  if (match) {
    var name = match[1];
    url += name != inName ? ':' + inName : '';
  }
  // compose script
  var code = "__componentScript('"
    + inName
    + "', function(){"
    + inScript
    + "});"
    + "\n//@ sourceURL=" + url + "\n"
  ;
  // inject script
  eval(code);
}

var context;

// global necessary for script injection
window.__componentScript = function(inName, inFunc) {
  inFunc.call(context);
};

// utility

// copy all properties from inProps (et al) to inObj
function mixin(inObj/*, inProps, inMoreProps, ...*/) {
  var obj = inObj || {};
  for (var i = 1; i < arguments.length; i++) {
    var p = arguments[i];
    try {
      for (var n in p) {
        copyProperty(n, p, obj);
      }
    } catch(x) {
    }
  }
  return obj;
}

// copy property inName from inSource object to inTarget object
function copyProperty(inName, inSource, inTarget) {
  var pd = getPropertyDescriptor(inSource, inName);
  Object.defineProperty(inTarget, inName, pd);
}

// get property descriptor for inName on inObject, even if
// inName exists on some link in inObject's prototype chain
function getPropertyDescriptor(inObject, inName) {
  if (inObject) {
    var pd = Object.getOwnPropertyDescriptor(inObject, inName);
    return pd || getPropertyDescriptor(Object.getPrototypeOf(inObject), inName);
  }
}

// exports

window.HTMLElementElement = HTMLElementElement;
// TODO(sjmiles): completely ad-hoc, used by Polymer.register
window.mixin = mixin;

})();

@@ -3239,18 +3239,24 @@
 // copy 
-al
+top leve
 l proper
@@ -3269,30 +3269,18 @@
 rom 
-inP
+p
 rops 
-(et al) to inO
+to o
 bj%0Af
@@ -3297,63 +3297,31 @@
 xin(
-inObj/*, inProps, inMoreProps, ...*/
+obj, props
 ) %7B%0A  
-var 
 obj = 
-inO
+o
 bj %7C
@@ -3330,83 +3330,8 @@
 %7B%7D;%0A
-  for (var i = 1; i %3C arguments.length; i++) %7B%0A    var p = arguments%5Bi%5D;%0A  
   tr
@@ -3338,18 +3338,16 @@
 y %7B%0A    
-  
 for (var
@@ -3353,16 +3353,20 @@
 r n in p
+rops
 ) %7B%0A    
@@ -3371,787 +3371,257 @@
     
-  copyProperty(n, p, obj);%0A      %7D%0A    %7D catch(x) %7B%0A    %7D%0A  %7D%0A  return obj;%0A%7D%0A%0A// copy property inName from inSource object to inTarget object%0Afunction copyProperty(inName, inSource, inTarget) %7B%0A  var pd = getPropertyDescriptor(inSource, inName);%0A  Object.defineProperty(inTarget, inName, pd);%0A%7D%0A%0A// get property descriptor for inName on inObject, even if%0A// inName exists on some link in inObject's prototype chain%0Afunction getPropertyDescriptor(inObject, inName) %7B%0A  if (inObject) %7B%0A    var pd = Object.getOwnPropertyDescriptor(inObject, inName);%0A    return pd %7C%7C getPropertyDescriptor(Object.getPrototypeOf(inObject), inName);%0A  %7D%0A%7D%0A%0A// exports%0A%0Awindow.HTMLElementElement = HTMLElementElement;%0A// TODO(sjmiles): completely ad-hoc, used by Polymer.register%0Awindow.mixin = mixin
+var pd = Object.getOwnPropertyDescriptor(props, n);%0A      if (pd) %7B%0A        pd.enumerable = true;%0A        Object.defineProperty(obj, n, pd);%0A      %7D%0A    %7D%0A  %7D catch(x) %7B%0A  %7D%0A  return obj;%0A%7D%0A%0A// exports%0A%0Awindow.HTMLElementElement = HTMLElementElement
 ;%0A%0A%7D

simplify mixin, enforce enumerability on installed properties