/***************************************************************************
                Running
                -----------------------------------------
	begin      : 2011/11/01
	copyright  : (C) 2011 SolutionBox Inc.
	author     : Service 1 Team
	email      : svc1@solbox.com
	version    : 3.0.1

    CopyRight(C) 2011 SolutionBox Inc. All Rights reserved.
    Redistribution and use in source and binary forms, with or with out
    modification, are not permitted in outside of SolutionBox Inc.
***************************************************************************/
#include "Running.h"
#include "Scheduler.h"
#include "ServiceConfig.h"
#include "Logger.h"
#include "Util.h"
#include "RcSyncdClientSocket.h"	// rc_syncd 客  烹脚阑 贸府且 client socket 按眉 积己 棺 立加
#include "RcSyncdRequest.h"

// runlist
CRunlist *CRunlist::m_inst = NULL;

CRunlist::CRunlist()
{
	pthread_mutex_init(&m_findmutex, NULL);
}

CRunlist::~CRunlist()
{
	pthread_mutex_destroy(&m_findmutex);
}

void CRunlist::init()
{
	if (CRunlist::m_inst == NULL)
	{
		CRunlist::m_inst = new CRunlist();
	}
}

CRunlist* CRunlist::getInstance()
{
	return CRunlist::m_inst;
}

void CRunlist::release()
{
	if (CRunlist::m_inst != NULL)
	{
		while(m_inst->m_list.size() > 0 )
		{
			sleep(1);
		}

		delete CRunlist::m_inst;
		CRunlist::m_inst = NULL;
	}
}

bool CRunlist::addlist(CRunning *run)
{
	bool r = true;
	pthread_mutex_lock(&m_findmutex);
	
	stringstream msg;
	time_t newstart = 0;
	time_t newend = 0;
	
	if( findnewtime(run->getstart(), run->getend(), newstart, newend) == false)
	{
		msg << "[running:" << pthread_self() << "] input values used.";
		LOG(LDBG, msg.str().c_str());
		newstart = run->getstart();
		newend = run->getend();
	}
	else 
	{
		msg << "[running:" << pthread_self() << "] changed values used.";
		LOG(LDBG, msg.str().c_str());
	}

	msg.str("");
	if( newstart == newend)
	{
		r = false;
		msg << "[running:" << pthread_self() << "]running start and end are the same.";
		cout << msg.str() << endl;
		LOG(LWAR, msg.str().c_str());
	}
	else if(newstart > newend)
	{
		r = false;
		msg << "[running:" << pthread_self() << "]running error[Start time is greater than the end of time]." << endl;
		msg << "           Start Time : " << time_t2string(run->getstart()) << " => " << time_t2string(run->getstart()) << endl;
		msg << "           End Time : " << time_t2string(run->getend()) << " => " << time_t2string(newend) << endl;
		
		cerr << msg.str() << endl;
		LOG(LERR, msg.str().c_str());
	}
	else 
	{
		run->setstart(newstart);
		run->setend(newend);
	}

	if(r == true)
		m_list.push_back(run);

	pthread_mutex_unlock(&m_findmutex);
	return r;
}

void CRunlist::remove(CRunning *run)
{
	pthread_mutex_lock(&m_findmutex);

	list<CRunning *>::iterator itor;
	itor = find(m_list.begin(), m_list.end(), run);
	if (itor != m_list.end())
	{
		m_list.erase(itor);
	}

	pthread_mutex_unlock(&m_findmutex);
}

bool CRunlist::findnewtime(time_t s, time_t e, time_t &ns, time_t &ne)
{
	stringstream msg;
	bool r = false;	
	ns = s;
	ne = e;

	msg << "[running:"<< pthread_self() << "] Run list count : " <<  m_list.size() <<
		",input time : " <<  time_t2string(ns) << "," << time_t2string(ne);

#ifdef _DEBUG
	cout << msg.str() << endl;
#endif //_DEBUG	
	LOG(LDBG, msg.str().c_str());

	list<CRunning *>::iterator it;
	for ( it=m_list.begin() ; it != m_list.end(); it++ )
	{		
		CRunning *pdata = static_cast<CRunning *>(*it);
		msg.str("");
		msg << "[running:"<< pthread_self() << "] get running :" << 
			time_t2string(pdata->getstart()) << "," << time_t2string(pdata->getend());
#ifdef _DEBUG
		cout << msg.str() << endl;
#endif //_DEBUG	
		LOG(LDBG, msg.str().c_str());

		if( ne > pdata->getend() )
		{
			if(ns >= pdata->getend() )
			{
				LOG(LDBG, "ne > pdata->getend(), ns >= pdata->getend()");
				continue;
			}
			else 
			{
				r = true;
				
				if( ns <= pdata->getstart() )
				{
					LOG(LDBG, "ne > pdata->getend(), ns < pdata->getend(), ns <= pdata->getstart() : ne = pdata->getstart()");
					ne = pdata->getstart();
				}
				else 
				{
					LOG(LDBG, "ne > pdata->getend(), ns < pdata->getend(), ns > pdata->getstart() : new ne, ns");
					ne = pdata->getstart();
					ns = ne - (e - s);
				}				
			}
		}
		else if( ne == pdata->getend() )
		{
			r = true;
			LOG(LDBG, "ne == pdata->getend(), ne =  pdata->getstart();");
			ne =  pdata->getstart();
		}
		else // ne < pdata->getend()
		{
			if(ne <= pdata->getstart() )
			{
				LOG(LDBG, "ne < pdata->getend(), ne <= pdata->getstart()");
				continue;
			}
			else // ne > pdata->getstart()
			{
				r = true;				
				if(ns <= pdata->getstart() )
				{
					LOG(LDBG, "ne < pdata->getend(), ne > pdata->getstart(), ns <= pdata->getstart() : ne = pdata->getstart()");
					ne =  pdata->getstart();
				}
				else  
				{
					LOG(LDBG, "ne < pdata->getend(), ne > pdata->getstart(), ns > pdata->getstart() : new(2) ne ns");
					ne = pdata->getstart();
					ns = ne - (e - s);
				}				
			}
		}
	}

	msg.str("");
	msg << "[running:"<< pthread_self() << "] Find Time." <<
		time_t2string(ns) << "," << time_t2string(ne);

#ifdef _DEBUG
	cout << msg.str() << endl;
#endif // _DEBUG
	LOG(LDBG, msg.str().c_str());

	return r;
}

time_t CRunlist::findnewtime(int findtype, time_t find)
{
	time_t r = 0;
	//pthread_mutex_lock(&m_findmutex);

	list<CRunning *>::iterator it;
	for ( it=m_list.begin() ; it != m_list.end(); it++ )
	{
		CRunning *pdata = static_cast<CRunning *>(*it);

		switch(findtype)
		{
		case CRunlist::START_TIME:
			r = pdata->includestart(find);
			break;
		case CRunlist::EDN_TIME:
			r = pdata->includeend(find);
			break;
		}
	}

	//pthread_mutex_unlock(&m_findmutex);
	return r;
}

// running
CRunning::CRunning(CScheduler* sch, int task, time_t r)
{
	m_scheduler = sch;
	m_taskindex = task;
	m_runed = r;
	m_starttime = 0;
	m_endtime = 0;
}

CRunning::~CRunning()
{
}

void* CRunning::runfn(void* pdata)
{
	CRunning* pObject = reinterpret_cast<CRunning *>(pdata);

	pthread_detach( pthread_self() );
	
	ostringstream msg;
	do
	{
		msg << "[running:" << pthread_self() << "] Task Index : "<< 
			pObject->m_taskindex << " START.";
		LOG(LDBG, msg.str().c_str());
		msg.str("");

		bool b = CRunlist::getInstance()->addlist(pObject);

		if(b == false)
		{
			msg << "[running:" << pthread_self() <<"]Inserted into the run list failed.";
			cerr << msg.str() << endl;
			LOG(LERR, msg.str().c_str());
			break;
		}

		pObject->m_scheduler->updatelastendtime(pObject->m_taskindex,
										pObject->m_endtime);

		string cmd;
		cmd = cmd + " " + time_t2string(pObject->m_starttime) + " " +
			time_t2string(pObject->m_endtime);

		msg << "call sync : " << cmd;

		// sync 夸没 贸府 
		// scheduler -> rc_syncd (local host)
		// 己傍 角菩 咯何绰 objRcSyncdRequest 按眉 郴何俊辑 肺彪 贸府 窃.
		CRcSyncdRequest objRcSyncdRequest;
		objRcSyncdRequest.SendSyncRequest( SYNC_TYPE::NORMAL, time_t2string(pObject->m_starttime), time_t2string(pObject->m_endtime));

		msg << "...Job End" ;
		LOG(LINF, msg.str().c_str());


		CRunlist::getInstance()->remove(pObject);
	}while( false );

#ifdef _DEBUG
	cout << "  RUNNING END index - "<< pObject->m_taskindex << ",now (" <<
		time_t2string(pObject->m_runed) << ")"<< endl;
#endif //_DEBUG
	msg.str("");
	msg << "[running:" << pthread_self() << "] END.";
	LOG(LDBG, msg.str().c_str());
	msg.str("");
	
	delete pObject;

	return NULL;
}

time_t CRunning::includestart(time_t s)
{
	time_t t = 0;
	return t;
}

time_t CRunning::includeend(time_t e)
{
	time_t t = 0;
	return t;
}

bool CRunning::run(time_t s, time_t e)
{
	m_starttime = s;
	m_endtime = e;
	
	pthread_t thread;
	int nRet = pthread_create(&thread, 0, CRunning::runfn, this);
	if( nRet )
	{
		ostringstream msg;
		msg << "Running Thread create failed.[" << errno <<"]";
		cerr << msg.str() << endl;
		LOG(LERR, msg.str().c_str());
		return false;
	}

	return true;
}
