/*

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;
  UmpleModel umpleModel;
 
  public void onSuccess(Token token, ParserDataPackage data)
  {
  
  /*
  we can filter the use statement by checking if ends with .ump 
  this is simpler and needs few modification
  
  the solution 2: if no file, save the mixset name for later use .
  this can be done by do some changes to the file .ump directly. Or, we can make the file throw a null pointer exception and hendel it in UseStatementAction
  in .ump
  
  
        
  if (! value.containts(".ump")) // TO DO : use statement with mixed files and mixsets
  {
    String mixsetName = value;
    int useLineNumber = token.getPosition().getLineNumber();
    UmpleFile mixsetUseFile = umpleModel.getUmpleFile(); 
      	
      	// check if it was added before 
      	
    Mixset mixset = umpleModel.getMixset(mixsetName);
    if(mixset  == null)
	{
	  Mixset tempMixset = new Mixset(mixsetName);
	  mixset.setUseUmpleFile(mixsetUseFile);
	  mixset.setUseUmpleLine(useLineNumber);
	  umpleModel.addMixsetOrFile(mixset);
	}
	else if ( mixset.getUseUmpleFile() == null)
	{
	  mixset.setUseUmpleFile(mixsetUseFile);
	  mixset.setUseUmpleLine(useLineNumber);
	}
	      	
       
      	
  }
  
 */
 
    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();
	        
	  }
	     
    }
  }
}

/* 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());
    }
  }
}
