/*
 * Created on 27 juin 2003
 * Copyright (C) Azureus Software, Inc, All Rights Reserved.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 */
package org.gudy.azureus2.core3.util;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;

/**
 * @author Olivier
 * 
 */
public class TimeFormatter {
  // XXX should be i18n'd
	static final String[] TIME_SUFFIXES = { "s", "m", "h", "d", "y" };

	public static final String[] DATEFORMATS_DESC = new String[] {
		"EEEE, MMMM d, yyyy GG",
		"EEEE, MMMM d, yyyy",
		"EEE, MMMM d, yyyy",
		"MMMM d, ''yy",
		"EEE, MMM d, ''yy",
		"MMM d, yyyy",
		"MMM d, ''yy",
		"yyyy/MM/dd",
		"''yy/MM/dd",
		"MMM dd",
		"MM/dd",
	};
	
	private static final SimpleDateFormat http_date_format = 
		new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US );

	static{
			// see http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.3.1
		
		http_date_format.setTimeZone(TimeZone.getTimeZone("GMT"));
	}
	
	private static final SimpleDateFormat cookie_date_format = 
		new SimpleDateFormat("EEE, dd-MMM-yyyy HH:mm:ss z", Locale.US );

	static{
			// see http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.3.1
		
		cookie_date_format.setTimeZone(TimeZone.getTimeZone("GMT"));
	}
	
	/**
	 * Format time into two time sections, the first chunk trimmed, the second
	 * with always with 2 digits.  Sections are *d, **h, **m, **s.  Section
	 * will be skipped if 0.   
	 * 
	 * @param time time in seconds
	 * @return Formatted time string
	 */
	public static String format(long time_secs) {
		if (time_secs == Constants.CRAPPY_INFINITY_AS_INT || time_secs >= Constants.CRAPPY_INFINITE_AS_LONG)
			return Constants.INFINITY_STRING;

		if (time_secs < 0)
			return "";

		// secs, mins, hours, days
		int[] vals = {
			(int) time_secs % 60,
			(int) (time_secs / 60) % 60,
			(int) (time_secs / 3600) % 24,
			(int) (time_secs / 86400) % 365,
			(int) (time_secs / 31536000)
			};

		int end = vals.length - 1;
		while (vals[end] == 0 && end > 0) {
			end--;
		}
		
		String result = vals[end] + TIME_SUFFIXES[end];

		/* old logic removed to prefer showing consecutive units
		// skip until we have a non-zero time section
		do {
			end--;
		} while (end >= 0 && vals[end] == 0);
		*/
		
		end--;
		
		if (end >= 0)
			result += " " + twoDigits(vals[end]) + TIME_SUFFIXES[end];

		return result;
	}

	/**
	 * format seconds into significant y d h m s (e.g. 12d 02h 03m 23s) and drop secs if wanted
	 * @param time_secs
	 * @param do_seconds
	 * @return
	 */
	public static String 
	format2(
		long 	time_secs, 
		boolean do_seconds ) 
	{	
		if (time_secs == Constants.CRAPPY_INFINITY_AS_INT || time_secs >= Constants.CRAPPY_INFINITE_AS_LONG)
			return Constants.INFINITY_STRING;

		if (time_secs < 0)
			return "";

		// secs, mins, hours, days
		int[] vals = {
			(int) time_secs % 60,
			(int) (time_secs / 60) % 60,
			(int) (time_secs / 3600) % 24,
			(int) (time_secs / 86400) % 365,
			(int) (time_secs / 31536000)
			};

		int start = vals.length - 1;
		while (vals[start] == 0 && start > 0) {
			start--;
		}
		
		int	end = do_seconds?0:1;
		
		if ( start==0&&!do_seconds ){
			start=1;
		}
		
		String result = "";
		
		for ( int i=start;i>=end;i--){
		
			result += (i==start?vals[i]:(" " + twoDigits(vals[i]))) + TIME_SUFFIXES[i];
		}
		
		return result;
	}
	
	public static String format100ths(long time_millis) {
		
		long time_secs = time_millis / 1000;

		int  hundredths = (int)(time_millis - time_secs*1000)/10;
		
		if ( time_millis == 0 || time_secs >= 60 ){
			
			return( format( time_secs ));
		}
		
		return( time_secs + "." + twoDigits( hundredths) + TIME_SUFFIXES[0]);
	}
	
	/**
	 * @param time millis 
	 */

	public static String formatColonMillis( long time )
	{
		if ( time > 0 ){
			if ( time < 1000 ){
				time = 1;
			}else{
				time = time / 1000;
			}
		}
		
		String str = formatColon( time );
		
		if ( str.startsWith( "00:" )){
			
			str = str.substring( 3 );
		}
		
		return( str );
	}
	
	/**
	 * Format time into "[[# y] # d] 00:00:00" format
	 * 
	 * @param time time in seconds
	 * @return
	 */
	
    public static String formatColon(long time)
    {
      if (time == Constants.CRAPPY_INFINITY_AS_INT || time >= Constants.CRAPPY_INFINITE_AS_LONG) return Constants.INFINITY_STRING;
      if (time < 0) return "";

      int secs = (int) time % 60;
      int mins = (int) (time / 60) % 60;
      int hours = (int) (time /3600) % 24;
      int days = (int) (time / 86400) % 365;
      int years = (int) (time / 31536000);
      
      String result = "";
      if (years > 0) result += years + "y ";
      if (years > 0 || days > 0) result += days + "d ";
      result += twoDigits(hours) + ":" + twoDigits(mins) + ":" + twoDigits(secs);

      return result;
    }
    
    private static String twoDigits(int i) {
      return (i < 10) ? "0" + i : String.valueOf(i);
    }
    
    	/**
    	 * parse time in h:m:s format to SECONDS
    	 * @param str
    	 * @return
    	 */
    
    public static int
    parseColon(
    	String	str )
    {
    	final int[]	multipliers = { 1, 60, 3600, 86400, 31536000 };
    	
    	String[]	bits = str.split( ":" );
    	
    	int	result = 0;
    	
    	for (int i=0;i<bits.length;i++){
    		
    		String bit = bits[bits.length-(i+1)].trim();
    		
    		if ( bit.length() > 0 ){
    			
    			result += multipliers[i] * Integer.parseInt( bit );
    		}
    	}
    	
    	return( result );
    }
    
    public static String
    formatNanoAsMilli(
    	long	nanos )
    {
    	final long truncator = 60*1000000000L;
    	
    	nanos = nanos - ((nanos/truncator) * truncator);
    	
    	return( String.valueOf(((double)nanos)/1000000) + " ms" );
    }
    
    public static String
    getHTTPDate(
    	long		millis )
    {
		synchronized( http_date_format ){
			
			return( http_date_format.format(new Date( millis )));
		}
    }
    
    public static long
    parseHTTPDate(
    	String		date )
    {
    	try{
    		synchronized( http_date_format ){
    		
    			return( http_date_format.parse( date ).getTime());
    		}
    	}catch( Throwable e ){
    		
    		Debug.out("Failed to parse HTTP date '" + date + "'" );
    		
    		return( 0 );
    	}
    }
    
    public static String
    getCookieDate(
    	long		millis )
    {
		synchronized( cookie_date_format ){
			
			return( cookie_date_format.format(new Date( millis )));
		}
    }
    
    public static String
    milliStamp()
    {
    	long nanos = SystemTime.getHighPrecisionCounter();
    	
    	final long truncator = 60*1000000000L;
    	
    	nanos = nanos - ((nanos/truncator) * truncator);

    	String	str = String.valueOf( nanos/1000000 );
    	
    	while( str.length() < 5 ){
    		
    		str = "0" + str;
    	}
    	
    	return( str + ": " );
    }
    
    public static void
    milliTrace(
    	String	str )
    {
    	System.out.println( milliStamp() + str );
    }
}
