// require ./singleton
// require ./array

"use strict";

var
    Singleton,
    Extensor;

// Object: javascript literal object
(function ($) {

    Extensor.new($, {

        attributes: function (object) {
            var
                attributes = [];

            for (let attribute of Object.keys(object)) {
                if (typeof object[attribute] !== "function") {
                    attributes.push(attribute);
                }
            }

            return attributes;
        },

        methods: function (object) {
            // the largest must stay first
            return Object.keys(object).difference(Object.attributes(object));
        },

        arrayToObject: function (array) {
            var
                object = {};

            array.forEach(function (v, i) {
                object[i] = v;
            });

            $.defineProperties(object, {
                length: {
                    value: array.length,
                    writable: true,
                    configurable: true
                }
            });

            return object;
        },

        delete: function (object, index) {
            delete object[index];
            if (object.length) {
                object.length -= 1;
            }
            return object;
        },

        indexOf: function (object, value) {
            // debugger
            for (let key of Object.keys(object)) {
                if (object[key] === value) {
                    return key;
                }
            }

            return undefined;
        },

        firstOfSlice: function (object, slice) {
            for (let key of Object.keys(object)) {
                if (object[key].search(slice) !== -1) {
                    return key;
                }
            }

            return undefined;
        },

        lastOfSlice: function (object, slice) {
            for (let key of Object.keys(object).desc()) {
                if (object[key].search(slice) !== -1) {
                    return key;
                }
            }

            return undefined;
        }
    });

    // Object.areEquivalents();
    Extensor.new($.prototype, {
        itsEquivalentTo: function (comparator) {
            var
                mainReference = this,
                primitiveTypes =
                    /(number|string|boolean|null|undefined|symbol)/,
                count = 0,
                attributesCount,

                mainReferenceAttrs,
                comparatorAttrs,

                mainReferenceMethods,
                comparatorMethods;

            // debugger
            if (mainReference === comparator) {
                return true;
            } else if (mainReference.constructor === comparator.constructor) {
                if (mainReference instanceof Object
                    && !(mainReference instanceof Function)) {
                    if (mainReference instanceof Node) {
                        if (mainReference.isEqualNode(comparator)) {
                            return true;
                        }
                    } else {
                        mainReferenceAttrs = Object.attributes(mainReference);
                        mainReferenceMethods = Object.methods(mainReference);
                        comparatorAttrs = Object.attributes(mainReference);
                        comparatorMethods = Object.methods(mainReference);

                        // if doesn't have attributes
                        if (!mainReferenceAttrs.length) {
                            if (mainReferenceMethods.length) {
                                if (mainReferenceMethods.length
                                    === comparatorMethods.length
                                    && mainReferenceMethods
                                        .itsEquivalentTo(comparatorMethods)) {
                                    return true;
                                }
                            } else if (mainReferenceMethods.length
                                === comparatorMethods.length) {
                                return true;
                            }
                        }


                        if (mainReferenceAttrs.length
                            === comparatorAttrs.length) {

                            attributesCount = mainReferenceAttrs.length;

                            for (let i of mainReferenceAttrs) {

                                if (typeof mainReference[i] === "boolean"
                                    && typeof comparator[i] === "boolean") {
                                    mainReference[i] = mainReference[i]
                                        .toString();
                                    comparator[i] = comparator[i]
                                        .toString();
                                }

                                if (mainReference[i] && comparator[i]) {
                                    if ((mainReference[i]).constructor
                                        === (comparator[i]).constructor) {
                                        if (mainReference[i]
                                            instanceof Object) {
                                            if (mainReference[i]
                                            .itsEquivalentTo(comparator[i])) {
                                                count += 1;
                                            }
                                        } else if (mainReference[i]
                                            === comparator[i]) {
                                            count += 1;
                                        }
                                    }
                                } else if (mainReference[i]
                                    === comparator[i]) {
                                    return true;
                                }
                            }
                            // debugger
                            if (count && count === attributesCount) {
                                return true;
                            }
                        }
                    }

                } else {
                    if (primitiveTypes.test(typeof mainReference)) {
                        if (mainReference === comparator) {
                            return true;
                        }
                    }
                }
            }

            return false;
        }
    });

}(Object));

@@ -2511,17 +2511,16 @@
 rAttrs,%0A
-%0A
         
@@ -2582,16 +2582,83 @@
 rMethods
+,%0A                mainReferenceAttr,%0A                comparatorAttr
 ;%0A%0A     
@@ -3382,37 +3382,34 @@
 .attributes(
-mainReference
+comparator
 );%0A         
@@ -3458,29 +3458,26 @@
 methods(
-mainReference
+comparator
 );%0A%0A    
@@ -4482,16 +4482,649 @@
 Attrs) %7B
+%0A                                mainReferenceAttr = mainReference%5Bi%5D;%0A                                comparatorAttr = comparator%5Bi%5D;%0A%0A                                mainReferenceAttrs = Object%0A                                    .attributes(mainReferenceAttr);%0A                                mainReferenceMethods = Object%0A                                    .methods(mainReferenceAttr);%0A                                comparatorAttrs = Object%0A                                    .attributes(comparatorAttr);%0A                                comparatorMethods = Object%0A                                    .methods(comparatorAttr);
 %0A%0A      
@@ -5173,19 +5173,20 @@
 eference
-%5Bi%5D
+Attr
  === %22bo
@@ -5248,19 +5248,20 @@
 mparator
-%5Bi%5D
+Attr
  === %22bo
@@ -5319,19 +5319,20 @@
 eference
-%5Bi%5D
+Attr
  = mainR
@@ -5331,35 +5331,36 @@
  = mainReference
-%5Bi%5D
+Attr
 %0A               
@@ -5443,19 +5443,20 @@
 mparator
-%5Bi%5D
+Attr
  = compa
@@ -5460,19 +5460,20 @@
 mparator
-%5Bi%5D
+Attr
 %0A       
@@ -5602,19 +5602,20 @@
 eference
-%5Bi%5D
+Attr
  && comp
@@ -5612,35 +5612,36 @@
 tr && comparator
-%5Bi%5D
+Attr
 ) %7B%0A            
@@ -5682,19 +5682,20 @@
 eference
-%5Bi%5D
+Attr
 ).constr
@@ -5755,19 +5755,20 @@
 mparator
-%5Bi%5D
+Attr
 ).constr
@@ -5825,35 +5825,36 @@
 f (mainReference
-%5Bi%5D
+Attr
 %0A               
@@ -5956,35 +5956,36 @@
 f (mainReference
-%5Bi%5D
+Attr
 %0A               
@@ -6040,19 +6040,20 @@
 mparator
-%5Bi%5D
+Attr
 )) %7B%0A   
@@ -6211,35 +6211,36 @@
 f (mainReference
-%5Bi%5D
+Attr
 %0A               
@@ -6274,35 +6274,36 @@
   === comparator
-%5Bi%5D
+Attr
 ) %7B%0A            
@@ -6482,19 +6482,20 @@
 eference
-%5Bi%5D
+Attr
 %0A       
@@ -6537,19 +6537,20 @@
 mparator
-%5Bi%5D
+Attr
 ) %7B%0A    

fix itsEquivalentTo