package org.spoofax.jsglr2.imploder;

import static org.spoofax.jsglr.client.imploder.ImploderAttachment.putImploderAttachment;

import java.util.Collections;
import java.util.List;

import org.spoofax.interpreter.terms.IStrategoConstructor;
import org.spoofax.interpreter.terms.IStrategoList;
import org.spoofax.interpreter.terms.IStrategoTerm;
import org.spoofax.interpreter.terms.ITermFactory;
import org.spoofax.jsglr.client.imploder.IToken;
import org.spoofax.jsglr.client.imploder.ImploderAttachment;

public class TermTreeFactory implements ITreeFactory<IStrategoTerm> {

    private final ITermFactory termFactory;

    public TermTreeFactory(ITermFactory termFactory) {
        this.termFactory = termFactory;
    }

    @Override public IStrategoTerm createStringTerminal(String sort, String value, IToken token) {
        IStrategoTerm stringTerminalTerm = termFactory.makeString(value);

        configure(stringTerminalTerm, sort, token, token);

        return stringTerminalTerm;
    }

    @Override public IStrategoTerm createNonTerminal(String sort, String constructor, List<IStrategoTerm> childASTs,
            IToken leftToken, IToken rightToken) {
        IStrategoConstructor constructorTerm =
                termFactory.makeConstructor(constructor != null ? constructor : sort, childASTs.size());
        IStrategoTerm nonTerminalTerm = termFactory.makeAppl(constructorTerm, toArray(childASTs));

        configure(nonTerminalTerm, sort, leftToken, rightToken);

        return nonTerminalTerm;
    }

    @Override public IStrategoTerm createList(String sort, List<IStrategoTerm> children, IToken leftToken,
            IToken rightToken) {
        IStrategoTerm listTerm = termFactory.makeList(toArray(children));

        configure(listTerm, sort, leftToken, rightToken);

        return listTerm;
    }

    @Override public IStrategoTerm createOptional(String sort, List<IStrategoTerm> children, IToken leftToken,
            IToken rightToken) {
        String constructor = children == null || children.isEmpty() ? "None" : "Some";

        return createNonTerminal(sort, constructor, children, leftToken, rightToken);
    }

    @Override public IStrategoTerm createTuple(String sort, List<IStrategoTerm> children, IToken leftToken,
            IToken rightToken) {
        IStrategoTerm tupleTerm = termFactory.makeTuple(toArray(children));

        configure(tupleTerm, sort, leftToken, rightToken);

        return tupleTerm;
    }

    @Override public IStrategoTerm createAmb(String sort, List<IStrategoTerm> alternatives, IToken leftToken,
            IToken rightToken) {
        IStrategoTerm alternativesListTerm = createList(null, alternatives, leftToken, rightToken);

        return createNonTerminal(null, "amb", Collections.singletonList(alternativesListTerm), leftToken, rightToken);
    }

    private static IStrategoTerm[] toArray(List<IStrategoTerm> children) {
        return children.toArray(new IStrategoTerm[children.size()]);
    }

    protected void configure(IStrategoTerm term, String sort, IToken leftToken, IToken rightToken) {
        // rightToken can be null, e.g. for an empty string lexical
        putImploderAttachment(term, false, sort, leftToken, rightToken != null ? rightToken : leftToken, false, false,
                false, false);
        if(term.getTermType() == IStrategoTerm.LIST) {
            IStrategoList sublist = (IStrategoList) term;
            IToken lastRightToken;
            while(!sublist.isEmpty()) {
                lastRightToken = ImploderAttachment.getRightToken(sublist.head());
                sublist = sublist.tail();
                leftToken = sublist.isEmpty() ? lastRightToken : ImploderAttachment.getLeftToken(sublist.head());
                // assuming rightToken is never null for lists
                putImploderAttachment(sublist, false, sort, leftToken, rightToken, false, false, false, false);
            }
        }
    }

}

@@ -1112,36 +1112,32 @@
 ldASTs,%0A        
-    
 IToken leftToken
@@ -1151,32 +1151,32 @@
 n rightToken) %7B%0A
+
         IStrateg
@@ -1615,36 +1615,32 @@
 oken leftToken,%0A
-    
         IToken r
@@ -1644,32 +1644,32 @@
 n rightToken) %7B%0A
+
         IStrateg
@@ -1921,36 +1921,32 @@
 oken leftToken,%0A
-    
         IToken r
@@ -1950,32 +1950,32 @@
 n rightToken) %7B%0A
+
         String c
@@ -2239,36 +2239,32 @@
 oken leftToken,%0A
-    
         IToken r
@@ -2268,32 +2268,32 @@
 n rightToken) %7B%0A
+
         IStrateg
@@ -2552,28 +2552,24 @@
  leftToken,%0A
-    
         ITok
@@ -2577,32 +2577,32 @@
 n rightToken) %7B%0A
+
         IStrateg
@@ -3132,16 +3132,16 @@
 lexical%0A
+
         
@@ -3250,32 +3250,16 @@
 , false,
-%0A               
  false, 

Fix formatting.