package transform;

import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

public class ScriptGenerator
{
    public List<String> m_warnings = new ArrayList<>();
    private List<String> m_operations = new ArrayList<>();

    @Override
    public String toString()
    {
        StringBuilder sb = new StringBuilder();

        sb.append("# Generated: " + ZonedDateTime.now( ZoneOffset.UTC ) + " (UTC)\n#\n");

        sb.append("# WARNINGS:\n#\n");
        for (String s : m_warnings)
        {
            sb.append(s);
            sb.append("\n");
        }
        if (m_warnings.isEmpty())
            sb.append("# I got 99 problems, but your changes ain't one.\n");

        sb.append("\n# SCRIPT:\n\nMODE FRAMED\n\n");
        for (String s : m_operations)
        {
            sb.append(s);
            sb.append("\n");
        }

        return sb.toString();
    }

    public void resolveMove(String fromPath, String toPath)
    {
        List<String> from = Arrays.asList(fromPath.split(","));
        List<String> to = Arrays.asList(toPath.split(","));

        if (Collections.frequency(from, "_list") != Collections.frequency(to, "_list"))
        {
            m_warnings.add("# I dare not generate code for this diff, because the paths differ in number of lists.\n" +
                    "# Please resolve the diff manually. (Severity: HIGH)\n" +
                    "#    " + fromPath + "\n# -> " + toPath);
            return;
        }

        List<String> operations = generatePivotPointMoves(from, to);
        if (!operations.isEmpty())
        {
            m_operations.add("# Resulting from observed grammar diff:\n#    " + fromPath + "\n# -> " + toPath);
            m_operations.addAll(operations);
            m_operations.add(""); // empty line
        }
    }

    /**
     * Lists ("_list") forms pivots points of sorts in the transformation. In the diffing part of the path,
     * each list must be matched up to its transformed equivalence. If the number of "_list"s diff, the change
     * can't be resolved with any certainty (Which list should be collapsed?).
     */
    private List<String> generatePivotPointMoves(List<String> from, List<String> to)
    {
        final String indentation = "    ";
        List<String> resultingOperations = new ArrayList<>();

        List<String> sourceList = new ArrayList<>();
        List<String> targetList = new ArrayList<>();

        int level = 0;
        List<Integer> listsAtFromDiffIndex = new ArrayList<>();
        for (int i = 0; i < from.size(); ++i)
        {
            String node = from.get(i);
            if (node.equals("_list"))
            {
                sourceList.add("it" + (level++));
                listsAtFromDiffIndex.add(i);
            }
            else
                sourceList.add(node);
        }

        level = 0;
        for (String node: to)
        {
            if (node.equals("_list"))
                targetList.add("it"+(level++));
            else
                targetList.add(node);
        }

        String tabs = "";
        for (int i = 0; i < listsAtFromDiffIndex.size(); ++i)
        {
            resultingOperations.add(tabs + "FOREACH it" + i + " : " + String.join(",", sourceList.subList(0, listsAtFromDiffIndex.get(i))));
            resultingOperations.add(tabs + "{");
            tabs += indentation;
        }

        resultingOperations.add(tabs + "MOVE " + String.join(",",sourceList) +
                "\n" + tabs + "  -> " + String.join(",",targetList));

        for (int i = 0; i < listsAtFromDiffIndex.size(); ++i)
        {
            tabs = "";
            for (int j = 1; j < (listsAtFromDiffIndex.size()-i); ++j)
                tabs += indentation;
            resultingOperations.add(tabs + "}");
        }

        return resultingOperations;
    }
}

@@ -1178,398 +1178,8 @@
 );%0A%0A
-        if (Collections.frequency(from, %22_list%22) != Collections.frequency(to, %22_list%22))%0A        %7B%0A            m_warnings.add(%22# I dare not generate code for this diff, because the paths differ in number of lists.%5Cn%22 +%0A                    %22# Please resolve the diff manually. (Severity: HIGH)%5Cn%22 +%0A                    %22#    %22 + fromPath + %22%5Cn# -%3E %22 + toPath);%0A            return;%0A        %7D%0A%0A
     
@@ -1243,16 +1243,16 @@
 m, to);%0A
+
         
@@ -1734,77 +1734,46 @@
 the 
-change%0A     * can't be resolved with any certainty (Which list should
+rightmost lists%0A     * are selected to
  be 
@@ -1785,10 +1785,8 @@
 psed
-?)
 .%0A  
@@ -2515,32 +2515,65 @@
      level = 0;%0A
+        int targetPathLists = 0;%0A
         for (Str
@@ -2626,32 +2626,291 @@
 quals(%22_list%22))%0A
+            %7B%0A                // Only replace a _list node with a itX node if there's a corresponding list in the from path.%0A                // otherwise, just pick the first element (0).%0A                if (targetPathLists %3C listsAtFromDiffIndex.size())%0A    
                 
@@ -2928,17 +2928,19 @@
 add(%22it%22
-+
+ + 
 (level++
@@ -2935,32 +2935,143 @@
 %22 + (level++));%0A
+                else%0A                    targetList.add(%220%22);%0A                ++targetPathLists;%0A            %7D%0A
             else

Make transform script generation slightly more aggressive.