package eu.dnetlib.functionality.webInterface.app;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import org.apache.log4j.Logger;

import eu.dnetlib.domain.functionality.DisplayType;
import eu.dnetlib.domain.functionality.DocumentDescription;
import eu.dnetlib.domain.functionality.DocumentExternalUrlDisplayType;
import eu.dnetlib.domain.functionality.DocumentField;
import eu.dnetlib.domain.functionality.InternalUrlDisplayType;
import eu.dnetlib.domain.functionality.PlainTextDisplayType;
import eu.dnetlib.domain.functionality.SearchDisplayType;
import eu.dnetlib.domain.functionality.Searchable;
import eu.dnetlib.domain.functionality.SearchableDate;
import eu.dnetlib.domain.functionality.SwitchDocumentField;
import eu.dnetlib.domain.functionality.WebInterfaceLayout;
import eu.dnetlib.domain.functionality.WebInterfaceSearchCriteria;
import eu.dnetlib.domain.functionality.DocumentDescription.View;
import eu.dnetlib.domain.functionality.DocumentField.Cutpoint;
import eu.dnetlib.domain.functionality.Searchable.Type;
import eu.dnetlib.functionality.webInterface.dao.WebInterfaceLayoutDao;
import gr.uoa.di.driver.dao.DAOException;

public class WebInterfaceLayoutManagerImpl implements WebLayoutManager {

	// private static boolean USE_CUSTOMISED_LAYOUT = false;
	private static Logger logger = Logger
			.getLogger(WebInterfaceLayoutManagerImpl.class);

	private String layoutName = null;
	private WebInterfaceLayoutDao dao = null;

	private List<Searchable> allFields = new ArrayList<Searchable>();
	private List<Searchable> searchFields = new ArrayList<Searchable>();
	private List<Searchable> refineFields = new ArrayList<Searchable>();
	private List<Searchable> browseFields = new ArrayList<Searchable>();
	private List<DocumentField> resultFields = new ArrayList<DocumentField>();
	private Map<String, Searchable> labelMap = new HashMap<String, Searchable>();
	private Map<String, Searchable> indexMap = new HashMap<String, Searchable>();
	private List<String> searchVocabularyNames = new ArrayList<String>();
	private List<String> browseVocabularyNames = new ArrayList<String>();
	private List<String> documentFieldVocabularyNames = new ArrayList<String>();

	private String cssFileName = null;

	private WebInterfaceLayout layout = null;

	public void init() {

		logger.debug("Getting web layout with name " + this.layoutName);

		WebInterfaceSearchCriteria criteria = new WebInterfaceSearchCriteria();
		criteria.setLayoutName(this.layoutName);

		WebInterfaceLayout layout = null;

		try {
			List<WebInterfaceLayout> list = this.dao.search(criteria);

			if (list.size() > 0)
				layout = list.get(list.size() - 1);

		} catch (DAOException de) {
			logger.error("Failed to get web layout xml from IS.", de);
		}

	//	layout = generateDefaultLayout();
		
		if (layout == null) {
			logger.debug("Layout + " + this.layoutName
					+ " not found. Generating default");

			layout = this.generateDefaultLayout();
		}

		updateLists(layout);
		this.cssFileName = layout.getCssFile();
		this.layout = layout;
	}

	private WebInterfaceLayout generateDefaultLayout() {

		WebInterfaceLayout layout = new WebInterfaceLayout("default", "DMF",
				"index");

		layout.setViewCollections(true);
		layout.setViewCommunities(true);
		layout.setViewRepositories(true);
		layout.setViewAnnouncements(true);
		layout.setViewUserProfile(true);
		layout.setViewSimilarDocuments(true);

		Searchable sable = new Searchable(Type.PLAIN);
		sable.setDescription("Author");
		sable.setShortDescription("author");
		sable.setName("author");
		sable.setIndexType("creator");
		sable.setInSearch(true);
		sable.setInRefine(true);
		sable.setInBrowse(false);
		sable.setSearchRank(1);
		sable.setRefineRank(1);
		sable.setSearchVocabulary(null);
		sable.setBrowseVocabulary(null);
		layout.getSearchFields().add(sable);

		sable = new Searchable(Type.PLAIN);
		sable.setDescription("Title");
		sable.setShortDescription("title");
		sable.setName("title");
		sable.setIndexType("title");
		sable.setInSearch(true);
		sable.setInRefine(false);
		sable.setInBrowse(false);
		sable.setSearchRank(2);
		sable.setRefineRank(2);
		sable.setSearchVocabulary(null);
		sable.setBrowseVocabulary(null);
		layout.getSearchFields().add(sable);

		sable = new Searchable(Type.PLAIN);
		sable.setDescription("Subject");
		sable.setShortDescription("subject");
		sable.setName("subject");
		sable.setIndexType("subject");
		sable.setInSearch(true);
		sable.setInRefine(true);
		sable.setInBrowse(false);
		sable.setSearchRank(3);
		sable.setRefineRank(3);
		sable.setSearchVocabulary(null);
		sable.setBrowseVocabulary(null);
		layout.getSearchFields().add(sable);

		sable = new Searchable(Type.PLAIN);
		sable.setDescription("Contributor");
		sable.setShortDescription("contributor");
		sable.setName("contributor");
		sable.setIndexType("contributor");
		sable.setInSearch(true);
		sable.setInRefine(true);
		sable.setInBrowse(false);
		sable.setSearchRank(4);
		sable.setRefineRank(4);
		sable.setSearchVocabulary(null);
		sable.setBrowseVocabulary(null);
		layout.getSearchFields().add(sable);

		sable = new Searchable(Type.PLAIN);
		sable.setDescription("Publisher");
		sable.setShortDescription("publisher");
		sable.setName("publisher");
		sable.setIndexType("publisher");
		sable.setInSearch(true);
		sable.setInRefine(true);
		sable.setInBrowse(false);
		sable.setSearchRank(5);
		sable.setRefineRank(5);
		sable.setSearchVocabulary(null);
		sable.setBrowseVocabulary(null);
		layout.getSearchFields().add(sable);

		sable = new Searchable(Type.PLAIN);
		sable.setDescription("Source");
		sable.setShortDescription("source");
		sable.setName("source");
		sable.setIndexType("source");
		sable.setInSearch(true);
		sable.setInRefine(true);
		sable.setInBrowse(false);
		sable.setSearchRank(6);
		sable.setRefineRank(6);
		sable.setSearchVocabulary(null);
		sable.setBrowseVocabulary(null);

		layout.getSearchFields().add(sable);
		sable = new Searchable(Type.PLAIN);
		sable.setDescription("Relation");
		sable.setShortDescription("relation");
		sable.setName("relation");
		sable.setIndexType("relation");
		sable.setInSearch(true);
		sable.setInRefine(false);
		sable.setInBrowse(false);
		sable.setSearchRank(7);
		sable.setSearchVocabulary(null);
		sable.setBrowseVocabulary(null);
		layout.getSearchFields().add(sable);

		sable = new SearchableDate();
		sable.setDescription("Publication Date");
		sable.setShortDescription("published");
		sable.setName("dateAccept");
		sable.setIndexType("dateAccepted");
		sable.setInSearch(true);
		sable.setSearchRank(8);
		((SearchableDate) sable).setFromYear(1980);
		TreeMap<Integer, String> tm = new TreeMap<Integer, String>();
		tm.put(new Integer(1), "in the last one month");
		tm.put(new Integer(2), "in the last 2 months");
		tm.put(new Integer(3), "in the last 3 months");
		tm.put(new Integer(6), "in the last 6 months");
		tm.put(new Integer(12), "in the last 1 year");
		tm.put(new Integer(24), "in the last 2 years");
		tm.put(new Integer(36), "in the last 3 years");
		tm.put(new Integer(60), "in the last 5 years");
		tm.put(new Integer(120), "in the last 10 years");
		((SearchableDate) sable).getPeriodBack().putAll(tm);
		layout.getSearchFields().add(sable);

		sable = new Searchable(Type.PLAIN);
		sable.setDescription("Document Language");
		sable.setShortDescription("language");
		sable.setName("lang");
		sable.setIndexType("language");
		sable.setInSearch(true);
		sable.setInRefine(true);
		sable.setInBrowse(true);
		sable.setSearchRank(9);
		sable.setRefineRank(7);
		sable.setBrowseRank(1);
		sable.setSearchVocabulary("Short list of language names");
		sable.setBrowseVocabulary("Names of languages");
		layout.getSearchFields().add(sable);

		sable = new Searchable(Type.PLAIN);
		sable.setDescription("Document Type");
		sable.setShortDescription("category");
		sable.setName("category");
		sable.setIndexType("CobjCategory");
		sable.setInSearch(true);
		sable.setInRefine(true);
		sable.setInBrowse(true);
		sable.setSearchRank(10);
		sable.setRefineRank(8);
		sable.setBrowseRank(2);
		sable.setSearchVocabulary("Names of Text Object Typologies");
		sable.setBrowseVocabulary("Names of Text Object Typologies");
		layout.getSearchFields().add(sable);

		sable = new Searchable(Type.PLAIN);
		sable.setDescription("Repositories");
		sable.setShortDescription("repo");
		sable.setName("repName");
		sable.setIndexType("repositoryName");
		sable.setInSearch(true);
		sable.setInRefine(true);
		sable.setInBrowse(true);
		sable.setSearchRank(11);
		sable.setRefineRank(9);
		sable.setBrowseRank(3);
		sable.setSearchVocabulary("Names of Repositories");
		layout.getSearchFields().add(sable);

		Map<View, DocumentDescription> documentDescriptions = new HashMap<View, DocumentDescription>();
		DocumentDescription dd = new DocumentDescription(View.SUMMARY_VIEW);
		List<DocumentField> fields = new ArrayList<DocumentField>();
		List<DisplayType> displays = new ArrayList<DisplayType>();

		SwitchDocumentField switchField = new SwitchDocumentField(
				"CobjTypology");

		DisplayType type = new DocumentExternalUrlDisplayType("identifier",
				"${title}");
		displays.add(type);
		DocumentField field = new DocumentField("identifier", "${title}", null,
				displays, "document_text", Cutpoint.VALUE, 1);
		field.setSecondaryLink("You can also visit...");
		field.setForceDescription(true);
		switchField.addSwitchDisplayField("Textual", field);

		type = new InternalUrlDisplayType("id", "${title}", "showEPublication",
				"epId");
		displays = new ArrayList<DisplayType>();
		displays.add(type);
		field = new DocumentField("id", null, null, displays, "document_ep",
				Cutpoint.VALUE, 100);
		switchField.addSwitchDisplayField("compound object", field);
		switchField.addSwitchDisplayField("data set", field);
		dd.putDocumentField(switchField);

		type = new SearchDisplayType("creator", "author");
		displays = new ArrayList<DisplayType>();
		displays.add(type);
		field = new DocumentField("creator", "Author(s)", null, displays,
				"resultsField", Cutpoint.VALUE, 100);
		fields.add(field);
		dd.putDocumentField(field);

		type = new PlainTextDisplayType("description");
		displays = new ArrayList<DisplayType>();
		displays.add(type);
		field = new DocumentField("description", "Description", null, displays,
				"resultsField", Cutpoint.PART, 300);
		fields.add(field);
		dd.putDocumentField(field);

		type = new InternalUrlDisplayType("repositoryName",
				"${repositoryName}", "showRepository", "name");
		displays = new ArrayList<DisplayType>();
		displays.add(type);
		type = new SearchDisplayType("repositoryName", "repName",
				"View repository documents");
		displays.add(type);
		field = new DocumentField("repositoryName", "Repository", null,
				displays, "resultsField", Cutpoint.LINE, 300);
		fields.add(field);
		dd.putDocumentField(field);

		type = new PlainTextDisplayType("language");
		displays = new ArrayList<DisplayType>();
		displays.add(type);
		field = new DocumentField("language", "Language(s)",
				"Names of Languages", displays, "resultsField", Cutpoint.VALUE,
				100);
		fields.add(field);
		dd.putDocumentField(field);
		documentDescriptions.put(dd.getView(), dd);

		dd = new DocumentDescription(View.DETAILED_VIEW);
		fields = new ArrayList<DocumentField>();
		displays = new ArrayList<DisplayType>();

		type = new DocumentExternalUrlDisplayType("identifier", "${title}");
		displays.add(type);
		field = new DocumentField("identifier", "${title}", null, displays,
				"document_text");
		field.setSecondaryLink("You can also visit...");
		field.setForceDescription(true);
		fields.add(field);
		dd.putDocumentField(field);

		type = new SearchDisplayType("creator", "author");
		displays = new ArrayList<DisplayType>();
		displays.add(type);
		field = new DocumentField("creator", "Author(s)", null, displays,
				"resultsField");
		fields.add(field);
		dd.putDocumentField(field);

		type = new PlainTextDisplayType("description");
		displays = new ArrayList<DisplayType>();
		displays.add(type);
		field = new DocumentField("description", "Description", null, displays,
				"resultsField");
		fields.add(field);
		dd.putDocumentField(field);

		type = new InternalUrlDisplayType("repositoryName",
				"${repositoryName}", "showRepository", "name");
		displays = new ArrayList<DisplayType>();
		displays.add(type);
		type = new SearchDisplayType("repositoryName", "repName",
				"View repository documents");
		displays.add(type);
		field = new DocumentField("repositoryName", "Repository", null,
				displays, "resultsField");
		fields.add(field);
		dd.putDocumentField(field);

		type = new PlainTextDisplayType("language");
		displays = new ArrayList<DisplayType>();
		displays.add(type);
		field = new DocumentField("language", "Language(s)",
				"Names of Languages", displays, "resultsField");
		fields.add(field);
		dd.putDocumentField(field);

		type = new PlainTextDisplayType("subject");
		displays = new ArrayList<DisplayType>();
		displays.add(type);
		field = new DocumentField("subject", "Subject(s)", null, displays,
				"resultsField");
		fields.add(field);
		dd.putDocumentField(field);

		type = new PlainTextDisplayType("publisher");
		displays = new ArrayList<DisplayType>();
		displays.add(type);
		field = new DocumentField("publisher", "Publisher(s)", null, displays,
				"resultsField");
		fields.add(field);
		dd.putDocumentField(field);

		type = new PlainTextDisplayType("contributor");
		displays = new ArrayList<DisplayType>();
		displays.add(type);
		field = new DocumentField("source", "Contributor(s)", null, displays,
				"resultsField");
		fields.add(field);
		dd.putDocumentField(field);

		type = new PlainTextDisplayType("source");
		displays = new ArrayList<DisplayType>();
		displays.add(type);
		field = new DocumentField("source", "Source(s)", null, displays,
				"resultsField");
		fields.add(field);
		dd.putDocumentField(field);

		type = new PlainTextDisplayType("dateAccepted");
		displays = new ArrayList<DisplayType>();
		displays.add(type);
		field = new DocumentField("dateAccepted", "Publication Date(s)", null,
				displays, "resultsField");
		fields.add(field);
		dd.putDocumentField(field);

		documentDescriptions.put(dd.getView(), dd);

		dd = new DocumentDescription(View.COMMUNITY_VIEW);
		fields = new ArrayList<DocumentField>();
		displays = new ArrayList<DisplayType>();
		type = new InternalUrlDisplayType("id", "${title}", "ShowDocument",
				"id");
		displays.add(type);
		field = new DocumentField("identifier", "${title}", null, displays,
				"resultsField", Cutpoint.VALUE, 100);
		field.setSecondaryLink("You can also visit...");
		field.setForceDescription(true);
		fields.add(field);
		dd.putDocumentField(field);

		type = new PlainTextDisplayType("creator");
		displays = new ArrayList<DisplayType>();
		displays.add(type);
		field = new DocumentField("creator", "Author(s)", null, displays,
				"resultsField", Cutpoint.VALUE, 100);
		fields.add(field);
		dd.putDocumentField(field);

		documentDescriptions.put(dd.getView(), dd);

		layout.getDocumentDescriptions().putAll(documentDescriptions);

		layout.setCssFile("driver_search.css");

		// layout.getBaseCollections().add("11-ad790e20-0f81-44dc-87b6-da308249ec6a_Q29sbGVjdGlvbkRTUmVzb3VyY2VzL0NvbGxlY3Rpb25EU1Jlc291cmNlVHlwZQ==");
		// layout.getBaseCollections().add("13-7552efc5-451a-4d25-9196-85fb884a2446_Q29sbGVjdGlvbkRTUmVzb3VyY2VzL0NvbGxlY3Rpb25EU1Jlc291cmNlVHlwZQ==");

		return layout;
	}

	private synchronized void updateLists(WebInterfaceLayout layout) {

		for (Searchable s : layout.getSearchFields()) {

			labelMap.put(s.getName(), s);
			indexMap.put(s.getIndexType().toLowerCase(), s);

			allFields.add(s);

			if (s.isInSearch()) {
				searchFields.add(s);
			}

			if (s.isInBrowse()) {
				browseFields.add(s);
			}

			if (s.isInRefine()) {
				refineFields.add(s);
			}

			if (s.getSearchVocabulary() != null) {
				searchVocabularyNames.add(s.getSearchVocabulary());
			}

			if (s.getBrowseVocabulary() != null) {
				browseVocabularyNames.add(s.getBrowseVocabulary());
			}

		}

		Map<View, DocumentDescription> descriptions = layout
				.getDocumentDescriptions();

		for (View view : descriptions.keySet()) {
			DocumentDescription docDscr = descriptions.get(view);
			List<DocumentField> fields = docDscr.getDocumentFields();
			for (DocumentField field : fields) {				
				if (field instanceof SwitchDocumentField) {
					Map<String, DocumentField> documentFieldMap = ((SwitchDocumentField) field).getDocumentFieldMap();
					for (String key:documentFieldMap.keySet()) {
						DocumentField swField = documentFieldMap.get(key);
						if (swField.getVocabulary() !=null) {
							documentFieldVocabularyNames.add(swField.getVocabulary());
						}
						resultFields.add(swField);
					}
			
				} else {				
					if (field.getVocabulary() != null) {
						documentFieldVocabularyNames.add(field.getVocabulary());
					}
					resultFields.add(field);
				}
			}
		}

		
		
		Collections.sort(searchFields, new Comparator<Searchable>() {
			public int compare(Searchable s1, Searchable s2) {
				return s1.getSearchRank() - s2.getSearchRank();
			}
		});
		Collections.sort(refineFields, new Comparator<Searchable>() {
			public int compare(Searchable s1, Searchable s2) {
				return s1.getSearchRank() - s2.getSearchRank();
			}
		});
	}

	public void setLayoutName(String layoutName) {
		this.layoutName = layoutName;
	}

	public WebInterfaceLayoutDao getDao() {
		return dao;
	}

	public void setDao(WebInterfaceLayoutDao dao) {
		this.dao = dao;
	}

	public List<Searchable> getAllFields() {
		return allFields;
	}

	public List<Searchable> getSearchFields() {
		return searchFields;
	}

	public List<Searchable> getBrowseFields() {
		return browseFields;
	}

	public List<DocumentField> getResultFields() {
		return resultFields;
	}

	public List<Searchable> getRefineFields() {
		return refineFields;
	}

	public Map<String, Searchable> getLabelMap() {
		return labelMap;
	}

	public Map<String, Searchable> getIndexMap() {
		return indexMap;
	}

	public List<String> getSearchVocabularyNames() {
		return searchVocabularyNames;
	}

	public String getCssFileName() {
		return this.cssFileName;
	}

	public List<String> getBrowseVocabularyNames() {
		return browseVocabularyNames;
	}

	public List<String> getDocumentFieldVocabularyNames() {
		return documentFieldVocabularyNames;
	}

	public WebInterfaceLayout getLayout() {
		return layout;
	}

	@Override
	public DocumentDescription getDescription(View view) {
		return (layout.getDocumentDescriptions().get(view) != null) ? layout
				.getDocumentDescriptions().get(view) : layout
				.getDocumentDescriptions().get(View.SUMMARY_VIEW);
	}

}
