part of mustache;

void _renderWithContext(_RenderContext ctx, List<_Node> nodes) {
  if (ctx.indent == null || ctx.indent == '') {
   nodes.forEach((n) => n.render(ctx));

  } else if (nodes.isNotEmpty) {
    // Special case to make sure there is not an extra indent after the last
    // line in the partial file.
    
    ctx.write(ctx.indent);
    
    for (var n in nodes.take(nodes.length - 1)) {
      n.render(ctx);
    }
        
    var node = nodes.last;
    if (node is _TextNode) {
      node.render(ctx, lastNode: true);
    } else {
      node.render(ctx);
    }
  }
}

abstract class _Node {
  
  _Node(this.start, this.end);
  
  void render(_RenderContext renderer);
  
  // The offset of the start of the token in the file. Unless this is a section
  // or inverse section, then this stores the start of the content of the
  // section.
  final int start;
  final int end;
  
  int contentStart;
  int contentEnd;
  
}


class _TextNode extends _Node {
  
  _TextNode(this.text, int start, int end) : super(start, end);
  
  final String text;
  
  void render(_RenderContext ctx, {lastNode: false}) {
    if (text == '') return;
    if (ctx.indent == null || ctx.indent == '') {
      ctx.write(text);
    } else if (lastNode && text.runes.last == _NEWLINE) {
      // Don't indent after the last line in a template.
      var s = text.substring(0, text.length - 1);
      ctx.write(s.replaceAll('\n', '\n${ctx.indent}'));
      ctx.write('\n');
    } else {
      ctx.write(text.replaceAll('\n', '\n${ctx.indent}'));
    }
  }
}

class _VariableNode extends _Node {
  
  _VariableNode(this.name, int start, int end, {this.escape: false})
    : super(start, end);
  
  final String name;
  final bool escape;
  
  void render(_RenderContext ctx) {
    
    var value = ctx.resolveValue(name);
    
    if (value is Function) {
      var context = new _LambdaContext(this, ctx, isSection: false);
      value = value(context);
      context.close();
    }
    
    if (value == _noSuchProperty) {
      if (!ctx.lenient) 
        throw ctx.error('Value was missing for variable tag: ${name}.', this);
    } else {
      var valueString = (value == null) ? '' : value.toString();
      var output = !escape || !ctx.htmlEscapeValues
        ? valueString
        : _htmlEscape(valueString);
      ctx.write(output);
    }
  }
  
  static const Map<String,String> _htmlEscapeMap = const {
    _AMP: '&amp;',
    _LT: '&lt;',
    _GT: '&gt;',
    _QUOTE: '&quot;',
    _APOS: '&#x27;',
    _FORWARD_SLASH: '&#x2F;' 
  };
  
  String _htmlEscape(String s) {
    
    var buffer = new StringBuffer();
    int startIndex = 0;
    int i = 0;
    for (int c in s.runes) {
      if (c == _AMP
          || c == _LT
          || c == _GT
          || c == _QUOTE
          || c == _APOS
          || c == _FORWARD_SLASH) {
        buffer.write(s.substring(startIndex, i));
        buffer.write(_htmlEscapeMap[c]);
        startIndex = i + 1;
      }
      i++;
    }
    buffer.write(s.substring(startIndex));
    return buffer.toString();
  }
}


class _SectionNode extends _Node {
  
  _SectionNode(this.name, int start, int end, this.delimiters,
      {this.inverse: false})
    : super(start, end);
  
  final String name;
  final String delimiters;
  final bool inverse;
  int contentStart;
  int contentEnd;
  final List<_Node> children = <_Node>[];
  
  //TODO can probably combine Inv and Normal to shorten.
  void render(_RenderContext ctx) => inverse
      ? renderInv(ctx)
      : renderNormal(ctx);
  
  void renderNormal(_RenderContext renderer) {
    var value = renderer.resolveValue(name);
    
    if (value == null) {
      // Do nothing.
    
    } else if (value is Iterable) {
      value.forEach((v) => _renderWithValue(renderer, v));
    
    } else if (value is Map) {
      _renderWithValue(renderer, value);
    
    } else if (value == true) {
      _renderWithValue(renderer, value);
    
    } else if (value == false) {
      // Do nothing.
    
    } else if (value == _noSuchProperty) {
      if (!renderer.lenient)
        throw renderer.error('Value was missing for section tag: ${name}.', this);
    
    } else if (value is Function) {
      var context = new _LambdaContext(this, renderer, isSection: true);
      var output = value(context);
      context.close();        
      renderer.write(output);
      
    } else {
      throw renderer.error('Invalid value type for section, '
        'section: ${name}, '
        'type: ${value.runtimeType}.', this);
    }
  }
  
  void renderInv(_RenderContext ctx) {
    var value = ctx.resolveValue(name);
    
    if (value == null) {
      _renderWithValue(ctx, null);
    
    } else if ((value is Iterable && value.isEmpty) || value == false) {
      _renderWithValue(ctx, name);
    
    } else if (value == true || value is Map || value is Iterable) {
      // Do nothing.
    
    } else if (value == _noSuchProperty) {
      if (ctx.lenient) {
        _renderWithValue(ctx, null);
      } else {
        throw ctx.error('Value was missing for inverse section: ${name}.', this);
      }
  
     } else if (value is Function) {       
      // Do nothing.
       //TODO in strict mode should this be an error?
  
    } else {
      throw ctx.error(
        'Invalid value type for inverse section, '
        'section: $name, '
        'type: ${value.runtimeType}.', this);
    }
  }
  
  void _renderWithValue(_RenderContext ctx, value) {
    ctx.pushValue(value);
    children.forEach((n) => n.render(ctx));
    ctx.popValue();
  }
}

class _PartialNode extends _Node {

  _PartialNode(this.name, int start, int end, this.indent)
    : super(start, end);
  
  final String name;
  
  // Used to store the preceding whitespace before a partial tag, so that
  // it's content can be correctly indented.
  final String indent;
  
  void render(_RenderContext ctx) {
    var partialName = name;
    _Template template = ctx.partialResolver == null
        ? null
        : ctx.partialResolver(partialName);
    if (template != null) {
      var partialCtx = new _RenderContext.partial(ctx, template, this.indent);
      _renderWithContext(partialCtx, template._nodes);
    } else if (ctx.lenient) {
      // do nothing
    } else {
      throw ctx.error('Partial not found: $partialName.', this);
    }
  }
}
