/*



    ========== licence begin  GPL
    Copyright (c) 1998-2005 SAP AG

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License
    as published by the Free Software Foundation; either version 2
    of the License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
    ========== licence end





*/

/*! 
  -----------------------------------------------------------------------------
 
  module: vcn52.cpp
 
  -----------------------------------------------------------------------------
 
  responsible:  BerndV
 
  special area: DBMServer Parameter History Class
   
  description:  DBMServer Parameter History Class - Implementation

  version:      7.2.

  -----------------------------------------------------------------------------
 
                          Copyright (c) 1998-2005 SAP AG
 
  -----------------------------------------------------------------------------
*/

/*
  -----------------------------------------------------------------------------
  includes
  -----------------------------------------------------------------------------
 */
#include <stdlib.h>
#include <stdio.h>

#include "heo02.h"
#include "heo06.h"
#include "hcn42.h"
#include "hcn90.h"
#include "hcn52.h"

/*
  -----------------------------------------------------------------------------
  private macros
  -----------------------------------------------------------------------------
 */
#define TXT_VALUE_DELETED "<<parameter inactive>>"
#define TXT_STATE_DELETED "D"
#define TXT_STATE_CHANGED "C"
#define TXT_STATE_ACTIVE  "A"
#define TXT_STATE_UNKNOWN " "

#define OFF_DATE            0
#define LEN_DATE            9
#define OFF_TIME            (OFF_DATE + LEN_DATE)
#define LEN_TIME            9
#define OFF_NAME            (OFF_TIME + LEN_TIME)
#define LEN_NAME           33
#define OFF_NEWVALUE        (OFF_NAME + LEN_NAME)
#define LEN_NEWVALUE       65
#define OFF_OLDVALUE        (OFF_NEWVALUE + LEN_NEWVALUE)
#define LEN_OLDVALUE       65
#define OFF_STATE           (OFF_OLDVALUE + LEN_OLDVALUE)
#define LEN_STATE           2
#define OFF_GROUP           (OFF_STATE + LEN_STATE)
#define LEN_GROUP          9

#define OFF_DATE_178            0
#define LEN_DATE_178            9
#define OFF_TIME_178            (OFF_DATE_178 + LEN_DATE_178)
#define LEN_TIME_178            9
#define OFF_NAME_178            (OFF_TIME_178 + LEN_TIME_178)
#define LEN_NAME_178           19
#define OFF_NEWVALUE_178        (OFF_NAME_178 + LEN_NAME_178)
#define LEN_NEWVALUE_178       65
#define OFF_OLDVALUE_178        (OFF_NEWVALUE_178 + LEN_NEWVALUE_178)
#define LEN_OLDVALUE_178       65
#define OFF_STATE_178           (OFF_OLDVALUE_178 + LEN_OLDVALUE_178)
#define LEN_STATE_178           2
#define OFF_GROUP_178           (OFF_STATE_178 + LEN_STATE_178)
#define LEN_GROUP_178           9
#define LEN_RECORD_178          (OFF_GROUP_178 + LEN_GROUP_178)

#define TXT_DATE            "DATE"
#define ID_DATE             1
#define TXT_TIME            "TIME"
#define ID_TIME             2
#define TXT_NAME            "NAME"
#define ID_NAME             4
#define TXT_NEWVALUE        "NEWVALUE"
#define ID_NEWVALUE         8
#define TXT_OLDVALUE        "OLDVALUE"
#define ID_OLDVALUE         16
#define TXT_STATE           "S"
#define TXT_STATEFULL       "STATE"
#define ID_STATE            32
#define TXT_GROUP           "GROUP"
#define ID_GROUP            64

#define ID_FULL             (ID_DATE + ID_TIME + ID_NAME + ID_NEWVALUE + ID_OLDVALUE + ID_STATE + ID_GROUP)
#define ID_EMPTY            0

#ifdef _WIN32
#define LEN_RECORD          (OFF_GROUP + LEN_GROUP + 2)
#else
#define LEN_RECORD          (OFF_GROUP + LEN_GROUP + 1)
#endif

#define KEY_NAME            "NAME"
#define KEY_GROUP           "GROUP"
#define KEY_FIELDS          "FIELDS"
#define KEY_DATE            "DATE"
#define KEY_STATE           "STATE"

#define CHAR_ASSIGN         '='
#define CHAR_DELIMETER      ','
#define TXT_MARK            "%"

/*
  -------------------------------------------------------------------------
  public constructor cn52ParamHistoryRecord :: cn52ParamHistoryRecord
  -------------------------------------------------------------------------
*/
cn52ParamHistoryRecord :: cn52ParamHistoryRecord
                           ( const tsp00_DbNamec        & szDBName,
                             const tcn002_XpValueName   & szName,
                             const tcn002_XpValueString & szNewValue,
                             const tcn002_XpValueString & szOldValue,
                             const tsp00_C8c            & szGroup,
                             const HistoryState           nState) 
{
  initMembers();

  m_szName     = szName;
  m_szNewValue = szNewValue;
  m_szOldValue = szOldValue;
  m_nState     = nState;
  m_szDBName   = szDBName;
  m_szGroup    = szGroup;

  tsp00_Date         DateP;
	tsp00_Time         TimeP;
  sqldattime(DateP, TimeP);
  m_szDate.p2c(DateP);
  m_szTime.p2c(TimeP);

  switch (m_nState) {
    case StDeleted:
      m_szState.rawAssign(TXT_STATE_DELETED);
      break;
    case StChanged:
      m_szState.rawAssign(TXT_STATE_CHANGED);
      break;
    case StActive:
      m_szState.rawAssign(TXT_STATE_ACTIVE);
      break;
    default:
      m_szState.rawAssign(TXT_STATE_UNKNOWN);
  } // end switch

  if (m_nState == StDeleted) {
    m_szNewValue.rawAssign(TXT_VALUE_DELETED);
  } // end if 

} // end cn52ParamHistoryRecord :: cn52ParamHistoryRecord
/*
  -------------------------------------------------------------------------
*/
cn52ParamHistoryRecord :: cn52ParamHistoryRecord
                           ( const tsp00_DbNamec    & szDBName ) 
{
  initMembers();

  m_szDBName   = szDBName;
} // end cn52ParamHistoryRecord :: cn52ParamHistoryRecord

/*
  -------------------------------------------------------------------------
  public destructor cn52ParamHistoryRecord :: ~cn52ParamHistoryRecord
  -------------------------------------------------------------------------
*/
cn52ParamHistoryRecord :: ~cn52ParamHistoryRecord()
{
  if (m_bFileOpen) {
    tsp05_RteFileError rteFileErr;
    sqlfclosec ( m_hFile, sp5vf_close_normal, &rteFileErr );
  } // end if
} // end cn52ParamHistoryRecord :: ~cn52ParamHistoryRecord

/*
  -------------------------------------------------------------------------
  private member function cn52ParamHistoryRecord :: migrateFile
  -------------------------------------------------------------------------
*/
bool cn52ParamHistoryRecord :: migrateFile(tsp00_ErrTextc  & szError)
{
  bool bOk = true;

  tsp05_RteFileError rteFileErr;
  tsp01_RteError     rteRTEError;
  tsp05_RteFileInfo  rteFileInfo;
  tsp00_Pathc        szFile;
  tsp00_Pathc        szTemp1;
  tsp00_Pathc        szTemp2;
  tsp00_Int4         hFile;
  tsp00_Int4         hTemp1;

  tcn52_C1024c       szLine;
  tsp00_Longint      nOut;

  bOk = (cn42GetFileName(m_szDBName, FGET_DBMPAHI_CN42, szFile) == OK_CN00);

  sqlfinfoc (szFile, &rteFileInfo, &rteFileErr );
  if (!rteFileInfo.sp5fi_exists) {
    return true;
  } // end if

  if (bOk) {
    szTemp1 = szFile;
    strcat(szTemp1, "1");
    szTemp2 = szFile;
    strcat(szTemp2, "2");

    sqlfopenc(szFile, sp5vf_text, sp5vf_read, sp5bk_buffered, &hFile, &rteFileErr );
    bOk = (rteFileErr.sp5fe_result == vf_ok);
  } // end if

  if (bOk) {
    // read the record
    sqlfreadc (hFile, szLine.asCharp(), szLine.size(), &nOut, &rteFileErr);

    if (nOut > LEN_RECORD_178) {
      sqlfclosec ( hFile, sp5vf_close_normal, &rteFileErr );
      return true;
    } // end if

    sqlfopenc(szTemp1, sp5vf_text, sp5vf_write, sp5bk_buffered, &hTemp1, &rteFileErr );
    bOk = (rteFileErr.sp5fe_result == vf_ok);
  } // end if

  while (bOk) {
    bOk = analyzeRec178(szLine);

    if (bOk) {
      // write file
      sqlfwritec (hTemp1, getRecord().asCharp(), -1, &rteFileErr);
      bOk = (rteFileErr.sp5fe_result == vf_ok);

      if (bOk) {
        sqlfreadc (hFile, szLine.asCharp(), szLine.size(), &nOut, &rteFileErr);
        bOk = (rteFileErr.sp5fe_result == vf_ok);
      } // end if

    } // end if

  } // end while

  bOk =  (rteFileErr.sp5fe_result == vf_eof) || (rteFileErr.sp5fe_result == vf_ok);

  sqlfclosec ( hFile,  sp5vf_close_normal, &rteFileErr );
  sqlfclosec ( hTemp1, sp5vf_close_normal, &rteFileErr );

  if (bOk) {
    if (sqlfilecopyc(szFile, szTemp2, &rteRTEError)) {
      if (!sqlfilecopyc(szTemp1, szFile, &rteRTEError)) {
        bOk = false;
        szError.rawAssign(rteRTEError.RteErrText);
        sqlfilecopyc(szTemp2, szFile, &rteRTEError);
      } // end if
    } else {
      bOk = false;
      szError.rawAssign(rteRTEError.RteErrText);
    } // end if
  } // end if

  if (!bOk) {
    szError.p2c(rteFileErr.sp5fe_text);
  } // end if

  sqlferasec(szTemp1, &rteFileErr);
  sqlferasec(szTemp2, &rteFileErr);

  return bOk;
} /// end cn52ParamHistoryRecord :: migrateFile

/*
  -------------------------------------------------------------------------
  public member function cn52ParamHistoryRecord :: appendToFile
  -------------------------------------------------------------------------
*/
bool cn52ParamHistoryRecord :: appendToFile(tsp00_ErrTextc  & szError)
{
  tsp00_Int4         hFile;
  tsp05_RteFileError rteFileErr;
  bool               bOk = true;

  bOk = migrateFile(szError);

  if (bOk) {
    bOk = (cn42OpenFile(m_szDBName, FGET_DBMPAHI_CN42, sp5vf_append, hFile, rteFileErr) == OK_CN00);
  } // end if 

  if (bOk) {
    // write file
    sqlfwritec (hFile, getRecord().asCharp(), -1, &rteFileErr);

    // close file
    if (rteFileErr.sp5fe_result != vf_ok) {
      szError.p2c(rteFileErr.sp5fe_text);
      bOk = false;
      sqlfclosec ( hFile, sp5vf_close_normal, &rteFileErr );
    } else {
      sqlfclosec ( hFile, sp5vf_close_normal, &rteFileErr );
      if (rteFileErr.sp5fe_result != vf_ok) {
        szError.p2c(rteFileErr.sp5fe_text);
      } // end if
    } // end if

  } else {
    szError.p2c(rteFileErr.sp5fe_text);
  } // end if

  return bOk;
} // end cn52ParamHistoryRecord :: appendToFile

/*
  -------------------------------------------------------------------------
  public member function cn52ParamHistoryRecord :: readFirst
  -------------------------------------------------------------------------
*/
bool cn52ParamHistoryRecord :: readFirst(tsp00_ErrTextc  & szError) 
{
  bool               bOk    = false;
  tsp05_RteFileError rteFileErr;

  szError.Init();

  for (int i = 0;i < MAX_KEYS_CN52; ++i) m_NameArray[i].Init(); 

  if (m_bFileOpen) {
    sqlfclosec ( m_hFile, sp5vf_close_normal, &rteFileErr );
    m_bFileOpen = false;
  } // end if

  if (migrateFile(szError)) {

    if (cn42OpenFile(m_szDBName, FGET_DBMPAHI_CN42, sp5vf_read, m_hFile, rteFileErr) == OK_CN00) {

      m_bFileOpen = true;

      sqlfseekc (m_hFile, LEN_RECORD * (-1),  sp5vf_seek_end, &rteFileErr);

      if (rteFileErr.sp5fe_result == vf_ok) {
        tcn52_C1024c       szRecord;
        tsp00_Longint      nOut;

        while (!bOk && rteFileErr.sp5fe_result == vf_ok) {
        
          // read the record
          sqlfreadc (m_hFile, szRecord.asCharp(), szRecord.size(), &nOut, &rteFileErr);

          if (rteFileErr.sp5fe_result == vf_ok) {
            // analayze the record
            bOk = analyzeRecord (szRecord);
            if (!bOk) {
              // go to next (that means previuos) record
              sqlfseekc (m_hFile, LEN_RECORD * (-1) * 2,  sp5vf_seek_cur, &rteFileErr);
            } // end if
          } else {
            szError.p2c(rteFileErr.sp5fe_text);
          } // end if

        } // end while

      } else if (rteFileErr.sp5fe_result != vf_noseek) {
        szError.p2c(rteFileErr.sp5fe_text);
      } // end if

      if ( rteFileErr.sp5fe_result != vf_ok) {
        sqlfclosec ( m_hFile, sp5vf_close_normal, &rteFileErr );
        bOk = false;
        m_bFileOpen = false;
      } // end if

    } else {
      szError.p2c(rteFileErr.sp5fe_text);
    } // end if

  } // end if

  return bOk;
} // end cn52ParamHistoryRecord :: readFirst

/*
  -------------------------------------------------------------------------
  public member function cn52ParamHistoryRecord :: readNext
  -------------------------------------------------------------------------
*/
bool cn52ParamHistoryRecord :: readNext(tsp00_ErrTextc  & szError) 
{
  bool               bOk = false;

  szError.Init();

  if (m_bFileOpen) {
    tsp05_RteFileError rteFileErr;

    // go to next (that means previuos) record
    sqlfseekc (m_hFile, LEN_RECORD * (-1) * 2,  sp5vf_seek_cur, &rteFileErr);

    if (rteFileErr.sp5fe_result == vf_ok) {
      tcn52_C1024c       szRecord;
      tsp00_Longint      nOut;

      while (!bOk && rteFileErr.sp5fe_result == vf_ok) {
        // read the record
        sqlfreadc (m_hFile, szRecord.asCharp(), szRecord.size(), &nOut, &rteFileErr);

        if (rteFileErr.sp5fe_result == vf_ok) {
          // analayze the record
          bOk = analyzeRecord (szRecord);
          if (!bOk) {
            // go to next (that means previuos) record
            sqlfseekc (m_hFile, LEN_RECORD * (-1) * 2,  sp5vf_seek_cur, &rteFileErr);
          } // end if
        } else {
          szError.p2c(rteFileErr.sp5fe_text);
        } // end if
      } // end while

    } else if (rteFileErr.sp5fe_result != vf_noseek) {
      szError.p2c(rteFileErr.sp5fe_text);
    } // end if

    if ( rteFileErr.sp5fe_result != vf_ok) {
      sqlfclosec ( m_hFile, sp5vf_close_normal, &rteFileErr );
      bOk = false;
      m_bFileOpen = false;
    } // end if

  } // end if

  return bOk;
} // end cn52ParamHistoryRecord :: readNext

/*
  -------------------------------------------------------------------------
  public member function cn52ParamHistoryRecord :: getRecord
  -------------------------------------------------------------------------
*/
const tcn52_C1024c & cn52ParamHistoryRecord :: getRecord() 
{
  // create record
  sprintf(m_szRecord, "%-*s%-*s%-*s%-*s%-*s%-*s%-*s", 
                      ((m_nFields & ID_DATE)     == 0) ? 0  : LEN_DATE,
                      ((m_nFields & ID_DATE)     == 0) ? "" : m_szDate.asCharp(),
                      ((m_nFields & ID_TIME)     == 0) ? 0  : LEN_TIME,
                      ((m_nFields & ID_TIME)     == 0) ? "" : m_szTime.asCharp(),
                      ((m_nFields & ID_NAME)     == 0) ? 0  : LEN_NAME,
                      ((m_nFields & ID_NAME)     == 0) ? "" : m_szName.asCharp(),
                      ((m_nFields & ID_NEWVALUE) == 0) ? 0  : LEN_NEWVALUE,
                      ((m_nFields & ID_NEWVALUE) == 0) ? "" : m_szNewValue.asCharp(),
                      ((m_nFields & ID_OLDVALUE) == 0) ? 0  : LEN_OLDVALUE,
                      ((m_nFields & ID_OLDVALUE) == 0) ? "" : m_szOldValue.asCharp(),
                      ((m_nFields & ID_STATE)    == 0) ? 0  : LEN_STATE,
                      ((m_nFields & ID_STATE)    == 0) ? "" : m_szState.asCharp(),
                      ((m_nFields & ID_GROUP)    == 0) ? 0  : LEN_GROUP,
                      ((m_nFields & ID_GROUP)    == 0) ? "" : m_szGroup.asCharp());

  return m_szRecord;
} // end cn52ParamHistoryRecord :: getRecord

/*
  -------------------------------------------------------------------------
  public member function cn52ParamHistoryRecord :: getHeader
  -------------------------------------------------------------------------
*/
const tcn52_C1024c & cn52ParamHistoryRecord :: getHeader() 
{
  
  // create record
  sprintf(m_szRecord, "%-*s%-*s%-*s%-*.*s%-*.*s%-*s%-*s", 
                        ((m_nFields & ID_DATE)     == 0) ? 0  : LEN_DATE,
                        ((m_nFields & ID_DATE)     == 0) ? "" : TXT_DATE,
                        ((m_nFields & ID_TIME)     == 0) ? 0  : LEN_TIME,
                        ((m_nFields & ID_TIME)     == 0) ? "" : TXT_TIME,
                        ((m_nFields & ID_NAME)     == 0) ? 0  : LEN_NAME,
                        ((m_nFields & ID_NAME)     == 0) ? "" : TXT_NAME,
                        ((m_nFields & ID_NEWVALUE) == 0) ? 0  : LEN_NEWVALUE,
                        ((m_nFields & ID_NEWVALUE) == 0) ? 0  : LEN_NEWVALUE,
                        ((m_nFields & ID_NEWVALUE) == 0) ? "" : TXT_NEWVALUE,
                        ((m_nFields & ID_OLDVALUE) == 0) ? 0  : LEN_OLDVALUE,
                        ((m_nFields & ID_OLDVALUE) == 0) ? 0  : LEN_OLDVALUE,
                        ((m_nFields & ID_OLDVALUE) == 0) ? "" : TXT_OLDVALUE,
                        ((m_nFields & ID_STATE)    == 0) ? 0  : LEN_STATE,
                        ((m_nFields & ID_STATE)    == 0) ? "" : TXT_STATE,
                        ((m_nFields & ID_GROUP)    == 0) ? 0  : LEN_GROUP,
                        ((m_nFields & ID_GROUP)    == 0) ? "" : TXT_GROUP);

  return m_szRecord;
} // end cn52ParamHistoryRecord :: getHeader

/*
  -------------------------------------------------------------------------
  public member function cn52ParamHistoryRecord :: setSelection
  -------------------------------------------------------------------------
*/
bool cn52ParamHistoryRecord :: setSelection(const tcn52_C1024c & aSelection) 
{
  tcn52_C1024c  szSelection = aSelection;
  bool          bOk         = true;
  _TCHAR        szToken[1024];
  _TCHAR      * pValue      = NULL;
  long          nToken      = 1;

  // init selection members
  m_szSelName.Init();
  m_szSelDate.Init();
  m_szSelGroup.Init();
  m_szSelState.Init();
  m_nFields = ID_FULL;

  // analyze tokens
  while (cn90GetToken(szSelection, szToken, nToken, 1024) && bOk) {
    pValue = _tcschr(szToken, CHAR_ASSIGN);

    if (pValue != NULL) {
      *pValue = CHAR_STRINGTERM_CN90;
      pValue++;

      if        ( _tcsicmp(szToken, KEY_NAME    ) == 0 ) {
        m_szSelName.rawAssign(pValue);
      } else if ( _tcsicmp(szToken, KEY_DATE    ) == 0 ) {
        m_szSelDate.rawAssign(pValue);
      } else if ( _tcsicmp(szToken, KEY_GROUP   ) == 0 ) {
        bOk = readStrings(pValue, m_szSelGroup);
      } else if ( _tcsicmp(szToken, KEY_STATE   ) == 0 ) {
        bOk = readStrings(pValue, m_szSelState);
      } else if ( _tcsicmp(szToken, KEY_FIELDS  ) == 0 ) { 
        bOk = readFields(pValue, m_nFields);
      } else {
        bOk = false;
      } // end if    

    } // end if

    nToken++;
  } // end while
  
  return bOk;
} // end cn52ParamHistoryRecord :: setSelection

/*
  -------------------------------------------------------------------------
  protected function cn52ParamHistoryRecord :: readFields
  -------------------------------------------------------------------------
*/
bool cn52ParamHistoryRecord :: readFields
                           ( _TCHAR       * pValue,
                             tsp00_Int4   & nFields) const
{
  _TCHAR   * pField     = pValue;
  _TCHAR   * pNextField = NULL;
  bool       bOk        = true;

  nFields = ID_EMPTY;

  while ((pField != NULL) && bOk) {

    // Terminate right entry
    pNextField = _tcschr(pField, CHAR_DELIMETER);
    if (pNextField != NULL) {
      *pNextField = CHAR_STRINGTERM_CN90;
      pNextField++;
    } // end if

    if        ( _tcsicmp(pField, TXT_DATE    ) == 0 ) {
      nFields = nFields + ID_DATE;
    } else if   ( _tcsicmp(pField, TXT_TIME    ) == 0 ) {
      nFields = nFields + ID_TIME;
    } else if   ( _tcsicmp(pField, TXT_NAME    ) == 0 ) {
      nFields = nFields + ID_NAME;
    } else if   ( _tcsicmp(pField, TXT_NEWVALUE) == 0 ) {
      nFields = nFields + ID_NEWVALUE;
    } else if   ( _tcsicmp(pField, TXT_OLDVALUE) == 0 ) {
      nFields = nFields + ID_OLDVALUE;
    } else if   ( _tcsicmp(pField, TXT_STATEFULL) == 0 ) {
      nFields = nFields + ID_STATE;
    } else if   ( _tcsicmp(pField, TXT_GROUP   ) == 0 ) {
      nFields = nFields + ID_GROUP;
    } else {
      bOk = false;
    } // end if

    pField = pNextField;
  } // end while

  return bOk;

} // end cn52ParamHistoryRecord :: readFields

/*
  -------------------------------------------------------------------------
  protected function cn52ParamHistoryRecord :: readStrings
  -------------------------------------------------------------------------
*/
bool cn52ParamHistoryRecord :: readStrings
                           ( _TCHAR       * pValue,
                             tcn52_C1024c & szString ) const
{
  _TCHAR   * pString     = pValue;
  _TCHAR   * pNextString = NULL;
  bool       bOk         = true;

  szString.Init();
  
  while ((pString != NULL) && bOk) {

    // Terminate right entry
    pNextString = _tcschr(pString, CHAR_DELIMETER);
    if (pNextString != NULL) {
      *pNextString = CHAR_STRINGTERM_CN90;
      pNextString++;
    } // end if

    strcat(szString, TXT_MARK);
    strcat(szString, pString);
    strcat(szString, TXT_MARK);

    pString = pNextString;
  } // end while

  return bOk;
} // end cn52ParamHistoryRecord :: readStrings

/*
  -------------------------------------------------------------------------
  protected function cn52ParamHistoryRecord :: analyzeRecord
  -------------------------------------------------------------------------
*/
bool cn52ParamHistoryRecord :: analyzeRecord
                           ( tcn52_C1024c & szRecord ) 
{
  bool bMatch = true;
  
  szRecord[OFF_DATE + LEN_DATE - 1]     = 0;
  szRecord[OFF_TIME + LEN_TIME - 1]     = 0;
  szRecord[OFF_NAME + LEN_NAME - 1]     = 0;
  szRecord[OFF_NEWVALUE + LEN_NEWVALUE - 1] = 0;
  szRecord[OFF_OLDVALUE + LEN_OLDVALUE - 1] = 0;
  szRecord[OFF_STATE + LEN_STATE - 1] = 0;

  m_szDate.rawAssign(cn90Strip(&szRecord[OFF_DATE]));
  m_szTime.rawAssign(cn90Strip(&szRecord[OFF_TIME]));
  m_szName.rawAssign(cn90Strip(&szRecord[OFF_NAME]));
  m_szNewValue.rawAssign(cn90Strip(&szRecord[OFF_NEWVALUE]));
  m_szOldValue.rawAssign(cn90Strip(&szRecord[OFF_OLDVALUE]));
  m_szState.rawAssign(cn90Strip(&szRecord[OFF_STATE]));
  m_szGroup.rawAssign(cn90Strip(&szRecord[OFF_GROUP]));

  if (_tcsicmp(m_szState, TXT_STATE_DELETED) == 0) {
    m_nState = StDeleted;
  } else if (_tcsicmp(m_szState, TXT_STATE_CHANGED) == 0) {
    m_nState = StChanged;
  } else if (_tcsicmp(m_szState, TXT_STATE_ACTIVE) == 0) {
    m_nState = StActive;
  } else {
    m_nState = StUnknown;
  } // end if

  if (!checkNameArray(m_szName)) {
    if (m_nState == StChanged) {
      m_nState = StActive;
      m_szState.rawAssign(TXT_STATE_ACTIVE);
    } // end if
  } // end if

  // check selcetion criteria
  if (m_szSelName.length() > 0) {
    bMatch = bMatch && (_tcsicmp(m_szSelName, m_szName) == 0);
  } // end if
  if (m_szSelDate.length() > 0) {
    bMatch = bMatch && (_tcsicmp(m_szSelDate, m_szDate) <= 0);
  } // end if
  if (m_szSelGroup.length() > 0) {
    tcn52_C1024c szLocal;
    szLocal.Init();
    strcat(szLocal, TXT_MARK);
    strcat(szLocal, m_szGroup);
    strcat(szLocal, TXT_MARK);
    bMatch = bMatch && (strstr(m_szSelGroup, szLocal) != NULL);
  } // end if
  if (m_szSelState.length() > 0) {
    tcn52_C1024c szLocal;
    szLocal.Init();
    strcat(szLocal, TXT_MARK);
    strcat(szLocal, m_szState);
    strcat(szLocal, TXT_MARK);
    bMatch = bMatch && (strstr(m_szSelState, szLocal) != NULL);
  } // end if

  return bMatch;
} // end cn52ParamHistoryRecord :: analyzeRecord

/*
  -------------------------------------------------------------------------
  protected function cn52ParamHistoryRecord :: analyzeRec178
  -------------------------------------------------------------------------
*/
bool cn52ParamHistoryRecord :: analyzeRec178
                           ( tcn52_C1024c & szRecord ) 
{
  int  nOffset  = strlen(szRecord) - LEN_RECORD_178;
  char cOffset[2];
  
  cOffset[0] = szRecord[OFF_NAME_178     + LEN_NAME_178     + nOffset - 1];
  cOffset[1] = 0;

  szRecord[OFF_DATE_178     + LEN_DATE_178               - 1] = 0;
  szRecord[OFF_TIME_178     + LEN_TIME_178               - 1] = 0;
  szRecord[OFF_NAME_178     + LEN_NAME_178     + nOffset - 1] = 0;
  szRecord[OFF_NEWVALUE_178 + LEN_NEWVALUE_178 + nOffset - 1] = 0;
  szRecord[OFF_OLDVALUE_178 + LEN_OLDVALUE_178 + nOffset - 1] = 0;
  szRecord[OFF_STATE_178    + LEN_STATE_178    + nOffset - 1] = 0;

  m_szDate.rawAssign(cn90Strip(&szRecord[OFF_DATE_178]));
  m_szTime.rawAssign(cn90Strip(&szRecord[OFF_TIME_178]));
  m_szName.rawAssign(cn90Strip(&szRecord[OFF_NAME_178]));
  if (nOffset > 0) {
    strcat(m_szName, cOffset);
  } // end if
  m_szNewValue.rawAssign(cn90Strip(&szRecord[OFF_NEWVALUE_178 + nOffset]));
  m_szOldValue.rawAssign(cn90Strip(&szRecord[OFF_OLDVALUE_178 + nOffset]));
  m_szState.rawAssign(cn90Strip(&szRecord[OFF_STATE_178 + nOffset]));
  m_szGroup.rawAssign(cn90Strip(&szRecord[OFF_GROUP_178 + nOffset]));

  if (_tcsicmp(m_szState, TXT_STATE_DELETED) == 0) {
    m_nState = StDeleted;
  } else if (_tcsicmp(m_szState, TXT_STATE_CHANGED) == 0) {
    m_nState = StChanged;
  } else if (_tcsicmp(m_szState, TXT_STATE_ACTIVE) == 0) {
    m_nState = StActive;
  } else {
    m_nState = StUnknown;
  } // end if

  return true;
} // end cn52ParamHistoryRecord :: analyzeRec178

/*
  -------------------------------------------------------------------------
  protected member function cn52ParamHistoryRecord :: initMembers
  -------------------------------------------------------------------------
*/
void cn52ParamHistoryRecord :: initMembers()
{
  m_szName.Init();
  m_szNewValue.Init();  
  m_szOldValue.Init();  
  m_nState = StUnknown;
  m_szDate.Init();  
  m_szTime.Init();  
  m_szState.Init();
  m_szDBName.Init();
  m_szGroup.Init();
  m_szRecord.Init();

  m_bFileOpen = false;

  m_hFile = 0;

  // init selection members
  m_szSelName.Init();
  m_szSelDate.Init();
  m_szSelGroup.Init();
  m_szSelState.Init();
  m_nFields = ID_FULL;

} // end cn52ParamHistoryRecord :: initMembers

/*
  -------------------------------------------------------------------------
  protected function cn52ParamHistoryRecord :: checkNameArray
  -------------------------------------------------------------------------
*/
bool cn52ParamHistoryRecord :: checkNameArray
                           ( const tcn002_XpValueName & szName ) 
{
  bool bFound     = true;
  int  nKey       = 0;
  int  nBaseKey   = 0;

  for (int i = 0; i <  szName.length(); ++i) nKey = nKey + szName[i];
  
  nKey     = (nKey * 4711) % MAX_KEYS_CN52;
  nBaseKey = nKey;

  while ( ( m_NameArray[nKey].length()                           > 0 ) &&
          ( strcmp(m_NameArray[nKey].asCharp(), szName.asCharp()) != 0 )    ) {

    ++nKey;
    nKey = nKey % MAX_KEYS_CN52;
    if (nKey == nBaseKey) break;
  } // while

  if ( m_NameArray[nKey].length() == 0 ) {
    m_NameArray[nKey] = szName;
    bFound = false;
  } // end if

  return bFound;
} // end cn52ParamHistoryRecord :: checkNameArray
