/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package opennlp.tools.similarity.apps;

import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;

import opennlp.tools.similarity.apps.utils.StringDistanceMeasurer;

import org.apache.commons.lang.StringUtils;

public class HitBase
{
	private static final Logger LOG = Logger.getLogger("opennlp.tools.similarity.apps.HitBase");

	private String abstractText;

	private String clickUrl;

	private String displayUrl;

	private String url;

	private String date;

	private String title;

	private Double generWithQueryScore;

	private String source;

	private List<String> originalSentences;

	private String pageContent;

	private List<Fragment> fragments;

	public HitBase()
	{
		super();
	}

	public String getPageContent()
	{
		return pageContent;
	}

	public HitBase(String orig, String[] generateds)
	{
		originalSentences = new ArrayList<String>();
		originalSentences.add(orig);

		fragments = new ArrayList<Fragment>();
		for (String sent : generateds)
		{
			Fragment f = new Fragment(sent, 0.0);
			fragments.add(f);
		}
		// the rest of params are null
	}

	public void setPageContent(String pageContent)
	{
		this.pageContent = pageContent;
	}

	public List<Fragment> getFragments()
	{
		return fragments;
	}

	public void setFragments(List<Fragment> fragments)
	{
		this.fragments = fragments;
	}

	public String getSource()
	{
		return source;
	}

	public void setSource(String source)
	{
		this.source = source;
	}

	public List<String> getOriginalSentences()
	{
		return originalSentences;
	}

	public void setOriginalSentences(List<String> originalSentences)
	{
		this.originalSentences = originalSentences;
	}

	public String getTitle()
	{
		return title;
	}

	public void setTitle(String title)
	{
		this.title = title;
	}

	public String getAbstractText()
	{
		return abstractText;
	}

	public void setAbstractText(String abstractText)
	{
		this.abstractText = abstractText;
	}

	public String getClickUrl()
	{
		return clickUrl;
	}

	public void setClickUrl(String clickUrl)
	{
		this.clickUrl = clickUrl;
	}

	public String getDisplayUrl()
	{
		return displayUrl;
	}

	public void setDisplayUrl(String displayUrl)
	{
		this.displayUrl = displayUrl;
	}

	public String getUrl()
	{
		return url;
	}

	public void setUrl(String url)
	{
		this.url = url;
	}

	public String getDate()
	{
		return date;
	}

	public void setDate(String date)
	{
		this.date = date;
	}

	public Double getGenerWithQueryScore()
	{
		return generWithQueryScore;
	}

	public void setGenerWithQueryScore(Double generWithQueryScore)
	{
		this.generWithQueryScore = generWithQueryScore;
	}

	public String toString()
	{
		// return "\n"+this.getUrl()+" | " +this.getTitle()+ " | "+ this.abstractText ;
		if (this.getFragments() != null && this.getFragments().size() > 0)
			return this.getFragments().toString();
		else
			return this.title;
	}

	public static String toString(List<HitBase> hits)
	{
		StringBuffer buf = new StringBuffer();
		Boolean pBreak = true;
		for (HitBase hit : hits)
		{
			String fragm = (hit.toString());
			if (fragm.length() > 15)
			{
				if (pBreak)
					buf.append(fragm + " | ");
				else
					buf.append(fragm + " | \n");
				// switch to opposite
				if (pBreak)
					pBreak = false;
				else
					pBreak = true;
			}

		}
		return buf.toString();
	}
	
	public static String toResultantString(List<HitBase> hits)
	{
		StringBuffer buf = new StringBuffer();
		Boolean pBreak = true;
		for (HitBase hit : hits)
		{
			String fragm = hit.getFragments().toString();
			if (fragm.length() > 15)
			{
				if (pBreak)
					buf.append(fragm + " | 	");
				else
					buf.append(fragm + " | \n");
				// switch to opposite
				if (pBreak)
					pBreak = false;
				else
					pBreak = true;
			}

		}
		return buf.toString().replace("[", "").replace("]", "").replace(" | ", "").replace(".,",".").
		replace(".\"", "\"").replace(". .", ".").replace(",.", ".");
	}

	public static List<HitBase> removeDuplicates(List<HitBase> hits)
	{
		StringDistanceMeasurer meas = new StringDistanceMeasurer();
		double imageDupeThresh = 0.8; // if more similar, then considered dupes
		List<Integer> idsToRemove = new ArrayList<Integer>();
		List<HitBase> hitsDedup = new ArrayList<HitBase>();
		try
		{
			for (int i = 0; i < hits.size(); i++)
				for (int j = i + 1; j < hits.size(); j++)
				{
					String title1 = hits.get(i).getTitle();
					String title2 = hits.get(j).getTitle();
					if (StringUtils.isEmpty(title1) || StringUtils.isEmpty(title2))
						continue;
					if (meas.measureStringDistance(title1, title2) > imageDupeThresh)
					{
						idsToRemove.add(j); // dupes found, later list member to be deleted
					}
				}
			for (int i = 0; i < hits.size(); i++)
				if (!idsToRemove.contains(i))
					hitsDedup.add(hits.get(i));
			if (hitsDedup.size() < hits.size())
			{
				LOG.info("Removed duplicates from relevant search results, including "
					+ hits.get(idsToRemove.get(0)).getTitle());
			}
		}
		catch (Exception e)
		{
			LOG.severe("Problem removing duplicates from relevant images: " + e);
		}
		return hitsDedup;
	}
}