/*

Copyright: All contributers to the Umple Project

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

Handlers for the RuleBasedParser.

*/
 
namespace cruise.umple.compiler;

external interface ParserAction{}
external interface LinkedFileHandler{}
external interface AnalyzerGeneratorHandler{}

/* This is the ParserAction to handle 'use' tokens in Umple. 
 *
 * This is called any time a 'useStatement' token is read, in which it 
 * dispatches a `RuleBasedParserThread` on the discovered token, which
 * effectively reads the new file into the token location
 */
class UseStatementParserAction{
  depend java.io.File;
  depend cruise.umple.parser.analysis.ParserAction;
  depend cruise.umple.parser.analysis.ParserDataPackage;
  depend cruise.umple.parser.analysis.RuleBasedParserThread;
  depend cruise.umple.parser.Token;
  
  isA ParserAction;
  
  public void onSuccess(Token token, ParserDataPackage data)
  {
    String value = token.getValue("use");
    String fileName="";
		String path = "";    
    int index =-1;
    if (data!=null && data.getFullFileAddress()!=null)    index = data.getFullFileAddress().lastIndexOf("/") ;
    if (index==-1) index = data.getFullFileAddress().lastIndexOf("\\");  
    if (index!=-1){
    	path = data.getFullFileAddress().substring(0,index+1 );
    }
    
    synchronized(data.getHasParsed())
    {
      fileName = data.getAnalyzer().getFile().getAbsoluteFile().getParentFile().getAbsolutePath() + File.separator + value;
      //I used this technique because I noticed this function is used to several purposes.
      // The correct implementation is just to set fileName = path +value; and remove the above code.
      //TODO: this issue must be investigated more. Currently it is working with the following solution. 
      File f = new File(fileName);
      if (!f.exists()) fileName = path +value;
      if(!data.getHasParsed().contains(f.getAbsolutePath()))
      {
        data.getHasParsed().add(f.getAbsolutePath());
        RuleBasedParserThread thread = new RuleBasedParserThread(
          data.getAnalyzer().getRules().get("$ROOT$"),
          token,
          fileName,
          data
        );
        data.getAnalyzer().addThread(thread);
        thread.start();
      }
    }
  }
}





class MixsetStatementParserAction{
  depend cruise.umple.compiler.UmpleModel;
  depend cruise.umple.parser.Position;
  depend cruise.umple.parser.analysis.ParserAction;
  depend cruise.umple.parser.analysis.ParserDataPackage;
  depend cruise.umple.parser.Token;
  depend java.util.stream.Stream;
  
  
  UmpleModel model;
  isA ParserAction;
  
  public void onSuccess(Token token, ParserDataPackage data)
  {
   /* Moved to UmpleInternal_CodeMixset
   String mixsetName = token.getValue("mixsetName");


    Mixset m = model.getMixset(mixsetName);
    
    // check if the mixset is was not added
    
    if( m == null)
	{
		//long count  = model.getMixsetOrFiles().stream().filter(m-> m.getName().equals(mixsetName)).count(); 
		m = new Mixset(mixsetName);
		model.addMixsetOrFile(m);
	}
	
	String mixsetBody = token.getValue("extraCode");	
	
	//inline mixset def.
	String entityType = token.getValue("entityType");
	String entityName = token.getValue("entityName");
	if(entityType != null) mixsetBody = entityType + " "+entityName + " { "+ mixsetBody + " }";	
	
	// mixset has one element
	String oneElementMixset = token.getValue("oneElement");
	if (oneElementMixset != null) mixsetBody = oneElementMixset;
	
	// mixset as inner enitity
	// getParentToken()
	// when mixset is inside a class or .... 
	//System.out.println(" getParentToken() : "+token.getParentToken());
	
	MixsetFragment mixsetFragment = new MixsetFragment(null, 99999, mixsetBody);
	m.addWaitingFragment(mixsetFragment);


   
 //  System.out.println("FullFileAddress: "+ data.getFullFileAddress()+", file Name: "+data.getFilename()+", Position : "+data.getPosition());  
   System.out.println("  ---- ----  Start Mixset Parsing ---- ----");
   System.out.println(""+token);
   System.out.println("MIXSET ::: "+ m + " Mixset Body  :"+mixsetBody);
   
   System.out.println("  ---- ----  End Mixset Parsing ---- ----");
  
  
  	System.out.println("\n\n\n\n");
  */
  }


}

/* This is the LinkedFileHandler for the Umple language. 
 *
 * This handler takes all linked files and appends a series of 'use' statements
 * to the end of the current input of the main file. This is all done prior to 
 * parsing so that the statements get interpreted properly.
 */
class UmpleLinkedFileHandler{ 
  depend java.io.File;
  depend cruise.umple.parser.analysis.LinkedFileHandler;
  
  isA LinkedFileHandler;

  public String onFileLink( String input, File[] linkedFiles ){
    for( File file : linkedFiles ){
      input += "\nuse " + file.getPath() + ";";
    }
    return input;
  }
}

/* This is the AnalyzerGeneratorHandler for the Umple language
 * 
 * This handler constructs Analyzers by name by using reflection
 * in the `cruise.umple.analysis` namespace
 */
class UmpleAnalyzerGeneratorHandler{
  depend cruise.umple.parser.analysis.AnalyzerGeneratorHandler;
  depend cruise.umple.parser.analysis.Analyzer;
  depend java.lang.reflect.*;
  depend java.lang.IllegalStateException;

  isA AnalyzerGeneratorHandler;
  
  public Analyzer generateFromName( String name ){
    try{
      String className = "cruise.umple.analysis."+name.substring(0,1).toUpperCase()+name.substring(1)+"Analyzer";
      Class cls = Class.forName(className);
      Analyzer a = (Analyzer) cls.newInstance();
      a.setName(name);
      return a;
    }
    catch(ClassNotFoundException e){
      return null;
    }
    catch(InstantiationException | IllegalAccessException | IllegalArgumentException  e){
      throw new IllegalStateException("Error instantiating class " + name + ": " + e.getMessage());
    }
  }
}
