<?php
class Intense_OAuth1 {
	public $consumer_key, $consumer_secret, $redirect_url, $access_token_url, $service, $authorize_url, $request_token_url, $OAuth_version, $timestamp, $nonce, $signature_method, $OAuth_url, $is_OAuth_Request, $authorize_extra;

	function Intense_OAuth1( $service, $request_token_url, $authorize_url, $access_token_url, $authorize_extra ) {
		$intense_visions_options = get_option( 'intense_visions_options' );

		$this->service = $service; //used for data keys and state
		$this->consumer_key = ( isset( $intense_visions_options['intense_' . $service . '_consumer_key'] ) ? $intense_visions_options['intense_' . $service . '_consumer_key'] : null );;
		$this->consumer_secret = ( isset( $intense_visions_options['intense_' . $service . '_consumer_secret'] ) ? $intense_visions_options['intense_' . $service . '_consumer_secret'] : null );
		$this->redirect_url = "http://" . $_SERVER['HTTP_HOST'] . "/wp-admin/admin.php?page=intense_visions_options&OAuth1=true&state=" . $service;
		$this->access_token_url = $access_token_url;		
		$this->authorize_url = $authorize_url;
		$this->request_token_url = $request_token_url;
		$this->OAuth_url = "http://" . $_SERVER['HTTP_HOST'] . "/wp-admin/admin.php?page=intense_visions_options&OAuth1=true&action=request_token&state=" . $service;
		$this->OAuth_version = '1.0';
		$this->timestamp = time();
		$this->nonce = md5( microtime() . mt_rand() );
		$this->signature_method = "HMAC-SHA1";
		$this->is_OAuth_Request = isset( $_GET['page'] ) && $_GET['page'] == 'intense_visions_options' && isset( $_GET['OAuth1'] ) && isset( $_GET['state'] ) && $_GET['state'] == $service;
		$this->authorize_extra = $authorize_extra;
	}

	function urlencode_rfc3986( $input ) {
		if ( is_array( $input ) ) {
			return array_map( array( 'Intense_OAuth1', 'urlencode_rfc3986' ), $input );
		} else if ( is_scalar( $input ) ) {
			return str_replace( '+', ' ', str_replace( '%7E', '~', rawurlencode( $input ) ) );
		} else {
			return '';
		}
	}

	function generate_parameters( $endpoint = null, $api_args = NULL, $method = null, $oauth_token = array() ) {
		$parameters = array(
			'oauth_nonce' => $this->nonce,
			'oauth_timestamp' => $this->timestamp,
			'oauth_consumer_key' => $this->consumer_key,
			'oauth_signature_method' => $this->signature_method,
			'oauth_version' => $this->OAuth_version,
			'oauth_callback' => urlencode( $this->redirect_url )
		);

		if ( isset( $oauth_token['oauth_token'] ) ) {
			$parameters['oauth_token'] = $oauth_token['oauth_token'];
		}

		if ( isset( $oauth_token['oauth_verifier'] ) ) {
			$parameters['oauth_verifier'] = $oauth_token['oauth_verifier'];
		}

		$parameters = ( !empty( $api_args ) ) ? array_merge( $parameters, $api_args ) : $parameters;
		uksort( $parameters, 'strnatcmp' );	

		return $parameters;
	}

	function generate_signature( $endpoint = null, $method = null, $parameters, $oauth_token = array() ) {
		$token_secret = ( isset( $oauth_token['oauth_token_secret'] ) ? $this->urlencode_rfc3986( $oauth_token['oauth_token_secret'] ) : "" );
		$signature_key = $this->urlencode_rfc3986( $this->consumer_secret ) . '&' . $token_secret;

		$query_string = build_query( $parameters, 'OAuth' );
		$base_string = $method . "&" . $this->urlencode_rfc3986( $endpoint ) . "&" . $this->urlencode_rfc3986( $query_string );

		return base64_encode(hash_hmac('sha1', $base_string, $signature_key, true));
	}

	function build_query( $parameters, $encode_method ) {
		uksort( $parameters, 'strnatcmp' );

		if ($encode_method == 'OAuth') {
			foreach ( $parameters as $key => $value ) {
				if ( is_array( $value ) ) {
					natsort( $value );

					foreach ( $value as $v2 ) {
						$pairs[] = ( ( $v2 == '' ) ? $this->urlencode_rfc3986( $key ) . "=0" : $this->urlencode_rfc3986( $key ) ) ."=" . $this->urlencode_rfc3986( $v2 );
					}
				}
				else {
					$pairs[] = ( ( $value == '' ) ? $this->urlencode_rfc3986( $key ) . "=0" : $this->urlencode_rfc3986( $key ) ) ."=" . $this->urlencode_rfc3986( $value );
				}
			}
		} else {
			foreach ( $parameters as $key => $value ) {
				if ( is_array( $value ) ) {
					natsort( $value );

					foreach ( $value as $v2 ) {
						$pairs[] = ( ( $v2 == '' ) ? urlencode( $key ) . "=0" : urlencode( $key ) ) ."=" . urlencode( $v2 );
					}
				}
				else {
					$pairs[] = ( ( $value == '' ) ? urlencode( $key ) . "=0" : urlencode( $key ) ) ."=" . urlencode( $value );
				}
			}
		}

		return implode( '&', $pairs );
	}

	function show_authentication_link() {
		return !empty( $this->consumer_key ) && !empty( $this->consumer_secret );
	}

	function get_oauth_link() {
		return '<a target="_blank" href="' . $this->OAuth_url . '"/>authenticate</a>';
	}

	function get_request_token_url() {
		$parameters = $this->generate_parameters( $this->request_token_url, null, "GET", null );
		$parameters['oauth_callback'] = $parameters['oauth_callback'] . urlencode( "&action=authorization_response" );
		$signature = $this->generate_signature( $this->request_token_url, "GET", $parameters, null );

		$parameters['oauth_signature'] = $signature;

		return $this->request_token_url . '?' . build_query( $parameters, 'URL' );
	}

	function get_OAuth_token() { 
		$response = wp_remote_get( $this->get_request_token_url(),
			  array(
			   'body' => array(				    
			   ),
			   'sslverify' => apply_filters( 'https_local_ssl_verify', false )
			  )
		);

		if ( !is_wp_error( $response ) && $response['response']['code'] < 400 && $response['response']['code'] >= 200 ) {
			parse_str($response['body'], $get_array);

			$oauth_token = $get_array['oauth_token'];
			$oauth_token_secret = $get_array['oauth_token_secret'];
			//$oauth_callback_confirmed = $get_array['oauth_callback_confirmed'];

			$this->persist_oauth_token_secret( $oauth_token_secret );	

			return $oauth_token;
		} else if ( is_wp_error( $response ) ) {
		  $error = $response->get_error_message();
		  $errormessage = $error;
		  $errortype = 'Wordpress Error';

		  echo $errormessage;
		  die(1);

	 	} else if ( $response['response']['code'] >= 400 ) {	 		
	  		$error = json_decode( $response['body'] );
			$errormessage = $error->error_message;
			$errortype = $error->error_type;

			echo $errormessage;
			die(1);
	 	}
	}

	function persist_oauth_token_secret( $oauth_token_secret ) {
		$file_name = 'intense_' . $this->service . 'oauth_token_secret.txt';
		$uploads = wp_upload_dir();

    	$intense_uploads_dir = trailingslashit($uploads['basedir']);
    	$intense_uploads_path = $uploads['baseurl'] . '/';

    	file_put_contents( $intense_uploads_dir . $file_name, $oauth_token_secret );
	}

	function get_saved_oauth_token_secret() {
		$file_name = 'intense_' . $this->service . 'oauth_token_secret.txt';
		$uploads = wp_upload_dir();

    	$intense_uploads_dir = trailingslashit($uploads['basedir']);
    	$intense_uploads_path = $uploads['baseurl'] . '/';

    	return file_get_contents( $intense_uploads_dir . $file_name );
	}

	function drop_oauth_token_secret() {
		$file_name = 'intense_' . $this->service . 'oauth_token_secret.txt';

		$uploads = wp_upload_dir();

    	$intense_uploads_dir = trailingslashit($uploads['basedir']);
    	$intense_uploads_path = $uploads['baseurl'] . '/';

		unlink( $intense_uploads_dir . $file_name );
	}

	function request_authorization( $oauth_token ) {		
		echo "<script> window.location = '" . $this->authorize_url  . "?oauth_token=" . $oauth_token . $this->authorize_extra . "'; </script>";
	}

	function get_access_token_url( $oauth_token ) {
		$parameters = $this->generate_parameters( $this->access_token_url, null, "GET", $oauth_token );
		$parameters['oauth_callback'] = $parameters['oauth_callback'] . urlencode( "&action=access_response" );
		$signature = $this->generate_signature( $this->access_token_url, "GET", $parameters, $oauth_token );

		$parameters['oauth_signature'] = $signature;

		return $this->access_token_url . '?' . build_query( $parameters, 'URL' );
	}

	function negociate_access_token( $oauth_token ) {
		$intense_visions_options = get_option( 'intense_visions_options' );

		$success = false;
		$auth_token = null;
		$auth_token_secret = null;

		$response = wp_remote_get( $this->get_access_token_url( $oauth_token ),
			  array(
			   'body' => array(				    
			   ),
			   'sslverify' => apply_filters( 'https_local_ssl_verify', false )
			  )
		);		

		if ( !is_wp_error( $response ) && $response['response']['code'] < 400 && $response['response']['code'] >= 200 ) {
			parse_str($response['body'], $get_array);

			$auth_token = $get_array['oauth_token'];
			$auth_token_secret = $get_array['oauth_token_secret'];			

			$success = true;
		} else if ( is_wp_error( $response ) ) {
		  $error = $response->get_error_message();
		  $errormessage = $error;
		  $errortype = 'Wordpress Error';

		  echo $errormessage;
	 	} else if ( $response['response']['code'] >= 400 ) {
	  		$error = json_decode( $response['body'] );
			$errormessage = $error->error_message;
			$errortype = $error->error_type;

			echo $errormessage;
	 	}

	 			
		$this->save_access_token( $auth_token, $auth_token_secret );

	 	if ( $success ) {
	 		echo "<script> opener.location.reload(true);self.close(); </script>";
	 	}

	 	$this->drop_oauth_token_secret();

	 	die(1);
	}

	function get_access_token() {
		///SMUGMUG HACK!!!
		///Smugmug will append to the callback url incorrectly. It will look something like
		/// http://.../?...&state=smugmug?oauth_token=... 
		/// when it should be 
		/// http://.../?...&state=smugmug&oauth_token=...
		if ( isset( $_GET['state'] ) && strpos( $_GET['state'], 'smugmug?' ) !== false && $this->service == 'smugmug' ) {			
			$this->service = 'smugmug';
			$this->is_OAuth_Request = true;			
			$_REQUEST['action'] = 'authorization_response';
			$_REQUEST['oauth_token'] = str_replace("smugmug?oauth_token=", '', $_GET['state'] );
			$_GET['state'] = 'smugmug';
		}		

		if ( $this->is_OAuth_Request ) {			
			$action = $_REQUEST['action'];
			$url = '';			

			switch ($action) {
				case 'request_token':					
					$oauth_token = $this->get_OAuth_token();					
					$this->request_authorization( $oauth_token );
					break;	
				case 'authorization_response':
					$oauth_token = $_REQUEST['oauth_token'];
					$oauth_verifier = $_REQUEST['oauth_verifier'];
					$oauth_token_secret = $this->get_saved_oauth_token_secret();

					$this->negociate_access_token( array( 
						'oauth_token' => $oauth_token, 
						'oauth_verifier' => $oauth_verifier,
						'oauth_token_secret' => $oauth_token_secret
					));
					break;	
				default:
					# code...
					break;
			}			
		}	
	}

	function save_access_token( $auth_token, $auth_token_secret ) {
		$intense_visions_options = get_option( 'intense_visions_options' );

		$intense_visions_options[ 'intense_' . $this->service . '_auth_token' ] = $auth_token;
		$intense_visions_options[ 'intense_' . $this->service . '_auth_token_secret' ] = $auth_token_secret;

		$args = array( 
			'opt_name' => 'intense_visions_options',
			'database' => null
		);

		if ( !isset( $args['database'] )) $args['database'] = null;

		if ( $args['database'] === 'transient' ) {
		 set_transient( $args['opt_name'] . '-transient', $intense_visions_options, $args['transient_time'] );
		} else if ( $args['database'] === 'theme_mods' ) {
		 set_theme_mod( $args['opt_name'] . '-mods', $intense_visions_options );
		} else if ( $args['database'] === 'theme_mods_expanded' ) {
		 foreach ( $intense_visions_options as $k=>$v ) {
		  set_theme_mod( $k, $v );
		 }
		} else {
		 update_option( $args['opt_name'], $intense_visions_options );
		}		
	}
}
