package Smells;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.TypeDeclaration;

import Analysis.ManagerOfDetectors;
import Detectors.DuplicatedCodeDector;
import Detectors.THRESHOLDS;

public abstract class Smell extends Object {
	public static BufferedWriter writer;
	public CompilationUnit unit;
	public IResource resource;
	public boolean DetectedWithCurrentThreshold = true;
	private SMELLTYPE type;
	protected int startPoint;
	private int length;
	public  String explaination = "";
	public ASTNode associatedNode;
	public long appearTime;
	public String comparetion = null;
	public String SwitchState;
	public static String forcompareted;
	public String method;
	//public String Suggestion;
    
	public Smell() {
		Date date = new Date();
		this.appearTime = date.getTime();
	}

	// 记录已经处理的记录的个数
	public abstract void toBeRmoved();
	
	public abstract String getSuggestion();
	public abstract void save(BufferedWriter b);

	public abstract void forcomparation();
	

	protected void setType(SMELLTYPE type) {
		this.type = type;
	}

	public SMELLTYPE getType() {
		return type;
	}

	public IFile getIFile() {
		IFile file = ResourcesPlugin.getWorkspace().getRoot().getFile(
				resource.getFullPath());

		return file;
	}

	private static String getFullyQualifiedName(final TypeDeclaration type) {
		String name = type.getName().getFullyQualifiedName();
		final CompilationUnit root = (CompilationUnit) type.getRoot();
		for (ASTNode t = type.getParent(); t != root; t = t.getParent()) {
			name = ((TypeDeclaration) t).getName().getFullyQualifiedName()
					+ '$' + name;
		}

		if (root.getPackage() != null) {
			final String packageName = root.getPackage().getName()
					.getFullyQualifiedName();
			name = packageName + '.' + name;
		}
		return name;
	}

	public String getText() {
		return SMELLTYPE.getText(getType());
	}



	 public abstract boolean Smellequal(Smell obj);

	public static List<Smell> removeDuplicated(List<Smell> existing,
			List<Smell> newSmells) {
		 List<Smell>statisticsList1=new ArrayList<Smell>();
	     List<Smell>statisticsList2=new ArrayList<Smell>();
		int oldcount=0;
		String newlocation;
		List<Smell> list = new ArrayList<Smell>();
		List<Smell> existbutClones = new ArrayList<Smell>();
		List<Smell> clones = new ArrayList<Smell>();
		for(Smell asmell: existing)
		{
			
			if(asmell.getType()!=SMELLTYPE.DUPLICATEDCODE)
				 
				existbutClones.add(asmell);
			else
				clones.add(asmell);
			
			
		}
		existing=existbutClones;
		
		
		
		if(newSmells.size()==0)
		{
			//System.out.println("新生成的SmellList大小是0");
			for (int j = 0; j < existing.size(); j++)
			{
				Smell exist = existing.get(j);
			if( !exist.resource.getLocation().toString().equals( ManagerOfDetectors.resourcelocation))
			{
				list.add(exist);}
		       
			      }
			
			
		//	System.out.println("文件"+ManagerOfDetectors.resourcelocation+"中的所有Smell消失");
			
			}
		
		
		else {                     
			
			newlocation=ManagerOfDetectors.resourcelocation;
        
		
		  int newsmellcount = 0;
		
		
		 for (int i = 0; i < newSmells.size(); i++) {
			int signal = 0;
			Smell newsmell = newSmells.get(i);

			for (int j = 0; j < existing.size(); j++) {
				Smell exist = existing.get(j);

				if (exist.Smellequal(newsmell)) {
					newsmell.appearTime = exist.appearTime;
					signal = 1;
				} else
					continue;

			}
			list.add(newsmell);
			if (signal == 0)
				{newsmellcount++;
			statisticsList1.add(newsmell);}
			
		}
		//System.out.println("该文件新增的Smell个数" + newsmellcount);

		
		for (int j = 0; j < existing.size(); j++) {

			Smell exist = existing.get(j);
			int singnal=0;
			for(int i=0;i<newSmells.size();i++)
			{   Smell newSmell=newSmells.get(i);
			    if(exist.Smellequal(newSmell)){ singnal=1;}
			}	
			
			if(!exist.resource.getLocation().toString().equals(newlocation)&&singnal==0)
				list.add(exist);
			
		}
 

	for (int j = 0; j < existing.size(); j++) {
			int signal=0;
			Smell exist = existing.get(j);
	  if(exist.resource.getLocation().toString().equals(newlocation))
				{  
		  for (int i = 0; i < newSmells.size(); i++) 
		      {
			   Smell newsmell = newSmells.get(i);
		
					if(exist.Smellequal(newsmell))
				signal=1;
	 
		         }
				
		
		   if (signal==0)
		   { oldcount++;	
		   statisticsList2.add(exist);}
				
			 }
	
			
	
		
	}
	//	System.out.println("文件"+newlocation+"中消失的Smell个数" + oldcount);
		statistics ( statisticsList1,
				 statisticsList2);
		}
			if(DuplicatedCodeDector.hasIdentified==false)
			{
				list.addAll(clones);
				
			}
	return list;
				
		
	}
	

	public static void statistics (List<Smell> list1,
			List<Smell> list2) 
	{
	int dispareLONGPARAMETER1=0;
	int dispareCOMMONMETHOD=0;
	int dispareDATACLASS=0;
	int dispareDUPLICATEDCODE=0;
	int disparePUBLICFILED=0;
	int dispareSWITCHTATEMENTS=0;
	int dispareLARGECLASS=0;
	int dispareLONGMETHOD=0;
	int dispareBADNAME=0;
	
	int newLONGPARAMETER1=0;
	int newCOMMONMETHOD=0;
	int newDATACLASS=0;
	int newDUPLICATEDCODE=0;
	int newPUBLICFILED=0;
	int newSWITCHTATEMENTS=0;
	int newLARGECLASS=0;
	int newLONGMETHOD=0;
	int newBADNAME=0;
	
	for(int i=0;i<list1.size();i++)
		{Smell smell=list1.get(i);
		
		
		switch(smell.getType())
	
		{  case  BADFILEDNAME:newBADNAME++;break;
		   case LONGPARAMETER:newLONGPARAMETER1++;break;
		   case COMMONMETHOD:newCOMMONMETHOD++;break;
		   case DATACLASS:newDATACLASS++;break;
		   case DUPLICATEDCODE:newDUPLICATEDCODE++;break;
		   case PUBLICFIELD:newPUBLICFILED++;break;
		   case SWITCHSTATEMENTS:newSWITCHTATEMENTS++;break;
		   case LARGECLASS:newLARGECLASS++;break;
		   case LONGMETHOD:newLONGMETHOD++;break;
		
			}
		}
	
	for(int i=0;i<list2.size();i++)
	{Smell smell=list2.get(i);
	switch(smell.getType())

	{ 
	   case LONGPARAMETER:dispareLONGPARAMETER1++;break;
	   case COMMONMETHOD:dispareCOMMONMETHOD++;break;
	   case DATACLASS:dispareDATACLASS++;break;
	   case DUPLICATEDCODE:dispareDUPLICATEDCODE++;break;
	   case PUBLICFIELD:disparePUBLICFILED++;break;
	   case SWITCHSTATEMENTS:dispareSWITCHTATEMENTS++;break;
	   case LARGECLASS:dispareLARGECLASS++;break;
	   case LONGMETHOD:dispareLONGMETHOD++;break;
	   case  BADFILEDNAME:dispareBADNAME++;break;
	 }
	}
	LongParameter.totalNoOfDetectorSmells+=newLONGPARAMETER1;
	Commonmethod.totalNoOfDetectorSmells+=newCOMMONMETHOD;
	DataClass.totalNoOfDetectorSmells+=newDATACLASS;
	PublicField.totalNoOfDetectorSmells+=newPUBLICFILED;
	SwitchStatements.totalNoOfDetectorSmells+=newSWITCHTATEMENTS;
	LargeClass.totalNoOfDetectorSmells+=newLARGECLASS;
	LongMethod.totalNoOfDetectorSmells+=newLONGMETHOD;
	Duplicatedcode.totalNoOfDetectorSmells+=newDUPLICATEDCODE;
	BadFiledName.totalNoOfDetectorSmells+=newBADNAME;
	
	
	LongParameter.totalNoOfDisparedSmells+=dispareLONGPARAMETER1;
	Commonmethod.totalNoOfDisparedSmells+=dispareCOMMONMETHOD;
	DataClass.totalNoOfDisparedSmells+=dispareDATACLASS;
	PublicField.totalNoOfDisparedSmells+=disparePUBLICFILED;
	SwitchStatements.totalNoOfDisparedSmells+=dispareSWITCHTATEMENTS;
	LargeClass.totalNoOfDisparedSmells+=dispareLARGECLASS;
	LongMethod.totalNoOfDisparedSmells+=dispareLONGMETHOD;
	Duplicatedcode.totalNoOfDisparedSmells+=dispareDUPLICATEDCODE;
	BadFiledName.totalNoOfDisparedSmells+=dispareBADNAME;

	}

		
	private static void AdjustThresholds(List<Smell> existing) {
		DataClass.adjustThreshold(existing);
		LargeClass.adjustThreshold(existing);
		LongMethod.adjustThreshold(existing);
		LongParameter.adjustThreshold(existing);
		Commonmethod.adjustThreshold(existing);
	}

	private static void LogNew(List<Smell> newSmells) {
		for (Smell aSmell : newSmells) {
			aSmell.CountNewSmell();

		}
	}

	public boolean IsNew() {
		// TODO Auto-generated method stub
		boolean Isnew = false;
		Date date = new Date();
		long duration = date.getTime() - this.appearTime
				- THRESHOLDS.HOWLONGISNEW;
	
		//System.out.println("Duration: " + duration);
		if (duration < 0)
			Isnew = true;
		return Isnew;
	}

	public abstract void CountNewSmell();

	public boolean Log2Remove() {
		String tab = "	";
		boolean result = false;
		try {

			if (writer == null) {
				File logFile = new File("d:\\logFile4Monitor.txt");
				writer = new BufferedWriter(new FileWriter(logFile, true));
			}
			writer.newLine();
			writer.write(getType().toString());
			writer.write(tab);
			Date date = new Date(appearTime);
			writer.write("CREATERTIME ");
			writer.write(DateFormat.getDateTimeInstance(DateFormat.SHORT,
					DateFormat.SHORT, Locale.US).format(date));
			writer.write(tab);
			date = new Date();
			writer.write("REMOVETIME ");
			writer.write(DateFormat.getDateTimeInstance(DateFormat.SHORT,
					DateFormat.SHORT, Locale.US).format(date));
			writer.flush();
			toBeRmoved();

		} catch (IOException e) {
			// TODO Auto-generated catch block

			e.printStackTrace();
		}
		return result;
	}

	public void setStartPoint(int startPoint) {
		this.startPoint = startPoint;
	}

	public int getStartPoint() {
		return startPoint;
	}

	public void setExplaination(String explaination) {
		this.explaination = explaination;
	}

	public int getLength() {
		return length;
	}

	public void setLength(int length) {
		this.length = length;
	}

}
