/*
 * This file is released under terms of BSD license
 * See LICENSE file for more information
 */

package cx2x.translator.language.helper.accelerator;

import cx2x.translator.common.Utility;
import cx2x.translator.config.Configuration;
import cx2x.translator.language.helper.target.Target;

import java.util.List;

/**
 * OpenMP base accelerator directive generator. Implements everything that is
 * common for host and device target.
 *
 * @author clementval
 */
class OpenMp extends AcceleratorGenerator {

  private static final String OPENMP_PREFIX = "omp";
  private static final String OPENMP_DECLARE = "declare";
  private static final String OPENMP_TARGET = "target";
  private static final String OPENMP_PARALLEL = "parallel";
  private static final String OPENMP_PRIVATE = "private";
  private static final String OPENMP_DO = "do";
  private static final String OPENMP_END = "end";

  /**
   * Constructs a new object with the given target.
   *
   * @param config Configuration information object.
   */
  OpenMp(Configuration config) {
    super(config);
  }

  @Override
  protected String getPrefix() {
    return OPENMP_PREFIX;
  }

  @Override
  protected String getStartParallelDirective() {
    if(getConfiguration().getCurrentTarget() == Target.CPU) {
      //!$omp parallel
      return String.format(FORMAT2,
          OPENMP_PREFIX, OPENMP_PARALLEL);
    } else {
      //!$omp target parallel do
      return String.format(FORMAT3,
          OPENMP_PREFIX, OPENMP_TARGET, OPENMP_PARALLEL);
    }
  }

  @Override
  public String getEndParallelDirective() {
    if(getConfiguration().getCurrentTarget() == Target.CPU) {
      //!$omp end parallel
      return String.format(FORMAT3,
          OPENMP_PREFIX, OPENMP_END, OPENMP_PARALLEL);
    } else {
      //!$omp end target parallel do
      return String.format(FORMAT4,
          OPENMP_PREFIX, OPENMP_END, OPENMP_TARGET, OPENMP_PARALLEL);
    }
  }

  @Override
  public String getSingleDirective(String clause) {
    //!$omp <clause>
    return String.format(FORMAT2, OPENMP_PREFIX, clause);
  }

  @Override
  protected String getParallelKeyword() {
    return OPENMP_PARALLEL;
  }

  @Override
  protected String getPrivateClause(String var) {
    return String.format(FORMATPAR, OPENMP_PRIVATE, var);
  }

  @Override
  protected String getPrivateClause(List<String> vars) {
    if(vars == null || vars.size() == 0) {
      return "";
    }
    return String.format(FORMATPAR, OPENMP_PRIVATE, Utility.join(",", vars));
  }

  @Override
  protected String getPresentClause(List<String> vars) {
    return ""; // TODO OpenMP
  }

  @Override
  protected String getRoutineDirective() {
    // TODO check
    return String.format(FORMAT3, OPENMP_PREFIX, OPENMP_DECLARE, OPENMP_TARGET);
  }

  @Override
  public boolean isCompileGuard(String rawDirective) {
    return rawDirective.toLowerCase().startsWith(OPENMP_PREFIX) &&
        rawDirective.toLowerCase().contains(COMPILE_GUARD);
  }

  @Override
  public AcceleratorDirective getDirectiveLanguage() {
    return AcceleratorDirective.OPENMP;
  }

  @Override
  public String getStartDataRegion() {
    return null; // TODO OpenMP
  }

  @Override
  public String getEndDataRegion() {
    return null; // TODO OpenMP
  }

  @Override
  public String getSequentialClause() {
    return null; // TODO OpenMP if makes sense
  }

  @Override
  protected String getStartLoopDirective(int value) {
    // TODO CPU/GPU difference
    //!$omp do
    return String.format(FORMAT2, OPENMP_PREFIX, OPENMP_DO);
  }

  @Override
  protected String getEndLoopDirective() {
    // TODO CPU/GPU difference
    //!$omp end do
    return String.format(FORMAT3, OPENMP_PREFIX, OPENMP_END, OPENMP_DO);
  }
}

@@ -1252,33 +1252,33 @@
 get() == Target.
-C
+G
 PU) %7B%0A      //!$
@@ -1281,16 +1281,23 @@
 //!$omp 
+target 
 parallel
@@ -1330,17 +1330,17 @@
 t(FORMAT
-2
+3
 ,%0A      
@@ -1349,32 +1349,47 @@
   OPENMP_PREFIX,
+ OPENMP_TARGET,
  OPENMP_PARALLEL
@@ -1418,31 +1418,24 @@
 //!$omp 
-target 
 parallel
  do%0A    
@@ -1418,35 +1418,32 @@
 //!$omp parallel
- do
 %0A      return St
@@ -1452,33 +1452,33 @@
 ng.format(FORMAT
-3
+2
 ,%0A          OPEN
@@ -1483,39 +1483,24 @@
 ENMP_PREFIX,
- OPENMP_TARGET,
  OPENMP_PARA
@@ -1628,17 +1628,17 @@
  Target.
-C
+G
 PU) %7B%0A  
@@ -1653,16 +1653,23 @@
 omp end 
+target 
 parallel
@@ -1694,33 +1694,33 @@
 ng.format(FORMAT
-3
+4
 ,%0A          OPEN
@@ -1733,32 +1733,47 @@
 FIX, OPENMP_END,
+ OPENMP_TARGET,
  OPENMP_PARALLEL
@@ -1806,31 +1806,24 @@
 omp end 
-target 
 parallel
  do%0A    
@@ -1814,19 +1814,16 @@
 parallel
- do
 %0A      r
@@ -1840,33 +1840,33 @@
 ng.format(FORMAT
-4
+3
 ,%0A          OPEN
@@ -1883,39 +1883,24 @@
  OPENMP_END,
- OPENMP_TARGET,
  OPENMP_PARA
@@ -3143,33 +3143,37 @@
 ; // TODO OpenMP
+ 4.5
 %0A
-
   %7D%0A%0A  @Override
@@ -3233,32 +3233,36 @@
 ; // TODO OpenMP
+ 4.5
 %0A  %7D%0A%0A  @Overrid
@@ -3339,22 +3339,11 @@
 nMP 
-if makes sense
+4.5
 %0A  %7D

Swap the conditional