/*
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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.
 *
*/

var utils = require('cordova/utils');

function each(objects, func, context) {
    for (var prop in objects) {
        if (objects.hasOwnProperty(prop)) {
            func.apply(context, [objects[prop], prop]);
        }
    }
}

function assignOrWrapInDeprecateGetter(obj, key, value, message) {
    if (message) {
        utils.defineGetter(obj, key, function() {
            window.console && console.log(message);
            return value;
        });
    } else {
        obj[key] = value;
    }
}

function include(parent, objects, clobber, merge) {
    each(objects, function (obj, key) {
        try {
          var result = obj.path ? require(obj.path) : {};

          if (clobber) {
              // Clobber if it doesn't exist.
              if (typeof parent[key] === 'undefined') {
                  assignOrWrapInDeprecateGetter(parent, key, result, obj.deprecated);
              } else if (typeof obj.path !== 'undefined') {
                  // If merging, merge properties onto parent, otherwise, clobber.
                  if (merge) {
                      recursiveMerge(parent[key], result);
                  } else {
                      assignOrWrapInDeprecateGetter(parent, key, result, obj.deprecated);
                  }
              }
              result = parent[key];
          } else {
            // Overwrite if not currently defined.
            if (typeof parent[key] == 'undefined') {
              assignOrWrapInDeprecateGetter(parent, key, result, obj.deprecated);
            } else if (merge && typeof obj.path !== 'undefined') {
              // If merging, merge parent onto result
              recursiveMerge(result, parent[key]);
              parent[key] = result;
            } else {
              // Set result to what already exists, so we can build children into it if they exist.
              result = parent[key];
            }
          }

          if (obj.children) {
            include(result, obj.children, clobber, merge);
          }
        } catch(e) {
          utils.alert('Exception building cordova JS globals: ' + e + ' for key "' + key + '"');
        }
    });
}

/**
 * Merge properties from one object onto another recursively.  Properties from
 * the src object will overwrite existing target property.
 *
 * @param target Object to merge properties into.
 * @param src Object to merge properties from.
 */
function recursiveMerge(target, src) {
    for (var prop in src) {
        if (src.hasOwnProperty(prop)) {
            if (typeof target.prototype !== 'undefined' && target.prototype.constructor === target) {
                // If the target object is a constructor override off prototype.
                target.prototype[prop] = src[prop];
            } else {
                target[prop] = typeof src[prop] === 'object' ? recursiveMerge(
                        target[prop], src[prop]) : src[prop];
            }
        }
    }
    return target;
}

module.exports = {
    build: function (objects) {
        return {
            intoButDoNotClobber: function (target) {
                include(target, objects, false, false);
            },
            intoAndClobber: function(target) {
                include(target, objects, true, false);
            },
            intoAndMerge: function(target) {
                include(target, objects, true, true);
            }
        };
    }
};

@@ -1029,32 +1029,267 @@
      %7D%0A    %7D%0A%7D%0A%0A
+function clobber(obj, key, value) %7B%0A    obj%5Bkey%5D = value;%0A    // Getters can only be overridden by getters.%0A    if (obj%5Bkey%5D !== value) %7B%0A        utils.defineGetter(obj, key, function() %7B%0A            return value;%0A        %7D);%0A    %7D%0A%7D%0A%0A
 function assignO
@@ -1335,24 +1335,24 @@
  message) %7B%0A
-
     if (mess
@@ -1423,26 +1423,8 @@
     
- window.console &&
  con
@@ -1501,32 +1501,40 @@
         
+clobber(
 obj
-%5Bkey%5D =
+, key,
  value
+)
 ;%0A    %7D%0A
@@ -3802,23 +3802,12 @@
     
-target%5Bprop%5D = 
+if (
 type
@@ -3835,63 +3835,153 @@
 ect'
- ? recursiveMerge(%0A                        
+) %7B%0A                    target%5Bprop%5D = recursiveMerge(target%5Bprop%5D, src%5Bprop%5D);%0A                %7D else %7B%0A                    clobber(
 target
-%5B
+, 
 prop
-%5D
 , sr
@@ -3992,21 +3992,27 @@
 op%5D)
- : src%5Bprop%5D;
+;%0A                %7D
 %0A   

Use JS getters to clobber getters in buider.js