<?php

namespace CoffeeScript;

class yy_If extends yy_Base
{
  public $children = array('condition', 'body', 'else_body');

  function constructor($condition, $body, $options = array())
  {
    $this->condition = (isset($options['type']) && $options['type'] === 'unless') ? $condition->invert() : $condition;
    $this->body = $body;
    $this->else_body = NULL;
    $this->is_chain = FALSE;
    $this->soak = isset($options['soak']) ? $options['soak'] : NULL;

    return $this;
  }

  function add_else($else_body)
  {
    if ($this->is_chain())
    {
      $this->else_body_node()->add_else($else_body);
    }
    else
    {
      $this->is_chain = $else_body instanceof yy_If;
      $this->else_body = $this->ensure_block($else_body);
    }

    return $this;
  }

  function body_node()
  {
    return $this->body ? $this->body->unwrap() : NULL;
  }

  function compile_node($options = array())
  {
    return $this->is_statement($options) ? $this->compile_statement($options) : $this->compile_expression($options);
  }

  function compile_expression($options)
  {
    $cond = $this->condition->compile($options, LEVEL_COND);
    $body = $this->body_node()->compile($options, LEVEL_LIST);

    $alt = ($tmp = $this->else_body_node()) ? $tmp->compile($options, LEVEL_LIST) : 'void 0';
    $code = "{$cond} ? {$body} : {$alt}";

    return (isset($options['level']) && $options['level'] >= LEVEL_COND) ? "({$code})" : $code;
  }

  function compile_statement($options)
  {
    $child = del($options, 'chainChild');
    $exeq = del($options, 'isExistentialEquals');

    if ($exeq)
    {
      return yy('If', $this->condition->invert(), $this->else_body_node(), array('type' => 'if'))->compile($options);
    }

    $cond = $this->condition->compile($options, LEVEL_PAREN);
    $options['indent'] .= TAB;
    $body = $this->ensure_block($this->body);
    $if_part = "if ({$cond}) {\n".$body->compile($options)."\n{$this->tab}}";

    if ( ! $child)
    {
      $if_part = $this->tab.$if_part;
    }

    if ( ! $this->else_body)
    {
      return $if_part;
    }

    $ret = $if_part.' else ';

    if ($this->is_chain())
    {
      $options['indent'] = $this->tab;
      $options['chainChild'] = TRUE;

      $ret .= $this->else_body->unwrap()->compile($options, LEVEL_TOP);
    }
    else
    {
      $ret .= "{\n".$this->else_body->compile($options, LEVEL_TOP)."\n{$this->tab}}";
    }

    return $ret;
  }

  function else_body_node()
  {
    return (isset($this->else_body) && $this->else_body) ? $this->else_body->unwrap() : NULL;
  }

  function ensure_block($node)
  {
    return $node instanceof yy_Block ? $node : yy('Block', array($node));
  }

  function is_chain()
  {
    return $this->is_chain;
  }

  function is_statement($options = array())
  {
    return (isset($options['level']) && $options['level'] === LEVEL_TOP) ||
      $this->body_node()->is_statement($options) ||
      (($tmp = $this->else_body_node()) && $tmp->is_statement($options));
  }

  function jumps($options = array())
  {
    $tmp = $this->body->jumps($options);

    if ( ! $tmp && isset($this->else_body))
    {
      $tmp = $this->else_body->jumps($options);
    }

    return $tmp;
  }

  function make_return($res = NULL)
  {
    if ( ! (isset($this->else_body) && $this->else_body))
    {
      if ($res)
      {
        $this->else_body = yy('Block', array(yy('Literal', 'void 0')));
      }
    }

    if ($this->body)
    {
      $this->body = yy('Block', array($this->body->make_return($res)));
    }

    if ($this->else_body)
    {
      $this->else_body = yy('Block', array($this->else_body->make_return($res)));
    }

    return $this;
  }

  function unfold_soak($options = NULL)
  {
    return $this->soak ? $this : FALSE;
  }
}

?>