/*
 * This file is released under terms of BSD license
 * See LICENSE file for more information
 */
package cx2x.translator.transformation.loop;

import cx2x.translator.language.base.ClawLanguage;
import cx2x.translator.transformation.ClawTransformation;
import cx2x.xcodeml.helper.XnodeUtil;
import cx2x.xcodeml.transformation.Transformation;
import cx2x.xcodeml.transformation.Transformer;
import cx2x.xcodeml.xnode.Xcode;
import cx2x.xcodeml.xnode.XcodeProgram;
import cx2x.xcodeml.xnode.Xnode;

/**
 * If extraction transformation
 *
 * @author clementval
 */
public class IfExtract extends ClawTransformation {

  private Xnode _doStmt = null;
  private Xnode _ifStmt = null;

  public IfExtract(ClawLanguage directive) {
    super(directive);
  }

  @Override
  public boolean analyze(XcodeProgram xcodeml, Transformer transformer) {
    _doStmt = _claw.getPragma().matchSibling(Xcode.FDOSTATEMENT);
    if(_doStmt == null) {
      xcodeml.addError("Do statement missing after directive.",
          _claw.getPragma().lineNo());
      return false;
    }
    _ifStmt = _doStmt.body().matchDirectDescendant(Xcode.FIFSTATEMENT);
    if(_ifStmt == null) {
      xcodeml.addError("If statement not found in the do statement.",
          _claw.getPragma().lineNo());
      return false;
    }
    if(_ifStmt.matchDirectDescendant(Xcode.ELSE) != null) {
      xcodeml.addError("If extraction works only with IF-THEN block.",
          _claw.getPragma().lineNo());
      return false;
    }
    int counterIfStmt = 0;
    for(Xnode n : _doStmt.body().children()) {
      if(n.opcode() != Xcode.FIFSTATEMENT
          && n.opcode() != Xcode.FPRAGMASTATEMENT)
      {
        xcodeml.addError("If statement is not purely nested in the do statement",
            _claw.getPragma().lineNo());
        return false;
      } else if(n.opcode() == Xcode.FIFSTATEMENT) {
        ++counterIfStmt;
      }
    }
    if(counterIfStmt > 1) {
      xcodeml.addError("Only one if statement can be present for extraction.",
          _claw.getPragma().lineNo());
      return false;
    }
    return true;
  }

  @Override
  public boolean canBeTransformedWith(XcodeProgram xcodeml,
                                      Transformation other)
  {
    return false;
  }

  @Override
  public void transform(XcodeProgram xcodeml, Transformer transformer,
                        Transformation other) throws Exception
  {
    // Copy the body of the if statement inside the body of the do statement
    Xnode then = _ifStmt.matchDirectDescendant(Xcode.THEN);
    XnodeUtil.appendBody(_doStmt.body(), then.body());


    // Copy the if statement and clean its body
    Xnode newIfStmt = _ifStmt.cloneNode();
    Xnode newThen = newIfStmt.matchDirectDescendant(Xcode.THEN);
    for(Xnode n : newThen.body().children()) {
      n.delete();
    }
    _ifStmt.delete();

    // Add the new if statement after the do statement
    XnodeUtil.insertAfter(_doStmt.element(), newIfStmt.element());

    // Insert the do statement in the new if statement
    newThen.body().insert(_doStmt, true);

    // Delete the old statements and pragma
    _doStmt.delete();
    _claw.getPragma().delete();
  }
}

@@ -1291,204 +1291,8 @@
   %7D%0A
-    if(_ifStmt.matchDirectDescendant(Xcode.ELSE) != null) %7B%0A      xcodeml.addError(%22If extraction works only with IF-THEN block.%22,%0A          _claw.getPragma().lineNo());%0A      return false;%0A    %7D%0A
     
@@ -2292,16 +2292,21 @@
 ode then
+Block
  = _ifSt
@@ -2339,24 +2339,68 @@
 code.THEN);%0A
+    Xnode thenDoStmt = _doStmt.cloneNode();%0A
     XnodeUti
@@ -2412,18 +2412,21 @@
 endBody(
-_d
+thenD
 oStmt.bo
@@ -2435,16 +2435,21 @@
 (), then
+Block
 .body())
@@ -2451,17 +2451,16 @@
 dy());%0A%0A
-%0A
     // C
@@ -2681,30 +2681,8 @@
    %7D
-%0A    _ifStmt.delete();
 %0A%0A  
@@ -2838,32 +2838,37 @@
 nt in the new if
+-then
  statement%0A    n
@@ -2892,95 +2892,818 @@
 ert(
-_doStmt, true);%0A%0A    // Delete the old statements and pragma%0A    _doStmt.delete();%0A    
+thenDoStmt, false);%0A%0A    Xnode elseBlock = _ifStmt.matchDirectDescendant(Xcode.ELSE);%0A    if(elseBlock != null) %7B%0A      Xnode elseDoStmt = _doStmt.cloneNode();%0A      XnodeUtil.appendBody(elseDoStmt.body(), elseBlock.body());%0A      Xnode newElse = newIfStmt.matchDirectDescendant(Xcode.ELSE);%0A      for(Xnode n : newElse.body().children()) %7B%0A        n.delete();%0A      %7D%0A      newElse.body().insert(elseDoStmt, false);%0A      Xnode duplicateIf = elseDoStmt.body().matchDirectDescendant(Xcode.FIFSTATEMENT);%0A      XnodeUtil.safeDelete(duplicateIf);%0A    %7D%0A%0A    // Delete the old statements and pragma%0A    Xnode duplicateIf =%0A        thenDoStmt.body().matchDirectDescendant(Xcode.FIFSTATEMENT);%0A    duplicateIf.delete();%0A    XnodeUtil.safeDelete(_ifStmt);%0A    XnodeUtil.safeDelete(_doStmt);%0A    XnodeUtil.safeDelete(
 _cla
@@ -3715,24 +3715,16 @@
 Pragma()
-.delete(
 );%0A  %7D%0A%7D

Enable else block in if-extract