import _ from "../util/index";
import { MethodError } from "../errors";
import { $Element, $NullElement } from "../types";
import PROP from "../util/accessorhooks";

var reDash = /[A-Z]/g,
    getPrivateProperty = (node, key) => {
        // convert from camel case to dash-separated value
        var value = node.getAttribute("data-" + key.replace(reDash, (l) => "-" + l.toLowerCase()));

        if (value != null) {
            // try to recognize and parse  object notation syntax
            if (value[0] === "{" && value[value.length - 1] === "}") {
                try {
                    value = JSON.parse(value);
                } catch (err) { }
            }
        }

        return value;
    };

/**
 * Get property or attribute value by name
 * @memberof! $Element#
 * @alias $Element#get
 * @param  {String|Array} [name] property or attribute name or array of names
 * @return {String|Object} a value of property or attribute
 * @example
 * link.get("title");       // => property title
 * link.get("data-custom"); // => custom attribute data-custom
 * link.get();              // => link's innerHTML
 * link.get("_prop");       // => private property _prop
 */
$Element.prototype.get = function(name) {
    var node = this[0],
        hook = PROP.get[name];

    if (hook) return hook(node, name);

    if (typeof name === "string") {
        if (name in node) {
            return node[name];
        } else if (name[0] !== "_") {
            return node.getAttribute(name);
        } else {
            let key = name.substr(1),
                data = this._,
                value;

            if (key in data) {
                value = data[key];
            } else {
                value = data[key] = getPrivateProperty(node, key);
            }

            return value;
        }
    } else if (_.isArray(name)) {
        return name.reduce((r, key) => { return r[key] = this.get(key), r }, {});
    } else {
        throw new MethodError("get", arguments);
    }
};

$NullElement.prototype.get = function() {};

@@ -169,548 +169,24 @@
 r re
-Dash = /%5BA-Z%5D/g,%0A    getPrivateProperty = (node, key) =%3E %7B%0A        // convert from camel case to dash-separated value%0A        var value = node.getAttribute(%22data-%22 + key.replace(reDash, (l) =%3E %22-%22 + l.toLowerCase()));%0A%0A        if (value != null) %7B%0A            // try to recognize and parse  object notation syntax%0A            if (value%5B0%5D === %22%7B%22 && value%5Bvalue.length - 1%5D === %22%7D%22) %7B%0A                try %7B%0A                    value = JSON.parse(value);%0A                %7D catch (err) %7B %7D%0A            %7D%0A        %7D%0A%0A        return value;%0A    %7D
+Upper = /%5BA-Z%5D/g
 ;%0A%0A/
@@ -1051,17 +1051,18 @@
 = this._
-,
+;%0A
 %0A       
@@ -1070,50 +1070,89 @@
     
-    value;%0A%0A            if (key in data) %7B
+if (!(key in data)) %7B%0A                data%5Bkey%5D = readPrivateProperty(node, key);
 %0A   
@@ -1156,35 +1156,45 @@
             
+%7D%0A%0A
     
-value =
+        return
  data%5Bkey%5D;%0A
@@ -1197,24 +1197,26 @@
 y%5D;%0A        
+%7D%0A
     %7D else %7B
@@ -1218,49 +1218,166 @@
 lse 
-%7B%0A                value = data%5Bkey%5D = get
+if (_.isArray(name)) %7B%0A        return name.reduce(toValueMap(this), %7B%7D);%0A    %7D else %7B%0A        throw new MethodError(%22get%22, arguments);%0A    %7D%0A%7D;%0A%0Afunction read
 Priv
@@ -1402,247 +1402,632 @@
 key)
-;
+ %7B
 %0A    
-        %7D%0A%0A            return value;%0A        %7D%0A    %7D else if (_.isArray(name)) %7B%0A        return name.reduce((r, key) =%3E %7B return r%5Bkey%5D = this.get(key), r %7D, %7B%7D);%0A    %7D else %7B%0A        throw new MethodError(%22get%22, arguments)
+// convert from camel case to dash-separated value%0A    key = key.replace(reUpper, (l) =%3E %22-%22 + l.toLowerCase());%0A%0A    var value = node.getAttribute(%22data-%22 + key);%0A%0A    if (value != null) %7B%0A        // try to recognize and parse  object notation syntax%0A        if (value%5B0%5D === %22%7B%22 && value%5Bvalue.length - 1%5D === %22%7D%22) %7B%0A            try %7B%0A                value = JSON.parse(value);%0A            %7D catch (err) %7B%0A                // just return the value itself%0A            %7D%0A        %7D%0A    %7D%0A%0A    return value;%0A%7D;%0A%0Afunction toValueMap(el) %7B%0A    return (memo, key) =%3E %7B%0A        return memo%5Bkey%5D = el.get(key), memo
 ;%0A    %7D
+;
 %0A%7D
-;
 %0A%0A$N

refactor $Element#get