#import "XMPPSystemInputActivityMonitor.h"
#import "XMPP.h"
#import "XMPPLogging.h"
#import "XMPPFramework.h"


#if ! __has_feature(objc_arc)
#warning This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC).
#endif


// Log levels: off, error, warn, info, verbose
#if DEBUG
static const int xmppLogLevel = XMPP_LOG_LEVEL_VERBOSE;
#else
static const int xmppLogLevel = XMPP_LOG_LEVEL_WARN;
#endif

const NSTimeInterval XMPPSystemInputActivityMonitorInactivityTimeIntervalNone = -1;

#define INACTIVITY_TIME_INTERVAL 300.0
#define TIMER_TIME_INTERVAL 1.0

@implementation XMPPSystemInputActivityMonitor

- (id)init
{
	return [self initWithDispatchQueue:NULL];
}

- (id)initWithDispatchQueue:(dispatch_queue_t)queue
{
	if ((self = [super initWithDispatchQueue:queue]))
	{
		inactivityTimeInterval = INACTIVITY_TIME_INTERVAL;
		active = YES;
	}
	return self;
}


- (BOOL)activate:(XMPPStream *)aXmppStream
{
	XMPPLogTrace();
	
	if ([super activate:aXmppStream])
	{
		XMPPLogVerbose(@"%@: Activated", THIS_FILE);

#if !TARGET_OS_IPHONE

		CFTimeInterval secondsSinceLastUserInteraction = CGEventSourceSecondsSinceLastEventType(kCGEventSourceStateHIDSystemState, kCGAnyInputEventType);
		
		NSDate *date = [NSDate dateWithTimeIntervalSinceNow:(secondsSinceLastUserInteraction * -1)];
		[self _setLastActivityDate:date];

        timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, moduleQueue);
        
        if (timer)
        {
    		dispatch_source_set_timer(timer, dispatch_walltime(NULL, 0), (TIMER_TIME_INTERVAL * NSEC_PER_SEC), 0);
    		dispatch_source_set_event_handler(timer, ^{                
                CFTimeInterval secondsSinceLastUserInteraction = CGEventSourceSecondsSinceLastEventType(kCGEventSourceStateHIDSystemState, kCGAnyInputEventType);

				NSDate *date = [NSDate dateWithTimeIntervalSinceNow:(secondsSinceLastUserInteraction * -1)];
				[self _setLastActivityDate:date];
            });
    		dispatch_resume(timer);
        }
#endif
		
		return YES;
	}
	
	return NO;
}

- (void)deactivate
{
	XMPPLogTrace();
    
	if(timer)
	{
	    dispatch_source_cancel(timer);
	    timer = NULL;
	}

	[super deactivate];
}

- (void)dealloc{
	
	if(timer)
	{
	    dispatch_source_cancel(timer);
	    timer = NULL;
	}
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma Internal
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

- (void)_setLastActivityDate:(NSDate *)flag{

	dispatch_block_t block = ^{
		lastActivityDate = flag;
				
		if(inactivityTimeInterval > XMPPSystemInputActivityMonitorInactivityTimeIntervalNone)
		{
			if(active && -[lastActivityDate timeIntervalSinceNow] > inactivityTimeInterval)
			{
				active = NO;
				[multicastDelegate xmppSystemInputActivityMonitorDidBecomeInactive:self];				
			}
			else if(!active && -[lastActivityDate timeIntervalSinceNow] < inactivityTimeInterval)
			{
				active = YES;
				[multicastDelegate xmppSystemInputActivityMonitorDidBecomeActive:self];
			}
			
		}else{
			active = YES;
		}

	};
	
	if (dispatch_get_specific(moduleQueueTag))
		block();
	else
		dispatch_async(moduleQueue, block);
}


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma Properties
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

- (BOOL)isActive
{
	__block BOOL result = YES;;
	
	dispatch_block_t block = ^{
		result = active;
	};
	
	if (dispatch_get_specific(moduleQueueTag))
		block();
	else
		dispatch_sync(moduleQueue, block);
	
	return result;
}

- (NSDate *)lastActivityDate
{
	__block NSDate *result = nil;;

	dispatch_block_t block = ^{
		result = lastActivityDate;
	};

	if (dispatch_get_specific(moduleQueueTag))
		block();
	else
		dispatch_sync(moduleQueue, block);

	return result;
}

- (NSTimeInterval)inactivityTimeInterval
{
	__block NSTimeInterval result = XMPPSystemInputActivityMonitorInactivityTimeIntervalNone;

	dispatch_block_t block = ^{
		result = inactivityTimeInterval;
	};

	if (dispatch_get_specific(moduleQueueTag))
		block();
	else
		dispatch_sync(moduleQueue, block);

	return result;
}

- (void)setInactivityTimeInterval:(NSTimeInterval)flag
{
	dispatch_block_t block = ^{
	       inactivityTimeInterval = flag;
	};

	if (dispatch_get_specific(moduleQueueTag))
		block();
	else
		dispatch_async(moduleQueue, block);
}

@end
