/*
 * Copyright 2009 Funambol, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/* $Id$ */

#include <Foundation/NSAutoreleasePool.h>
#include <Foundation/NSThread.h>
#include <Foundation/NSTimer.h>
#include <Foundation/NSRunLoop.h>
#include "Timer.h"
#include "LoggerMacroses.h"

static const char * c_LogName = "Timer";

@interface TimerTicker : NSObject
{
@private
	int _ticksCount;
	NS_DM_Client::NS_Common::Timer *m_pTimer;
	NSTimer *_timer;
	NSTimeInterval _interval;
}
- (id) initWithTimer:(NS_DM_Client::NS_Common::Timer*)t andInterval:(NSTimeInterval)ti;
- (void) tick:(NSTimer*)theTimer;
- (void) run;
@end


using namespace NS_DM_Client;
using namespace NS_DM_Client::NS_Common;


Timer::Timer() :
	m_isRunning(false), m_ticksCount(-1), m_timerInterval(0), 
	m_pCallback(NULL), m_pThread(NULL), m_pTimerStarter(NULL)
{
}

Timer::~Timer()
{
	Stop();
}

bool Timer::IsRunning()
{
	return m_isRunning;
}

void Timer::SetCallback(Callback *c)
{
	m_pCallback = c;
}

void Timer::SetInterval(int t)
{
	m_timerInterval = t;
}

void Timer::SetTicksCount(int count)
{
	m_ticksCount = count;
}

void Timer::Start()
{
	if (m_isRunning) return;

	if (m_timerInterval)
	{
		if (m_ticksCount == -1 || m_ticksCount > 0)
		{
			// Separate timer thread is created.
			// Thread creates its own NSAutorelease pool, timer is registered in the NSRunningLoop of the new thread.
			m_pTimerStarter = [[TimerTicker alloc] initWithTimer:this andInterval:m_timerInterval];
			m_pThread = [[NSThread alloc] initWithTarget:(id)m_pTimerStarter  
												selector:@selector(run) 
												  object:nil];
			[(id)m_pThread start];
			m_isRunning = true;
		}
	}
}

void Timer::Stop()
{
	if (m_isRunning)
	{
		[(id)m_pTimerStarter release];
		[(id)m_pThread release];
		m_pTimerStarter = nil;
		m_pThread = nil;
		m_isRunning = false;
	}
}

void Timer::NotifyCallback()
{
	if (m_pCallback) m_pCallback->Call();
}



@implementation TimerTicker

- (id) initWithTimer:(NS_DM_Client::NS_Common::Timer*)t andInterval:(NSTimeInterval)ti
{
	self = [super init];
	if (self) 
	{
		m_pTimer = t;
		_ticksCount = t->m_ticksCount;
		_interval = ti;
	}
	return self;
}

- (void) dealloc
{
	[_timer invalidate];
	_timer = nil;
	[super dealloc];
}

- (void) tick:(NSTimer*)theTimer
{
	if (_ticksCount == 0)
	{
		[_timer invalidate];
		_timer = nil;
	}
	else
	{
		if (_ticksCount > 0)
			_ticksCount--;
		m_pTimer->NotifyCallback();				
	}
}

- (void) run
{
	NSAutoreleasePool *aPool = [[NSAutoreleasePool alloc] init];
	NSRunLoop* runLoop = [NSRunLoop currentRunLoop];

	if (_ticksCount)
		[self tick:nil];
	
	if (_ticksCount)
		_timer = [NSTimer scheduledTimerWithTimeInterval:_interval 
												  target:self
												selector:@selector(tick:) 
												userInfo:nil 
												 repeats:true];
	[runLoop run];
	[aPool release];
}

@end
