package elements;

import java.util.LinkedList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.lang.*;
import org.etsi.t3d.T3D;

import de.ugoe.cs.swe.trex.core.analyzer.rfparser.LocationAST;
import de.ugoe.cs.swe.trex.core.analyzer.rfparser.TTCN3ParserTokenTypes;

public class TTCN3Comment {
	private String commentsXML;	
		

	
	private LinkedList<String> desc = new LinkedList<String>();
	private LinkedList<String> author = new LinkedList<String>();
	private LinkedList<String> config = new LinkedList<String>();
	private LinkedList<String> exception = new LinkedList<String>();
	private LinkedList<String> member = new LinkedList<String>();
	private LinkedList<String> param = new LinkedList<String>();
	private LinkedList<String> purpose = new LinkedList<String>();
	private LinkedList<String> remark = new LinkedList<String>();
	private LinkedList<String> Return = new LinkedList<String>();
	private LinkedList<String> see = new LinkedList<String>();
	private LinkedList<String> since = new LinkedList<String>();
	private LinkedList<String> status = new LinkedList<String>();
	private LinkedList<String> url = new LinkedList<String>();
	private LinkedList<String> verdict = new LinkedList<String>();
	private LinkedList<String> version = new LinkedList<String>();
	
	private LinkedList<String> warnings = new LinkedList<String>();
	private LinkedList<String> seeRefs = new LinkedList<String>();

	
	public TTCN3Comment(LocationAST node){
		
	}
	
	
	
	//TODO: WHY WHY WHY OH WHY?!?!?!?!?!??! REORGANIZE AND REFACTOR
	public TTCN3Comment(String rawComments, int elementType){
		if(rawComments != null && !rawComments.equals("")){
			rawComments = "\n" + rawComments;
			rawComments = rawComments.replaceAll("\\r", "");
			rawComments = rawComments.replaceAll("\\n(\\s|\\*|/)*", "\n").replaceAll("\\n+","\n");
			rawComments = rawComments.trim() + "\r___NEWTAG___";
			rawComments = rawComments.replaceAll(" @see", " @esee").replaceAll(" @url", " @eurl");
			rawComments = rawComments.replaceAll("\\n@", "\r___NEWTAG___@");
			
			getComments(rawComments, T3D.activeProfile.getCommentTagsConfiguration().getDescTag(), desc);
			getComments(rawComments, T3D.activeProfile.getCommentTagsConfiguration().getAuthorTag(), author);
			getComments(rawComments, T3D.activeProfile.getCommentTagsConfiguration().getConfigTag(), config);
			getComments(rawComments, T3D.activeProfile.getCommentTagsConfiguration().getExceptionTag(), exception);
			getComments(rawComments, T3D.activeProfile.getCommentTagsConfiguration().getMemberTag(), member);
			getComments(rawComments, T3D.activeProfile.getCommentTagsConfiguration().getParamTag(), param);
			getComments(rawComments, T3D.activeProfile.getCommentTagsConfiguration().getPurposeTag(), purpose);
			getComments(rawComments, T3D.activeProfile.getCommentTagsConfiguration().getRemarkTag(), remark);
			getComments(rawComments, T3D.activeProfile.getCommentTagsConfiguration().getReturnTag(), Return);
			getComments(rawComments, T3D.activeProfile.getCommentTagsConfiguration().getSeeTag(), see);
			getComments(rawComments, T3D.activeProfile.getCommentTagsConfiguration().getSinceTag(), since);
			getComments(rawComments, T3D.activeProfile.getCommentTagsConfiguration().getStatusTag(), status);
			getComments(rawComments, T3D.activeProfile.getCommentTagsConfiguration().getUrlTag(), url);
			getComments(rawComments, T3D.activeProfile.getCommentTagsConfiguration().getVerdictTag(), verdict);
			getComments(rawComments, T3D.activeProfile.getCommentTagsConfiguration().getVersionTag(), version);
			
			
			if (T3D.activeProfile.isCheckConsistentTagUsage()) {
				if (config.size() >= 2)
					warnings.add(getWarningMultipleTags("@" + T3D.activeProfile.getCommentTagsConfiguration().getConfigTag()));
				if (purpose.size() >= 2)
					warnings.add(getWarningMultipleTags("@" + T3D.activeProfile.getCommentTagsConfiguration().getPurposeTag()));
				if (Return.size() >= 2)
					warnings.add(getWarningMultipleTags("@" + T3D.activeProfile.getCommentTagsConfiguration().getReturnTag()));
				if (since.size() >= 2)
					warnings.add(getWarningMultipleTags("@" + T3D.activeProfile.getCommentTagsConfiguration().getSinceTag()));
				if (status.size() >= 2)
					warnings.add(getWarningMultipleTags("@" + T3D.activeProfile.getCommentTagsConfiguration().getStatusTag()));
				if (version.size() >= 2)
					warnings.add(getWarningMultipleTags("@" + T3D.activeProfile.getCommentTagsConfiguration().getVersionTag()));

				if (elementType != TTCN3ParserTokenTypes.TestcaseDef && config.size() >= 1) {
					warnings.add(getWarningExtraTags("@" + T3D.activeProfile.getCommentTagsConfiguration().getConfigTag()));
				}
				if (elementType != TTCN3ParserTokenTypes.SignatureDef && exception.size() >= 1) {
					warnings.add(getWarningExtraTags("@" + T3D.activeProfile.getCommentTagsConfiguration().getExceptionTag()));
				}
				if (elementType != TTCN3ParserTokenTypes.TypeDef
						&& elementType != TTCN3ParserTokenTypes.TemplateDef
						&& elementType != TTCN3ParserTokenTypes.ModuleParDef
						&& elementType != TTCN3ParserTokenTypes.ConstDef
						&& member.size() >= 1) {
					warnings.add(getWarningExtraTags("@" + T3D.activeProfile.getCommentTagsConfiguration().getMemberTag()));
				}
				if (elementType != TTCN3ParserTokenTypes.TemplateDef
						&& elementType != TTCN3ParserTokenTypes.SignatureDef
						&& elementType != TTCN3ParserTokenTypes.FunctionDef
						&& elementType != TTCN3ParserTokenTypes.AltstepDef
						&& elementType != TTCN3ParserTokenTypes.TestcaseDef
						&& elementType != TTCN3ParserTokenTypes.ExtFunctionDef
						&& param.size() >= 1) {
					warnings.add(getWarningExtraTags("@" + T3D.activeProfile.getCommentTagsConfiguration().getParamTag()));
				}
				if (elementType != TTCN3ParserTokenTypes.TestcaseDef && purpose.size() >= 1) {
					warnings.add(getWarningExtraTags("@" + T3D.activeProfile.getCommentTagsConfiguration().getPurposeTag()));
				}
				if (elementType != TTCN3ParserTokenTypes.FunctionDef
						&& elementType != TTCN3ParserTokenTypes.SignatureDef
						&& elementType != TTCN3ParserTokenTypes.ExtFunctionDef
						&& Return.size() >= 1) {
					warnings.add(getWarningExtraTags("@" + T3D.activeProfile.getCommentTagsConfiguration().getReturnTag()));
				}
				if (elementType != TTCN3ParserTokenTypes.FunctionDef
						&& elementType != TTCN3ParserTokenTypes.TestcaseDef
						&& elementType != TTCN3ParserTokenTypes.AltstepDef
						&& verdict.size() >= 1) {
					warnings.add(getWarningExtraTags("@" + T3D.activeProfile.getCommentTagsConfiguration().getVerdictTag()));
				}

				if (T3D.activeProfile.isCheckFunctionDescTagsRequired())
				if (elementType != TTCN3ParserTokenTypes.FunctionDef
//						&& elementType != TTCN3ParserTokenTypes.TestcaseDef
//						&& elementType != TTCN3ParserTokenTypes.AltstepDef
						&& desc.size() <= 0) {
					warnings.add(getWarningMissingTags("@" + T3D.activeProfile.getCommentTagsConfiguration().getDescTag()));
				}

				
				for (String d : desc)
					if (d.length() <= 0)
						warnings.add(getWarningEmptyTags("@" + T3D.activeProfile.getCommentTagsConfiguration().getDescTag()));
				for (String d : author)
					if (d.length() <= 0)
						warnings.add(getWarningEmptyTags("@" + T3D.activeProfile.getCommentTagsConfiguration().getAuthorTag()));
				for (String d : config)
					if (d.length() <= 0)
						warnings.add(getWarningEmptyTags("@" + T3D.activeProfile.getCommentTagsConfiguration().getConfigTag()));
				for (String d : exception)
					if (d.length() <= 0)
						warnings.add(getWarningEmptyTags("@" + T3D.activeProfile.getCommentTagsConfiguration().getExceptionTag()));
				for (String d : member)
					if (d.length() <= 0)
						warnings.add(getWarningEmptyTags("@" + T3D.activeProfile.getCommentTagsConfiguration().getMemberTag()));
				for (String d : param)
					if (d.length() <= 0)
						warnings.add(getWarningEmptyTags("@" + T3D.activeProfile.getCommentTagsConfiguration().getParamTag()));
				for (String d : purpose)
					if (d.length() <= 0)
						warnings.add(getWarningEmptyTags("@" + T3D.activeProfile.getCommentTagsConfiguration().getPurposeTag()));
				for (String d : remark)
					if (d.length() <= 0)
						warnings.add(getWarningEmptyTags("@" + T3D.activeProfile.getCommentTagsConfiguration().getRemarkTag()));
				for (String d : Return)
					if (d.length() <= 0)
						warnings.add(getWarningEmptyTags("@" + T3D.activeProfile.getCommentTagsConfiguration().getReturnTag()));
				for (String d : see)
					if (d.length() <= 0)
						warnings.add(getWarningEmptyTags("@" + T3D.activeProfile.getCommentTagsConfiguration().getSeeTag()));
				for (String d : since)
					if (d.length() <= 0)
						warnings.add(getWarningEmptyTags("@" + T3D.activeProfile.getCommentTagsConfiguration().getSinceTag()));
				for (String d : status)
					if (d.length() <= 0)
						warnings.add(getWarningEmptyTags("@" + T3D.activeProfile.getCommentTagsConfiguration().getStatusTag()));
				for (String d : url)
					if (d.length() <= 0)
						warnings.add(getWarningEmptyTags("@" + T3D.activeProfile.getCommentTagsConfiguration().getUrlTag()));
				for (String d : verdict)
					if (d.length() <= 0)
						warnings.add(getWarningEmptyTags("@" + T3D.activeProfile.getCommentTagsConfiguration().getVerdictTag()));
				for (String d : version)
					if (d.length() <= 0)
						warnings.add(getWarningEmptyTags("@" + T3D.activeProfile.getCommentTagsConfiguration().getVersionTag()));
			}
		}
	
	for(String seeRef : see)
		seeRefs.add(seeRef);
	}
	
	private String getWarningMultipleTags(String tagname){
		return "Multiple " + tagname + " tags found (may only contain one)";
	}
	
	private String getWarningExtraTags(String tagname){
		return tagname + " tag found (may not be used here)";
	}
	
	private String getWarningEmptyTags(String tagname){
		return "Empty tag found: " + tagname;
	}

	private String getWarningMissingTags(String tagname){
		return "Required " + tagname + " tag is missing";
	}

	
	private String getIdentifier(String comment, int pos){
		String subString = comment.substring(pos, comment.length());
		
		int endpos = subString.indexOf(" ");
		if(endpos == -1)
			endpos = subString.length();
//		System.out.println("-" + subString.substring(0, endpos) + "-");
		return subString.substring(0, endpos).trim();		
	}
	
	private String replaceTag(String c, String tag){
		int pos;
		c += " ";
		while(c.contains(" @" + tag + " ")){
			pos = c.indexOf(" @" + tag + " ");
			if(pos != -1){
				String identifier = getIdentifier(c, pos+ (tag.length() + 3));
				c = c.replaceAll("@" + tag + " " + identifier + " ", "<" + tag + ">" + identifier + "</" + tag + ">");
			}else
				break;
		}
		return c.trim();
	}
	
	private String replaceSee(String c){
		return replaceTag(c, "esee");
	}
	
	private String replaceUrl(String c){
		return replaceTag(c, "eurl");
	}
	
	private String formatComment(String c){
		return StringEscapeUtils.escapeXml(c).replaceAll("  ", " ").replaceAll("\n", " ").replaceAll("\t", " ").replaceAll("\r", "");

	}
	
	public String toString(){
		commentsXML = "";
		if(!isEmpty()){
			commentsXML += "\n<comment>";
			for(String d : desc)
				commentsXML += ("\n<desc>" + replaceUrl(replaceSee(formatComment(d))) + "</desc>");
			
			for(String d : author)
				commentsXML += ("\n<author>" + replaceUrl(replaceSee(formatComment(d))) + "</author>");
			
			for(String d : config)
				commentsXML += ("\n<config>" + replaceUrl(replaceSee(formatComment(d))) + "</config>");
		
			for(String d : exception)
				commentsXML += ("\n<exception>" + replaceUrl(replaceSee(formatComment(d))) + "</exception>");
		
			for(String d : member)
				commentsXML += ("\n<member>" + replaceUrl(replaceSee(formatComment(d))) + "</member>");

			for(String d : param)
				commentsXML += ("\n<param>" + replaceUrl(replaceSee(formatComment(d))) + "</param>");
			for(String d : purpose)
				commentsXML += ("\n<purpose>" + replaceUrl(replaceSee(formatComment(d))) + "</purpose>");
					
			for(String d : remark)
				commentsXML += ("\n<remark>" + replaceUrl(replaceSee(formatComment(d))) + "</remark>");
			
			for(String d : Return)
					commentsXML += ("\n<return>" + replaceUrl(replaceSee(formatComment(d))) + "</return>");
			
			for(String d : see)
				commentsXML += ("\n<see>" + formatComment(d) + "</see>");
			
			for(String d : since)
				commentsXML += ("\n<since>" + replaceUrl(replaceSee(formatComment(d))) + "</since>");
			
			for(String d : status)
				commentsXML += ("\n<status>" + replaceUrl(replaceSee(formatComment(d))) + "</status>");
			
			for(String d : url)
				commentsXML += ("\n<url>" + formatComment(d) + "</url>");
			
			for(String d : verdict)
				commentsXML += ("\n<verdict>" + replaceUrl(replaceSee(formatComment(d))) + "</verdict>");
			
			for(String d : version)
				commentsXML += ("\n<version>" + replaceUrl(replaceSee(formatComment(d))) + "</version>");
			
			commentsXML += "</comment>";
						
		}
		if(commentsXML.length() > 20)
			return commentsXML;
		else
			return "";
	}
	
	private boolean isEmpty(){
		return false;
	}
		
	private void getComments(String commentblock, String tag, LinkedList<String> vector){
		Pattern p = Pattern.compile("@" + tag + "(.|\\n)*\\r___NEWTAG___");
		Matcher m = p.matcher(commentblock);
		while (m.find() == true){
			String comment = m.group().replaceFirst("@"+tag, "").replaceFirst("\r___NEWTAG___", "").trim();
			vector.add(comment);
		}		
	}
	
	public LinkedList<String> getDocumentedParameters(){
		LinkedList <String> docParNames = new LinkedList<String>();		
		for(String parString : param){
			if(parString.indexOf(" ") > 0)
				docParNames.add(parString.substring(0, parString.indexOf(" ")));
		}		
		return docParNames;
	}

	public LinkedList<String> getDescriptions(){
		LinkedList <String> descriptions = new LinkedList<String>();		
		for(String descString : desc)
				descriptions.add(descString);
		return descriptions;
	}
	
	public LinkedList<String> getWarnings() {
		return warnings;
	}	
}
