package gr.uoa.di.web.utils;

import eu.dnetlib.domain.data.Document;
import eu.dnetlib.domain.enabling.Vocabulary;
import eu.dnetlib.domain.functionality.DisplayType;
import eu.dnetlib.domain.functionality.DocumentExternalUrlDisplayType;
import eu.dnetlib.domain.functionality.DocumentField;
import eu.dnetlib.domain.functionality.DocumentField.Cutpoint;
import eu.dnetlib.domain.functionality.ExternalUrlDisplayType;
import eu.dnetlib.domain.functionality.InternalUrlDisplayType;
import eu.dnetlib.domain.functionality.PlainTextDisplayType;
import eu.dnetlib.domain.functionality.SearchDisplayType;
import eu.dnetlib.domain.functionality.UrlDisplayType;
import gr.uoa.di.web.utils.webdocument.StyledValue;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;

import org.apache.log4j.Logger;

public class HTMLGenerator {

	public static Logger logger = Logger.getLogger(HTMLGenerator.class);
	
	public static List<StyledValue> generate(DocumentField field, Document document, 
			Vocabulary vocabulary, Locale locale) {

		List<StyledValue> htmlValuesList = new ArrayList<StyledValue>();
		int characterCount = 0;
		String fieldName = field.getName();
		List<String> fieldValues = document.getFieldValues(fieldName);
		generateHTMLValues(fieldName, fieldValues, characterCount, document,
				htmlValuesList, field, vocabulary, locale);
		return htmlValuesList;
	}

	private static void generateHTMLValues(String fieldName,
			List<String> fieldValues, int characterCount, Document document,
			List<StyledValue> htmlValuesList, DocumentField field,
			Vocabulary vocabulary, Locale locale) {
		
		//logger.debug("For fieldname " + fieldName + " fieldvalues " + fieldValues);
		Cutpoint cutpoint = field.getCutpoint();
		int maxCharacters = field.getMaxCharacters();

		List<DisplayType> displays = new ArrayList<DisplayType>();
		if ((fieldValues == null || fieldValues.isEmpty()) && field.getForceDescription() != null
				&& field.getForceDescription()) {
			fieldName = LocaleDescriptionUtil.getFieldDescription(field.getDescriptionMap(), locale).substring
				(2, LocaleDescriptionUtil.getFieldDescription(field.getDescriptionMap(), locale).length() - 1);
			fieldValues = document.getFieldValues(fieldName);
			List<DisplayType> simpleDisplayList = new ArrayList<DisplayType>();
			simpleDisplayList.add(new PlainTextDisplayType(fieldName));	
			displays = simpleDisplayList;
		
		} else if (fieldValues == null) {
			return;
			
		} else {
			
			displays = field.getDisplays();
		}
		
		for (int i = 0; i < fieldValues.size()
				&& (characterCount < maxCharacters); i++) {

			String fieldValue = document.getFieldValues(fieldName).get(i);
			if (vocabulary != null) {
				String englishName = vocabulary.getEnglishName(fieldValue);
				if (englishName != null) {
					fieldValue = englishName;
				}
			}

			for (DisplayType displayType : displays) {
				StringBuilder builder = new StringBuilder();
				String secondaryLink = LocaleDescriptionUtil.getSecondaryLink(field, locale);
				if (htmlValuesList.size() > 0 && secondaryLink!= null && 
						!LocaleDescriptionUtil.getSecondaryLink(field, locale).isEmpty()) {
					fieldValue = secondaryLink;
				}
				
				int messageSize = 0;

				if (displayType instanceof SearchDisplayType) {
					messageSize = generateHMTLValue(builder,
							(SearchDisplayType) displayType, document,
							fieldName, fieldValue, locale);
					
				} else if (displayType instanceof InternalUrlDisplayType) {
					messageSize = generateHMTLValue(builder,
							(InternalUrlDisplayType) displayType, document,
							fieldName, fieldValue, locale);
					
				} else if (displayType instanceof ExternalUrlDisplayType) {
					messageSize = generateHMTLValue(builder,
							(ExternalUrlDisplayType) displayType, document,
							fieldName, fieldValue, locale);
					
				} else {
					messageSize = generateHMTLValue(builder,
							(PlainTextDisplayType) displayType, document,
							fieldName, fieldValue, locale);			
				}					
						
				StyledValue styledValue = null;
				String cssClass = field.getCssClass(document);
				
				if (characterCount + messageSize > maxCharacters) {
					String value = null;
					switch (cutpoint) {
					case LINE:
						value = builder.toString();
						styledValue = new StyledValue(value, cssClass);
						htmlValuesList.add(styledValue);
						break;
					case VALUE:
						if (characterCount <= maxCharacters) {
							value = builder.toString();
							styledValue = new StyledValue(value, cssClass);
							htmlValuesList.add(styledValue);
						}
						break;
					case PART:
						String s = builder.toString();
						if (displayType instanceof UrlDisplayType){
							String anchor = null;
							if (displayType instanceof SearchDisplayType) {
								anchor = getAnchor((SearchDisplayType)displayType, document, fieldValue).toString();
							} else if (displayType instanceof InternalUrlDisplayType) {
								anchor = getAnchor((InternalUrlDisplayType)displayType, document, fieldValue).toString();
							} else if (displayType instanceof ExternalUrlDisplayType) {
								anchor = getAnchor((ExternalUrlDisplayType)displayType, document, fieldValue).toString();
							}
							
							String label = getLabel(document, displayType, fieldName, fieldValue, locale);
							
							if (maxCharacters - characterCount > 0) {
								label = label.substring(0, maxCharacters - characterCount)
										+ "...";
							} else {
								label = label.substring(0, maxCharacters) + "...";
							}
							
							value = anchor + label + "</a>";
							styledValue = new StyledValue(value, cssClass);
							htmlValuesList.add(styledValue);
							
						} else {					
							if (maxCharacters - characterCount > 0) {
								s = s.substring(0, maxCharacters - characterCount)
										+ "...";
							} else {
								s = s.substring(0, maxCharacters) + "...";
							}
							styledValue = new StyledValue(s, cssClass);
							htmlValuesList.add(styledValue);
						}
						break;
					}
				} else {
					styledValue = new StyledValue(builder.toString(), cssClass);
					htmlValuesList.add(styledValue);
				}

				characterCount += messageSize;
			}	
		}
	}

	private static int generateHMTLValue(StringBuilder builder,
			SearchDisplayType displayType, Document document, String fieldName,
			String fieldValue, Locale locale) {

		String finalValue = getLabel(document, displayType, fieldName,
				fieldValue, locale);
		builder.append(getAnchor(displayType, document, fieldValue));
		builder.append(finalValue);
		builder.append("</a>");
		return finalValue.length();

	}

	private static int generateHMTLValue(StringBuilder builder,
			ExternalUrlDisplayType displayType, Document document,
			String fieldName, String fieldValue, Locale locale) {

		String finalValue = getLabel(document, displayType, fieldName,
				fieldValue, locale);

		builder.append(getAnchor(displayType, document, fieldValue));
			builder.append(finalValue);
		builder.append("</a>");

		return finalValue.length();
	}

	private static int generateHMTLValue(StringBuilder builder,
			InternalUrlDisplayType displayType, Document document,
			String fieldName, String fieldValue, Locale locale) {
		
		String finalValue =getLabel(document, displayType, fieldName,
				fieldValue, locale);
		
		builder.append(getAnchor(displayType, document, fieldValue));
		builder.append(finalValue);
		builder.append("</a>");
		return finalValue.length();
	}


	private static int generateHMTLValue(StringBuilder builder,
			PlainTextDisplayType displayType, Document document,
			String fieldName, String fieldValue, Locale locale) {
		String finalValue = getLabel(document, displayType, fieldName,
				fieldValue, locale);
		builder.append(finalValue);
		return finalValue.length();
	}

	private static StringBuilder generateHref(String action,
			Map<String, String> parameters, StringBuilder builder) {
		builder.append(" href=\'").append(action).append(".action?");
		int i = 0;
		for (String parameterName : parameters.keySet()) {
			builder.append(parameterName).append("=").append(
					parameters.get(parameterName));
			if (i < parameters.keySet().size() - 1) {
				builder.append("&");
			}
			i++;
		}
		builder.append("\'");

		return builder;
	}

	private static String getDisplayDescription(DisplayType displayType,
			Locale locale) {
		Map<Locale, String> descriptionMap = displayType.getDescriptionMap();
		if (descriptionMap != null) {
			String description = descriptionMap.get(locale);
			if (description == null) {
				return descriptionMap.get(new Locale("en", "GB"));
			}
			return description;

		}
		
		return null;

	}
	

	public static String getLabel(Document document, DisplayType displayType,
			String fieldName, String fieldValue, Locale locale) {
		return DisplayValueGenerator.replaceFieldValueExpression(document,
				getDisplayDescription(displayType, locale), fieldName,
				fieldValue);
	}

	public static StringBuilder getAnchor(SearchDisplayType displayType, 
			Document document, String fieldValue) {
	
		StringBuilder builder = new StringBuilder();
		Map<String, String> parameters = new HashMap<String, String>();

		String query = 
			"(" + displayType.getLabel() + "=" + "\"" + fieldValue + "\"" + ")";
		
		parameters.put(displayType.getParameter(), query);

		builder.append("<a");
		builder.append(" class=\"searchlink\"");
			generateHref(displayType.getAction(), parameters, builder);
		builder.append(">");

		return builder;
	}

	public static StringBuilder getAnchor(ExternalUrlDisplayType displayType,
			Document document, String fieldValue) {

		StringBuilder builder = new StringBuilder();
		String encodedFieldValue = null;
		try {
			encodedFieldValue = URLEncoder.encode(fieldValue, "UTF-8"); 
		} catch (UnsupportedEncodingException e) {
			encodedFieldValue = fieldValue;
		}

		Map<String, String> parameters = new HashMap<String, String>();
		parameters.put(displayType.getParameter(), encodedFieldValue);
		if (displayType instanceof DocumentExternalUrlDisplayType) {
			parameters.put("docId", document.getFieldValues("id").get(0));
		}

		builder.append("<a");
		generateHref(displayType.getAction(), parameters, builder);
		builder.append(" class=\"externallink\"");
		builder.append(" target=\"_blank\"");
		builder.append(">");

		return builder;
	}
	
	public static StringBuilder getAnchor(InternalUrlDisplayType displayType, 
			Document document, String fieldValue) {
		
		StringBuilder builder = new StringBuilder();
		
		Map<String, String> parameters = new HashMap<String, String>();
		parameters.put(displayType.getParameter(), fieldValue);
		
		builder.append("<a");
			generateHref(displayType.getAction(), parameters, builder);
		builder.append(">");
		
		return builder;
	}
}
