package Smells;

import java.io.BufferedWriter;
import java.util.ArrayList;
import java.util.List;

import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
import Analysis.printer;
import Detectors.THRESHOLDS;

public class LongMethod extends Smell {
	public static int totalNoOfDetectorSmells=0;
	public static int totalNoOfDisparedSmells=0;
	String Suggestion="Decompose it into shorter ones (Menu Refactor-->Extract Method)";
	ArrayList<String> list2=new ArrayList<String>();
	
	
	
	
		public LongMethod() {
	setType(SMELLTYPE.LONGMETHOD);
	}
		public String getSuggestion()
		{
			return Suggestion;
			
					}
	public static void AdjustThresholdAfterStatistics()
		{
			double RATION;
			if(totalNoOfDetectorSmells<=10)return;
			
		 RATION=totalNoOfDisparedSmells/totalNoOfDetectorSmells;
			if(! THRESHOLDS.IsOurOfRange( RATION))
			{ THRESHOLDS.setLONGMETHOD_LINES(THRESHOLDS.AdjustThreshold(THRESHOLDS.getLONGMETHOD_LINES(),  RATION));}
			totalNoOfDetectorSmells=0;
			totalNoOfDisparedSmells=0;
		}
	@Override
	public boolean Smellequal(Smell obj) {
		if(!(obj instanceof Smell)) return false;
	      Smell target= (Smell) obj;
	     if(target==null) return false;
	    // if(target.unit!=this.unit) return false;
	     if(target.getType()!=this.getType()) return false;
	      	MethodDeclaration targetMethod= (MethodDeclaration)target.associatedNode;
	    	MethodDeclaration thisMethod=(MethodDeclaration)associatedNode;
	    	
	    	String targetTypeName=targetMethod.getName().getFullyQualifiedName().trim();
	       	String thisTypeName=thisMethod.getName().getFullyQualifiedName().trim();
	    	if(targetTypeName.compareToIgnoreCase(thisTypeName)!=0)
	    		return false;
	    	return true;
	}
	
	public void save(BufferedWriter bw)
	{   
	  
				String filelocation=this.resource.getLocation().toString();
		
		
		
		try{ 
			 bw.newLine();
			 bw.append(SMELLTYPE.getText(this.getType()));
			 bw.append(THRESHOLDS.tab);
			 bw.append(filelocation);
			 bw.append(THRESHOLDS.tab);
			 bw.append(Long.toString(this.appearTime));
			 bw.append(THRESHOLDS.tab);
	     if (!(this.associatedNode instanceof MethodDeclaration))  // obj是否是TypeDeclaration的一个实例
				return;// failed
	     MethodDeclaration Method = (MethodDeclaration) this.associatedNode;
			bw.append(Method.getName().toString());
			List list1=Method.parameters();
			
			for(int i=0;i<list1.size();i++)           //比较参数
		   {
				Object obj=list1.get(i);
		  	     if (!(obj instanceof SingleVariableDeclaration))
						continue;
		  	   SingleVariableDeclaration parameter = (SingleVariableDeclaration) obj;
					
		  	     String pname= parameter.getName().toString();
		  	     String ptype=parameter.getType().toString();
		  	    list2.add(ptype);
		    	list2.add("< ");
		  	    list2.add(pname);
		     	list2.add("< ");
		     	list2.add("**");
		  	//   bw.append(ptype);
		  	  // bw.append("< ");
		  	//   bw.append(pname);
		  	//   bw.append("< ");
		  	  
		   }	
			bw.append(list2.toString());
			
			
		
		
		
		
		}
		
			catch(Exception e) {
  	     printer.print(e); }
		
		
	}

	
	
	
	public void forcomparation()
	{
		  if (!(this.associatedNode instanceof MethodDeclaration))  // obj是否是TypeDeclaration的一个实例
				return;// failed
	     MethodDeclaration Method = (MethodDeclaration) this.associatedNode;
			forcompareted=Method.getName().toString().concat(list2.toString());
		}
		 
	
	
	private static int totalSmellsWithCurrentThreshold=0;
	private static int totalRemovedSemllsWithCurrentThreshold=0;
	@Override
	public void toBeRmoved() {
		if(this.DetectedWithCurrentThreshold)
		{
			totalRemovedSemllsWithCurrentThreshold++;			
		}
	}

	@Override
	public void CountNewSmell() {
		if(this.DetectedWithCurrentThreshold)
		{
		    totalSmellsWithCurrentThreshold++;	
		}
	}
	public static boolean adjustThreshold(List<Smell> existing)
	{
	 printer.println("Total Semlls: " +totalSmellsWithCurrentThreshold);	
	 printer.println("Resovled Semlls: " +totalRemovedSemllsWithCurrentThreshold);
	 if(totalSmellsWithCurrentThreshold==0) return false;
     double ratio=totalRemovedSemllsWithCurrentThreshold/(double)totalSmellsWithCurrentThreshold;
         if(!THRESHOLDS.IsOurOfRange(ratio))
         {
        	return  false; //no need to adjust the threshold        	 
         }
         THRESHOLDS.setLONGMETHOD_LINES(THRESHOLDS.AdjustThreshold(THRESHOLDS.getLONGMETHOD_LINES(), ratio)); 
         
         //TODO 重新检查smell
         for(Smell asmell : existing)
         {
        	 if(asmell instanceof LongMethod)
        	           asmell.DetectedWithCurrentThreshold=false;
         }
         totalSmellsWithCurrentThreshold=0;
         totalRemovedSemllsWithCurrentThreshold=0;
         return true;
	}
}
