<html>
  <body>
  <script src="display.js"></script>
  <script src="script.js"></script>
  </body>
</html>
'use strict';

let cat = {
  name: 'Fluffy',
  color: 'White',
  phone: {
    house: 891,
    off: 112
  }
  // official name:'Fluffy Cat'
  //Such Identifier is Invalid
};

display(cat);
display(cat.color);
/*
Bracket notation to access the properties
this is important coz ofeten the I dentifier Name are often
supplied with invalid identifierName
*/
display(cat['color']);

cat['official name'] = 'Fluffy Cat';
display(cat['official name']);

//PropertyDescriptor
display(Object.getOwnPropertyDescriptor(cat, 'name'));

//Changing the property behaviour

Object.defineProperty(cat, 'name', {
  writable: false
});
display(Object.getOwnPropertyDescriptor(cat, 'name'));
/*below line throw error
Uncaught TypeError: Cannot assign to read only 
property 'name' of object '#<Object>'
NOTE: The Error is only thrpwn in the strict Mode
*/
//cat.name = 'Floppy';

/*
If the property contains an object
then the modification is allowed.
As the property name is just a pointer to the object.
If the read-Only need to be applied to the object
then below needs to be done after making the {writable:fale}
Object.freeze(cat.phone)
*/
Object.defineProperty(cat, 'phone', {
  writable: false
});
Object.getOwnPropertyDescriptor(cat, 'phone');
cat.phone.off = 990;
display(cat.phone);

//Object.freeze(cat.phone);
//script.js:56 Uncaught TypeError: Cannot assign to read only property 'off' of object '#<Object>'
//cat.phone.off = 991;

//ENUMERABLE Property
/*
Setting Enumerable to false 
1.Effects Seriallization
2.hides the property from the OBJECT keys
3.But we can directly see the property value
*/
display('Enumerable Properties to true');
for (let propertyName in cat) {
  display(propertyName + ' : ' + cat[propertyName]);
}
Object.defineProperty(cat, 'name', {
  enumerable: false
});


display('Enumerable Properties to false');
for (let propertyName in cat) {
  display(propertyName + ' : ' + cat[propertyName]);
}
display('Direct accessing the value bby name:',cat['name']);

//Object keys
display(Object.keys(cat));

//Seriallization
display(JSON.stringify(cat));

//Direct Access:
display(cat.name);
display(cat['name']);
Object.defineProperty(cat, 'name', {
  enumerable: true
});

//Configurable:
/*
on setting the configurable to fale following things get restricted:
configurable property
Enumerable property
delete the exisitng property of the object
*/

Object.defineProperty(cat, 'name', {
 // configurable: false
});
//below lines throw error
//Object.defineProperty(cat, 'name', {enumerable : false});

//Cannot redefine property: name

/*
Object.defineProperty(cat, 'name', {
  configurable: true
});
*/
//Cannot delete property 'name' of #<Object>
//delete cat.name;

//GETTERS And SETTERS
Object.defineProperty(cat,'phone',{writable:true});
//Object.freeze(cat,'phone');

Object.defineProperty(cat,'fullPhone',{
  get:function(){
    return this.phone.house.toString() +this.phone.off;
  },
  set: function(value){
    this.phone.house =Number(value.split(' ')[0].toString());
    this.phone.off = Number(value.split(' ')[1].toString());
  }
});
display(cat.phone.house);
display(cat.phone.off);

display('Full Phone',cat.fullPhone);
cat.fullPhone = '123 345'
display(cat.fullPhone);




















function display() {
  for (var i = 0; i < arguments.length; i++) {
    if (typeof arguments[i] === 'object') 
      displayObject(arguments[i])
    else
      displayValue(arguments[i], true)
  }
}
function display1() {
  for (var i = 0; i < arguments.length; i++) {
    if (typeof arguments[i] === 'object') 
      displayObject(arguments[i])
    else
      displayValue(arguments[i], true)
  }
}

function displayObject(object) {
  if (object == null)
    displayValue('null')
  displayValue(getTypeName(object) + ' {')
  for(var propertyName in object) {
    if (propertyName != 'constructor') {
      displayValue(propertyName + ': ' + object[propertyName], false, true);
    }
  }
  displayValue('}', true)
}

function displayValue(value, addMargin, addPadding) {
  var div = document.createElement('div');
  div.style.fontSize='32px'
  if (addMargin)
    div.style.marginBottom='30px'
  if (addPadding)
    div.style.paddingLeft='30px'
  div.textContent = value;
  document.body.appendChild(div)
}

function getTypeName(object) {
   var funcNameRegex = /function (.{1,})\(/;
   var results = (funcNameRegex).exec(object.constructor.toString());
   return (results && results.length > 1) ? results[1] : "";
}