package dyvil.tools.dpf.ast.value;

import dyvil.collection.List;
import dyvil.collection.Map;
import dyvil.collection.mutable.ArrayList;
import dyvil.tools.dpf.ast.Expandable;
import dyvil.tools.dpf.visitor.StringInterpolationVisitor;
import dyvil.tools.dpf.visitor.ValueVisitor;
import dyvil.tools.parsing.ast.IASTNode;
import dyvil.tools.parsing.lexer.LexerUtil;

public class StringInterpolation extends ValueCreator implements Value, StringInterpolationVisitor, Expandable
{
	protected List<String> strings = new ArrayList<>();
	protected List<Value>  values  = new ArrayList<>();
	
	@Override
	public void visitStringPart(String string)
	{
		this.strings.add(string);
	}
	
	@Override
	protected void setValue(Value value)
	{
		this.values.add(value);
	}
	
	@Override
	public ValueVisitor visitValue()
	{
		return this;
	}
	
	@Override
	public void visitEnd()
	{
	}
	
	@Override
	public void accept(ValueVisitor visitor)
	{
		StringInterpolationVisitor v = visitor.visitStringInterpolation();
		int len = this.values.size();
		String s = this.strings.get(0);
		v.visitStringPart(s);
		
		for (int i = 0; i < len; i++)
		{
			this.values.get(i).accept(v.visitValue());
			v.visitStringPart(s);
		}
		
		v.visitEnd();
	}
	
	@Override
	public Object expand(Map<String, Object> mappings, boolean mutate)
	{
		// StringInterpolation stringInterpolation = mutate ? this : new StringInterpolation();

		StringBuilder builder = new StringBuilder();

		int index = 0;
		for (Value value : this.values)
		{
			Object o = Expandable.expand(value, mappings, mutate);

			builder.append(this.strings.get(index++));
			Constant constant;

			if (o instanceof String)
			{
				builder.append(o.toString());
			}
			else if (o instanceof Constant && (constant = (Constant) o).isConstant())
			{
				constant.appendString(builder);
			}
			else if (o instanceof Value)
			{
				// TODO What now?
				return this;
			}
			else
			{
				builder.append(o);
			}
		}

		// Add the last String
		builder.append(this.strings.get(index));

		return builder.toString();
	}

	@Override
	public String toString()
	{
		return IASTNode.toString(this);
	}

	@Override
	public void toString(String prefix, StringBuilder buffer)
	{
		int len = this.values.size();
		String s = this.strings.get(0);
		buffer.append('"');
		LexerUtil.appendStringLiteralBody(s, buffer);

		for (int i = 0; i < len; i++)
		{
			buffer.append("\\(");
			this.values.get(i).toString(prefix, buffer);
			s = this.strings.get(i + 1);
			buffer.append(')');
			LexerUtil.appendStringLiteralBody(s, buffer);
		}
		buffer.append('"');
	}
}

@@ -951,17 +951,29 @@
 Visitor 
-v
+stringVisitor
  = visit
@@ -1005,16 +1005,22 @@
 on();%0A%09%09
+final 
 int len 
@@ -1045,63 +1045,60 @@
 ();%0A
+%0A
 %09%09
-S
+s
 tring
- s = this.strings.get(0);%0A%09%09v.visitStringPart(s
+Visitor.visitStringPart(this.strings.get(0)
 );%0A%09
@@ -1164,17 +1164,29 @@
 .accept(
-v
+stringVisitor
 .visitVa
@@ -1196,17 +1196,29 @@
 ());%0A%09%09%09
-v
+stringVisitor
 .visitSt
@@ -1230,22 +1230,56 @@
 art(
-s);%0A%09%09%7D%0A%09%09%0A%09%09v
+this.strings.get(i + 1));%0A%09%09%7D%0A%09%09%0A%09%09stringVisitor
 .vis
@@ -1932,30 +1932,8 @@
 %09%09%7B%0A
-%09%09%09%09// TODO What now?%0A
 %09%09%09%09
@@ -2285,42 +2285,8 @@
 ();%0A
-%09%09String s = this.strings.get(0);%0A
 %09%09bu
@@ -2331,33 +2331,51 @@
 ringLiteralBody(
-s
+this.strings.get(0)
 , buffer);%0A%0A%09%09fo
@@ -2483,40 +2483,8 @@
 r);%0A
-%09%09%09s = this.strings.get(i + 1);%0A
 %09%09%09b
@@ -2539,17 +2539,39 @@
 ralBody(
-s
+this.strings.get(i + 1)
 , buffer

Fix DPF StringInterpolation.accept