/*

Copyright: All contributers to the Umple Project

This file is made available subject to the open source license found at:
https://umple.org/license

Methods for the metamodel found in Umple.ump. Most of these are mixins.

 */


namespace cruise.umple.compiler;

use Method;
use Class;
use Association;
use Constraint;
/**
 * In Umple_Code.ump: Methods for manipulating the Model
 */
class UmpleModel
{

    //ParsingTime represents Parsing end time
    //gTime1 represents code generation start time
    //gTime2 represents code generation end time
    Double parsingTime = 0.0;
    internal Double gTime1 = 0.0;
    internal Double gTime2 = 0.0;
    
    Map<String, String> hashMap = new HashMap<String, String>();
    
  public static String[] findValidLanguages()
  {
    final String NONTERMINAL = "generate";
    final String START_TOKEN = "[=language:";
    final String END_TOKEN   = "]";
    final String DELIMITER   = "\\|";
    
    
    String[] result = new String[0];
    
    boolean lineFound = false;
    try
    {
      InputStream in = null;
      BufferedReader reader = null;
      try
      {
        in     = UmpleModel.class.getResourceAsStream("/umple_core.grammar");
        reader = new BufferedReader(new InputStreamReader(in));
        String line;
        while (((line = reader.readLine()) != null) && !lineFound ) 
        {
           if( line.startsWith(NONTERMINAL) && line.contains(START_TOKEN))
           {
             int start_index = line.indexOf(START_TOKEN) + START_TOKEN.length();
             int end_index = line.indexOf(END_TOKEN);
             String languages = line.substring( start_index, end_index );
             result = languages.split(DELIMITER);
             lineFound = true;
           }
        }
      }finally
      {
        in.close();
        reader.close();
      }
    }catch( IOException e ){
      throw new RuntimeException("Error opening '/umple_core.grammar' resource", e);
    }
    Arrays.sort(result);
    return result;
  }
  
  after constructor{
    if(aUmpleFile!=null){
      String[] linkedFilenames = aUmpleFile.getLinkedFiles().split("use");
      
      for( String filename : linkedFilenames ){
        // Remove blankspace and newlines
        filename = filename.trim();
        // Create a file from the name, removing the last ';' from the string
        if( filename.length()>1 ){
          this.linkedFiles.add(new File(filename.substring(0,filename.length()-1)));
        }
      }
    }
  }
  
  public UmpleModel(UmpleFile umpleFile, List<File> linkedFiles ){
    this(umpleFile);
    this.linkedFiles = linkedFiles;
  }

  public List<UmpleElement> getUmpleElements()
  {
    List<UmpleElement> all = new ArrayList<UmpleElement>();
    all.addAll(getUmpleClasses());
    all.addAll(getUmpleInterfaces());
    return all;
  }

  public UmpleInterface addUmpleInterface(String name)
  {
    UmpleInterface newInterface = getUmpleInterface(name);
    if (newInterface == null)
    {
      newInterface = new UmpleInterface(name, this);
      addUmpleInterface(newInterface);
    }
    return newInterface;
  }

  public void addGenerate(String lang)
  {
    addGenerate(new GenerateTarget(lang, null));
  }

  public void addGenerate(Collection <?extends GenerateTarget> c)
  {
    generates.addAll(c);
  }

  public String getDefaultGenerate()
  {
    // Note that this method should be getDefaultGenerateLanguage
    // To avoid rippling changes throughout the code, the name is left as is
    if (numberOfGenerates() == 0)
    {
      return null;
    }
    else
    {
      return getGenerate(0).getLanguage();
    }
  }

  public String getDefaultGeneratePath()
  {
    if (numberOfGenerates() == 0)
    {
      return null;
    }
    else
    {
      return getGenerate(0).getPath() == null ? "./" : getGenerate(0).getPath();
    }
  }

  public void clearGenerates()
  {
    generates.clear();
  }

  public boolean hasAnalyzer(String name)
  {
    return analyzers.containsKey(name);
  }

  public Analyzer getAnalyzer(String name)
  {
    return analyzers.get(name);
  }
/*
 * Creates a new parser, loads the input, parses, then analyses; analyser generates
 */
  public void run()
  {
    boolean failed = false;
    String input;
    RuleBasedParser parser = new RuleBasedParser();
    
    UmpleInternalParser analyzer = new UmpleInternalParser("UmpleInternalParser",this,parser);
    ParseResult result = null;
    
    try {   
      result = parser.parse(
        new File(umpleFile.getPath() + File.separator + umpleFile.getFileName()),
        this.linkedFiles.toArray(new File[0]));
    }
    catch (Exception ex)
    {
      result = parser.parse("classDefinition",""); // Fake to ensure can proceed
      lastResult = result;
      result.addErrorMessage(new ErrorMessage(9000,new Position("",0,0,0),
        "Could not parse Umple model. Please report an issue with this entire message and your input code to Umple developers. \nStack dump follows\n"+cruise.umple.util.ExceptionDumper.dumpCompilerError(ex)
        ));
      throw new UmpleCompilerException(result.toString(),null);
    }
    catch (StackOverflowError ex)
    {
      result = parser.parse("classDefinition",""); // Fake to ensure can proceed
      lastResult = result;
      result.addErrorMessage(new ErrorMessage(9000,new Position("",0,0,0),
        "Could not parse Umple model. Please report an issue with this entire message and your input code to Umple developers. \nStack Overflow in Parsing.\n"+cruise.umple.util.ExceptionDumper.dumpCompilerError(ex)
        ));
      throw new UmpleCompilerException(result.toString(),null);
    }       
    
    this.extractAnalyzersFromParser(parser);

    failed = failed || !result.getWasSuccess();
    lastResult = result;

    if(!failed)
      result = analyzer.analyze(getShouldGenerate());

    failed |= !result.getWasSuccess();

    if(failed || result.getHasWarnings())
      throw new UmpleCompilerException(result.toString(),null);
  }

/*
 * Creates a generator for you based on the provided Language
 */
  public CodeGenerator newGenerator(String language)
  {
    String realLanguage = language;
    
    // Ensure the target is specified in the proper case.
    VALIDATE_GENERATE:
    for( String lang : UmpleModel.validLanguages ){
      if(lang.equalsIgnoreCase(language)){
        realLanguage = lang;
        break VALIDATE_GENERATE;
      }
    }

		
    if (language.equalsIgnoreCase("Cpp")) realLanguage="RTCpp";
    else if (language.equalsIgnoreCase("SimpleCpp")) realLanguage="RTCpp";
    
    String className = StringFormatter.format("cruise.umple.compiler.{0}Generator",realLanguage);
    Class<?> classDefinition = null;
    String msgIfNotFound = "Code generator "+realLanguage+ " not found. Check spelling. Specify --help.";
    try {
      classDefinition = Class.forName(className);
      CodeGenerator generator = (CodeGenerator) classDefinition.newInstance();
      generator.setModel(this);
      return generator;
    }
    catch (ClassNotFoundException cnf) {
      System.err.println(msgIfNotFound);
      try {
        classDefinition = Class.forName("cruise.umple.compiler.NothingGenerator");
        CodeGenerator generator = (CodeGenerator) classDefinition.newInstance();
        generator.setModel(this);
        return generator;
      }
      catch(Exception ex3) {
      throw new RuntimeException("Unable to instantiate the Nothing code generator.",ex3);
      }
    }
    catch (Exception ex2) {
      System.err.println(msgIfNotFound);
      throw new RuntimeException("Unable to instantiate "+realLanguage+ ".",ex2);
    }
  }


/*
 * Generates the actual code for each generation target
 */
  public String generate()
  {
    String lang="Unknown";
    mixset Filter {
      applyFilter(null);
    }
    boolean foundGenerator;
    parsingTime = System.currentTimeMillis()/1000.0;
    try
    {
      for (GenerateTarget target : getGenerates())
      {
        lang=target.getLanguage();
        CodeGenerator generator = newGenerator(lang);
        generator.setOutput(target.getPath());
        CodeBlock.languageUsed = lang;
        for (String subopt : target.getSuboptions()) {
        	 generator.setSuboption(subopt);
        }
        gTime1 = System.currentTimeMillis()/1000.0;
        generator.generate();
        gTime2 = System.currentTimeMillis()/1000.0;
        Double gTime = gTime2 - gTime1;
        hashMap.put(lang,(String.valueOf(gTime)));
      }
      return null; // generators all worked
    }
    catch (Exception ex)
    {
      return("Could not generate "+lang+"\nPlease report an issue with this entire message and your input code to Umple developers.\nStack Trace Follows.\n"+
        cruise.umple.util.ExceptionDumper.dumpCompilerError(ex));
    }
   }
   

  public Map<String, CodeTranslator> getAllTranslators() {
    Map<String, CodeTranslator> allTranslators = new HashMap<String, CodeTranslator>();
    CodeGenerator tempCodeGen = null;
    for(GenerateTarget t : getGenerates())
    {
      if((tempCodeGen = newGenerator(t.getLanguage())) instanceof CodeTranslator) {
        allTranslators.put(t.getLanguage(), (CodeTranslator)tempCodeGen);
      }
    }

    return allTranslators;
  }



  
  /*
   * Extracts Analyzers from a <code>RuleBasedParser</code>, assigning the
   * analyzers to this model
   *
   * @param parser the <code>RuleBasedParser</code> to extract parsers from.
   */
  public void extractAnalyzersFromParser( RuleBasedParser parser ){
    setAnalyzers(parser.getAnalyzer().getAnalyzerMap());
  }
  
  // Issue 1008 - Helper function to determine if the Umple Model has a particular enumeration
  public boolean hasEnum(String enumName) {
    for (UmpleEnumeration uEnum : getEnums()) {
      if (uEnum.getName().equals(enumName)) {
        return true;
      }
    }
    return false;
  }
  //this function return true if a model is of a particular language that contains specified suboption
  public boolean modelHasSuboption(String lang, String subOption){
    boolean suboptionFound=false;
    for (GenerateTarget target : getGenerates()){
      if (target.tarHasSubOption(subOption)&&target.getLanguage().equals(lang)){
        return true;
      }
    }
    return false;
  }
}

/*
 */
class Key
{
  public boolean isProvided()
  {
    return isDefault || members.size() > 0;
  }

  public boolean isMember(String name)
  {
    return (name == null) ? false : indexOfMember(name) != -1;
  }

  public boolean isMember(UmpleVariable av)
  {
    return (av == null) ? false : isMember(av.getName());
  }
}

/*
 */
class Depend
{
  public String getPackageName()
  {
    if (name == null || "".equals(name))
    {
      return "";
    }
    int dotIndex = name.lastIndexOf(".");
    return dotIndex >= 0 ? name.substring(0,dotIndex) : name;
  }
}



/*
 */
class UmpleElement
{
  public void appendExtraCode(String newCode)
  {
    appendExtraCode(newCode,true);
  }

  public void resetExtraCode()
  {
  	extraCode = new ExtraCode();
  }

  public void appendExtraCode(String newCode, boolean addNewline)
  {
    if (newCode == null)
    {
      return;
    }
    if (extraCode.getHasCode() && addNewline)
    {
      newCode = System.getProperty("line.separator") + newCode;
    }
    extraCode.appendExtraCode(newCode);
  }

  public void appendExtraCode(boolean flag, CodeBlock cb)
  {
    extraCode.appendExtraCode(cb);
  }

  public boolean hasExtraCode()
  {
    return extraCode.getHasCode();
  }

  public String getExtraCode()
  {
    return extraCode.getExtraCode();
  }
  
  // Methods related to co-ordinates. 
  // These are stored in an instance of Coordinate as x y width height
  // For GVClass diagram both UmpleClass and UmpleInterface need to specify
  // pos
  public boolean hasPosition() {
    if(getCoordinates() == null) {
      return(false);
    }
    return true;
  }
  
  // Returns the pos string needed by graphviz neato or fdp to position element
  // Used if suboption 'gvmanual" is present.
  // y is negated since in Umple coordinates run from top to bottom, but in gv it is bottom to top
  // value is in inches as required by graphviz
  // Graphviz positions refer to the centre of the node to be displayed
  // whereas the Umple positions refer to the left and top
  // returns empty string if there is no coordinate stored
  public String getPosition(Double expand) {
    if(hasPosition()) {
      Coordinate c = getCoordinates();
      // round 2 places and save as string. Also convert points to inches
      
      // Gets Centre as that is what GV expects
      String xpos=String.format("%.2f",((c.getX() + c.getWidth()/2.0)/72.0*expand)); 
      String ypos=String.format("%.2f",-((c.getY() + c.getHeight()/2.0)/72.0*expand));
//      String xpos=String.format("%.2f",(c.getX()/72.0*expand)); 
//      String ypos=String.format("%.2f",-(c.getY()/72.0*expand));

      return("pos=\""+xpos+","+ypos+"!\" ");
    }
    return("");
  } 

  // Used for a comments in GV when debugging
  public String getUmplePosition() {
    if(hasPosition()) {
      Coordinate c = getCoordinates();
      return(" leftX="+c.getX()+" rightY="+c.getY()+" w="+c.getWidth()+" h="+c.getHeight());
    }
    return("");
  } 
}


class UmpleClassifier{
  
  depend java.nio.file.*;
  depend cruise.umple.compiler.*;
	
	/*
  Counts the number of occurrences of the character <code>needle</code> in the 
  supplied string <code>haystack</code>.
  
  @param haystack the string to search for
  @param needle the character to find
  @return the number of occurrences of that character
  */
  private static int countOccurrences(String haystack, char needle)
  {
    int count = 0;
    for (int i = 0; i < haystack.length(); ++i)
    {
      if (haystack.charAt(i) == needle)
      {
        ++count;
      }
    }
    return count;
  }
  
  
  /*
  Replaces all instances of '\' with '/' in path strings
  
  @param str a string path to change
  @return the new string
  */
  private static String deWindowsify(String str)
  {
    return str.replace('\\','/');
  }
  
  
  /*
  Obtains the relative path between the source file for the UmpleClassifier and 
  and the package name given the target language
  
  @param filename the file name to get the relative path from
  @param language The language target to compare
  
  @return The string relative path between the parent and position
  */
  public String getRelativePath(String filename, String language)
  {    
    String p = getPackageName();
 	
    if (filename == null)
    {
      return "";
    }
    
    if(filename.startsWith("lib:")) {
      return "";
    }
    
    //Find path relative to namespace folders
    String packageName = getPackageName();
    if (packageName == null || packageName.equals(""))
    { //No package, file is output in current directory
      return Paths.get(filename).getFileName().toString();
    } 
    else
    { //Has a package, add appropriate number of ..
      int pathCount = countOccurrences(packageName, '.') + 1;
      StringBuilder build = new StringBuilder();
      for (int i = 0; i < pathCount; i++)
      {
        build.append("../");
      }
      
      //Add on relative path from generator location
      if (getSourceModel() == null)
      {
        build.append(Paths.get(filename).getFileName());
        return deWindowsify(build.toString());
      }
      Path currentPath = Paths.get(getSourceModel().getUmpleFile().getPath()).toAbsolutePath();
      Path generatesPath = null;
      GenerateTarget [] generates = getSourceModel().getGenerates();
      for (int i = 0; i < generates.length; i++)
      {
        if (generates[i].getLanguage().equals(language))
        {
          String genPath = generates[i].getPath();
          if(genPath.startsWith("lib:")) {
            genPath = genPath.substring(4);
          }
          generatesPath = currentPath.resolve(Paths.get(genPath)).normalize();
        }
      }
      if (generatesPath != null)
      {
      	Path result = generatesPath.relativize(currentPath);
      	if (!result.equals(Paths.get("")))
      	{
      	  result = result.normalize();
      	  build.append(result.toString() + '/');
      	}
      }
      
      build.append(Paths.get(filename).getFileName());
      return deWindowsify(build.toString());
    }
  }  
  
}



/*
 */
class UmpleVariable
{
  public String getUpperCaseName()
  {
    if (name == null || name.length() == 0)
    {
      return name;
    }
    else if (name.length() == 1)
    {
      return name.toUpperCase();
    }
    else
    {
      return name.toUpperCase().charAt(0) + name.substring(1);
    }
  }

  public boolean isImmutable()
  {
    return "immutable".equals(modifier);
  }

  public String normalizeValue(String aType, String aValue)
  {
    if (aType == null || aValue == null || aValue.length() == 0)
    {
      return aValue;
    }
    else if (("Float".equals(aType)) && ("f".equals(aValue.substring(aValue.length()-1))))
    {
      return aValue.substring(0, aValue.length()-1);
    }
    else
    {
      return aValue;
    }
  }
}

/*
 */
class GeneratedElement
{

  private Map<String, String> lookups = new HashMap<String, String>();
  private Map<String, List<String>> multiLookups = new HashMap<String,List<String>>();

  public void setLookup(String aKey, String aValue)
  {
    lookups.put(aKey, aValue);
  }

  public String getLookup(String aKey)
  {
    if (aKey == null)
    {
      return null;
    }
    else
    {
      return lookups.get(aKey);
    }
  }

  public boolean addMultiLookup(String aKey, String aValue)
  {
    List<String> oldList = null;
    if (multiLookups.containsKey(aKey))
    {
      oldList = multiLookups.get(aKey);
    }
    else
    {
      oldList = new ArrayList<String>();
    }

    if (aValue == null || "".equals(aValue) || oldList.contains(aValue))
    {
      return false;
    }

    oldList.add(aValue);
    multiLookups.put(aKey, oldList);
    return true;
  }

  public String[] getMultiLookup(String aKey)
  {
    if (aKey == null || !multiLookups.containsKey(aKey))
    {
      return new String[0];
    }
    else
    {
      List<String> list = multiLookups.get(aKey);

      return list.toArray(new String[list.size()]);
    }
  }

  public String toString()
  {
    String answer = "<<";
    for (String aKey : lookups.keySet())
    {
      answer += "[" + aKey + ":" + lookups.get(aKey) + "]";
    }
    answer += ">>";
    return answer;
  }
}

/*
 */
class Point
{

  public static Point create(int n)
  {
    int p = (int)Math.sqrt(n) + 1;
    if (n - (p-2)*p <= p)
    {
      return new Point(n - (p-2)*p, p);
    }
    else
    {
      return new Point(p, n - (p-1) * p);
    }
  }

  public String toString()
  {
    return "(" + getX() + "," + getY() + ")";
  }
}

/*
 */
class Comment
{
  Boolean isInline = true;

  // deep copy constructor
  public Comment(Comment aComment)
  {
    text = aComment.getText();
    annotation = aComment.getAnnotation();
    isInline = aComment.getIsInline();
  }
  /**
   * Used to take a comment and process it into a format appropriate for displaying in generated code.
   *
   * For example, you may want a bunch of inline comments put together and displayed as Javadoc.  This accomplishes that (among others).
   *
   * @param type Indicates the type of comment which determines how the comments are formatted.  The types are: Hash, Javadoc, Attribute Javadoc, Association Javadoc, Method Javadoc, RubyMultiline, RubyMultiline Internal and Multiline.  Defaults to "//" if not specified.
   * @param allComments A list of comments to be processed and formatted all together as one.
   *
   * @return The processed/formatted comment appropriate for use in generated code output.
   */
  public static String format(String type,List<Comment> allComments)
  {
    return format(type, allComments, true);
  }

  public static String format(String type,List<Comment> allComments, boolean allowAnnotations)
  {
    //String commentDelimiter = type == "Hash" ? "# " : (type == "Javadoc") ? " * " : (type == "Attribute Javadoc") ? "   * " : (type == "Association Javadoc") ? "   * " : (type == "Method Javadoc") ? "   * " : (type == "RubyMultiline") ? "  " : (type == "Multiline") ? "" : "// ";

    String commentDelimiter;
    List<String> deferredAnnotations = new ArrayList<String>();

    // Set the comment delimiter based on the type of the comment. (ex. For Javadoc prepend "*" before every comment line)
    if (type == "Hash")
    {
      commentDelimiter = "# ";
    }
    else if (type == "Javadoc")
    {
      commentDelimiter = " * ";
    }
    else if (type == "Attribute Javadoc")
    {
      commentDelimiter = "   * ";
    }
    else if (type == "Association Javadoc")
    {
      commentDelimiter = "   * ";
    }
    else if (type == "Method Javadoc")
    {
      commentDelimiter = "   * ";
    }
    else if (type == "RubyMultiline")
    {
      commentDelimiter = " ";
    }
    else if (type == "RubyMultiline Internal")
    {
      commentDelimiter = " ";
    }
    else if (type == "Multiline")
    {
      commentDelimiter = "";
    }
    else
    {
      commentDelimiter = "// ";
    }

    if (allComments.size() == 0)
    {
      return null;
    }

    String output = "";
    Boolean foundComment = false;

    for (Comment c : allComments)
    {
      boolean couldTreatAsAnnotation = allowAnnotations;
      
      if (type == "RubyMultiline" || type == "RubyMultiline Internal") {
        couldTreatAsAnnotation = false;
      }
      
      if (type == "Javadoc" || type == "Attribute Javadoc" || type == "Association Javadoc" || type == "Method Javadoc" || type == "RubyMultiline" || type == "RubyMultiline Internal")
      {
        int startIndex = 0;

        // Go through each letter of the current comment to find start of content.
        for (int i = 0; i < c.getText().length(); i++)
        {
          char letter = c.getText().charAt(i);

          // Remove these letters until the actual content is found in the line.
          if (letter == ' ' || letter == '\t' || letter == '*')
          {
            startIndex++;
          }
          // Comment content found, set comment to start here.
          else
          {
            c.setText(c.getText().substring(startIndex));
            break;
          }
        }

        // Special case where the comment line had no content (only spaces, tabs or asterisks).
        if (startIndex == c.getText().length())
        {
          c.setText(c.getText().substring(startIndex));
        }
      }
      
      // If it is an annotation, add at end
      if(c.isAnnotation() && couldTreatAsAnnotation) {
        deferredAnnotations.add(c.getText());
      }
      else
      {
        foundComment = true;
        output += commentDelimiter + c.getText() + "\n";
      }
    }

    // Finalize the comment based on what type it was. (ex. For Javadoc place the "/**" and "*/" around the comment)
    if(foundComment) {
      if (type == "Javadoc")
      {
        output = "/**\n" + output + " */";
      }
      else if (type == "Attribute Javadoc")
      {
        output = "  /**\n" + output + "   */";
      }
      else if (type == "Association Javadoc")
      {
        output = "  /**\n" + output + "   */";
      }
      else if (type == "Method Javadoc")
      {
        output = "  /**\n" + output + "   */";
      }
      else if (type == "RubyMultiline")
      {
        // initialize sb at least as large as the output with 1 comment
        StringBuilder sb = new StringBuilder( output.length() + 2 ); 
        sb.append("#");
        char c;
        for( int i=0; i < output.length(); ++i ){
          c = output.charAt(i);
          sb.append(c);
          if( (c == '\n') && (i != output.length()-1) ){
            sb.append("#");
          }
        }
        output = sb.toString();
      }
      else if (type == "RubyMultiline Internal")
      {
        // initialize sb at least as large as the output with 1 comment
        StringBuilder sb = new StringBuilder( output.length() + 2 ); 
        sb.append("#");
        char c;
        for( int i=0; i < output.length(); ++i ){
          c = output.charAt(i);
          sb.append(c);
          if( (c == '\n') && (i != output.length()-1) ){
            sb.append("  #");
          }
        }
        output = sb.toString();
      }
      else if (type == "Multiline")
      {
        output = "/*\n" + output + "*/";
      }
    }
    
    // Process all deferred annotations if any
    boolean firstAnnotation = true;
    for (String d: deferredAnnotations) {
      if(firstAnnotation) {
        output = output + "\n";
        firstAnnotation = false;
      }
      output = output + "  "+ d + "\n";
    }

    return output.trim();
  }
}
/*
 */
class Requirement{
  // deep copy constructor
  public Requirement(Requirement aReq)
  {
    identifier = aReq.getIdentifier();
    statement = aReq.getStatement();
    who = aReq.getWho();
    when = aReq.getWhen();
    what = aReq.getWhat();
    why = aReq.getWhy();
    language = aReq.getLanguage();
  }
  public static List<Comment> convertToComment(List<ReqImplementation> reqSelected,UmpleModel aModel){
    List<Comment> reqTextOnly = new ArrayList<Comment>();
    String reqText = new String();
    String reqImpID = "";
    for (ReqImplementation reqImpl : reqSelected){
      reqImpID = reqImpl.getIdentifier();
      Requirement findRequirement = aModel.getAllRequirements().get(reqImpID);
      if(findRequirement != null)
     {
      reqText = findRequirement.getStatement().trim();

      reqText = findRequirement.getIdentifier() + ": " + reqText;

      String [] reqTextList = reqText.split("\n");

      for (String line : reqTextList){
        // convert text of req to comment and format like a comment
        Comment reqComment = new Comment(line);      
        reqTextOnly.add(reqComment);
        }
      }
     else
     {
        String commentmssg = "No requirement found for this requirement identifier:"+reqImpID;
        Comment NoComment = new Comment(commentmssg);
        reqTextOnly.add(NoComment);
     }
    }
    return reqTextOnly;
  }

  public static String format(String type, List<ReqImplementation> reqSelected,UmpleModel aModel){
    List<Comment> listOfReq = convertToComment(reqSelected,aModel);
    return Comment.format(type, listOfReq); 
  }

  public static String translateToHTML(String content, String lang){
    // Translate from md to html
    //if (language.equals("md")){
    //  content = content;
    //}

    return content;
  }

}

mixset Constraint {
  use constraint/Umple_CodeConstraint.ump;
}
use class/Umple_CodeAssociation.ump;
use class/Umple_CodeAttribute.ump;
use class/Umple_CodeClass.ump;
use class/Umple_CodeMethod.ump;
use class/Umple_CodeCoordinate.ump; 
mixset StateMachine {
  use stateMachine/Umple_Code_StateMachine.ump;
}
mixset Filter{
  use filter/Umple_Code_Filter.ump;
}
mixset Trait {
  use trait/Umple_Code_Trait.ump;
}

use Test_Code.ump;
