/*******************************************************************************
*                                                                              *
* Société de Transports de Montréal.                                    	   *
* 2012                                                                         *
*                                                                              *
* Projet Zones Tests                                                           *
*                                                                              *
*                                                                              *
*                                                                              *
*******************************************************************************/
/*
    Description:
    Classe haut niveau de gestion des modules d'entrées/sorties externes (Sealevel).

*/

/* ************************************************************************** */
/* Revision:
### 20121213 JFM
    Verision d'origine.

### YYYYMMDD Description du besoin ou du bug
    Description du changement.
 */

/* ************************************************************************** */
#include "ExternalIOMgr.h"
#include "ZTconfigmgr.h"
#ifndef WINDOWS_OS
#include "Seaio430driver.h"
#include "Seaio440driver.h"
#include "Seaio470driver.h"
#endif
#include "EngLog.h"

CExternalIOMgr::CExternalIOMgr():
    mNbOpenedModules(0)
{
}
CExternalIOMgr::~CExternalIOMgr()
{
    for(int i = 0; i < mExternalModulesList.size(); i++)
    {
        if(mExternalModulesList.at(i))
            delete mExternalModulesList.at(i);
    }

    mExternalModulesList.clear();
	mExternalIODriver.CloseSeaMaxInterface();
}



void CExternalIOMgr::DestroyModule()
{
}

unsigned int CExternalIOMgr::InitExternalIO()
{
	if(mExternalIODriver.OpenSeaMaxInterface(CZTConfigMgr::instance()->GetExtIOIPAddress()) == RET_ERROR)
	{
		CEngLog::instance()->AddLogString("Impossible de se connecter aux modules d'entrées/sorties externes",1);
		return EXTIO_MGR_RET_ERR_CANNOT_CONNECT;
	}

	//Cycle the interface initialization.  This prevents the communication
	//failure in case the app is recovering from a crash.
	mExternalIODriver.CloseSeaMaxInterface();
	usleep(500000);
	if(mExternalIODriver.OpenSeaMaxInterface(CZTConfigMgr::instance()->GetExtIOIPAddress()) == RET_ERROR)
	{
		CEngLog::instance()->AddLogString("Impossible de se connecter aux modules d'entrées/sorties externes",1);
		return EXTIO_MGR_RET_ERR_CANNOT_CONNECT;
	}

    //Open each module and make shure the configuration matches the slave address
    QList<stExtModulesConfig_t> * ModulesList = 0;
    int i;

	//Parse list extracted from config file and create modules instances.
    ModulesList = CZTConfigMgr::instance()->GetExtIOModulesConfigList();
    for(i = 0; i < ModulesList->size(); i++)
    {

        switch(ModulesList->at(i).ModuleType)
        {
            case EXT_IO_TYPE_430:
            {
				CSeaIO430Module *NewModule = new CSeaIO430Module();

				unsigned int Ret = NewModule->OpenModule(ModulesList->at(i).ModuleSlaveAddress,mExternalIODriver.GetSeaMaxInterfacePtr(),ModulesList->at(i).ModuleID);

				switch(Ret)
				{
					case EXT_MOD_RET_MODULE_ALREADY_OPENED:
					case EXT_MOD_RET_ERR_INVALID_POINTER:
					{
						return EXTIO_MGR_RET_ERR_CANNOT_OPEN_MODULE;
						break;
					}
					case EXT_MOD_RET_ERR_MODULE_OFFLINE:
					{
						return EXTIO_MGR_RET_ERR_MOD_OFFLINE;
						break;
					}
					case EXT_MOD_RET_ERR_MODULE_TYPE_MISMATCH:
					{
						return EXTIO_MGR_RET_ERR_MOD_TYPE_MISMATCH;
						break;
					}
					case EXTIO_MGR_RET_OK:
					{
						mExternalModulesList.append(NewModule);
						mNbOpenedModules++;
						break;
					}
					default:
					{
						CEngLog::instance()->AddLogString("CExternalIOMgr::InitExternalIO.  Erreur non gérée...",1);
						return EXTIO_MGR_RET_ERR_CANNOT_OPEN_MODULE;
					}
				}
                break;
            }
            case EXT_IO_TYPE_440:
            {
				CSeaIO440Module *NewModule = new CSeaIO440Module();
				unsigned int Ret = NewModule->OpenModule(ModulesList->at(i).ModuleSlaveAddress,mExternalIODriver.GetSeaMaxInterfacePtr(),ModulesList->at(i).ModuleID);

				switch(Ret)
				{
					case EXT_MOD_RET_MODULE_ALREADY_OPENED:
					case EXT_MOD_RET_ERR_INVALID_POINTER:
					{
						return EXTIO_MGR_RET_ERR_CANNOT_OPEN_MODULE;
						break;
					}
					case EXT_MOD_RET_ERR_MODULE_OFFLINE:
					{
						return EXTIO_MGR_RET_ERR_MOD_OFFLINE;
						break;
					}
					case EXT_MOD_RET_ERR_MODULE_TYPE_MISMATCH:
					{
						return EXTIO_MGR_RET_ERR_MOD_TYPE_MISMATCH;
						break;
					}
					case EXTIO_MGR_RET_OK:
					{
						mExternalModulesList.append(NewModule);
						mNbOpenedModules++;
						break;
					}
					default:
					{
						CEngLog::instance()->AddLogString("CExternalIOMgr::InitExternalIO.  Erreur non gérée...",1);
						return EXTIO_MGR_RET_ERR_CANNOT_OPEN_MODULE;
					}
				}
                break;
            }
            case EXT_IO_TYPE_470:
            {
				CSeaIO470Module *NewModule = new CSeaIO470Module();
				unsigned int Ret = NewModule->OpenModule(ModulesList->at(i).ModuleSlaveAddress,mExternalIODriver.GetSeaMaxInterfacePtr(),ModulesList->at(i).ModuleID);

				switch(Ret)
				{
					case EXT_MOD_RET_MODULE_ALREADY_OPENED:
					case EXT_MOD_RET_ERR_INVALID_POINTER:
					{
						return EXTIO_MGR_RET_ERR_CANNOT_OPEN_MODULE;
						break;
					}
					case EXT_MOD_RET_ERR_MODULE_OFFLINE:
					{
						return EXTIO_MGR_RET_ERR_MOD_OFFLINE;
						break;
					}
					case EXT_MOD_RET_ERR_MODULE_TYPE_MISMATCH:
					{
						return EXTIO_MGR_RET_ERR_MOD_TYPE_MISMATCH;
						break;
					}
					case EXTIO_MGR_RET_OK:
					{
						mExternalModulesList.append(NewModule);
						mNbOpenedModules++;
						break;
					}
					default:
					{
						CEngLog::instance()->AddLogString("CExternalIOMgr::InitExternalIO.  Erreur non gérée...",1);
						return EXTIO_MGR_RET_ERR_CANNOT_OPEN_MODULE;
					}
				}
                break;
            }
            case EXT_IO_TYPE_INVALID:
            default:
            {
                //TODO: Manage this erroneous occurence ???
                //this would be a programming error :(
                break;
            }
        }

    }

    return EXTIO_MGR_RET_OK;
}

CExternalIOModule * CExternalIOMgr::GetModuleHandle(eExternalModuleType_t ModuleType, unsigned int ModuleID)
{
	CExternalIOModule* ModulePtr;
    for(int i = 0; i < mExternalModulesList.size(); i++)
    {
		ModulePtr = mExternalModulesList.at(i);
//		qDebug("TYPE %d",ModulePtr->GetType());
//		qDebug("ID %d",ModulePtr->GetID());
		if(ModulePtr->GetType() == ModuleType && ModulePtr->GetID() == ModuleID)
		{
			return ModulePtr;
		}
    }
	return 0;
}

unsigned int  CExternalIOMgr::InitIO()
{
	return InitExternalIO();
}

CIOModule * CExternalIOMgr::GetModule(eIOModuleType_t type, unsigned int ModuleID)
{
	switch(type)
	{
		case IO_MODULE_INPUT_TYPE:
		{
			return (CSeaIO430Module*)GetModuleHandle(EXT_IO_TYPE_430,ModuleID);
			break;
		}
		case IO_MODULE_OUTPUT_TYPE:
		{
			return (CSeaIO440Module *)GetModuleHandle(EXT_IO_TYPE_440,ModuleID);

			break;
		}
		case IO_MODULE_MIXED_TYPE:
		{
			return (CSeaIO470Module *)GetModuleHandle(EXT_IO_TYPE_470,ModuleID);
			break;
		}
		default:
		case IO_MODULE_INVALID_TYPE:
		{
			return 0;
			break;
		}
	}


}
