/*****************************************************************************
 *
 * $Workfile: Status.cpp $
 *
 * Copyright (C) 1997 Hewlett-Packard Company.
 * Copyright (C) 1997 Microsoft Corporation.
 * All rights reserved.
 *
 * 11311 Chinden Blvd.
 * Boise, Idaho 83714
 *
 *****************************************************************************/

#include "precomp.h"

#include "snmpmgr.h"
#include "stdoids.h"
#include "status.h"


/********************************************************
    status notes:

    1. ASYNCH_NETWORK_ERROR handled by calling function,
        GetObjectSNMP() located in snmp.c

*********************************************************/



//constants==============================================
#define NA 0
#define OTHER_ALERTS        MAX_ASYNCH_STATUS+1
#define WARNING_ALERTS      MAX_ASYNCH_STATUS+2
#define CRITICAL_ALERTS     MAX_ASYNCH_STATUS+3

//hrPrinterDetectedErrorState Masks
#define LOW_PAPER               0x00000080
#define NO_PAPER                0x00000040
#define LOW_TONER               0x00000020
#define NO_TONER                0x00000010
#define DOOR_OPEN               0x00000008
#define PAPER_JAM               0x00000004
#define OFF_LINE                0x00000002
#define SERVICE_REQUESTED       0x00000001


//subunit status
#define AVAIL_IDLE              0L          //available and idle
#define AVAIL_STDBY             2L          //available and in standby
#define AVAIL_ACTIVE            4L          //available and active
#define AVAIL_BUSY              6L


#define UNAVAIL_ONREQ           1L          //unavailable and on-request
#define UNAVAIL_BROKEN          3L          //unavailable because broken
#define AVAIL_UNKNOWN           5L

#define NON_CRITICAL_ALERT      8L
#define CRITICAL_ALERT          16L

#define OFF_LINEx               32L

#define TRANS                   64L         //transitioning to intended state


#define NUM_TRAYS 2

/*************
   Printer     hrDeviceStatus  hrPrinterStatus  hrPrinterDetectedErrorState
   Status

   Normal         running(2)     idle(3)        none set

   Busy/          running(2)     printing(4)
   Temporarily
   Unavailable

   Non Critical   warning(3)     idle(3) or     could be: lowPaper,
   Alert Active                  printing(4)    lowToner, or
                                                serviceRequested

   Critical       down(5)        other(1)       could be: jammed,
   Alert Active                                 noPaper, noToner,
                                                coverOpen, or
                                                serviceRequested

   Unavailable    down(5)        other(1)

   Moving off-    warning(3)     idle(3) or     offline
   line                          printing(4)




   Smith, Wright, Hastings, Zilles & Gyllenskog                   [Page 14]

   RFC 1759                      Printer MIB                     March 1995


   Off-line       down(5)        other(1)       offline

   Moving         down(5)        warmup(5)
   on-line

   Standby        running(2)     other(1)
*************/

//lookup table for basic status
// [device status][printer status]
#define LOOKUP_TABLE_ROWS  5
#define LOOKUP_TABLE_COLS  5
BYTE basicStatusTable[LOOKUP_TABLE_COLS][LOOKUP_TABLE_ROWS] =
{
                    /*other                 unknown idle              printing                      warmup*/
/*unknown*/ { NA,                       NA,         NA,                     NA,                                 NA },
/*running*/ { ASYNCH_POWERSAVE_MODE,    NA,         ASYNCH_ONLINE,          ASYNCH_PRINTING,                    ASYNCH_WARMUP },
/*warning*/ { NA,                       NA,         WARNING_ALERTS,         WARNING_ALERTS,                     WARNING_ALERTS },
/*testing*/ { OTHER_ALERTS,             NA,         NA,                     ASYNCH_PRINTING_TEST_PAGE,          NA },
/*down*/    { CRITICAL_ALERTS,          NA,         NA,                     NA,                                 ASYNCH_WARMUP }
};


///////////////////////////////////////////////////////////////////////////////
//  StdMibGetPeripheralStatus
//      Returns Printer status ( Async Code )
//          or ASYNCH_STATUS_UNKNOWN     if Printer MIB is not supported on the device

DWORD
StdMibGetPeripheralStatus( const char in *pHost,
                           const char in *pCommunity,
                           DWORD      in dwDevIndex)
{
    DWORD       dwRetCode   = NO_ERROR;
    DWORD       errorState;
    WORD        wLookup     = NA;
    RFC1157VarBindList  variableBindings;

    UINT  OID_HRMIB_hrDeviceStatus[]                = { 1, 3, 6, 1, 2, 1, 25, 3, 2, 1, 5, dwDevIndex};
    UINT  OID_HRMIB_hrPrinterStatus[]               = { 1, 3, 6, 1, 2, 1, 25, 3, 5, 1, 1, dwDevIndex};
    UINT  OID_HRMIB_hrPrinterDetectedErrorState[]   = { 1, 3, 6, 1, 2, 1, 25, 3, 5, 1, 2, dwDevIndex};

    AsnObjectIdentifier OT_DEVICE_STATUS[] = {  { OID_SIZEOF(OID_HRMIB_hrDeviceStatus), OID_HRMIB_hrDeviceStatus },
                                                { OID_SIZEOF(OID_HRMIB_hrPrinterStatus), OID_HRMIB_hrPrinterStatus },
                                                { OID_SIZEOF(OID_HRMIB_hrPrinterDetectedErrorState), OID_HRMIB_hrPrinterDetectedErrorState },
                                                { 0, 0 } };
    // build the variable bindings list
    variableBindings.list = NULL;
    variableBindings.len = 0;

    CSnmpMgr    *pSnmpMgr = new CSnmpMgr(pHost, pCommunity, dwDevIndex);

    if ( !pSnmpMgr )
    {
        return ERROR_OUTOFMEMORY;
    }

    if (pSnmpMgr->GetLastError() != SNMPAPI_NOERROR )
    {
        delete pSnmpMgr;
        return ASYNCH_STATUS_UNKNOWN;
    }

    dwRetCode = pSnmpMgr->BldVarBindList(OT_DEVICE_STATUS, &variableBindings);
    if (dwRetCode != SNMPAPI_NOERROR)
    {
        SnmpUtilVarBindListFree(&variableBindings);
        delete pSnmpMgr;
        return ASYNCH_STATUS_UNKNOWN;
    }

    // get the status objects
    dwRetCode = pSnmpMgr->Get(&variableBindings);
    if (dwRetCode != NO_ERROR)
    {
        SnmpUtilVarBindListFree(&variableBindings);
        delete pSnmpMgr;
        if (dwRetCode == SNMP_ERRORSTATUS_NOSUCHNAME)
            dwRetCode = ASYNCH_ONLINE;
        else
            dwRetCode = ASYNCH_STATUS_UNKNOWN;
        return dwRetCode;
    }


    if(dwRetCode == NO_ERROR)
    {
        if( (variableBindings.list[0].value.asnValue.number-1 < 0) ||
            (variableBindings.list[0].value.asnValue.number-1>=LOOKUP_TABLE_COLS) )
        {
            wLookup = OTHER_ALERTS;
        }
        else if( (variableBindings.list[1].value.asnValue.number-1 < 0) ||
                 (variableBindings.list[1].value.asnValue.number-1 >=LOOKUP_TABLE_ROWS) )
        {
            wLookup = OTHER_ALERTS;
        }
        else
        {
            wLookup = basicStatusTable[variableBindings.list[0].value.asnValue.number-1]
                                      [variableBindings.list[1].value.asnValue.number-1];
        }
        switch(wLookup)
        {
            case NA:
                dwRetCode = ASYNCH_STATUS_UNKNOWN;
                break;

            case CRITICAL_ALERTS:
                GetBitsFromString((LPSTR)(variableBindings.list[2].value.asnValue.string.stream),
                    variableBindings.list[2].value.asnValue.string.length, &errorState );
                dwRetCode = ProcessCriticalAlerts(errorState);
                break;

            case WARNING_ALERTS:
                GetBitsFromString((LPSTR)(variableBindings.list[2].value.asnValue.string.stream),
                    variableBindings.list[2].value.asnValue.string.length, &errorState );
                dwRetCode = ProcessWarningAlerts(errorState);
                break;

            case OTHER_ALERTS:
                GetBitsFromString((LPSTR)(variableBindings.list[2].value.asnValue.string.stream),
                    variableBindings.list[2].value.asnValue.string.length, &errorState );
                dwRetCode = ProcessOtherAlerts( errorState);
                break;

            default:
                dwRetCode = wLookup;
                break;
        }
    }
    else
    {
        dwRetCode = ASYNCH_STATUS_UNKNOWN;
    }


    SnmpUtilVarBindListFree(&variableBindings);
    delete pSnmpMgr;

    return dwRetCode;

}   // StdMibGetPeripheralStatus()


///////////////////////////////////////////////////////////////////////////////
//  ProcessCriticalAlerts  - determine active critical error
//
//      returns the device status for Critical Alerts ( ASYNC_XXXXX )

DWORD
ProcessCriticalAlerts( DWORD    errorState )
{
    DWORD status = ASYNCH_ONLINE;

    if ( errorState & DOOR_OPEN) {
        status = ASYNCH_DOOR_OPEN;
    }
    else if( errorState & NO_TONER) {
        status = ASYNCH_TONER_GONE;
    }
    else if( errorState & NO_PAPER) {
        status = ASYNCH_PAPER_OUT;
    }
    else if( errorState & PAPER_JAM ) {
        status = ASYNCH_PAPER_JAM;
    }
    else if(errorState & SERVICE_REQUESTED) {
        status = ASYNCH_PRINTER_ERROR;
    }
    else if( errorState & OFF_LINE) {
        status = ASYNCH_OFFLINE;
    }
    else
        status = ASYNCH_PRINTER_ERROR;

    return status;

}   // ProcessCriticalAlerts()

///////////////////////////////////////////////////////////////////////////////
//  ProcessWarningAlerts  - determine active warning
//
//      returns the device status for Critical Alerts ( ASYNC_XXXXX )

DWORD
ProcessWarningAlerts( DWORD errorState )
{
    DWORD status = ASYNCH_ONLINE;

    if( errorState & LOW_PAPER) {
        status = ASYNCH_ONLINE;
    }
    else if(errorState & LOW_TONER) {
        status = ASYNCH_TONER_LOW;
    }
    else if( errorState & SERVICE_REQUESTED) {

        // Changed it from ASYNCH_INTERVENTION; since if hrDeviceStatus = warning,
        // the printer can still print even though hrPrinterDetectedErrorState = serviceRequested
        //

        status = ASYNCH_ONLINE;
    }
    else if( errorState == 0) {
        status = ASYNCH_ONLINE;
    }
    else {
        status = ASYNCH_STATUS_UNKNOWN;
    }

    return status;
}   // ProcessWarningAlerts()

///////////////////////////////////////////////////////////////////////////////
//  ProcessWarningAlerts  - determine status for other Alerts
//      returns the device status for Critical Alerts ( ASYNC_XXXXX )
DWORD ProcessOtherAlerts( DWORD errorState )
{
    DWORD status = ASYNCH_ONLINE;

    //
    // This is a place holder for future functionality
    //

    status = ASYNCH_STATUS_UNKNOWN;

    return status;
}   // ProcessOtherAlerts

///////////////////////////////////////////////////////////////////////////////
//  GetBitsFromString  -
//      extracts the bin numbers from collection string returned by the get
//
void GetBitsFromString( LPSTR    getVal,
                        DWORD    getSiz,
                        LPDWORD  bits)
{
   char* ptr = (char*)bits;
   *bits = 0;

#if defined(_INTEL) || defined(WINNT)

   switch(getSiz)
   {
      case 1:
         ptr[0] = getVal[0];
         break;

      case 2:
         ptr[1] = getVal[0];
         ptr[0] = getVal[1];
         break;

      case 3:
         ptr[2] = getVal[0];
         ptr[1] = getVal[1];
         ptr[0] = getVal[2];
         break;

      case 4:
         ptr[3] = getVal[0];
         ptr[2] = getVal[1];
         ptr[1] = getVal[2];
         ptr[0] = getVal[3];
         break;
   }

#elif defined(_MOTOROLLA)

   switch(getSiz)
   {
      case 1:
         ptr[3] = getVal[0];
         break;

      case 2:
         ptr[2] = getVal[0];
         ptr[3] = getVal[1];
         break;

      case 3:
         ptr[1] = getVal[0];
         ptr[2] = getVal[1];
         ptr[3] = getVal[2];
         break;

      case 4:
         ptr[0] = getVal[0];
         ptr[1] = getVal[1];
         ptr[2] = getVal[2];
         ptr[3] = getVal[3];
         break;
   }

#else

   #error #define a swap method ( _INTEL, _MOTOROLLA )

#endif /* _INTEL, _MOTOROLLA */

}   // GetBitsFromString()