<?php

abstract class JSBase
{

  public $excludeBrackets = false;

  public $values = array ();

  /**
   *
   * @var JSBase $parent
   */
  public $parent = null;

  /**
   *
   * @var string $key
   */
  public $key = null;

  public function __construct(array $array = array())
  {
    $this->values = $array;
  }

  public function add($key, $value)
  {
    $this->values [$key] = $value;
  }

  /**
   *
   * @param string $key          
   * @return JSArray
   */
  public function addArray($key)
  {
    if (isset ( $this->values [$key] ) && $this->values [$key] instanceof JSArray)
      return $this->values [$key];
    $value = new JSArray ();
    $value->key = $key;
    $value->parent = $this;
    $this->add ( $key, $value );
    return $value;
  }

  /**
   *
   * @param string $key          
   * @return JSObject
   */
  public function addObject($key)
  {
    if (isset ( $this->values [$key] ) && $this->values [$key] instanceof JSObject)
      return $this->values [$key];
    $value = new JSObject ();
    $value->key = $key;
    $value->parent = $this;
    $this->add ( $key, $value );
    return $value;
  }

  protected function formatValue($value)
  {
    if (is_bool ( $value ))
      return $value ? "true" : "false";
    
    if (is_int ( $value ))
      return "{$value}";
    
    if (is_float ( $value ))
      return "{$value}";
    
    if (is_array ( $value ))
      $value = new JSArray ( $value );
    
    if (is_object ( $value ) && ! ($value instanceof JSBase))
      $value = new JSObject ( ( array ) $value );
    
    if ($value instanceof JSBase)
      return $value->__toString ();
    
    return "\"" . str_replace ( "\"", "\\\"", "{$value}" ) . "\"";
  }

  protected abstract function formatItem($index, $key, $value);

  protected abstract function getOpenBracket();

  protected abstract function getCloseBracket();

  public function __toString()
  {
    $buffer = new StringWriter ();
    $index = 0;
    if (! $this->excludeBrackets)
      $buffer->writeline ( $this->getOpenBracket () );
    foreach ( $this->values as $key => $value )
    {
      if ($index > 0)
        $buffer->writeline ( "," );
      $buffer->write( $this->formatItem ( $index, $key, $value ) );
      $index ++;
    }
    $buffer->writeline();
    if (! $this->excludeBrackets)
      $buffer->write ( $this->getCloseBracket () );
    return $buffer->__toString ();
  }
}