<?php

// DO NOT CALL THIS CLASS DIRECTLY. CALL VIA: pb_backupbuddy_destination in bootstrap.php.

class pb_backupbuddy_destination_dropbox { // Change class name end to match destination name.
	
	public static $destination_info = array(
		'name'			=>		'Dropbox (v1)',
		'description'	=>		'Dropbox.com is a popular online storage provider offering 2 GB of free storage to start with. Premium upgrades are available.',
		'category'		=>		'legacy', // best, normal, legacy
	);
	
	// Default settings. Should be public static for auto-merging.
	public static $default_settings = array(
		'type'			=>		'dropbox',	// MUST MATCH your destination slug. Required destination field.
		'title'			=>		'',		// Required destination field.
		'token'			=>		'',
		'directory'		=>		'backupbuddy',
		'archive_limit'	=>		0,
		'disable_file_management'	=>		'0',		// When 1, _manage.php will not load which renders remote file management DISABLED.
		'disabled'					=>		'0',		// When 1, disable this destination.
	);
	
	private static $_init_count = 0;
	
	
	public static function init() {
		if ( self::$_init_count == 0 ) {
			$memory = self::memory_guesstimate();
			self::$destination_info['description'] .= ' BackupBuddy estimates <b>you will be able to transfer backups up to ' . round( $memory['hypothesis'], 0 ) . ' MB with your current memory limit of ' . $memory['limit'] . ' MB</b>. Additionally, Dropbox limits API uploads to 150MB max. <a href="http://dropbox.com" target="_blank">Learn more here.</a>';
		}
		self::$_init_count++;
	}
	
	
	
	/*	send()
	 *	
	 *	Send one or more files.
	 *	
	 *	@param		array			$files		Array of one or more files to send.
	 *	@return		boolean						True on success, else false.
	 */
	public static function send( $settings = array(), $files = array(), $send_id = '' ) {
		global $pb_backupbuddy_destination_errors;
		if ( '1' == $settings['disabled'] ) {
			$pb_backupbuddy_destination_errors[] = __( 'Error #48933: This destination is currently disabled. Enable it under this destination\'s Advanced Settings.', 'it-l10n-backupbuddy' );
			return false;
		}
		if ( ! is_array( $files ) ) {
			$files = array( $files );
		}
		
		$token = &$settings['token'];
		$directory = '/' . ltrim( $settings['directory'], '/\\' );
		$limit = $settings['archive_limit'];
		
		
		// Normalize picky dropbox directory.
		$directory = trim( $directory, '\\/' );
		
		pb_backupbuddy::status( 'details', 'About to load Dropbuddy library...' );
		require_once( pb_backupbuddy::plugin_path() . '/destinations/dropbox/lib/dropbuddy/dropbuddy.php' );
		pb_backupbuddy::status( 'details', 'Dropbuddy loaded.' );
		//pb_backupbuddy::status( 'details', 'Authenticating to dropbox with token: `' . implode( ';', $token ) . '`.' );
		$dropbuddy = new pb_backupbuddy_dropbuddy( $token );
		pb_backupbuddy::status( 'details', 'Dropbuddy object created.' );
		if ( $dropbuddy->authenticate() !== true ) {
			pb_backupbuddy::status( 'details',  'Dropbox authentication failed in send().' );
			return false;
		} else {
			pb_backupbuddy::status( 'details', 'Authenticated to Dropbox.' );
		}
		
		$memory = pb_backupbuddy_destination_dropbox::memory_guesstimate();
		pb_backupbuddy::status( 'details', 'Dropbox limitation estimated to be max transfer size of ' . round( $memory['hypothesis'], 0 ) . 'MB based on PHP memory limit of ' . $memory['limit'] . 'MB & current loaded WordPress plugins.' );
		
		pb_backupbuddy::status( 'details', 'Looping through files to send to Dropbox.' );
		foreach( $files as $file ) {
			pb_backupbuddy::status( 'details',  'About to put file `' . basename( $file ) . '` (' . pb_backupbuddy::$format->file_size( filesize( $file ) ) . ') to Dropbox (v1).' );
			try {
				$status = $dropbuddy->put_file( $directory . '/' . basename( $file ), $file );
			} catch( Dropbox_Exception $e ) {
				pb_backupbuddy::status( 'error', 'Dropbox exception caught. Error #8954785: ' . $e->getMessage() );
				return false;
			}
			if ( $status === true ) {
				pb_backupbuddy::status( 'details',  'SUCCESS sending to Dropbox!' );
			} else {
				pb_backupbuddy::status( 'details',  'Dropbox file send FAILURE. HTTP Status: ' . $status['httpStatus'] . '; Body: ' . $status['body'], 'error' );
				return false;
			}
			
			
			// Start remote backup limit
			if ( $limit > 0 ) {
				pb_backupbuddy::status( 'details',  'Dropbox file limit in place. Proceeding with enforcement.' );
				
				$meta_data = $dropbuddy->get_meta_data( $directory );
				
				// Create array of backups and organize by date
				$bkupprefix = backupbuddy_core::backup_prefix();
				
				$backups = array();
				foreach ( (array) $meta_data['contents'] as $looping_file ) {
					if ( '1' == $looping_file['is_dir'] ) { // Additional safety layer to ignore subdirectory.
						continue;
					}
					// check if file is backup
					if ( ( strpos( $looping_file['path'], 'backup-' . $bkupprefix . '-' ) !== false ) ) {
						$backups[$looping_file['path']] = strtotime( $looping_file['modified'] );
					}
				}
				arsort($backups);
				
				if ( ( count( $backups ) ) > $limit ) {
					pb_backupbuddy::status( 'details',  'Dropbox backup file count of `' . count( $backups ) . '` exceeds limit of `' . $limit . '`.' );
					$i = 0;
					$delete_fail_count = 0;
					foreach( $backups as $buname => $butime ) {
						$i++;
						if ( $i > $limit ) {
							if ( !$dropbuddy->delete( $buname ) ) { // Try to delete backup on Dropbox. Increment failure count if unable to.
								pb_backupbuddy::status( 'details',  'Unable to delete excess Dropbox file: `' . $buname . '`' );
								$delete_fail_count++;
							}
						}
					}
					
					if ( $delete_fail_count !== 0 ) {
						backupbuddy_core::mail_error( sprintf( __('Dropbox remote limit could not delete %s backups.', 'it-l10n-backupbuddy' ), $delete_fail_count) );
					}
				}
			} else {
				pb_backupbuddy::status( 'details',  'No Dropbox file limit to enforce.' );
			}
			// End remote backup limit
		} // end foreach.
		pb_backupbuddy::status( 'details', 'All files sent.' );
		
		return true; // Success if made it this far.
			
			
	} // End send().
	
	
	
	/*	test()
	 *	
	 *	Tests ability to write to this remote destination.
	 *	TODO: Should this delete the temporary test directory to clean up after itself?
	 *	
	 *	@param		array			$settings	Destination settings.
	 *	@return		bool|string					True on success, string error message on failure.
	 */
	public static function test( $settings, $files = array() ) {
		
		return false; // WE DO NOT HAVE A REMOTE TEST FOR THIS CURRENTLY.
		
	} // End test().
	
	
	
	/*	memory_guesstimate()
	 *	
	 *	Estimates the amount of available memory for loading a ZIP file. This guesses
	 *	the max file size that could be sent due to memory constraints.
	 *	
	 *	@param		
	 *	@return				Associate array with multiple items.
	 */
	public static function memory_guesstimate() {
		
		// CALCULATE MEMORY. **********************************************
		$this_val = ini_get( 'memory_limit' );
		if ( preg_match( '/(\d+)(\w*)/', $this_val, $matches ) ) {
			$this_val = $matches[1];
			$unit = $matches[2];
		
			if ( 'g' == strtolower( $unit ) ) {
				// Convert GB to MB.
				$this_val = $this_val = $this_val * 1024;
			}
		} else {
			$limit = 0;
		}
		
		$memory_usage = memory_get_peak_usage() / 1048576;
		$memory_limit = $this_val;
		$memory_free = $this_val - $memory_usage;
		$memory_hypothesis = ( $memory_free - 2 - ( $memory_free * .10 ) ) / 2; // Free memory minus 2MB minus a 10% free memory fudge factor/wiggle room. Underestimate.  -- July 13, 2012: Now dividing by 2 due to having to load via file_get_contents and copy into $body. Doubles mem usage sadly.
		
		if ( $memory_hypothesis > 150 ) {
			$memory_hypothesis = 150;
		}
		
		return array(
			'usage'			=> $memory_usage,
			'limit'			=> $memory_limit,
			'free'			=> $memory_free,
			'hypothesis'	=> $memory_hypothesis,
		);
		
	} // End memory_guesstimate().
	
	
} // End class.