<?php
// Windows Azure SDK v0.3.1_2011-08
// http://www.windowsazure.com/en-us/develop/php/
// https://github.com/WindowsAzure/azure-sdk-for-php
include BackWPup::get_plugin_data( 'PluginDir' ) . '/sdk/WindowsAzure/WindowsAzure.php';
// Pear libs include
// http://www.pear.com/
set_include_path( get_include_path() . PATH_SEPARATOR . BackWPup::get_plugin_data( 'PluginDir' ) . '/sdk/PEAR/');

/**
 * Documentation: http://www.windowsazure.com/en-us/develop/php/how-to-guides/blob-service/
 */
class BackWPup_Destination_MSAzure extends BackWPup_Destinations {

	/**
	 * @return mixed
	 */
	public function __construct() {

		$this->info[ 'ID' ]          = 'MSAZURE';
		$this->info[ 'name' ]        = __( 'MS Azure', 'backwpup' );
		$this->info[ 'description' ] = __( 'Backup to Microsoft Azure (Blob)', 'backwpup' );
		$this->info[ 'URI' ]         = translate( BackWPup::get_plugin_data( 'PluginURI' ), 'backwpup' );
		$this->info[ 'author' ]      = BackWPup::get_plugin_data( 'Author' );
		$this->info[ 'authorURI' ]   = translate( BackWPup::get_plugin_data( 'AuthorURI' ), 'backwpup' );
		$this->info[ 'version' ]     = BackWPup::get_plugin_data( 'Version' );

	}

	/**
	 * @return array
	 */
	public function option_defaults() {

		return array( 'msazureaccname' => '', 'msazurekey' => '', 'msazurecontainer' => '', 'msazuredir' => trailingslashit( sanitize_title_with_dashes( get_bloginfo( 'name' ) ) ), 'msazuremaxbackups' => 15, 'msazuresyncnodelete' => TRUE );
	}


	/**
	 * @param $jobid
	 */
	public function edit_tab( $jobid ) {
		?>
		<h3 class="title"><?php _e( 'MS Azure access keys', 'backwpup' ); ?></h3>
		<p></p>
		<table class="form-table">
			<tr valign="top">
				<th scope="row"><label for="msazureaccname"><?php _e( 'Account name', 'backwpup' ); ?></label></th>
				<td>
					<input id="msazureaccname" name="msazureaccname" type="text"
						   value="<?php echo esc_attr( BackWPup_Option::get( $jobid, 'msazureaccname' ) );?>" class="regular-text" autocomplete="off" />
				</td>
			</tr>
			<tr valign="top">
				<th scope="row"><label for="msazurekey"><?php _e( 'Access key', 'backwpup' ); ?></label></th>
				<td>
					<input id="msazurekey" name="msazurekey" type="password"
						   value="<?php echo esc_attr( BackWPup_Encryption::decrypt( BackWPup_Option::get( $jobid, 'msazurekey' ) ) );?>" class="regular-text" autocomplete="off" />
				</td>
			</tr>
		</table>

		<h3 class="title"><?php _e( 'Blob container', 'backwpup' ); ?></h3>
		<p></p>
		<table class="form-table">
			<tr valign="top">
				<th scope="row"><label for="msazurecontainerselected"><?php _e( 'Container selection', 'backwpup' ); ?></label></th>
				<td>
					<input id="msazurecontainerselected" name="msazurecontainerselected" type="hidden" value="<?php echo esc_attr( BackWPup_Option::get( $jobid, 'msazurecontainer' ) );?>" />
					<?php if ( BackWPup_Option::get( $jobid, 'msazureaccname' ) && BackWPup_Option::get( $jobid, 'msazurekey' ) ) $this->edit_ajax( array(
																																						 'msazurehost'     => BackWPup_Option::get( $jobid, 'msazurehost' ),
																																						 'msazureaccname'  => BackWPup_Option::get( $jobid, 'msazureaccname' ),
																																						 'msazurekey'      => BackWPup_Encryption::decrypt( BackWPup_Option::get( $jobid, 'msazurekey' ) ),
																																						 'msazureselected' => BackWPup_Option::get( $jobid, 'msazurecontainer' )
																																					) ); ?>
				</td>
			</tr>
			<tr valign="top">
				<th scope="row"><label for="newmsazurecontainer"><?php _e( 'Create a new container', 'backwpup' ); ?></label></th>
				<td>
					<input id="newmsazurecontainer" name="newmsazurecontainer" type="text" value="" class="small-text" autocomplete="off" />
				</td>
			</tr>
		</table>

		<h3 class="title"><?php _e( 'Backup settings', 'backwpup' ); ?></h3>
		<p></p>
		<table class="form-table">
			<tr valign="top">
				<th scope="row"><label for="idmsazuredir"><?php _e( 'Folder in container', 'backwpup' ); ?></label></th>
				<td>
					<input id="idmsazuredir" name="msazuredir" type="text" value="<?php echo esc_attr( BackWPup_Option::get( $jobid, 'msazuredir' ) ); ?>" class="regular-text" />
				</td>
			</tr>
			<tr valign="top">
				<th scope="row"><?php _e( 'File deletion', 'backwpup' ); ?></th>
				<td>
					<?php
					if ( BackWPup_Option::get( $jobid, 'backuptype' ) == 'archive' ) {
						?>
                        <label for="idmsazuremaxbackups"><input id="idmsazuremaxbackups" name="msazuremaxbackups" type="text" size="3" value="<?php echo esc_attr( BackWPup_Option::get( $jobid, 'msazuremaxbackups' ) );?>" class="small-text" />&nbsp;
						<?php  _e( 'Number of files to keep in folder.', 'backwpup' ); BackWPup_Help::tip( __( 'Oldest files will be deleted first. 0 = no deletion', 'backwpup' ) ); ?></label>
						<?php } else { ?>
						<label for="idmsazuresyncnodelete"><input class="checkbox" value="1"
							   type="checkbox" <?php checked( BackWPup_Option::get( $jobid, 'msazuresyncnodelete' ), TRUE ); ?>
							   name="msazuresyncnodelete" id="idmsazuresyncnodelete" /> <?php _e( 'Do not delete files while syncing to destination!', 'backwpup' ); ?></label>
						<?php } ?>
				</td>
			</tr>
		</table>
		<?php
	}


	/**
	 * @param $jobid
	 */
	public function edit_form_post_save( $jobid ) {
		$message="";

		BackWPup_Option::update( $jobid, 'msazureaccname', isset( $_POST[ 'msazureaccname' ] ) ? $_POST[ 'msazureaccname' ] : '' );
		BackWPup_Option::update( $jobid, 'msazurekey', isset( $_POST[ 'msazurekey' ] ) ? BackWPup_Encryption::encrypt( $_POST[ 'msazurekey' ] ) : '' );
		BackWPup_Option::update( $jobid, 'msazurecontainer', isset( $_POST[ 'msazurecontainer' ] ) ? $_POST[ 'msazurecontainer' ] : '' );

		$_POST[ 'msazuredir' ] = trailingslashit( str_replace( '//', '/', str_replace( '\\', '/', trim( stripslashes( $_POST[ 'msazuredir' ] ) ) ) ) );
		if ( substr( $_POST[ 'msazuredir' ], 0, 1 ) == '/' )
			$_POST[ 'msazuredir' ] = substr( $_POST[ 'msazuredir' ], 1 );
		if ( $_POST[ 'msazuredir' ] == '/' )
			$_POST[ 'msazuredir' ] = '';
		BackWPup_Option::update( $jobid, 'msazuredir', $_POST[ 'msazuredir' ] );

		BackWPup_Option::update( $jobid, 'msazuremaxbackups', isset( $_POST[ 'msazuremaxbackups' ] ) ? (int)$_POST[ 'msazuremaxbackups' ] : 0 );
		BackWPup_Option::update( $jobid, 'msazuresyncnodelete', ( isset( $_POST[ 'msazuresyncnodelete' ] ) && $_POST[ 'msazuresyncnodelete' ] == 1 ) ? TRUE : FALSE );

		//create a new container
		if ( ! empty( $_POST[ 'newmsazurecontainer' ] ) && ! empty( $_POST[ 'msazureaccname' ] ) && ! empty( $_POST[ 'msazurekey' ] ) ) {
			try {
				$blobRestProxy = WindowsAzure\Common\ServicesBuilder::getInstance()->createBlobService( 'DefaultEndpointsProtocol=https;AccountName=' . $_POST[ 'msazureaccname' ] . ';AccountKey=' . $_POST[ 'msazurekey' ] );
				$container_options = new WindowsAzure\Blob\Models\CreateContainerOptions();
				$container_options->setPublicAccess( WindowsAzure\Blob\Models\PublicAccessType::NONE );
				$blobRestProxy->createContainer( $_POST[ 'newmsazurecontainer' ], $container_options );
				BackWPup_Option::update( $jobid, 'msazurecontainer', $_POST[ 'newmsazurecontainer' ] );
				$message .= sprintf( __( 'MS Azure container "%s" created.', 'backwpup' ), $_POST[ 'newmsazurecontainer' ] ) . '<br />';
			}
			catch ( Exception $e ) {
				$message .= sprintf( __( 'MS Azure container create: %s', 'backwpup' ), $e->getMessage() ) . '<br />';
			}
		}

		return $message;
	}


	/**
	 * @param $jobdest
	 * @param $backupfile
	 */
	public function file_delete( $jobdest, $backupfile ) {

		$files = get_site_transient( 'backwpup_'. strtolower( $jobdest ), FALSE );
		list( $jobid, $dest ) = explode( '_', $jobdest );

		if ( BackWPup_Option::get( $jobid, 'msazureaccname' ) && BackWPup_Option::get( $jobid, 'msazurekey' ) && BackWPup_Option::get( $jobid, 'msazurecontainer' ) ) {
			try {
				$blobRestProxy = WindowsAzure\Common\ServicesBuilder::getInstance()->createBlobService( 'DefaultEndpointsProtocol=https;AccountName=' . BackWPup_Option::get( $jobid, 'msazureaccname' ) . ';AccountKey=' . BackWPup_Encryption::decrypt( BackWPup_Option::get( $jobid, 'msazurekey' ) ) );
				$blobRestProxy->deleteBlob( BackWPup_Option::get( $jobid, 'msazurecontainer' ), $backupfile );
				//update file list
				foreach ( $files as $key => $file ) {
					if ( is_array( $file ) && $file[ 'file' ] == $backupfile )
						unset( $files[ $key ] );
				}
			}
			catch ( Exception $e ) {
				BackWPup_Admin::message( 'MS AZURE: ' . $e->getMessage() );
			}
		}

		set_site_transient( 'backwpup_' . strtolower( $jobdest ), $files, 60 * 60 * 24 * 7 );
	}

	/**
	 * @param $jobid
	 * @param $get_file
	 */
	public function file_download( $jobid, $get_file ) {
		try {
			$blobRestProxy = WindowsAzure\Common\ServicesBuilder::getInstance()->createBlobService( 'DefaultEndpointsProtocol=https;AccountName=' . BackWPup_Option::get( $jobid, 'msazureaccname' ) . ';AccountKey=' . BackWPup_Encryption::decrypt( BackWPup_Option::get( $jobid, 'msazurekey' ) ) );
			$blob = $blobRestProxy->getBlob( BackWPup_Option::get( $jobid, 'msazurecontainer' ), $get_file );
			header( "Pragma: public" );
			header( "Expires: 0" );
			header( "Cache-Control: must-revalidate, post-check=0, pre-check=0" );
			header( "Content-Type: application/octet-stream" );
			header( "Content-Disposition: attachment; filename=" . basename( $get_file ) . ";" );
			header( "Content-Transfer-Encoding: binary" );
			header( "Content-Length: " . $blob->getProperties()->getContentLength() );
			@set_time_limit( 0 );
			fpassthru( $blob->getContentStream() );
			die();
		}
		catch ( Exception $e ) {
			die( $e->getMessage() );
		}
	}

	/**
	 * @param $jobdest
	 * @return mixed
	 */
	public function file_get_list( $jobdest ) {
		return get_site_transient( 'backwpup_' . $jobdest );
	}

	/**
	 * @param $job_object
	 * @return bool
	 */
	public function job_run_archive( $job_object ) {

		$job_object->substeps_todo = 2;

		$job_object->log( sprintf( __( '%d. Try sending backup to a Microsoft Azure (Blob)&#160;&hellip;', 'backwpup' ), $job_object->steps_data[ $job_object->step_working ][ 'STEP_TRY' ] ), E_USER_NOTICE );
		try {

			$blobRestProxy = WindowsAzure\Common\ServicesBuilder::getInstance()->createBlobService('DefaultEndpointsProtocol=https;AccountName=' . $job_object->job[ 'msazureaccname' ] . ';AccountKey=' . BackWPup_Encryption::decrypt( $job_object->job[ 'msazurekey' ] ) );

			//test vor existing container
			$containers    = $blobRestProxy->listContainers()->getContainers();

			$container_url = '';
			foreach( $containers as $container ) {
				if ( $container->getName() == $job_object->job[ 'msazurecontainer' ] ) {
					$container_url = $container->getUrl();
					break;
				}
			}

			if ( empty( $container_url ) ) {
				$job_object->log( sprintf( __( 'MS Azure container "%s" does not exist!', 'backwpup'), $job_object->job[ 'msazurecontainer' ] ), E_USER_ERROR );

				return TRUE;
			} else {
				$job_object->log( sprintf( __( 'Connected to MS Azure container "%s".', 'backwpup'), $job_object->job[ 'msazurecontainer' ] ), E_USER_NOTICE );
			}


			$job_object->log( __( 'Starting upload to MS Azure&#160;&hellip;', 'backwpup' ), E_USER_NOTICE );
			$blobRestProxy->createBlockBlob( $job_object->job[ 'msazurecontainer' ], $job_object->job[ 'msazuredir'  ] . $job_object->backup_file,  fopen( $job_object->backup_folder . $job_object->backup_file, 'r' ) );
			$job_object->substeps_done = 1;
			$job_object->log( sprintf( __( 'Backup transferred to %s', 'backwpup' ), $container_url . '/' . $job_object->job[ 'msazuredir'  ] . $job_object->backup_file ), E_USER_NOTICE );
			if ( !empty( $job_object->job[ 'jobid' ] ) )
				BackWPup_Option::update( $job_object->job[ 'jobid' ] , 'lastbackupdownloadurl', network_admin_url( 'admin.php' ) . '?page=backwpupbackups&action=downloadmsazure&file=' . $job_object->job[ 'msazuredir'  ] . $job_object->backup_file . '&jobid=' . $job_object->job[ 'jobid' ] );


			$backupfilelist = array();
			$filecounter    = 0;
			$files          = array();
			$blob_options = new WindowsAzure\Blob\Models\ListBlobsOptions();
			$blob_options->setPrefix( $job_object->job[ 'msazuredir'  ] );
			$blobs          = $blobRestProxy->listBlobs( $job_object->job[ 'msazurecontainer' ], $blob_options )->getBlobs();

			if ( is_array( $blobs ) ) {
				foreach ( $blobs as $blob ) {
					$file = basename( $blob->getName() );
					if ( $job_object->is_backup_archive( $file ) )
						$backupfilelist[ $blob->getProperties()->getLastModified()->getTimestamp() ] = $file;
					$files[ $filecounter ][ 'folder' ]      = $container_url . "/" . dirname( $blob->getName() ) . "/";
					$files[ $filecounter ][ 'file' ]        = $blob->getName();
					$files[ $filecounter ][ 'filename' ]    = basename( $blob->getName() );
					$files[ $filecounter ][ 'downloadurl' ] = network_admin_url( 'admin.php' ) . '?page=backwpupbackups&action=downloadmsazure&file=' . $blob->getName() . '&jobid=' . $job_object->job[ 'jobid' ];
					$files[ $filecounter ][ 'filesize' ]    = $blob->getProperties()->getContentLength();
					$files[ $filecounter ][ 'time' ]        = $blob->getProperties()->getLastModified()->getTimestamp()  + ( get_option( 'gmt_offset' ) * 3600 );
					$filecounter ++;
				}
			}
			// Delete old backups
			if ( ! empty ($job_object->job[ 'msazuremaxbackups' ] ) && $job_object->job[ 'msazuremaxbackups' ] > 0 ) {
				if ( count( $backupfilelist ) > $job_object->job[ 'msazuremaxbackups' ] ) {
					ksort( $backupfilelist );
					$numdeltefiles = 0;
					while ( $file = array_shift( $backupfilelist ) ) {
						if ( count( $backupfilelist ) < $job_object->job[ 'msazuremaxbackups' ] )
							break;
						$blobRestProxy->deleteBlob( $job_object->job[ 'msazurecontainer' ], $job_object->job[ 'msazuredir'  ] . $file );
						foreach ( $files as $key => $filedata ) {
							if ( $filedata[ 'file' ] == $job_object->job[ 'msazuredir' ] . $file )
								unset( $files[ $key ] );
						}
						$numdeltefiles ++;
					}
					if ( $numdeltefiles > 0 )
						$job_object->log( sprintf( _n( 'One file deleted on Microsoft Azure container.', '%d files deleted on Microsoft Azure container.', $numdeltefiles, 'backwpup' ), $numdeltefiles ), E_USER_NOTICE );
				}
			}
			set_site_transient( 'backwpup_' . $job_object->job[ 'jobid' ] . '_msazure', $files, 60 * 60 * 24 * 7 );
		}
		catch ( Exception $e ) {
			$job_object->log( E_USER_ERROR, sprintf( __( 'Microsoft Azure API: %s', 'backwpup' ), htmlentities( $e->getMessage() ) ), $e->getFile(), $e->getLine() );
		}
		$job_object->substeps_done = 2;

		return TRUE;
	}

	/**
	 * @param $job_object
	 * @return bool
	 */
	public function can_run( $job_object ) {

		if ( empty( $job_object->job[ 'msazureaccname' ] ) )
			return FALSE;

		if ( empty( $job_object->job[ 'msazurekey' ]) )
			return FALSE;

		if ( empty( $job_object->job[ 'msazurecontainer' ] ) )
			return FALSE;

		return TRUE;
	}

	/**
	 *
	 */
	public function edit_inline_js() {
		//<script type="text/javascript">
		?>
            function msazuregetcontainer() {
                var data = {
                    action: 'backwpup_dest_msazure',
                    msazureaccname: $('#msazureaccname').val(),
                    msazurekey: $('#msazurekey').val(),
                    msazureselected: $('#msazurecontainerselected').val(),
                    _ajax_nonce: $('#backwpupajaxnonce').val()
                };
                $.post(ajaxurl, data, function(response) {
                    $('#msazurecontainererror').remove();
                    $('#msazurecontainer').remove();
                    $('#msazurecontainerselected').after(response);
                });
            }
            $('#msazureaccname').change(function() {msazuregetcontainer();});
            $('#msazurekey').change(function() {msazuregetcontainer();});
	<?php
	}

	/**
	 * @param string $args
	 */
	public function edit_ajax( $args = '' ) {

		$error = '';

		if ( is_array( $args ) ) {
			$ajax = FALSE;
		}
		else {
			if ( ! current_user_can( 'backwpup_jobs_edit' ) )
				wp_die( -1 );
			check_ajax_referer( 'backwpup_ajax_nonce' );
			$args[ 'msazureaccname' ]  = $_POST[ 'msazureaccname' ];
			$args[ 'msazurekey' ]      = $_POST[ 'msazurekey' ];
			$args[ 'msazureselected' ] = $_POST[ 'msazureselected' ];
			$ajax            = TRUE;
		}
		echo '<span id="msazurecontainererror" style="color:red;">';

		if ( ! empty( $args[ 'msazureaccname' ] ) && ! empty( $args[ 'msazurekey' ] ) ) {
			try {
				$blobRestProxy = WindowsAzure\Common\ServicesBuilder::getInstance()->createBlobService( 'DefaultEndpointsProtocol=https;AccountName=' . $args[ 'msazureaccname' ] . ';AccountKey=' . BackWPup_Encryption::decrypt( $args[ 'msazurekey' ] ) );
				$containers    = $blobRestProxy->listContainers()->getContainers();
			}
			catch ( Exception $e ) {
				$error = $e->getMessage();
			}
		}

		if ( empty( $args[ 'msazureaccname' ] ) )
			_e( 'Missing account name!', 'backwpup' );
		elseif ( empty( $args[ 'msazurekey' ] ) )
			_e( 'Missing access key!', 'backwpup' );
		elseif ( ! empty( $error ) )
			echo esc_html( $error );
		elseif ( empty( $containers ) )
			_e( 'No container found!', 'backwpup' );
		echo '</span>';

		if ( !empty( $containers ) ) {
			echo '<select name="msazurecontainer" id="msazurecontainer">';
			foreach ( $containers as $container ) {
				echo "<option " . selected( strtolower( $args[ 'msazureselected' ] ), strtolower( $container->getName() ), FALSE ) . ">" . $container->getName() . "</option>";
			}
			echo '</select>';
		}
		if ( $ajax )
			die();
		else
			return;
	}
}
