/*
 * Created on 16 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.io.InputStreamReader;
import java.io.LineNumberReader;
import java.nio.charset.Charset;
import java.security.AccessControlException;
import java.util.Locale;
import java.util.StringTokenizer;
import java.util.TimeZone;
import java.util.regex.Pattern;

/**
 *  
 * @author Olivier
 *
 */

public class 
Constants 
{
  public static final String EMPTY_STRING = "";
  public static final String SF_WEB_SITE			= "http://plugins.vuze.com/";
 
  public static final String AELITIS_TORRENTS		= "http://cf1.vuze.com/torrent/torrents/";
  public static final String AELITIS_FILES			= "http://cf1.vuze.com/torrent/files/";
  public static final String AZUREUS_WIKI 			= "http://wiki.vuze.com/w/";
  
  public static final String  VERSION_SERVER_V4 	= "version.vuze.com";
  public static final String  VERSION_SERVER_V6 	= "version6.vuze.com";

  public static final String DHT_SEED_ADDRESS_V4		= "dht.vuze.com";
  public static final String DHT_SEED_ADDRESS_V6		= "dht6.vuze.com";
  public static final String DHT_SEED_ADDRESS_V6_TUNNEL	= "dht6tunnel.vuze.com";
  
  public static final String NAT_TEST_SERVER		= "nettest.vuze.com";
  public static final String NAT_TEST_SERVER_HTTP	= "http://nettest.vuze.com/";
   
  public static final String SPEED_TEST_SERVER		= "speedtest.vuze.com";
  
  public static final String PAIRING_URL			= "https://pair.vuze.com/pairing";

  
  public static final String[] AZUREUS_DOMAINS = { "azureusplatform.com", "azureus.com", "aelitis.com", "vuze.com" };
  
  public static final String DEFAULT_ENCODING 	= "UTF8";
  public static final String BYTE_ENCODING 		= "ISO-8859-1";
  public static final Charset	BYTE_CHARSET;
  public static final Charset	DEFAULT_CHARSET;

  public static final int	DEFAULT_INSTANCE_PORT	= 6880;
  public static final int	INSTANCE_PORT;
  
  static{
	  String ip_str = System.getProperty( "azureus.instance.port", String.valueOf( DEFAULT_INSTANCE_PORT ));
	  
	  int	ip;
	  try{
		  ip = Integer.parseInt( ip_str );
	  }catch( Throwable e ){
		  ip = DEFAULT_INSTANCE_PORT;
	  }
	  
	  INSTANCE_PORT = ip;
	  
	  Charset	bc 	= null;
	  Charset	dc	= null;
	  
	  try{
	  	bc 	= Charset.forName( Constants.BYTE_ENCODING );
	 	dc	= Charset.forName( Constants.DEFAULT_ENCODING );

	}catch( Throwable e ){
		
		e.printStackTrace();
	}
	
  	BYTE_CHARSET 	= bc;
  	DEFAULT_CHARSET	= dc;
  }
  
  public static final Locale LOCALE_ENGLISH = new Locale("en", "");
  
  static{
	  try{
		  String	timezone = System.getProperty( "azureus.timezone", null );
		  
		  if ( timezone != null ){
			
			  TimeZone.setDefault( TimeZone.getTimeZone( timezone ));
		  }  
		}catch( Throwable e ){
						
				// can happen in applet
		
			if ( e instanceof AccessControlException ){
				
			}else{
			
				e.printStackTrace();
			}
		}
  }
  
  public static final String INFINITY_STRING	= "\u221E"; // "oo";pa  
  public static final int    CRAPPY_INFINITY_AS_INT  = 365*24*3600; // seconds (365days)
  public static final long   CRAPPY_INFINITE_AS_LONG = 10000*365*24*3600; // seconds (10k years)
  
  public static boolean DOWNLOAD_SOURCES_PRETEND_COMPLETE	= false;
	  
  	// keep the CVS style constant coz version checkers depend on it!
  	// e.g. 2.0.8.3
    //      2.0.8.3_CVS
    //      2.0.8.3_Bnn       // incremental build
  
  public static String APP_NAME = "Vuze";
  public static final String AZUREUS_NAME	  					= "Azureus";
  public static final String AZUREUS_PROTOCOL_NAME_PRE_4813	  	= "Azureus";
  public static final String AZUREUS_PROTOCOL_NAME	  			= "Vuze";
  public static final String AZUREUS_VERSION  = "5.6.0.0";
  public static final String BUILD_VERSION  = "@build.version@";   //Ant replace
  public static final String AZUREUS_SUBVER	  = "";
  public static final byte[] VERSION_ID       = ("-" + "AZ" + "5600" + "-").getBytes();  //MUST be 8 chars long!

  private static final boolean FORCE_NON_CVS = System.getProperty( "az.force.noncvs", "0" ).equals( "1" );
  
  public static final boolean IS_CVS_VERSION = isCVSVersion( AZUREUS_VERSION ) && !FORCE_NON_CVS;
  
  public static final String  OSName = System.getProperty("os.name");
  
  public static final boolean isOSX				= OSName.toLowerCase().startsWith("mac os");
  public static final boolean isLinux			= OSName.equalsIgnoreCase("Linux");
  public static final boolean isSolaris			= OSName.equalsIgnoreCase("SunOS");
  public static final boolean isFreeBSD			= OSName.equalsIgnoreCase("FreeBSD");
  public static final boolean isWindowsXP		= OSName.equalsIgnoreCase("Windows XP");
  public static final boolean isWindows95		= OSName.equalsIgnoreCase("Windows 95");
  public static final boolean isWindows98		= OSName.equalsIgnoreCase("Windows 98");
  public static final boolean isWindows2000		= OSName.equalsIgnoreCase("Windows 2000");
  public static final boolean isWindowsME		= OSName.equalsIgnoreCase("Windows ME");
  public static final boolean isWindows9598ME	= isWindows95 || isWindows98 || isWindowsME;
  
  public static boolean isSafeMode = false;

  public static final boolean isWindows	= OSName.toLowerCase().startsWith("windows");
  // If it isn't windows or osx, it's most likely an unix flavor
  public static final boolean isUnix = !isWindows && !isOSX;
 
  public static final boolean isWindowsVista;
  public static final boolean isWindowsVistaSP2OrHigher;
  public static final boolean isWindowsVistaOrHigher;
  public static final boolean isWindows7OrHigher;
  public static final boolean isWindows8OrHigher;
  
  
  // Common Patterns
	public static final Pattern PAT_SPLIT_COMMAWORDS = Pattern.compile("\\s*,\\s*");
	public static final Pattern PAT_SPLIT_COMMA = Pattern.compile(",");
	public static final Pattern PAT_SPLIT_DOT = Pattern.compile("\\.");
	public static final Pattern PAT_SPLIT_SPACE = Pattern.compile(" ");
	public static final Pattern PAT_SPLIT_SLASH_N = Pattern.compile("\n");
	
  
  public static final boolean is64Bit;
  
  static{
	  boolean _is64Bit;
	  
	  try{
		  _is64Bit = System.getProperty( "os.arch" ).contains( "64" );
		  
	  }catch( Throwable e ){
		  
		  _is64Bit = false;
	  }
	  
	  is64Bit = _is64Bit;
	  
	  if ( isWindows ){

		  Float ver = null;

		  try{
			  ver = new Float( System.getProperty( "os.version" ));

		  }catch (Throwable e){
		  }

		  boolean vista_sp2_or_higher	= false;

		  if ( ver == null ){
			  
			  isWindowsVista			= false;
			  isWindowsVistaOrHigher 	= false;
			  isWindows7OrHigher		= false;
			  isWindows8OrHigher		= false;
			  
		  }else{
			  float f_ver = ver.floatValue();
			  	
			  isWindowsVista			= f_ver == 6;
			  isWindowsVistaOrHigher 	= f_ver >= 6;
			  isWindows7OrHigher	 	= f_ver >= 6.1f;
			  isWindows8OrHigher	 	= f_ver >= 6.2f;
		  
			  if ( isWindowsVista ){
			  
		            LineNumberReader lnr = null;
		            
		    	    try{
		    	        Process p = 
		    	        	Runtime.getRuntime().exec( 
		    	        		new String[]{
		    	        				"reg",
		    	        				"query",
		    	        				"HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion",
		    	        				"/v",
		    	        				"CSDVersion" });
		              
		    	        lnr = new LineNumberReader( new InputStreamReader( p.getInputStream()));
		    	        		    	        
		    	        while( true ){
		    	        	
		    	        	String	line = lnr.readLine();
		    	        	
		    	        	if ( line == null ){
		    	        		
		    	        		break;
		    	        	}
		    	        	
		    	            if ( line.matches( ".*CSDVersion.*" )){
		    	            	
		    	            	vista_sp2_or_higher = line.matches( ".*Service Pack [2-9]" );
		    	            	
		    	                break;
		    	            }
		    	        }
		    	    }catch( Throwable e ){
		    	    	
		    	    }finally{
		    	    	
		                if ( lnr != null ){
		                	
		                    try{
		                    	lnr.close();
		                        
		                    }catch( Throwable e ){
		                    }
		                }
		            }
		    	}
		  }
		  
		  isWindowsVistaSP2OrHigher = vista_sp2_or_higher;
	  }else{
		  
		  isWindowsVista			= false;
		  isWindowsVistaSP2OrHigher	= false;
		  isWindowsVistaOrHigher 	= false;
		  isWindows7OrHigher 		= false;
		  isWindows8OrHigher 		= false;
	  }
  }
  
  public static final boolean isOSX_10_5_OrHigher;
  public static final boolean isOSX_10_6_OrHigher;
  public static final boolean isOSX_10_7_OrHigher;
  public static final boolean isOSX_10_8_OrHigher;
  
  static{
	  if ( isOSX ){
		 
		  int	first_digit 	= 0;
		  int	second_digit	= 0;
		  
		  try{
			  String os_version = System.getProperty( "os.version" );

			  String[] bits = os_version.split( "\\." );
			
			  first_digit = Integer.parseInt( bits[0] );
			  
			  if ( bits.length > 1 ){
			  
				  second_digit = Integer.parseInt( bits[1] );
			  }
		  }catch( Throwable e ){
			  
		  }
		  
		  isOSX_10_5_OrHigher = first_digit > 10 || ( first_digit == 10 && second_digit >= 5 );
		  isOSX_10_6_OrHigher = first_digit > 10 || ( first_digit == 10 && second_digit >= 6 );
		  isOSX_10_7_OrHigher = first_digit > 10 || ( first_digit == 10 && second_digit >= 7 );
		  isOSX_10_8_OrHigher = first_digit > 10 || ( first_digit == 10 && second_digit >= 8 );
		  
	  }else{
		  
		  isOSX_10_5_OrHigher = false;
		  isOSX_10_6_OrHigher = false;
		  isOSX_10_7_OrHigher = false;
		  isOSX_10_8_OrHigher = false;
	  }
  }
  
  public static final boolean	isAndroid;
  
  static{
	  String vm_name = System.getProperty( "java.vm.name", "" );
	  
	  isAndroid = vm_name.equalsIgnoreCase( "Dalvik" );
  }
  
  	// Android is roughly 1.6 (reports as 0 for java.version)
  
  public static final String	JAVA_VERSION;
  public static final int		API_LEVEL;
  
  static{
	  String java_version 	= isAndroid?"1.6":System.getProperty("java.version");
	  int	 api_level 		= 0;
	  
	  if ( isAndroid ){
		  
		  String sdk_int = System.getProperty( "android.os.build.version.sdk_int", "0" );
		  
		  try{
			  api_level = Integer.parseInt( sdk_int );
			  
			  if ( api_level > 0  && api_level <= 8 ){
					  
				  java_version = "1.5";	  
			  }
		  }catch( Throwable e ){
		  }
	  }
	  
	  JAVA_VERSION 	= java_version;
	  API_LEVEL		= api_level;
  }
  
  public static final boolean isJava7OrHigher;
  
  static{
	  	// http://www.oracle.com/technetwork/java/javase/versioning-naming-139433.html
	  	// should always start with n.n.
	  
	  	// unless it is Android where it is always 0
	  
	  boolean	_7plus;
	  
	  try{
		  String[]	bits = JAVA_VERSION.split( "\\." );
		  
		 int	first	= Integer.parseInt( bits[0] );
		 int	second 	= Integer.parseInt( bits[1] );
		  
		  _7plus = first > 1 || second >= 7;
			  
	  }catch( Throwable e ){
		  
		  System.err.println( "Unparsable Java version: " + JAVA_VERSION );
		  
		  e.printStackTrace();
		  
		  _7plus = false;	// derp
	  }
	  
	  isJava7OrHigher = _7plus;
  }
  
  public static final String	FILE_WILDCARD = isWindows?"*.*":"*";
  
  	// use this if you want to prevent the constant getting cached in separately built objects (e.g. plugins)
  
  public static String
  getCurrentVersion()
  {
	  return( AZUREUS_VERSION );
  }
  	/**
  	 * Gets the current version, or if a CVS version, the one on which it is based 
  	 * @return
  	 */
  
  public static String
  getBaseVersion()
  {
  	return( getBaseVersion( AZUREUS_VERSION ));
  }
  
  public static String
  getBaseVersion(
  	String	version )
  {
  	int	p1 = version.indexOf("_");	// _CVS or _Bnn
  	
  	if ( p1 == -1 ){
  		
  		return( version );
  	}
  	
  	return( version.substring(0,p1));
  }
  
  	/**
  	 * is this a formal build or CVS/incremental 
  	 * @return
  	 */
  
  public static boolean
  isCVSVersion()
  {
  	return IS_CVS_VERSION; 
  }
  
  public static boolean
  isCVSVersion(
  	String	version )
  {
  	return( version.indexOf("_") != -1 );  
  }
  
  	/**
  	 * For CVS builds this returns the incremental build number. For people running their own
  	 * builds this returns -1 
  	 * @return
  	 */
  
  public static int
  getIncrementalBuild()
  {
  	return( getIncrementalBuild( AZUREUS_VERSION ));
  }
  
  public static int
  getIncrementalBuild(
  	String	version )
  {
  	if ( !isCVSVersion(version)){
  		
  		return( 0 );
  	}
  	
  	int	p1 = version.indexOf( "_B" );
  	
  	if ( p1 == -1 ){
  		
  		return( -1 );
  	}
  	
  	try{
  		return( Integer.parseInt( version.substring(p1+2)));
  		
  	}catch( Throwable e ){
  		
  		System.out.println("can't parse version");
  		
  		return( -1 );
  	}
  }
  
	public static boolean
  	isCurrentVersionLT(
  		String	version )
  	{
  		return( compareVersions( AZUREUS_VERSION, version ) < 0 );
  	}
	
  	public static boolean
  	isCurrentVersionGE(
  		String	version )
  	{
  		return( compareVersions( AZUREUS_VERSION, version ) >= 0 );
  	}
  	
		/**
		 * compare two version strings of form n.n.n.n (e.g. 1.2.3.4)
		 * @param version_1	
		 * @param version_2
		 * @return -ve -> version_1 lower, 0 = same, +ve -> version_1 higher
		 */
	
	public static int
	compareVersions(
		String		version_1,
		String		version_2 )
	{	
		try{
			version_1 = version_1.replaceAll( "_CVS", "_B100" );
			version_2 = version_2.replaceAll( "_CVS", "_B100" );
			
			if ( version_1.startsWith("." )){
				version_1 = "0" + version_1;
			}
			if ( version_2.startsWith("." )){
				version_2 = "0" + version_2;
			}

			version_1 = version_1.replaceAll("[^0-9.]", ".");
			version_2 = version_2.replaceAll("[^0-9.]", ".");
			
			StringTokenizer	tok1 = new StringTokenizer(version_1,".");
			StringTokenizer	tok2 = new StringTokenizer(version_2,".");
			
			while( true ){
				if ( tok1.hasMoreTokens() && tok2.hasMoreTokens()){
				
					int	i1 = Integer.parseInt(tok1.nextToken());
					int	i2 = Integer.parseInt(tok2.nextToken());
				
					if ( i1 != i2 ){
						
						return( i1 - i2 );
					}
				}else if ( tok1.hasMoreTokens()){
					
					int	i1 = Integer.parseInt(tok1.nextToken());
	
					if ( i1 != 0 ){
						
						return( 1 );
					}
				}else if ( tok2.hasMoreTokens()){
					
					int	i2 = Integer.parseInt(tok2.nextToken());
	
					if ( i2 != 0 ){
						
						return( -1 );
					}
				}else{
					return( 0 );
				}
			}
		}catch( Throwable e ){
			
			e.printStackTrace();
			
			return( 0 );
		}
	}
	
	public static boolean
	isValidVersionFormat(
		String		version )
	{
		if ( version == null || version.length() == 0 ){
			
			return( false );
		}
		
		for (int i=0;i<version.length();i++){
			
			char	c = version.charAt(i);
			
			if ( !( Character.isDigit( c ) || c == '.' )){
				
				return( false) ;
			}
		}
	
		if ( version.startsWith( "." ) || version.endsWith( "." ) || version.indexOf( ".." ) != -1 ){
				
			return( false );
		}
		
		return( true );
	}
	
	public static boolean
	isAzureusDomain(
		String	host )
	{
		host = host.toLowerCase();

		for (int i=0; i<AZUREUS_DOMAINS.length; i++) {

			String domain = (String) AZUREUS_DOMAINS[i];

			if ( domain.equals( host )){

				return( true );
			}

			if ( host.endsWith("." + domain)){

				return( true );
			}
		}
		
		return( false );
	}
	
	public static void main(String[] args) {
		System.out.println(compareVersions("3.0.0.1", "3.0.0.0"));
		System.out.println(compareVersions("3.0.0.0_B1", "3.0.0.0"));
		System.out.println(compareVersions("3.0.0.0", "3.0.0.0_B1"));
		System.out.println(compareVersions("3.0.0.0_B1", "3.0.0.0_B4"));
		System.out.println(compareVersions("3.0.0.0..B1", "3.0.0.0_B4"));
	}
}
