package tim.prune.gui.colour;

import java.awt.Color;
import java.text.DateFormat;
import java.util.Calendar;
import java.util.HashMap;
import java.util.TimeZone;

import tim.prune.config.Config;
import tim.prune.config.TimezoneHelper;
import tim.prune.data.DataPoint;
import tim.prune.data.Timestamp;
import tim.prune.data.Track;
import tim.prune.data.TrackInfo;

/**
 * Point colourer giving a different colour to each date.
 * Uses the currently selected timezone, so the results
 * may be different when selecting a different timezone
 */
public class DateColourer extends DiscretePointColourer
{
	// Doesn't really matter what format is used here, as long as dates are different
	private static final DateFormat DEFAULT_DATE_FORMAT = DateFormat.getDateInstance();
	// Selected timezone for deciding which date a timestamp falls on
	private TimeZone _selectedTimezone = null;

	/**
	 * Constructor
	 * @param inStartColour start colour of scale
	 * @param inEndColour end colour of scale
	 * @param inWrapLength number of unique colours before wrap
	 * @param inWideHues true for wide mode, false for narrow
	 */
	public DateColourer(Color inStartColour, Color inEndColour,
		int inWrapLength, boolean inWideHues)
	{
		super(inStartColour, inEndColour, inWrapLength, inWideHues);
	}

	/**
	 * Calculate the colours for each of the points in the given track
	 * @param inTrackInfo track info object
	 * @param inConfig config object, used to get timezone
	 */
	@Override
	public synchronized void calculateColours(TrackInfo inTrackInfo, Config inConfig)
	{
		// Note, this method needs to be synchronized because otherwise the
		// Calendar objects in the different threads get confused and the
		// wrong colours are generated.

		_selectedTimezone = TimezoneHelper.getSelectedTimezone(inConfig);
		// initialise the array to the right size
		Track track = inTrackInfo == null ? null : inTrackInfo.getTrack();
		final int numPoints = track == null ? 0 : track.getNumPoints();
		init(numPoints);
		// Make a hashmap of the already-used dates
		HashMap<String, Integer> usedDates = new HashMap<>(20);
		// Also store the previous one, because they're probably consecutive
		String prevDate = null;
		int prevIndex = -1;

		// loop over track points
		for (int i=0; i<numPoints; i++)
		{
			DataPoint p = track.getPoint(i);
			if (p != null && !p.isWaypoint())
			{
				int dayIndex = 0; // default index 0 will be used if no date found
				String date = getDate(p.getTimestamp());
				if (date != null)
				{
					// Check if it's the previous one
					if (date.equals(prevDate)) {
						dayIndex = prevIndex;
					}
					else
					{
						// Look up in the hashmap to see if it's been used before
						Integer foundIndex = usedDates.get(date);
						if (foundIndex == null)
						{
							// not been used before, so add it
							dayIndex = usedDates.size() + 1;
							usedDates.put(date, dayIndex);
						}
						else
						{
							// found it
							dayIndex = foundIndex;
						}
						// Remember what we've got for the next point
						prevDate = date;
						prevIndex = dayIndex;
					}
				}
				// if date is null (no timestamp or invalid) then dayIndex remains 0
				setColour(i, dayIndex);
			}
		}

		// generate the colours needed
		generateDiscreteColours(usedDates.size() + 1);
	}


	/**
	 * Find which date (in the currently selected timezone) the given timestamp falls on
	 * @param inTimestamp timestamp
	 * @return String containing description of date, or null
	 */
	private String getDate(Timestamp inTimestamp)
	{
		if (inTimestamp == null || !inTimestamp.isValid()) {
			return null;
		}
		Calendar cal = inTimestamp.getCalendar(null);
		// use selected time zone, not system one
		DEFAULT_DATE_FORMAT.setTimeZone(_selectedTimezone);
		return DEFAULT_DATE_FORMAT.format(cal.getTime());
	}
}
