// object utilities - marcus phillips
//
// a namespace for general object-orientation helpers

ou = Object();







// add_property()
//
// the add_property() function creates get() and set() methods on a target object (if not already applied), as well as a private variable ('_varname')
//
// use the following form
/*
  var my_obj = Object();
  ou.add_property(my_obj, 'foo', 4);
  alert(my_obj.get('foo')); // -> 4
  my_obj.set('foo', 3);
  alert(my_obj.get('foo')); // -> 3
*/

ou.add_property = function( target, name, default_value, allow_get, allow_set ){
  if( typeof(allow_get) === 'undefined' ){ allow_get = true; }
  if( typeof(allow_set) === 'undefined' ){ allow_set = true; }

  ou.add_property._conform(target);
  target.get._allow(name, allow_get);
  target.set._allow(name, allow_set);

  target.set(name, default_value);
};

ou.add_property._version = 'ju_property';

ou.add_property._conform = function( target ){
  if( ! ou.add_property._is_compatible(target) ){ alert('error - object not compatible with ju_accessor'); } //todo: throw
  if( target.get === undefined ){ target.get = ou.add_property._make_getter(); }
  if( target.set === undefined ){ target.set = ou.add_property._make_setter(); }
};

ou.add_property._is_compatible = function( target ){
  return(
    ( target.get === undefined || target.get._version !== 'ju_property' ) &&
    ( target.set === undefined || target.set._version !== 'ju_property' )
  );
};

ou.add_property._make_getter = function(){
  return ou.add_property._make_access_function(
    function( name        ){
      return this['_'+name];
    }
  );
};

ou.add_property._make_setter = function(){
  return ou.add_property._make_access_function(
    function( name, value ){
      this['_'+name] = value;
      return true;
    }
  );
};

ou.add_property._make_access_function = function( access_function_body ){
  var access_function = function(){
    if( ! access_function._allowences[arguments[0]] ){ alert('error - this access is not allowed'); } // todo: throw an error? todo: this assumes the first argument will always be the name of the attribute being accessed
    return access_function_body.apply(this, arguments);
  };
  access_function._version = ou.add_property._version;
  access_function._allowences = {};
  access_function._allow = function( name, state ){ access_function._allowences[name] = state; };
  return access_function;
};

