/*
 * Xailer source code:
 *
 * Records.prg
 * Clase TRecords()
 *
 * Copyright 2003, 2007 Jose F. Gimenez
 * Copyright 2003, 2007 Xailer.com
 * All rights reserved
 *
 */

#include "Xailer.ch"
#include "error.ch"
#include "Dataset.ch"


//--------------------------------------------------------------------------

CLASS XRecords FROM TComponent

PUBLIC:
   DATA oDataSource  READONLY AS TDataSource
   DATA oDataSet     AS TDataSet
   DATA aStruct      INIT {}
   DATA lIsTable     INIT .F.

   METHOD Create( oDataSet, lTable ) CONSTRUCTOR
   METHOD Destroy()  // --> Self
   METHOD Open()                       VIRTUAL
   METHOD Close()                      VIRTUAL
   METHOD AddNew()                     VIRTUAL
   METHOD Edit()                       VIRTUAL
   METHOD Save()                       INLINE .T. // --> .T.
   METHOD Update()                     INLINE .F. // --> .F.
   METHOD Cancel()                     VIRTUAL
   METHOD Delete()                     VIRTUAL
   METHOD CanEdit()                    INLINE .F. // --> .F.
   METHOD CanBrowse()                  INLINE .T. // --> .T.

   METHOD FieldCount()                 INLINE Len( ::aRecord )
   METHOD FieldInfo( nField, nType )
   METHOD FieldGet( n )                VIRTUAL
   METHOD FieldPut( n, v )             VIRTUAL

   METHOD Recno()                      INLINE 0 // --> Zero
   METHOD RecCount()                   INLINE 0 // --> Zero
   METHOD Eof()                        INLINE .T. // --> .T.
   METHOD Bof()                        INLINE .T. // --> .T.
   METHOD GoTop()                      VIRTUAL
   METHOD GoBottom()                   VIRTUAL
   METHOD Goto( Value )                VIRTUAL
   METHOD Skip( n )                    VIRTUAL
   METHOD nSkip( n )                   INLINE 0 // --> Zero

   METHOD KeyCount()                   INLINE 0 // --> Zero
   METHOD KeyNo()                      INLINE 0 // --> Zero
   METHOD KeyGoto( n )                 VIRTUAL

   METHOD Refresh()                    VIRTUAL
   METHOD RefreshCurrent()             VIRTUAL

   METHOD Locate( cExp, lContinue )    VIRTUAL
   METHOD Filter( cExp )               VIRTUAL
   METHOD Sort( cExp )                 VIRTUAL
   METHOD AutoSeek( cExp )             INLINE .F. // --> .F.

   METHOD Clone()                      VIRTUAL
   METHOD Deleted()                    INLINE .F. // --> .F.
   METHOD GetRows()                    INLINE {} // --> aRows
   METHOD GetRow( nRow )               INLINE {} // --> aRow

RESERVED:
   DATA aRecord INIT {} // Valores originales en Edit e iniciales en AddNew

   METHOD CreateRecord( nLen )           INLINE ::aRecord := Array( nLen )
   METHOD ResetRecord()                  INLINE ::aRecord := {}
   METHOD InitValue( n )                 INLINE ::aRecord[ n ]

   METHOD LoadRecord( aFields )
   METHOD BlankRecord( aFields )

   METHOD GetFilterExp( oDBBrowse )      INLINE ""
   METHOD GetSeekExp( oDBBrowse, cSeek ) INLINE ""
   METHOD Commit()                       VIRTUAL
   METHOD RecLock()                      INLINE .T.
   METHOD RecUnLock()                    INLINE .T.
   METHOD RecordID( xValue )
   METHOD HasChanged( oField, xValue )   INLINE oField:HasChanged( xValue )

ENDCLASS

//--------------------------------------------------------------------------

METHOD LoadRecord( aFields ) CLASS XRecords

   LOCAL oField

   IF Len( ::aRecord ) != Len( aFields )
      ::CreateRecord( Len( aFields ) )
   ENDIF

   FOR EACH oField IN aFields
      ::aRecord[ oField:__EnumIndex() ] := oField:Load()
   NEXT

RETURN NIL

//--------------------------------------------------------------------------

METHOD BlankRecord( aFields ) CLASS XRecords

   LOCAL oField

   FOR EACH oField IN aFields
      ::aRecord[ oField:__EnumIndex() ] := oField:Blank()
   NEXT

RETURN Nil

//--------------------------------------------------------------------------

METHOD Create( oDataSet, lTable ) CLASS XRecords

   DEFAULT lTable TO .F.

   ::oDataSource  := oDataSet:oDataSource
   ::oDataSet     := oDataSet
   ::lIsTable     := lTable

RETURN Self

//--------------------------------------------------------------------------

METHOD Destroy( lFree ) CLASS XRecords

   DEFAULT lFree TO .F.

   ::Close()

   IF lFree
      ::oDataSet    := Nil
      ::oDataSource := Nil
   ENDIF

RETURN ::Super:Destroy( lFree )

//--------------------------------------------------------------------------

METHOD FieldInfo( nField, nPos ) CLASS XRecords

   LOCAL aInfo := Array( XA_FLDINFO_COUNT )

   aInfo[ XA_FLDINFO_NAME ]       := ::aStruct[ nField, XA_FLDINFO_NAME ]
   aInfo[ XA_FLDINFO_SQLTYPE ]    := ::aStruct[ nField, XA_FLDINFO_SQLTYPE ]
   aInfo[ XA_FLDINFO_BASICTYPE ]  := ::aStruct[ nField, XA_FLDINFO_BASICTYPE ]
   aInfo[ XA_FLDINFO_SQLLEN ]     := ::aStruct[ nField, XA_FLDINFO_SQLLEN ]
   aInfo[ XA_FLDINFO_BASICLEN ]   := ::aStruct[ nField, XA_FLDINFO_BASICLEN ]
   aInfo[ XA_FLDINFO_SQLDEC ]     := ::aStruct[ nField, XA_FLDINFO_SQLDEC ]
   aInfo[ XA_FLDINFO_BASICDEC ]   := ::aStruct[ nField, XA_FLDINFO_BASICDEC ]
   aInfo[ XA_FLDINFO_ALLOWSNULL ] := ::aStruct[ nField, XA_FLDINFO_ALLOWSNULL ]
   aInfo[ XA_FLDINFO_EDITABLE ]   := ::aStruct[ nField, XA_FLDINFO_EDITABLE ]
   aInfo[ XA_FLDINFO_DEFVALUE ]   := ::aStruct[ nField, XA_FLDINFO_DEFVALUE ]
   aInfo[ XA_FLDINFO_AUTOINC ]    := ::aStruct[ nField, XA_FLDINFO_AUTOINC ]
   aInfo[ XA_FLDINFO_PK ]         := ::aStruct[ nField, XA_FLDINFO_PK ]
   aInfo[ XA_FLDINFO_TABLE ]      := ::aStruct[ nField, XA_FLDINFO_TABLE ]

   IF ! Empty( nPos )
      RETURN aInfo[ nPos ]
   ENDIF

RETURN aInfo

//--------------------------------------------------------------------------
// Forma más precisa de recuperar y establecer la posición de un registro en un
// recordset, sin baserse en el Recno que realmente sólo es válido para algunos
// datasets. Este método recupera y establece el 'bookmark' en base a toda la
// información de registro, partiendo de la premisa de que no DEBE de haber dos
// registro idénticos

METHOD RecordID( xValue ) CLASS XRecords

   LOCAL aInfo
   LOCAL nAt


   IF xValue <> NIL
      nAt := AScan( ::GetRows(), {|v| CheckRow( v, xValue ) } )
      IF nAt > 0
         ::Goto( nAt )
      ENDIF
      RETURN xValue
   ENDIF

RETURN AClone( ::GetRow() )

//--------------------------------------------------------------------------

STATIC FUNCTION CheckRow( aRow, aSearch )

   LOCAL nFor, nLen

   nLen := Len( aRow )

   FOR nFor := 1 TO nLen
      IF !( aRow[ nFor ] ==  aSearch[ nFor ] )
         RETURN .F.
      ENDIF
   NEXT

RETURN .T.

//--------------------------------------------------------------------------
