gt: 			if ( file.isComplete() && !file.isCopiedToDevice()){
context: /*
   * Created on Jul 10, 2009
   * Created by Paul Gardner
   * 
   * Copyright 2009 Vuze, 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; version 2 of the License only.
   * 
   * 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 com.aelitis.azureus.core.devices.impl;
  
  import java.io.File;
  import java.io.IOException;
  import java.util.ArrayList;
  import java.util.List;
  import java.util.Map;
  
  import org.gudy.azureus2.core3.config.COConfigurationManager;
  import org.gudy.azureus2.core3.internat.MessageText;
  import org.gudy.azureus2.core3.util.AERunnable;
  import org.gudy.azureus2.core3.util.AESemaphore;
  import org.gudy.azureus2.core3.util.AEThread2;
  import org.gudy.azureus2.core3.util.AsyncDispatcher;
  import org.gudy.azureus2.core3.util.Debug;
  import org.gudy.azureus2.core3.util.FileUtil;
  import org.gudy.azureus2.core3.util.IndentWriter;
  
  import com.aelitis.azureus.core.devices.DeviceManagerException;
  import com.aelitis.azureus.core.devices.TranscodeException;
  import com.aelitis.azureus.core.devices.TranscodeFile;
  import com.aelitis.azureus.core.devices.TranscodeTargetListener;
  
  
  public class 
  DeviceMediaRendererManual 
  	extends DeviceMediaRendererImpl
  {
  	private static final Object	COPY_ERROR_KEY 		= new Object();
  	private static final Object	COPY_PENDING_KEY 	= new Object();
  
  	private boolean				can_copy_to_folder	= true;
  	private boolean				copy_outstanding;
  	private boolean				copy_outstanding_set;
  	private AEThread2			copy_thread;
  	private AESemaphore			copy_sem = new AESemaphore( "Device:copy" );
  	private AsyncDispatcher		async_dispatcher = new AsyncDispatcher( 5000 );
  
  	protected
  	DeviceMediaRendererManual(
  		DeviceManagerImpl	_manager,
  		String				_uid,
  		String				_classification,
  		boolean				_manual,
  		String				_name )
  	{
  		super( _manager, _uid, _classification, _manual, _name );
  	}
  	
  	protected
  	DeviceMediaRendererManual(
  		DeviceManagerImpl	_manager,
  		Map					_map )
  	
  		throws IOException
  	{
  		super(_manager, _map );
  	}
  	
  	protected void
  	initialise()
  	{
  		super.initialise();
  		
  		if ( getPersistentBooleanProperty( PP_COPY_OUTSTANDING, false )){
  		
  			setCopyOutstanding();
  		}
  		
  		addListener( 
  			new TranscodeTargetListener()
  			{
  				public void
  				fileAdded(
  					TranscodeFile		file )
  				{
  					updateStatus( file );
  				}
  				
  				public void
  				fileChanged(
  					TranscodeFile		file,
  					int					type,
  					Object				data )
  				{
  					updateStatus( file );
  				}
  				
  				public void
  				fileRemoved(
  					TranscodeFile		file )
  				{	
  						// do this to pick up change in copy-to-device state caused by removal
  					
  					setCopyOutstanding();
  				}
  				
  				private void
  				updateStatus(
  					TranscodeFile		file )
  				{
  					if ( file.isComplete() && !file.isCopiedToDevice()){
  						
  						setCopyOutstanding();
  					}
  				}
  			});
  	}
  	
  	public boolean 
  	canAssociate() 
  	{
  		return( false );
  	}
  	
  	public boolean
  	canRestrictAccess()
  	{
  		return( false );
  	}
  	
  	public boolean
  	canFilterFilesView() 
  	{
  		return( false );
  	}
  	
  	public boolean
  	isBrowsable()
  	{
  		return( false );
  	}
  	
  	public boolean
  	canCopyToFolder()
  	{
  		return( can_copy_to_folder );
  	}
  	
  	public void
  	setCanCopyToFolder(
  		boolean		can )
  	{
  		can_copy_to_folder = can;
  		
  		if ( !can ){
  			
  			setPersistentBooleanProperty( PP_COPY_OUTSTANDING, false );
  			
  			synchronized( this ){
  				copy_outstanding 		= false;
  				copy_outstanding_set	= false;
  			}
  		}
  	}
  	
  	public File
  	getCopyToFolder()
  	{
  		String str = getPersistentStringProperty( PP_COPY_TO_FOLDER, null );
  		
  		if ( str == null ){
  			
  			return( null );
  		}
  		
  		return( new File( str ));
  	}
  	
  	public void
  	setCopyToFolder(
  		File		file )
  	{
  		setPersistentStringProperty( PP_COPY_TO_FOLDER, file==null?null:file.getAbsolutePath());
  		
  		if ( getAutoCopyToFolder()){
  			
  			setCopyOutstanding();
  		}
  	}
  	
  	public boolean
  	isLivenessDetectable()
  	{
  		return( getPersistentBooleanProperty( PP_LIVENESS_DETECTABLE, false ));
  	}
  	
  	public void
  	setLivenessDetectable(
  		boolean	b )
  	{
  		setPersistentBooleanProperty( PP_LIVENESS_DETECTABLE, true );
  	}
  	
  	public int
  	getCopyToFolderPending()
  	{
  		if ( !can_copy_to_folder ){
  			
  			return( 0 );
  		}
  		
  		synchronized( this ){
  			
  			if ( !copy_outstanding ){
  				
  				return( 0 );
  			}
  		}
  
  		TranscodeFileImpl[] files = getFiles();
  		
  		int result = 0;
  			
  		for ( TranscodeFileImpl file: files ){
  
  			if ( file.isComplete() && !file.isCopiedToDevice()){
  				
  				result++;
  			}
  		}
  		
  		return( result );
  	}
  	
  	public boolean
  	getAutoCopyToFolder()
  	{
  		return( getPersistentBooleanProperty( PP_AUTO_COPY, PP_AUTO_COPY_DEFAULT  ));
  	}
  		
  	public void
  	setAutoCopyToFolder(
  		boolean		auto )
  	{
  		setPersistentBooleanProperty( PP_AUTO_COPY, auto );
  			
  		setCopyOutstanding();
  	}
  	
  	public void 
  	manualCopy() 
  	
  		throws DeviceManagerException 
  	{
  		if ( getAutoCopyToFolder()){
  			
  			throw( new DeviceManagerException( "Operation prohibited - auto copy enabled" ));
  		}
  		
  		doCopy();
  	}
  	
  	protected void
  	setCopyOutstanding()
  	{
  		if ( !can_copy_to_folder ){
  			
  			return;
  		}
  		
  		synchronized( this ){
  			
  			copy_outstanding_set = true;
  			
  			if ( copy_thread == null ){
  				
  				copy_thread = 
  					new AEThread2( "Device:copier", true )
  					{
  						public void
  						run()
  						{
  							performCopy();
  						}
  					};
  									
  				copy_thread.start();
  			}
  			
  			copy_sem.release();
  		}
  	}
  	
  	public boolean
  	isAudioCompatible(
  		TranscodeFile		transcode_file )
  	{
  		if ( getDeviceClassification().equals( "sony.PSP" )){
  			
  			try{
  				File file = transcode_file.getSourceFile().getFile();
  				
  				if ( file.exists()){
  					
  					String name = file.getName().toLowerCase();
  					
  					if ( name.endsWith( ".mp3" ) || name.endsWith( ".wma" )){
  						
  						((TranscodeFileImpl)transcode_file).setCopyToFolderOverride( ".." + File.separator + "MUSIC" );
  						
  						return( true );
  					}
  				}
  			}catch( Throwable e ){
  				
  				log( "audio compatible check failed", e );
  			}
  		}
  		
  		return( false );
  	}
  	
  	protected void
  	performCopy()
  	{
  		if ( !can_copy_to_folder ){
  			
  			return;
  		}
  		
  		synchronized( this ){
  
  			copy_outstanding = true;
  		
  			async_dispatcher.dispatch(
  				new AERunnable()
  				{
  					public void
  					runSupport()
  					{
  						setPersistentBooleanProperty( PP_COPY_OUTSTANDING, true );
  					}
  				});
  		}
  		
  		while( true ){
  			
  			if ( copy_sem.reserve( 10*1000 )){
  				
  				while( copy_sem.reserveIfAvailable());
  			}
  						
  			boolean	auto_copy = getAutoCopyToFolder();
  			
  			boolean	nothing_to_do = false;
  			
  			synchronized( this ){
  
  				if ( !auto_copy ){
  											
  					copy_thread = null;
  						
  					nothing_to_do = true;
  					
  				}else{
  
  					copy_outstanding_set = false;
  				}
  			}
  			
  			if ( nothing_to_do ){
  				
  				setError( COPY_ERROR_KEY, null );
  				
  				int pending = getCopyToFolderPending();
  				
  				if ( pending == 0 ){
  					
  					setInfo( COPY_PENDING_KEY, null );
  					
  				}else{
  					
  					String str = MessageText.getString( "devices.info.copypending", new String[]{ String.valueOf( pending ) });
  					
  					setInfo( COPY_PENDING_KEY, str );
  				}
  				return;
  			}
  			
  
  			if ( doCopy()){
  				
  				break;
  			}
  		}
  	}
  	
  	protected boolean
  	doCopy()
  	{
  		if ( !can_copy_to_folder ){
  			
  			return( true );
  		}
  		
  		setInfo( COPY_PENDING_KEY, null );
  
  		
  		File	copy_to = getCopyToFolder();
  		
  		List<TranscodeFileImpl>	to_copy = new ArrayList<TranscodeFileImpl>();
  
  		boolean	borked = false;
  		
  		TranscodeFileImpl[] files = getFiles();
  			
  		int	pending = 0;
  		
  		for ( TranscodeFileImpl file: files ){
  				
  