package com.shopizer.search.services.worker;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;

import javax.inject.Inject;



import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;

import com.shopizer.search.services.IndexKeywordRequest;
import com.shopizer.search.services.field.BooleanField;
import com.shopizer.search.services.field.DoubleField;
import com.shopizer.search.services.field.Field;
import com.shopizer.search.services.field.IntegerField;
import com.shopizer.search.services.field.ListField;
import com.shopizer.search.services.field.LongField;
import com.shopizer.search.services.field.StringField;
import com.shopizer.search.services.impl.SearchDelegate;
import com.shopizer.search.utils.CustomIndexConfiguration;
import com.shopizer.search.utils.CustomIndexFieldConfiguration;
import com.shopizer.search.utils.DateUtil;
import com.shopizer.search.utils.DynamicIndexNameUtil;
import com.shopizer.search.utils.FileUtil;
import com.shopizer.search.utils.SearchClient;


public class KeywordIndexerImpl implements IndexWorker {
	
	@Inject
	DeleteKeywordsImpl deleteKeywordsImpl;
	
	@Inject
	private SearchDelegate searchDelegate;
	
	
	private static Logger log = Logger.getLogger(KeywordIndexerImpl.class);

	private static boolean init = false;

	private List<CustomIndexConfiguration> indexConfigurations = null;


	public List<CustomIndexConfiguration> getIndexConfigurations() {
		return indexConfigurations;
	}

	public void setIndexConfigurations(
			List<CustomIndexConfiguration> indexConfigurations) {
		this.indexConfigurations = indexConfigurations;
	}

	private static Map<String,CustomIndexConfiguration>  indexConfigurationsMap = null;

	private synchronized void init() {
		
		if(init) {
			return;
		}
		
		init = true;
		try {
			
			if(indexConfigurations!=null) {
				
				for(Object o : indexConfigurations) {
					
					CustomIndexConfiguration ic = (CustomIndexConfiguration)o;
					String key = ic.getCreateOnIndexName();
					if(indexConfigurationsMap==null) {
						indexConfigurationsMap = new HashMap();
					}
					if(StringUtils.isBlank(key)) {
						log.error("*********************************************");
						log.error("Require property createOnIndexName in keyword indexer");
						log.error("*********************************************");
						continue;
					}
					indexConfigurationsMap.put(key, ic);
					
					//settings mapping

					String mappingFile = null;
					String settingsFile = null;
					if(!StringUtils.isBlank(ic.getMappingFileName())) {
						mappingFile = ic.getMappingFileName();
					}
					if(!StringUtils.isBlank(ic.getSettingsFileName())) {
						settingsFile = ic.getSettingsFileName();
					}
					
					if(mappingFile!=null || settingsFile!=null) {
						
						String metadata = null;
						String settingsdata = null;
						try {
							
							if(mappingFile!=null) {
								metadata = FileUtil.readFileAsString(mappingFile);
							}
							
							if(settingsFile!=null) {
								settingsdata = FileUtil.readFileAsString(settingsFile);
							}

							if(!StringUtils.isBlank(ic.getIndexName())) {
								
								if(!searchDelegate.indexExist(ic.getCollectionName())) {
									searchDelegate.createIndice(metadata, settingsdata, ic.getCollectionName(), ic.getIndexName());
								}
							}
							
						} catch (Exception e) {
							log.error(e);
							log.error("*********************************************");
							log.error(e);
							log.error("*********************************************");
							init=false;
						}
					}

					
					

				}
				
			}
			
			init = true;
			
		} catch (Exception e) {
			log.error("*********************************************");
			log.error(e);
			log.error("*********************************************");
		}
		
		

		
	}

	@SuppressWarnings("rawtypes")
	public void execute(SearchClient client, String json, String collection, String object, String id, ExecutionContext context)
			throws Exception {
		
			if(!init) {
				init();
			}
			
			try {
				

		
			//new logic
			if(indexConfigurationsMap!=null && indexConfigurationsMap.containsKey(object)) {
				
				
				//get json
				Map indexData = (Map)context.getObject("indexData");
				

				CustomIndexConfiguration conf = indexConfigurationsMap.get(object);
				
				
/*				String collectionName = DynamicIndexNameUtil.getIndexName(conf.getCollectionName(),indexData);
				StringTokenizer t = new StringTokenizer(conf.getCollectionName(),"_");
				int countToken = t.countTokens();
				if(countToken>1) {
					
					StringBuilder iName = new StringBuilder();
					int count = 1;
					while(t.hasMoreTokens()) {
						
						String elem = t.nextToken();
						iName.append(DynamicIndexNameUtil.getIndexName(elem,indexData));
						if(count<countToken) {
							iName.append("_");
						}
						count++;
					}
					collectionName = iName.toString();
				} */
				
				//get fields to index
				List fields = conf.getFields();
				if(fields!=null) {
					
					List k = null;
					for(Object o : fields) {
						
						
						CustomIndexFieldConfiguration cifc = (CustomIndexFieldConfiguration)o;
						
						String fieldName = cifc.getFieldName();

						if(fieldName.trim().toLowerCase().equals("id")) {//we have our own id
							continue;
						}
						

						String fieldType = cifc.getFieldType();
						
						
						if(!StringUtils.isBlank(fieldType)) {
							if(fieldType.equals("List")) {

									try {
										List keyWords = (List)indexData.get(fieldName);
										
										if(keyWords!=null) {
										
											if(k==null) {
												k = new ArrayList();
											}
											k.addAll(keyWords);
										}
										
									} catch (Exception e) {//might have one instead of a list
										String keyword = (String)indexData.get(fieldName);
										
										if(keyword!=null) {
										
											if(k==null) {
												k = new ArrayList();
											}
											k.add(keyword);
									
										}
									}

							} else {//String
								
									String keyword = (String)indexData.get(fieldName);
								
									if(keyword!=null) {
									
										if(k==null) {
											k = new ArrayList();
										}
										k.add(keyword);
								
									}
							}
						}//end field type
						
				}//end for


				if(k!=null) {
					
					Collection bulks = new ArrayList();
					
					StringBuilder kw = new StringBuilder();
					int i = 1;
					for(Object o : k) {
	
						
						IndexKeywordRequest kr = new IndexKeywordRequest();
						
						//id is the key trimed in lower case
						String value = (String)o;
						
						if(StringUtils.isBlank(value)) {
							continue;
						}
						
						//kr.setId(value.toLowerCase().trim());
						//get id from original object
						
						String _id = (String)indexData.get("id");
						kr.setId(_id);
						kr.setKey(value);
						
						//check fields to add
						
						if(conf.getFilters()!=null && conf.getFilters().size()>0) {
							
							for(Object oo : conf.getFilters()) {
								
								CustomIndexFieldConfiguration filter = (CustomIndexFieldConfiguration)oo;
								
								String fieldName = filter.getFieldName();
								
								String fieldType = filter.getFieldType();
								
								Field f = null;
								
								if(fieldType.equals("List")) {
									List ooo = (List)indexData.get(fieldName);
									f = new ListField();
									f.setValue(ooo);
									f.setName(fieldName);
									kr.getFilters().add(f);
									
								} else if(fieldType.equals("Boolean")) {
									
									String s = (String)indexData.get(fieldName);
									Boolean ooo = new Boolean(s);
									f = new BooleanField();
									f.setValue(ooo);
									f.setName(fieldName);
									kr.getFilters().add(f);
									
								} else if(fieldType.equals("Integer")) {
									
									//String s = (String)indexData.get(fieldName);
									Integer ooo = (Integer)indexData.get(fieldName);
									f = new IntegerField();
									f.setValue(ooo);
									f.setName(fieldName);
									kr.getFilters().add(f);
									
								} else if(fieldType.equals("Long")) {
									
									//String s = (String)indexData.get(fieldName);
									Long ooo = (Long)indexData.get(fieldName);
									f = new LongField();
									f.setValue(ooo);
									f.setName(fieldName);
									kr.getFilters().add(f);
	
								} else if(fieldType.equals("Double")) {
									
									//String s = (String)indexData.get(fieldName);
									Double ooo = (Double)indexData.get(fieldName);
									f = new DoubleField();
									f.setValue(ooo);
									f.setName(fieldName);
									kr.getFilters().add(f);
									
								} else if(fieldType.equals("Date")) {
									
									String d = (String)indexData.get(fieldName);
									//parse date
									try {
										Date dt = DateUtil.formatDate(d);
										f = new DoubleField();
										f.setValue(dt);
										f.setName(fieldName);
										kr.getFilters().add(f);
									} catch (Exception e) {
										log.error("Invalid date format " + d);
									}

									
								} else {
									
									String ooo = (String)indexData.get(fieldName);
									f = new StringField();
									f.setValue(ooo.toLowerCase());
									f.setName(fieldName);
									kr.getFilters().add(f);
									
								}
							}
							
							
						}
						
						
						
						bulks.add(kr);
						
					}
					
					
					//delete previous keywords for the same id
					//deleteKeywordsImpl.deleteObject(client, collectionName, id);
					deleteKeywordsImpl.deleteObject(client, conf.getCollectionName(), conf.getIndexName(), id);

					//searchDelegate.bulkIndexKeywords(bulks, collectionName, "keyword");
					searchDelegate.bulkIndexKeywords(bulks, conf.getCollectionName(), conf.getIndexName());
					
				}
				
				
				
			}
				
				
				
			}
			
			} catch (Exception e) {
				log.error("Cannot index keywords, maybe a timing ussue for no shards available",e);
			}
		
		
		
		
/*			if(!StringUtils.isBlank(collectionName) && keyWordsToIndex!=null && keyWordsToIndex.size()>0) {
		
				SearchServiceImpl service = new SearchServiceImpl();
	
				
				ObjectMapper mapper = new ObjectMapper();
				Map<String,Object> indexData = mapper.readValue(json, Map.class);
				

				List k = null;
				
				String indexName = getIndexName(collectionName,indexData);
				//tokenize ?
				StringTokenizer t = new StringTokenizer(collectionName,"_");
				if(t.countTokens()>1) {
					
					StringBuilder iName = new StringBuilder();
					int count = 1;
					while(t.hasMoreTokens()) {
						
						
						String elem = t.nextToken();
						iName.append(getIndexName(elem,indexData));
						if(count<t.countTokens()) {
							iName.append("_");
						}
					}
					
					indexName = iName.toString();

				} 
				
				
				for(Object o : keyWordsToIndex.keySet()) {
					
					String fieldName = (String)o;

					
					if(fieldName.trim().toLowerCase().equals("id")) {//we have our own id
						continue;
					}
					

					
					String fieldType = (String)keyWordsToIndex.get(fieldName);
					if(!StringUtils.isBlank(fieldType)) {
						if(fieldType.equals("List")) {

								try {
									List keyWords = (List)indexData.get(fieldName);
									
									if(keyWords!=null) {
									
										if(k==null) {
											k = new ArrayList();
										}
										k.addAll(keyWords);
									
									}
									
								} catch (Exception e) {//might have one instead of a list
									String keyword = (String)indexData.get(fieldName);
									
									if(keyword!=null) {
									
										if(k==null) {
											k = new ArrayList();
										}
										k.add(keyword);
								
									}
								}

						} else {//String
							
								String keyword = (String)indexData.get(fieldName);
							
								if(keyword!=null) {
								
									if(k==null) {
										k = new ArrayList();
									}
									k.add(keyword);
							
								}
							
						}
						
					}
				}//end for
*/					
					

				
	
						
				//}
			
			//}


	}

	@Override
	public void init(SearchClient client) {
		if(!init) {
			init();
		}
		
	}
	


}
