/* CLASS: VARLIBIN.CLS
  Variable server session: Instance of VarServerLib
  lastError is set by gingerbread calls, which typically return nil on failure.
  This allows such methods to return descriptors (numbers) on success.
 */!!

inherit(VarServLib, #VarLibInst, #(sessionID
radixTextColl /* for radix menu */
), 2, nil)!!

now(class(VarLibInst))!!

/* semiPRIVATE -- called by VarServLib:openSession() only */
Def new(self, hWnd)
{
  ^initialize( new(self:ancestor), hWnd )
}
!!

now(VarLibInst)!!

/* PUBLIC
   Returns 0 or nil
*/
Def changeDisplayRadix(self, radixIndex)
{
  if pcallLock(self) then
    lastError := pcall(procs[#VSCHANGERADIX], sessionID, radixIndex) ;
    pcallUNLock(self);
  else 
    lastError := ERR_PCALL_RECURSION ;
  endif ;
  if (lastError <> GOOD) then
    displayError( ErrorTextLibClass$Inst, lastError, CHECK_MODE ) ;
    ^nil
  endif;
  ^GOOD;
}!!

/* PUBLIC
   Nota Bene: openSession() is defined in VarServLib.
*/
Def closeSession(self)
{
  if open?(self)
  then
    if pcallLock(self)
    then
      lastError := pcall( procs[#VSENDSESSION], sessionID ) ;
      pcallUNLock(self);
    else 
      lastError := ERR_PCALL_RECURSION ;
    endif ;
    sessionID := nil ;
  else
    lastError := ER_VS_CLIENT_DISCREP ;  /* indicates bad session id */
  endif ;
  
  if (lastError = GOOD)
  then ^lastError /* success */
  else ^nil
  endif ;
}
!!

/* PUBLIC
  Return error code
*/
Def closeVar(self, varId)
{
  if pcallLock(self)
  then
    lastError := pcall(procs[#VSCLOSEVAR], sessionID, varId) ;
    pcallUNLock(self);
  else 
    lastError := ERR_PCALL_RECURSION ;
  endif ;
  
  if (lastError = GOOD)
  then ^lastError /* success */
  else
    displayError( ErrorTextLibClass$Inst, lastError, CHECK_MODE);
    ^nil
  endif ;
}!!

/* PUBLIC
  Return #( newFieldWidth, charsetStr ) or nil
*/
Def editFieldValue(self, varID, bufNum, lineNum, fieldWidth, fieldStr, startChar
                  | charBufRef, aStr, fieldWidthRef)
{
  fieldWidthRef := new( Struct, 4 ) ;
  putWord( fieldWidthRef, asInt(fieldWidth), 0 ) ;

  charBufRef := new( Struct, 4 ) ;
  putLong( charBufRef, asciiz(fieldStr), 0 ) ; /* pointer to string */
/*@@ break("->editFieldValue"); @@*/
  if pcallLock(self)
  then
    lastError := pcall(procs[#VSEDITVALUE], 
               asLong(sessionID), varID, asLong(bufNum), lineNum, 
               fieldWidthRef, charBufRef, asInt(startChar)) ;
    pcallUNLock(self);
  else 
    lastError := ERR_PCALL_RECURSION ;
  endif ;
/*@@ break("editFieldValue->"); @@*/

  if (lastError = GOOD)
  then
    /* string from C (pointer to) string */
    aStr := getTextFromAddress( longAt(charBufRef, 0) ) ;
/*@@  break(aStr); @@*/
    ^tuple( wordAt(fieldWidthRef, 0), aStr )
  else
    displayFormattedError(ErrorTextLibClass$Inst, 
       lastError, CHECK_MODE, nil, nil, nil);
    ^nil
  endif ;
}!!

/* PUBLIC
  Return max # lines per buffer or nil
*/
Def getLinesForVar(self, varId | numLinesRef)
{
  numLinesRef := new( Struct, 4 ) ;

  if pcallLock(self)
  then
    lastError := pcall( procs[#VSGETLINESFORVAR],
                      asLong(sessionID), asLong(varId), numLinesRef ) ;
    pcallUNLock(self);
  else 
    lastError := ERR_PCALL_RECURSION ;
  endif ;
  
  if (lastError = GOOD)
  then ^longAt( numLinesRef, 0 )
  else
    displayError( ErrorTextLibClass$Inst, lastError, CHECK_MODE) ;
    ^nil
  endif ;
}!!

/* PUBLIC
  Return max # lines per buffer or nil
*/
Def getLinesPerBuf(self | bufSizeRef)
{
  bufSizeRef := new( Struct, 4 ) ;

  if pcallLock(self)
  then
    lastError := pcall( procs[#VSGETBUFFERSIZE],
                      asLong(sessionID), bufSizeRef ) ;
    pcallUNLock(self);
  else 
    lastError := ERR_PCALL_RECURSION ;
  endif ;
  
  if (lastError = GOOD)
  then ^byteAt( bufSizeRef, 0 )
  else
    displayError( ErrorTextLibClass$Inst, lastError, CHECK_MODE);
    ^nil
  endif ;
}!!

/* PRIVATE */
Def initialize(self, hWnd | sesPtr, bufPtr)
{
  sesPtr := new( Struct, 4 ) ;
  bufPtr := new( Struct, 4 ) ;

  if pcallLock(self)
  then
    lastError := pcall( procs(VarServLibClass$Inst)[#VSSTARTSESSION], 
       hWnd, sesPtr, bufPtr ) ;
    pcallUNLock(self);
  else 
    lastError := ERR_PCALL_RECURSION ;
  endif ;

  if (lastError = GOOD) then
    sessionID := longAt(sesPtr,0) ;
    ^self
  endif;
  ^nil /* failure */
}
!!

/* PUBLIC
  Return BufferRef or nil
*/
Def newFieldValue(self, varID, bufNum, lineNum, charOffset, fieldStr
                  | displayBufRef)
{
  displayBufRef := new( Struct, 4 ) ;
/*@@ break("->newFieldValue"); /*@@*/
  if pcallLock(self)
  then
    lastError := pcall( procs[#VSNEWVALUE], 
               sessionID, varID, asLong(bufNum), asInt(lineNum), 
               asInt(charOffset), asciiz(fieldStr), displayBufRef ) ;
    pcallUNLock(self);
  else 
    lastError := ERR_PCALL_RECURSION ;
  endif ;
/*@@ break("newFieldValue->"); /*@@*/

  if (lastError = GOOD)
  then ^longAt( displayBufRef, 0 )
  else
    /* displayError( ErrorTextLibClass$Inst, lastError, CHECK_MODE) ; */
    displayFormattedError(ErrorTextLibClass$Inst, 
       lastError, CHECK_MODE, nil, nil, nil);
    ^nil
  endif ;
}!!

/* PUBLIC */
Def open?(self)
{
  ^sessionID  /* session id is nil if not a valid session */
}
!!

/* PUBLIC
  Return varId or nil
*/
Def openComponentVar(self, rootVarID, bufNum, lineNum, varStr | varIdRef)
{
  varIdRef := new( Struct, 4 ) ;

  if pcallLock(self)
  then
    lastError := pcall( procs[#VSOPENCOMPONENTVAR],
                      asLong(sessionID), asLong(rootVarID), 
                      asInt(bufNum), asInt(lineNum), 
                      asciiz(varStr), 1L, varIdRef ) ;
    pcallUNLock(self);
  else 
    lastError := ERR_PCALL_RECURSION ;
  endif ;
  
  if (lastError = GOOD)
  then
    ^longAt( varIdRef, 0 )
  else
    displayError( ErrorTextLibClass$Inst, lastError, CHECK_MODE) ;
    ^nil
  endif ;
}!!

/* PUBLIC
  Return varId or nil
*/
Def openCompositeVar(self, rootVarID, varStr, startOffset | varIdRef)
{
  varIdRef := new( Struct, 4 ) ;

  if pcallLock(self)
  then
    lastError := pcall( procs[#VSOPENCOMPOSITEVAR],
                      asLong(sessionID), asLong(rootVarID), 
                      asciiz(varStr), asInt(startOffset), 
                      1, varIdRef ) ;
    pcallUNLock(self);
  else 
    lastError := ERR_PCALL_RECURSION ;
  endif ;
  
  if (lastError = GOOD)
  then
    ^longAt( varIdRef, 0 )
  else
    displayError( ErrorTextLibClass$Inst, lastError, CHECK_MODE);
    ^nil
  endif ;
}!!

/* PUBLIC
  Return varId or nil
*/
Def openVar(self, symbolID | varIdRef)
{
  varIdRef := new( Struct, 4 ) ;

  if pcallLock(self)
  then
    lastError := pcall( procs[#VSOPENVAR],
                      sessionID, symbolID, 1, varIdRef ) ;
    pcallUNLock(self);
  else 
    lastError := ERR_PCALL_RECURSION ;
  endif ;

  if (lastError = GOOD)
  then ^longAt( varIdRef, 0 )
  else
    displayError( ErrorTextLibClass$Inst, lastError, CHECK_MODE);
   ^nil
  endif ;
}!!

/* PUBLIC
  Return BufferRef or nil
*/
Def readVar(self, varID | displayBufRef)
{
  displayBufRef := new( Struct, 4 ) ;

  if pcallLock(self)
  then
    lastError := pcall( procs[#VSREADVAR],
                      asLong(sessionID), asLong(varID), displayBufRef ) ;
    pcallUNLock(self);
  else 
    lastError := ERR_PCALL_RECURSION ;
  endif ;
  
  if (lastError = GOOD)
  then ^longAt( displayBufRef, 0 )
  else
    displayError( ErrorTextLibClass$Inst, lastError, CHECK_MODE ) ;
    ^nil
  endif ;
}!!

/* PUBLIC
  Return BufferRef or nil
*/
Def readVarAtN(self, varID, bufNum | displayBufRef)
{
  displayBufRef := new( Struct, 4 ) ;

  if pcallLock(self)
  then
    lastError := pcall(procs[#VSREADVARATNBUF], 
                     sessionID, varID, asLong(bufNum), displayBufRef) ;
    pcallUNLock(self);
  else 
    lastError := ERR_PCALL_RECURSION ;
  endif ;
  
  if (lastError = GOOD)
  then ^longAt( displayBufRef, 0 )
  else
    displayError( ErrorTextLibClass$Inst, lastError, CHECK_MODE ) ;
    ^nil
  endif ;
}!!

/* PUBLIC
   Return BufferRef or nil
*/
Def readVarAtNFromFrame(self, varID, bufNum, frameNum | displayBufRef)
{
  if pcallLock(self) then
    displayBufRef := new( Struct, 4 ) ;
    lastError := pcall(procs[#VSREADSTACKVAR],
                     sessionID, varID, 
                     asLong(bufNum), asInt(frameNum), 
                     displayBufRef) ;
    pcallUNLock(self);
  else
    lastError := ERR_PCALL_RECURSION;
  endif;

  if (lastError = GOOD) then
    ^longAt( displayBufRef, 0 )
  else
    displayError( ErrorTextLibClass$Inst, lastError, CHECK_MODE);
    ^nil
  endif ;
}!!

/* PRIVATE */
Def setIVars(self, hL, n, o, p, gNS)
{
  hLib     := hL ;
  name     := n  ;
  ordinals := o  ;
  procs    := p  ;
  globalNameSymbol := gNS ;
}
!!

/* PRIVATE
   Take a "VS_DISPLAY_BUFFER_TYPE *" and grab its text.
   Use the low-level Struct & prims for speed.
   Free the storage at longCAddress
   Return #( bufNum, continued?, size(textColl) )
*/
Def setRadixTextCol(self, longCAddress | aStruct, textLen, handle)
{
  if not(longCAddress) cor (longCAddress = 0L)
  then
    add( (radixTextColl := new(TextCollection, 1)), "" ) ;
    ^nil
  endif ;

  /* struct less the text */
  aStruct := copyFromLong( new(Struct,12), longCAddress ) ;

  /* how much text did we get? -- # chars */
  textLen := longAt( aStruct, 8 ) ;

  /* make a new TextColletion and convert the string into it */
  add( (radixTextColl := new(TextCollection, 1)), "" ) ;

  insertText( radixTextColl, 
/*removeNulls(*/ physicalString(copyFromLong(new(Struct,textLen), 
                                                (longCAddress + 12) ))
            ) ;

  /* free the C storage */
  if ((handle = wordAt(longCAddress)) <> 0)
  then
    Call GlobalFree(handle) ;
  else
    cFree( MallocLibClass$Inst, longCAddress ) ;
  endif ;

  /* Whew! */
  ^tuple( longAt(aStruct, 4), atMSB(aStruct, 2), size(radixTextColl) )
}
!!

/* PRIVATE/TEST */
Def setSessionID(self, id)
{ sessionID := id ; }
!!

/* PUBLIC
  Return symbol descriptor or nil
*/
Def symbolIDfrom(self, varID | symbolRef)
{
  symbolRef := new( Struct, 4 ) ;

  if pcallLock(self)
  then
    lastError := pcall( procs[#VSVARSYMBOL], sessionID, varID, symbolRef ) ;
    pcallUNLock(self);
  else 
    lastError := ERR_PCALL_RECURSION ;
  endif ;
  
  if (lastError = GOOD)
  then ^longAt( symbolRef, 0 )
  else
    displayError( ErrorTextLibClass$Inst, lastError, CHECK_MODE);
    ^nil
  endif ;
}!!
