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(term, false, sort, leftToken, rightToken, false, false,
                false, false);
        }
    }

}

@@ -1112,32 +1112,36 @@
 ldASTs,%0A        
+    
 IToken leftToken
@@ -1155,32 +1155,32 @@
 n rightToken) %7B%0A
-
         IStrateg
@@ -1210,16 +1210,20 @@
 rTerm =%0A
+    
         
@@ -1311,24 +1311,24 @@
 Ts.size());%0A
-
         IStr
@@ -1619,32 +1619,36 @@
 oken leftToken,%0A
+    
         IToken r
@@ -1652,32 +1652,32 @@
 n rightToken) %7B%0A
-
         IStrateg
@@ -1929,32 +1929,36 @@
 oken leftToken,%0A
+    
         IToken r
@@ -1962,32 +1962,32 @@
 n rightToken) %7B%0A
-
         String c
@@ -2251,32 +2251,36 @@
 oken leftToken,%0A
+    
         IToken r
@@ -2284,32 +2284,32 @@
 n rightToken) %7B%0A
-
         IStrateg
@@ -2564,32 +2564,36 @@
 oken leftToken,%0A
+    
         IToken r
@@ -2597,32 +2597,32 @@
 n rightToken) %7B%0A
-
         IStrateg
@@ -3263,32 +3263,36 @@
 , false, false,%0A
+    
             fals
@@ -3294,32 +3294,32 @@
  false, false);%0A
-
         if(term.
@@ -3733,26 +3733,16 @@
 ));%0A    
-        %7D%0A
         
@@ -3792,16 +3792,20 @@
 r lists%0A
+    
         
@@ -3822,36 +3822,39 @@
 loderAttachment(
-term
+sublist
 , false, sort, l
@@ -3888,32 +3888,16 @@
 , false,
-%0A               
  false, 
@@ -3896,32 +3896,46 @@
  false, false);%0A
+            %7D%0A
         %7D%0A    %7D%0A

Put attachments on actual sublists.