#Include "Comers.Ch"
#Include "XbtCom.Ch"
#Define CRLF CHR(13) + CHR(10)
#Define ESC CHR(27)
#Define LF CHR(10)
#Define GS CHR(29)
#Define MFB CHR(128)
#Define MFE CHR(131)
#Define MFB1 CHR(129)
#Define MFB2 CHR(130)
#Define ACK CHR(6)
#Define NAK CHR(21)
#Define STX CHR(2)
#Define ETX CHR(3)
#Define FS CHR(28)

CLASS eCard
  HIDDEN
  VAR Port
  VAR Baud
  VAR cParity
  VAR Bit
  VAR nParity
  VAR Error
  VAR PosId
  VAR Ok
  METHOD Connect
  METHOD Cmd
  METHOD Lrc
  METHOD ReadData
  METHOD Send
  METHOD Read
  METHOD Cmd2Tab
  METHOD GetCrc
  METHOD GetTlv
  METHOD SetInfo
  METHOD EndTrans
  EXPORTED
  METHOD Init
  METHOD SetPort
  METHOD GetPort
  METHOD Ready
  METHOD GetError
  METHOD GetStatus
  METHOD GetPosId
  METHOD Platnosc
ENDCLASS

METHOD eCard:Init(nPort, nBaud, cParity, nBit, nParity)
::Port := IF(nPort = NIL, 1, nPort)
::Baud := IF(nBaud = NIL, 9600, nBaud)
::cParity := IF(cParity = NIL, "N", cParity)
::Bit := IF(nBit = NIL, 8, nBit)
::nParity := IF(nParity = NIL, 1, nParity)
::Error := ""
::PosId := ""
::Ok := .F.
RETURN (self)

METHOD eCard:SetPort(nPort)
::Port := nPort
RETURN (self)

METHOD eCard:GetPort()
RETURN (IF(::Ok, ::Port, 0))

METHOD eCard:Connect()
LOCAL lRet := .F., cParity := NIL
IF Dll_Func("AdvExtern.Dll", "ComOpen", ::Port)
  IF Dll_Func("AdvExtern.Dll", "ComInit", ::Port, ::Baud, cParity)
    lRet := .T.
    Dll_Func("AdvExtern.Dll", "ComSendMode", ::Port, WRITE_TIMEOUT, 100 * 15)
    Dll_Func("AdvExtern.Dll", "ComReadMode", ::Port, READ_TIMEOUT, 100 * 15)
    Dll_Func("AdvExtern.Dll", "ComSFlush", ::Port)
    Dll_Func("AdvExtern.Dll", "ComFlush", ::Port)
  ENDIF
ENDIF
RETURN (lRet)

METHOD eCard:GetError()
RETURN (::Error)

METHOD eCard:GetStatus()
LOCAL cRet := ""
cRet := "Pos ID : " + ::PosId
cRet += ", Status : " + IF(::Ok, "OK", "brak")
RETURN (cRet)

METHOD eCard:GetPosId()
RETURN (::PosId)

METHOD eCard:Ready()
LOCAL lRet := .F., aRet := {}, aLine := {}
IF ::Ok
  lRet := .T.
ELSEIF ::Connect()
  aRet := ::Send({"UP00199", "", SPACE(14)}, 3)
  IF LEN(aRet) > 0
    aLine := aRet[1]
    IF LEN(aLine) >= 4
      IF aLine[1] .AND. aLine[2] == "UP10152" .AND. aLine[3] == "00"
        lRet := .T.
        ::PosId := aLine[4]
      ENDIF
    ENDIF
  ENDIF
  Dll_Proc("AdvExtern.Dll", "ComClose", ::Port)
  IF !lRet
    ::Error := "Nieprawidłowe urządzenie"
  ENDIF
ELSE
  ::Error := "Brak możliwości otwarcia portu do komunikacji"
ENDIF
::Ok := lRet
RETURN (lRet)

METHOD eCard:SetInfo(oInfo, cText)
IF oInfo <> NIL
  oInfo:aChild[3]:SetCaption(Txt(cText))
ENDIF
RETURN (self)

METHOD eCard:Platnosc(nKwota, oInfo)
LOCAL aTlv := {}, lRet := .F., aRet := {}, aLast := {}, nSec := 0, nPos := 0
IF ::Ok .AND. ::Connect()
  AADD(aTlv, {"DF0102", StrZero(1,4)})
  AADD(aTlv, {"DF020521", StrZero(nKwota * 100, 8)})
  ::SetInfo(@oInfo, "Żądanie zapłaty")
  nSec := SECONDS() + 180
  aRet := ::Send({"UP00101", "", ::GetTlv(aTlv)}, 5)
  aLast := ACLONE(aRet)
  DO WHILE !::EndTrans(aRet)
    nPos := LEN(aRet)
    IF aRet[nPos][3] == "00"
      ::SetInfo(@oInfo, "Analiza pakietu")
    ELSEIF aRet[nPos][3] == "01"
      ::SetInfo(@oInfo, "Oczekiwanie na odczyt karty")
    ELSEIF aRet[nPos][3] == "02"
      ::SetInfo(@oInfo, "Oczekiwanie na weryfikację autentyczności")
    ELSEIF aRet[nPos][3] == "03"
      ::SetInfo(@oInfo, "Drukowanie odcinka")
    ELSEIF aRet[nPos][3] == "04"
      ::SetInfo(@oInfo, "Głosowa autoryzacja")
    ELSEIF LEFT(aRet[nPos][3], 1) == "1"
      ::SetInfo(@oInfo, "Łączenie z serwerem : próba " + RIGHT(aRet[1][2], 1))
    ENDIF
    aRet := ::Read()
    IF LEN(aRet) == 0
      IF SECONDS() < nSec
        aRet := ACLONE(aLast)
      ENDIF
    ELSE
      aLast := ACLONE(aRet)
    ENDIF
  ENDDO
  IF LEN(aRet) >= 1
    nPos := LEN(aRet)
    IF aRet[nPos][3] == "00"
      ::SetInfo(@oInfo, "Transakcja zakceptowana")
      lRet := .T.
    ELSEIF aRet[nPos][3] == "01"
      ::Error := "Transakcja odrzucona przez serwer autoryzacyjny"
    ELSEIF aRet[nPos][3] == "02"
      ::Error := "Transakcja odrzucona z powodu innej przyczyny"
    ELSEIF aRet[nPos][3] == "99"
      ::Error := "Transakcja odrzucona z powodów technicznych komunikacji"
    ELSE
      ::Error := "Transakcja odrzucona : kod błędu : " + aRet[nPos][3]
    ENDIF
    IF !lRet
      ::SetInfo(@oInfo, "Transakcja odrzucona")
    ENDIF
  ELSE
    ::Error := "Błąd transmisji z terminalem"
  ENDIF
  Dll_Proc("AdvExtern.Dll", "ComClose", ::Port)
ENDIF
RETURN (lRet)

METHOD eCard:EndTrans(aTab)
LOCAL lRet := .F., nPos := 0
IF LEN(aTab) > 0
  nPos := LEN(aTab)
  IF LEN(aTab[nPos]) >= 3
    IF aTab[nPos][2] == "UP10151"
      lRet := .T.
    ENDIF
  ELSE
    lRet := .T.
  ENDIF
ELSE
  lRet := .T.
ENDIF
RETURN (lRet)

METHOD eCard:GetTlv(aTab)
LOCAL cRet := ""
FOR Licznik := 1 TO LEN(aTab)
  cRet += aTab[Licznik][1]
  cRet += aTab[Licznik][2]
NEXT
RETURN (cRet)

METHOD eCard:Lrc(cCmd)
LOCAL cRet := "", Licznik := 0, nCheck := 0
FOR Licznik := 2 TO LEN(cCmd)
  nCheck := Dll_Func("AdvExtern.Dll", "NumericXOR", nCheck, ASC(SUBSTR(cCmd, Licznik, 1)))
NEXT
cRet := CHR(nCheck)
RETURN (cRet)

METHOD eCard:Cmd(aTab)
LOCAL cRet := STX, Licznik := 0
FOR Licznik := 1 TO LEN(aTab)
  cRet += IF(Licznik > 1, FS, "")
  cRet += aTab[Licznik]
NEXT
cRet += ETX
cRet += ::Lrc(cRet)
RETURN (cRet)

METHOD eCard:GetCrc(aTab)
LOCAL cRet := STX, Licznik := 0
FOR Licznik := 1 TO LEN(aTab)
  cRet += IF(Licznik > 1, FS, "")
  cRet += aTab[Licznik]
NEXT
cRet += ETX
cRet := ::Lrc(cRet)
RETURN (cRet)

METHOD eCard:ReadData()
LOCAL cRet := "", cRead := "", nIle := 0, lTimeOut := .T.
IF lTimeOut
  cRet := Dll_Func("AdvExtern.Dll", "ComRead", ::Port)
ELSE
  Sleep(100)
  nIle := Dll_Func("AdvExtern.Dll", "ComCount", ::Port)
  DO WHILE nIle > 0
    cRead := Dll_Func("AdvExtern.Dll", "ComRead", ::Port, nIle)
    cRet += cRead
    Sleep(10)
    nIle := Dll_Func("AdvExtern.Dll", "ComCount", ::Port)
  ENDDO
ENDIF
RETURN (cRet)

METHOD eCard:Cmd2Tab(cTxt)
LOCAL aRet := {}, nAt := 0, cCmd := "", aPom := {}, cCrc := "", aCrc := {}
DO WHILE !EMPTY(cTxt)
  IF LEFT(cTxt, 1) == STX
    cTxt := SUBSTR(cTxt, 2)
    nAt := AT(ETX, cTxt)
    nAt := IF(nAt = 0, LEN(cTxt) + 1, nAt)
    cCmd := LEFT(cTxt, nAt - 1)
    cCrc := SUBSTR(cTxt, nAt + 1, 1)
    cTxt := SUBSTR(cTxt, nAt + 2)
    IF !EMPTY(cCmd)
      aPom := {.F.}
      aCrc := {}
      nAt := AT(FS, cCmd)
      DO WHILE nAt > 0
        AADD(aPom, LEFT(cCmd, nAt - 1))
        AADD(aCrc, LEFT(cCmd, nAt - 1))
        cCmd := SUBSTR(cCmd, nAt + 1)
        nAt := AT(FS, cCmd)
      ENDDO
      IF !EMPTY(cCmd)
        AADD(aPom, cCmd)
        AADD(aCrc, cCmd)
      ENDIF
      IF LEN(aPom) > 1
        IF cCrc == ::GetCrc(aCrc)
          aPom[1] := .T.
        ENDIF
        AADD(aRet, ACLONE(aPom))
      ENDIF
    ENDIF
  ELSE
    cTxt := ""
  ENDIF
ENDDO
RETURN (aRet)

METHOD eCard:Send(aTab, nTimeOut)
LOCAL cCmd := "", nRet := 0, aRet := {}
cCmd := ::Cmd(aTab)
nRet := Dll_Func("AdvExtern.Dll", "ComSend", ::Port, cCmd)
aRet := ::Read(nTimeOut)
RETURN (aRet)

METHOD eCard:Read(nTimeOut)
LOCAL cRet := "", aRet := {}
IF nTimeOut <> NIL
  Dll_Func("AdvExtern.Dll", "ComReadMode", ::Port, READ_TIMEOUT, 100 * nTimeOut)
ENDIF
cRet := ::ReadData()
IF LEFT(cRet, 1) == ACK
  Dll_Func("AdvExtern.Dll", "ComSend", ::Port, ACK)
  cRet := SUBSTR(cRet, 2)
  aRet := ::Cmd2Tab(cRet)
ELSEIF !EMPTY(cRet)
  Dll_Func("AdvExtern.Dll", "ComSend", ::Port, ACK)
  aRet := ::Cmd2Tab(cRet)
ENDIF
RETURN (aRet)
*