All Downloads are FREE. Search and download functionalities are using the official Maven repository.

dev.memento.MementoList Maven / Gradle / Ivy

The newest version!
/**
 * MementoList.java
 * 
 * Copyright 2010 Frank McCown
 *
 *  Licensed 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.
 *
 *  
 *  This keeps a list of all the Mementos which are known for a given URL.
 */

package dev.memento;

/*
 * #%L
 * MementoWeb Java Client Stubs
 * %%
 * Copyright (C) 2012 - 2013 The British Library
 * %%
 * Licensed 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.
 * #L%
 */


import java.io.Serializable;
import java.text.DateFormatSymbols;
import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.TreeMap;
import java.util.TreeSet;

import org.apache.log4j.Logger;


public class MementoList extends ArrayList implements Serializable {
	Logger log = Logger.getLogger(MementoList.class.getCanonicalName());

	private static final long serialVersionUID = 1L;

	public static final String LOG_TAG = "MementoBrowser_tag";
	
	// Unique, ordered list of dates found in the mementos
	//private SortedSet  mYearList;
	
	private TreeMap> mYearList;
	
	// Should be used very infrequently. www.cnn.com uses it because there are
	// thousands of mementos per year in some cases.
	private TreeMap>> mYearToMonthList;
	
	// The currently selected memento
	private int mCurrent = -1;
	
	public MementoList() {
		//mYearList = new TreeSet();		
		mYearList = new TreeMap>();
		mYearToMonthList = new TreeMap>>();
	}
	
	@Override
	public void add(int index, Memento memento) {
		//String year = Integer.toString(memento.getDateTime().getYear());
		//mYearList.add(year);
		int year = memento.getDateTime().getYear();
		addMementoToYearList(year, memento);		
		super.add(index, memento);
	}

	@Override
	public boolean add(Memento memento) {

		//String year = Integer.toString(memento.getDateTime().getYear());
		//mYearList.add(year);
		int year = memento.getDateTime().getYear();
		addMementoToYearList(year, memento);	
		return super.add(memento);
	}

	private void addMementoToYearList(int year, Memento memento) {
		TreeSet list = mYearList.get(year);
		if (list != null) {
			list.add(memento);
		}
		else {
			list = new TreeSet();
			list.add(memento);
			mYearList.put(year, list);
		}
	}	
		
	@Override
	public void clear() {
		mYearList.clear();
		mYearToMonthList.clear();
		mCurrent = -1;
		super.clear();
	}	
	
	/**
	 * Returns the Memento which is currently displayed or null if there
	 * is no current Memento.
	 * @return
	 */
	public Memento getCurrent() {
		if (mCurrent >= 0 && mCurrent < size())
			return get(mCurrent);
		else
			return null;
	}
	
	
	/**
	 * Returns the memento that is closest to the supplied date.
	 * Returns null if there are no mementos.
	 * @return
	 */
	public Memento getClosestDate(SimpleDateTime date) {
		
		int i = 0;
		while (i < size() && get(i).getDateTime().compareTo(date) < 0) 
    		i++;
		
		if (size() == 0)
			return null;
		else if (i == size())
			return getLast();
		else if (i == 0 || get(i).getDateTime().compareTo(date) == 0)
			return get(i);
		else {
			// See if date is closer to i or i-1
			Date newerDate = get(i).getDateTime().getDate();
			Date olderDate = get(i-1).getDateTime().getDate();
						
			int diffInDays1 = (int)Math.round((newerDate.getTime() - date.getDate().getTime()) 
	                 / (1000 * 60 * 60 * 24));			
			
			int diffInDays2 = (int)Math.round((date.getDate().getTime() - olderDate.getTime()) 
	                 / (1000 * 60 * 60 * 24));			
			
			if (diffInDays1 < diffInDays2)
				return get(i);
			else
				return get(i-1);
		}			
	}
	
	
	/**
	 * Return the index of the Memento with the given datetime, -1 if it
	 * could not be found.
	 * @param date
	 * @return
	 */
	public int getIndex(SimpleDateTime datetime) {
    	for (int i = 0; i < size(); i++) {
    		if (get(i).getDateTime().equals(datetime))
    			return i;
    	}
    	
    	return -1;
	}
	
	/**
	 * Return the index of the Memento with the given date, -1 if it
	 * could not be found.
	 * @param date
	 * @return
	 */
	public int getIndexByDate(SimpleDateTime date) {
    	for (int i = 0; i < size(); i++) {   		
    		if (get(i).getDateTime().equalsDate(date))
    			return i;
    	}
    	return -1;
	}
	

	/**
	 * Set the current index to the given integer if the number is >= -1 
	 * (for the case of "un-setting" the index up to the size-1.
	 * @param index
	 */
	public void setCurrentIndex(int index) {
		if (index >= -1 && index < size())
			mCurrent = index;
	}
	
	/**
	 * Return the index of the "current" Memento in the list (0 to size-1) or
	 * -1 if there is no current Memento.
	 * @return
	 */
	public int getCurrentIndex() {
		return mCurrent;
	}
	
	/**
	 * Returns the first Memento in the list or null if there are no Mementos.
	 * @return
	 */
	public Memento getFirst() {
		if (this.size() > 0)
			return get(0);
		else
			return null;
	}
	
	/**
	 * Returns the last Memento in the list or null if there are no Mementos.
	 * @return
	 */
	public Memento getLast() {	
		if (this.size() > 0)
			return get(size() - 1);
		else
			return null;
	}
		
	/**
	 * Return the next memento and update internal pointer.
	 * Return null if we're at the end of the list or there
	 * are no mementos.
	 */
	public Memento getNext() {
		if (mCurrent >= 0 && mCurrent < this.size() - 1) {
			mCurrent++;
			return get(mCurrent);
		}
		else
			return null;
	}
	
	/**
	 * Get the next memento after the given date. Return null if
	 * we're at the end of the list or there are no mementos.
	 * @param date
	 * @return
	 */
	public Memento getNext(SimpleDateTime date) {
		
		// Search through the mementos
		int i = 0;
		while (i < size() && get(i).getDateTime().compareTo(date) < 0) 
    		i++;
				
		if (i == size())
			return null;    // At the end of the list!
		else if (get(i).getDateTime().compareTo(date) == 0) {
			// Found the exact one
			i++;
			if (i == size())
				return null;   // At the end of the list!
			else
				return get(i);
		}
		else {
			// Memento with date not found so return this memento which
			// has a newer date
			return get(i);
		}
	}
	
	public Memento getPrevious() {
		if (mCurrent > 0 && mCurrent < this.size()) {
			mCurrent--;
			return get(mCurrent);
		}
		else {
			log.debug("getPrevious: Unable to find previous. mCurrent=" + mCurrent);
			return null;
		}			
	}
	
	/**
	 * Get the previous memento before the given date. Return null if
	 * we're at the end of the list or there are no mementos.
	 * @param date
	 * @return
	 */
	public Memento getPrevious(SimpleDateTime date) {
		
		// Search through the mementos
		int i = 0;
		while (i < size() && get(i).getDateTime().compareTo(date) < 0) 
    		i++;
				
		if (i == 0)
			return null;    // At the beginning of the list
		else if (i < size() && get(i).getDateTime().compareTo(date) == 0) {
			i--;
			if (i < 0)
				return null;   // At the beginning of the list!
			else
				return get(i);
		}
		else {
			// Memento with date not found so return the previous memento which
			// has an older date
			return get(i - 1);
		}
	}
	
	
	@SuppressWarnings("unchecked")
	public CharSequence[] getAllDates() {
		
		// Must use clone in case the list is still being built.  If using the original,
		// a ConcurrentModificationException to be thrown.
		ArrayList copy = (ArrayList) this.clone();
		
		CharSequence[] dates = new CharSequence[size()];
		int i = 0;
    	for (Memento m : copy) { 
    		dates[i] = m.getDateTime().dateAndTimeFormatted();
    		i++;
    	}
    	
    	return dates;
	}
	
	/**
	 * Return the years and number of dates available for each year for all the 
	 * mementos. 
	 * @return
	 */
	public TreeMap getAllYears() {
						
		TreeMap years = new TreeMap();
		
		int totalMementos = 0;
		for (Map.Entry> entry : mYearList.entrySet()) {
			int year = entry.getKey();
			TreeSet mementos = entry.getValue();
			years.put(year, mementos.size());	
			totalMementos += mementos.size();
		}
		
		log.debug("totalMementos = " + totalMementos + "  size = " + this.size());
    	return years;
	}
	
	/**
	 * Returns the available months for the mementos given the year. 
	 * @param year
	 * @return
	 */
	public LinkedHashMap getMonthsForYear(int year) {
			
		LinkedHashMap months = new LinkedHashMap();
		
		if (mYearToMonthList.size() == 0 || !mYearToMonthList.containsKey(year)) {
			// Need to build list from scratch		
						
			TreeSet mementos =  mYearList.get(year);
			if (mementos == null) {
				return months;
			}
			
			// Array of all months and their mementos for this year
			ArrayList> monthList = mYearToMonthList.get(year);
			if (monthList == null) {
				monthList = new ArrayList>();
				
				// List contains no mementos for 12 months
				for (int mon = 0; mon < 12; mon++) {
					monthList.add(null);
				}
				
				mYearToMonthList.put(year, monthList);
			}
			
			for (Memento m : mementos) {
								
				//String month = m.getDateTime().getMonthName();
				int month = m.getDateTime().getMonth();
								
				// List of all mementos for this year and month
				ArrayList mementoList = monthList.get(month - 1);
				if (mementoList == null) {
					mementoList = new ArrayList();
					monthList.add(month - 1, mementoList);	
				}
				
				mementoList.add(m);									
			}
		}

		
		// Return month counts, but ignore months with no dates
		DateFormatSymbols df = new DateFormatSymbols();
		months = new LinkedHashMap();
		ArrayList> monthList = mYearToMonthList.get(year);
		for (int mon = 0; mon < 12; mon++) {
			//System.out.println("month = " + mon);
			if (monthList.get(mon) != null) {
				String monthName = df.getMonths()[mon];
				months.put(monthName, monthList.get(mon).size());	
				//System.out.println("  size = " + monthList.get(mon).size());
			}
		}
	    	
		return months;
	}
	
	public CharSequence[] getDatesForYear(int year) {
				    	
		TreeSet mementos = mYearList.get(year);
		if (mementos == null) {
			// FIXME if (Log.LOG) Log.e(LOG_TAG, "getDatesForYear: No mementos could be found for the selected year " + year);
			return new CharSequence[0];
		}
		
		CharSequence[] dates = new CharSequence[mementos.size()];
		int i = 0;
		for (Memento m : mementos) {
			dates[i] = m.getDateAndTimeFormatted();
			i++;
		}
		
		//return mementos.toArray(new CharSequence[0]);
		return dates;    	
	}
	
	public Memento[] getByYear(int year) {
		
		TreeSet mementos = mYearList.get(year);
		if (mementos == null) {
			return new Memento[0];
		}
				
		return mementos.toArray(new Memento[0]);
	}
	
	public Memento[] getByMonthAndYear(int month, int year) {
				
		if (month < 1 || month > 12)
			return null;
		
		ArrayList> monthList = mYearToMonthList.get(year);
		
		if (monthList == null) {
		
			// This could happen if mYearToMonthList wasn't populated yet
			getMonthsForYear(year);
			
			monthList = mYearToMonthList.get(year);
			if (monthList == null) {
				// Now we definitely can't find this year
				return new Memento[0];
			}
		}		
		
		ArrayList mlist = monthList.get(month - 1);
		if (mlist == null)
			return new Memento[0];
		
		return mlist.toArray(new Memento[0]);
	}
	
	public CharSequence[] getDatesForMonthAndYear(int month, int year) {
		
		if (month < 1 || month > 12)
			return null;
		
		ArrayList> monthList = mYearToMonthList.get(year);
		
		if (monthList == null) {
		
			// This could happen if mYearToMonthList wasn't populated yet
			getMonthsForYear(year);
			
			monthList = mYearToMonthList.get(year);
			if (monthList == null) {
				// Now we definitely can't find this year
				return new CharSequence[0];
			}
		}		
		
		ArrayList mlist = monthList.get(month - 1);
		if (mlist == null)
			return new CharSequence[0];
		
		CharSequence[] dates = new CharSequence[mlist.size()];
		int i = 0;
    	for (Memento m : mlist) { 
    		dates[i] = m.getDateAndTimeFormatted();
    		i++;
    	}
    	
    	return dates;
	}

	public boolean isFirst(SimpleDateTime date) {
		if (size() > 0)
			return get(0).getDateTime().equals(date);
		else
			return false;				
	}
	
	public boolean isLast(SimpleDateTime date) {
		if (size() > 0)
			return get(size() - 1).getDateTime().equals(date);
		else
			return false;				
	}
	
	public void displayAll() {
		System.out.println("All mementos:");
    	int i = 1;
    	for (Memento m : this) {
    		System.out.println(i + ". " + m);
    		i++;
    	}
	}	
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy