/*
 *
 * NOTES:
 *
 * REVISIONS:
 *
 *  cad08Sep93: Trapping set to handle wierd cases
 *  cad10Sep93: Simplified, seems to work
 *  pcy20Sep93: Wait for possible top fan event to occur
 *  pcy08Apr94: Trim size, use static iterators, dead code removal
 *  mwh30Jun94: if BYPASS_SOFTWARE sleep 3 secs to see if TOPFANFAILURE (1x)
 *  mwh30Jun94: had to add unistd.h for sleep on unix
 *  cgm12Apr96: Add destructor with unregister
 *  clk24Jun98: In Set, changed Sensor::Set to theCommControllerSet
 */

#define INCL_BASE
#define INCL_DOS
#define INCL_NOPM

#include "cdefine.h"

extern "C" {
#if (C_OS & C_OS2)
#include <os2.h>
#endif
#include <stdlib.h>
#include <stdio.h>
#if (C_OS & C_UNIX)
#include <unistd.h>
#endif
}

#include "bypmodes.h"
#include "comctrl.h"
#include "event.h"
#include "pollparm.h"
#include "timerman.h"

BypassModeSensor :: BypassModeSensor(PDevice aParent, PCommController aCommController)
			  : StateSensor(aParent, aCommController, BYPASS_MODE, AREAD_WRITE),
                            theBypassCause(0)
{
#ifdef SINGLETHREADED
    theAlreadyOnBypassFlag = 0;
#endif
    storeState(UPS_NOT_ON_BYPASS);
    theCommController->RegisterEvent(theSensorCode, this);

    // We force registering for this cause protocol doesn't handle it
    //
    theCommController->RegisterEvent(STATE_REGISTER, this);
}

BypassModeSensor :: ~BypassModeSensor()
{
    theCommController->UnregisterEvent(theSensorCode, this);
    theCommController->UnregisterEvent(STATE_REGISTER, this);
}
#if 0
***  Removed for size concerns.  This is really a redundant feature since
***  protocol generates these events

INT BypassModeSensor::Validate(INT aCode, const PCHAR aValue)
{
    INT err = ErrNO_ERROR;
    if(aCode!=theSensorCode)  {
      	err = ErrINVALID_CODE;
    }
    else  {
	err = StateSensor::Validate(aCode, aValue);
    }
    return err; 
}

#endif

INT BypassModeSensor::Update(PEvent anEvent)
{
    INT val = atoi(anEvent->GetValue());

    switch(val)  {
       case UPS_ON_BYPASS:
          theBypassCause = atoi(anEvent->GetAttributeValue(BYPASS_CAUSE));
	  //
	  // Another UPSLinkism. If on bypass by top fan failure, the UPS
	  // also tells us on bypass by computer select which is what we
	  // use to indicate a software bypass
	  //
          if(theBypassCause == BYPASS_BY_SOFTWARE)  {
	      CHAR value[32];
#ifdef SINGLETHREADED
              if (!theAlreadyOnBypassFlag) {
                  theAlreadyOnBypassFlag = 1;

#if (C_OS & C_WIN311)
		_theTimerManager->Wait(3000L);	// changed wait to 3 seconds 3/15/94 jod
#else
		sleep(3);	// three seconds
#endif
              }
#else
              _theTimerManager->Wait(3000L);	// changed wait to 3 seconds 3/15/94 jod
#endif
	      theCommController->Get(TRIP1_REGISTER, value);
	      if(atoi(value) & TOPFANFAILUREMASK)  {
		  anEvent->SetAttributeValue(BYPASS_CAUSE, 
					     BYPASS_BY_TOP_FAN_FAILURE);
                  theBypassCause = BYPASS_BY_TOP_FAN_FAILURE;
	      }
	  }
          break;

       case UPS_NOT_ON_BYPASS:
#ifdef SINGLETHREADED
          theAlreadyOnBypassFlag = 0;
#endif
          theBypassCause = 0;
   }
   return Sensor::Update(anEvent);
}


BypassModeSensor::Get(INT aCode, PCHAR aValue)
{
   CHAR state_value[32];
   CHAR trip_value[32];
   CHAR trip1_value[32];
   theCommController->Get(STATE_REGISTER, state_value);
   theCommController->Get(TRIP_REGISTER, trip_value);
   theCommController->Get(TRIP1_REGISTER, trip1_value);

   INT state = 0;
   if((atoi(state_value) & (SWITCHEDBYPASSMASK | COMPSELECTBYPASSMASK)) ||
      (atoi(trip_value) & (OVERTEMPMASK | BATTERYCHARGERMASK)) ||
      (atoi(trip1_value) & (BYPASSDCIMBALANCEMASK | BYPASSOUTPUTLIMITSMASK | TOPFANFAILUREMASK)))  {
      state = UPS_ON_BYPASS;
   }
   else  {
      state = UPS_NOT_ON_BYPASS;
   }
   sprintf(aValue, "%d", state);
   return ErrNO_ERROR;
}


INT BypassModeSensor::Set(const PCHAR aValue)
{
    INT err = ErrNO_ERROR;

    switch (atoi(aValue)) {
      case INITIATE_BYPASS:
//	sprintf(buf,"%d",UPS_ON_BYPASS);
//	err = StateSensor::Set(buf);
//       aValue[0]=0;
	err = theCommController->Set(theSensorCode, aValue);
	break;

      case CANCEL_BYPASS:
	// Let real value get set when state change in UPS is detected
	// Will cause double events, but should be OK
	//
//       aValue[0]=0;
	err = theCommController->Set(theSensorCode, aValue);
	break;

      default:
	err =  ErrINVALID_VALUE;
	break;
    }
    return err;
}