/*
 
 Copyright (C) 2009-2011 id Software LLC, a ZeniMax Media company. 

 This file is part of the WOLF3D iOS v2.1 GPL Source Code. 

 
 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.
 
 */

#import <Foundation/Foundation.h>

#import <StoreKit/StoreKit.h>
#import <StoreKit/SKPaymentTransaction.h>
#import <StoreKit/SKError.h>

#import <UIKit/UIAlertView.h>

#import "iphone_store.h"


@interface MyStoreObserver : NSObject<SKProductsRequestDelegate, SKPaymentTransactionObserver> {
	
}

// SKProductsRequestDelegate methods
- (void)productsRequest: (SKProductsRequest *)request didReceiveResponse: (SKProductsResponse *)response;

// SKPaymentTransactionObserver methods
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions;
- (void)paymentQueue:(SKPaymentQueue *)queue removedTransactions:(NSArray *)transactions;

- (void)paymentQueue:(SKPaymentQueue *)queue restoreCompletedTransactionsFailedWithError:(NSError *)error;
- (void)paymentQueueRestoreCompletedTransactionsFinished:(SKPaymentQueue *)queue;

// MyStoreObserver methods
- (void)completeTransaction:(SKPaymentTransaction *)transaction;
- (void)failedTransaction:(SKPaymentTransaction *)transaction;
- (void)restoreTransaction:(SKPaymentTransaction *)transaction;
- (void)finalizeTransaction:(SKPaymentTransaction *)transaction;

@end

// The single instance of the store observer. This is created in InAppPurchaseInit and released
// in InAppPurchaseShutdown.
static MyStoreObserver *storeObserver;

// Flag to indicate whether a purchase is in progress or not. This is set to true in
// InAppPurchaseStartPurchase and false when the request either succeeds or fails.
static bool isInProgress = false;

static InAppPurchaseCallbackPtr clientCallback;

@implementation MyStoreObserver

/*
========================
productsRequest:didReceiveResponse

Called by the system when the application gets product information about an In-App Purchase.
========================
*/
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response
{
	NSArray *myProduct = response.products;
    
	// For now, immediately request payment for any items the user has requested.
	for (SKProduct *product in myProduct)
	{
		SKPayment *payment = [SKPayment paymentWithProduct:product];
		[[SKPaymentQueue defaultQueue] addPayment:payment];
	}
	
	// We should handle the case of an empty array, this seems to occur if we send a request
	// with a nonexistant product ID, but there may be other cases.
	// TODO: Need a timeout to be even more robust.
	if ( [myProduct count] == 0 ) {
		if ( clientCallback ) {
			clientCallback( IAP_FAILURE );
		}
	}
	
    [request autorelease];
}

/*
========================
paymentQueue:updatedTransactions

Called by the system when purchase requests are updated.
========================
*/
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions
{
	for (SKPaymentTransaction *transaction in transactions)
    {
        switch (transaction.transactionState)
        {
            case SKPaymentTransactionStatePurchased:
                [self completeTransaction:transaction];
                break;
            case SKPaymentTransactionStateFailed:
                [self failedTransaction:transaction];
                break;
            case SKPaymentTransactionStateRestored:
                [self restoreTransaction:transaction];
            default:
                break;
        }
    }
}

- (void)paymentQueue:(SKPaymentQueue *)queue removedTransactions:(NSArray *)transactions
{

}

- (void)paymentQueue:(SKPaymentQueue *)queue restoreCompletedTransactionsFailedWithError:(NSError *)error
{

}


- (void)paymentQueueRestoreCompletedTransactionsFinished:(SKPaymentQueue *)queue
{

}

/*
========================
completeTransaction

Called by updatedTransactions when a request is completed.
========================
*/
- (void)completeTransaction:(SKPaymentTransaction *)transaction
{
	[self finalizeTransaction:transaction];
}

/*
========================
failedTransaction

Called by updatedTransactions when a request fails.
========================
*/
- (void)failedTransaction:(SKPaymentTransaction *)transaction
{
	if (transaction.error.code != SKErrorPaymentCancelled)
    {
#if !TARGET_OS_TV
        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"In-App Purchase error"
												  message:[transaction.error localizedDescription]
												  delegate:nil
												  cancelButtonTitle:@"OK"
												  otherButtonTitles:nil];
												  
		[alert show];
		[alert release];
#endif
    }
    [[SKPaymentQueue defaultQueue] finishTransaction: transaction];
	
	isInProgress = false;
	
	if ( clientCallback ) {
		clientCallback( IAP_FAILURE );
	}
}

/*
========================
restoreTransaction

Called by updatedTransactions when a request is restored. This can behave identically to
completeTransaction.
========================
*/
- (void)restoreTransaction:(SKPaymentTransaction *)transaction
{
	[self finalizeTransaction:transaction.originalTransaction];
}

/*
========================
finalizeTransaction

This method actually delivers the purchased item to the user. Currently, this means setting
a key in NSUserDefaults equal to the product ID to TRUE.
========================
*/
- (void)finalizeTransaction:(SKPaymentTransaction *)transaction
{
	NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
	
	NSString *productID = transaction.payment.productIdentifier;
	
	[defaults setBool:TRUE forKey:productID];

	[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
	
	isInProgress = false;
	
	if ( clientCallback ) {
		clientCallback( IAP_SUCCESS );
	}
}

@end





/*
========================
InAppPurchaseInit

Creates the instance of the payment observer and adds it to the payment queue. This should be
called at application launch.
========================
*/
void InAppPurchaseInit(void) {
	if ( !storeObserver ) {
		storeObserver = [[MyStoreObserver alloc] init];
		
		// Add the observer here in case purchase requests were interrupted last time.
		[[SKPaymentQueue defaultQueue] addTransactionObserver:storeObserver];
	}
	
}

void InAppPurchaseShutdown(void) {
	[storeObserver release];
	storeObserver = nil;
}

/*
========================
InAppPurchaseStartPurchase

If payments are enabled, starts an In-App Purchase transaction for the given product identifier.
If payments are not enabled, reminds the user that they can be enabled.
If a request is currently in progress, nothing happens, as only one request at a time is
allowed.
========================
*/
void InAppPurchaseStartPurchase( const char * productIdentifier ) {
	// Only allow one request at a time.
	if ( isInProgress ) {
		return;
	}
	
	if ( [SKPaymentQueue canMakePayments] ) {
		// Start transaction.
		if ( storeObserver == nil ) {
			printf( "In-App Purchase system not initialized. Can't purchase anything!\n" );
			return;
		}
		
		isInProgress = true;
		
		// convert the C string to an NSString.
		NSString *productKey = [[NSString alloc] initWithCString:productIdentifier
												 encoding:NSASCIIStringEncoding];
		
		SKProductsRequest *request= [[SKProductsRequest alloc] initWithProductIdentifiers: [NSSet setWithObject: productKey]];
		
		// The set retains the string, so we can release it now.
		[productKey release];
		
		request.delegate = storeObserver;
		[request start];
	} else {
		// User has disabled In-App purchases in settings. Kindly remind him that he can
		// enable purchases again.
#if !TARGET_OS_TV
		UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"In-App Purchases are disabled"
			message:@"You can enable In-App purchases in your device's settings."
			delegate:nil
			cancelButtonTitle:@"OK"
			otherButtonTitles:nil];
			
		[alert show];
		[alert release];
#endif
	}

}

/*
========================
InAppPurchaseHasPurchased

Queries the standard NSUserDefaults object for a boolean key equal to the product identifier.
If this key is true, the user has purchased the product. If the key is false, the user has
not purchased the product.
========================
*/
bool InAppPurchaseHasPurchased( const char * productIdentifier ) {
	// Convert the C string to an NSString for use with NSUserDefaults.
	NSString *productKey = [[NSString alloc] initWithCString:productIdentifier
											 encoding:NSASCIIStringEncoding];
	
	// Purchase records are stored in the standardUserDefaults, with a key equal to the product
	// identifier.
	NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    BOOL hasProduct = [defaults boolForKey:productKey];
	
	// This string was alloced above, but since it isn't needed anymore, it must be released.
	[productKey release];
	
	// Convert Objective-C BOOL type to standard C99 _Bool type.
	return ( hasProduct )? true: false;
}

/*
========================
InAppPurchaseIsInProgress

Returns true if an In-App Purchase request is currently pending. Only one request can be active
at a time.
========================
*/
bool InAppPurchaseIsInProgress( void ) {
	return isInProgress;
}

/*
========================
InAppPurchaseSetCallback

Sets a functino pointer to be called when the in-app purchase transaction in complete, either
successfully or unsuccessfully.
========================
*/
void InAppPurchaseSetCallback( InAppPurchaseCallbackPtr function ) {
	clientCallback = function;
}

