Content Supported by Sourcelens Consulting

**************************************************************************
**************************************************************************
* 	Summary of Classes:
*
*	CSEngine - base engine
*
*		Setup - save environment
*		Clearnup - restore environment
*		Error - common error handling
*		Alert - displays MessageBox alert
*		GetOS - returns operating system code (see #DEFINES)
*		JustPath - returns path of file name
*		JustStem - returns stem of file name (name only with no extension)
*		JustFName - returns file name
*		ForceExt - forces file to have certain extension
*		AddBs - adds backslash (colon for Macs) to file path if needed
*		GetDBCAlias - returns DBC alias
**************************************************************************

#INCLUDE csdefs.h
******************************************************************************
DEFINE CLASS CSEngine AS custom
******************************************************************************

	* Globals
	Start = .F.				&& start app or cancel
	iHelpContextID = 0		&& used as default
	cDBCName = ""			&&DBC name
	cDBCAlias = ""			&&DBC Alias name
	cDBCTable = ""			&&DBC Table name
	SetErrorOff = .F.		&&bypass normal Error handling
	HadError = .f.			&&error occurred
	iError = -1				&&error number
	cMessage = ''			&&error message
	ThermRef = ""			&&reference to thermometer
	nCurrentOS = 0			&&operating system code
	oServer = null			&&Middle Tire Server

	DatabaseName = CS_DATABASE
	DatabaseFile = ""
	DatabaseIsOpened = .F.
	ShowOpenDatabase = .T.
	CursorAlias = ""
	CursorType = NO_CURSOR
	RowConflict = .T.
	ConflictAlias = ""
	CurrentPage = 1
    OnlineStatus = ""               
	dimension aEnvironment[1]
	
	* middle-tire server procedures
	PROCEDURE ServerStart
		this.oServer = createobj('Bizrules.Salaryrule')
		IF !this.ServerIsStarted()
			* Let's try to register the server
			RUN /N BIZRULES.EXE /RegServer
			this.oServer = createobj('Bizrules.Salaryrule')
			IF !this.ServerIsStarted()	
				this.oServer = .null.
				RETURN .F.
			ENDIF
		ENDIF
	ENDPROC

	PROCEDURE ServerStop
		this.oServer = .null.
	ENDPROC

	FUNCTION ServerIsStarted
		RETURN (TYPE('this.oServer') == 'O' AND !ISNULL(this.oServer))
	ENDFUNC

	FUNCTION ServerValidateRow
		PARAMETER llReturn
		LOCAL lcError
		PRIVATE cTitle,nSalary,dBirth,dHire,cCountry

		cTitle = Title
		nSalary = Salary
		dBirth = Birth_date
		dHire = Hire_date
		cCountry = Country

		lcError = this.oServer.validate(m.cTitle, m.nSalary, m.dBirth, m.dHire, m.cCountry)
		IF !EMPTY(m.lcError)
			this.Alert(m.lcError, MB_ICONEXCLAMATION + MB_OK, BIZRULEERROR_LOC)
			RETURN .F.
		ENDIF
		RETURN .T.
	ENDFUNC

	procedure Destroy
		this.Cleanup
	endproc
	
	procedure Init
		this.Setup()
	endproc
	
	procedure Setup
		clear program
		dimension this.aEnvironment[30, 1]
		this.aEnvironment[1,1] = SET("TALK")
		SET TALK OFF
		this.aEnvironment[2,1] = on('escape')
		this.aEnvironment[3,1] = set('escape')
		push key clear
		this.aEnvironment[4,1] = set("compatible")
		set compatible off noprompt
		this.aEnvironment[6,1] = select()
		this.aEnvironment[7,1] = set("exclusive")
		this.aEnvironment[8,1] = set("message", 1)
		this.aEnvironment[9,1] = set("safety")
		set safety off
		this.aEnvironment[10,1] = set("path")
		this.aEnvironment[12,1] = set("fields")
		set fields off
		this.aEnvironment[13,1] = set("fields", 2)
		set fields local
		this.aEnvironment[14,1] = on("error")
		this.aEnvironment[15,1] = set('point')
		this.aEnvironment[16,1] = set("deleted")
		this.aEnvironment[18,1] = SET("database")
		this.aEnvironment[19,1] = set("exact")
		set exact on
		this.aEnvironment[20,1] = set("echo")
		set echo off
		this.aEnvironment[21,1] = set("memowidth")
		this.aEnvironment[22,1] = set("udfparms")
		set udfparms to value
		this.aEnvironment[23,1] = set("near")
		set near off
		this.aEnvironment[24,1] = set("unique")
		set unique off
		this.aEnvironment[25,1] = set("ansi")
		set ansi off
		this.aEnvironment[26,1] = set("carry")
		set carry off
		this.aEnvironment[27,1] = set("cpdialog")
		set cpdialog off
		this.aEnvironment[28,1] = set("status bar")
		this.aEnvironment[29,1] = sys(5) + curdir()
		IF TYPE("m.cCSDir")="C" AND !EMPTY(m.cCSDir)
			cCSDir = THIS.justpath(m.cCSDir)
			SET DEFAULT TO (m.cCSDir)
		ENDIF
		this.aEnvironment[30,1] = set("date")

		on key label f1 oEngine.Help
		ON ERROR oEngine.Error
	endproc
	
	procedure Cleanup
		* copy this.aEnvironment to local aEnvironment so we can macro substitute directly
		local array aEnvironment[alen(this.aEnvironment,1), alen(this.aEnvironment,2)]
		=acopy(this.aEnvironment, aEnvironment)
		on key label f1
		on key
		set compatible &aEnvironment[4,1]
		select (aEnvironment[6,1])
		set exclusive &aEnvironment[7,1]
		set message to [&aEnvironment[8,1]]
		set safety &aEnvironment[9,1]
		if !empty(aEnvironment[10,1])
			set path to &aEnvironment[10, 1]
		else
			set path to
		endif
		set fields &aEnvironment[12,1]
		set fields &aEnvironment[13,1]
		on error &aEnvironment[14,1]
		set point to "&aEnvironment[15,1]"
		set deleted &aEnvironment[16,1]
		if empty(aEnvironment[18,1])
			set database to
		else
			set database to &aEnvironment[18,1]
		endif
		set exact &aEnvironment[19,1]
		set echo &aEnvironment[20,1]
		set memowidth to (aEnvironment[21,1])
		set udfparms to &aEnvironment[22,1]
		set near &aEnvironment[23,1]
		set unique &aEnvironment[24,1]
		set ansi &aEnvironment[25,1]
		set carry &aEnvironment[26,1]
		set cpdialog &aEnvironment[27,1]
		set status bar &aEnvironment[28,1]
		set default to (aEnvironment[29,1])
		set date to &aEnvironment[30,1]
		set escape &aEnvironment[3,1]
		on escape &aEnvironment[2,1]
		set talk &aEnvironment[1,1]
		pop key
	endproc
	
	PROCEDURE Error
		Parameters nError, cMethod, nLine, oObject, cMessage
		local cAction
		THIS.HadError = .T.
		this.iError = m.nError
		this.cMessage = iif(empty(m.cMessage), message(), m.cMessage)
		m.cMessage = iif(empty(m.cMessage), message(), m.cMessage)
		if type('m.oObject') = 'O' .and. .not. isnull(m.oObject) .and. at('.', m.cMethod) = 0
			m.cMethod = m.oObject.Name + '.' + m.cMethod
		endif
		
		IF this.SetErrorOff
			RETURN
		ENDIF
			
		if C_DEBUG
			do case
			case m.cAction='RETRY'
				this.HadError = .f.
				clear typeahead
				set step on
				&cAction
			case m.cAction='IGNORE'
				this.HadError = .f.
				return
			endcase
		else
			m.cAction = this.Alert(message(), MB_ICONEXCLAMATION + MB_OK)
			* m.cAction = this.Alert(ERRORMESSAGE_LOC, MB_ICONEXCLAMATION + ;
			*		MB_OK, ERRORTITLE_LOC)
		endif
	ENDPROC
	
	PROCEDURE Alert
		parameters m.cMessage, m.cOptions, m.cTitle, m.cParameter1, m.cParameter2
		private m.cOptions, m.cResponse
		m.cOptions = iif(empty(m.cOptions), 0, m.cOptions)
		if parameters() > 3 && a parameter was passed
			m.cMessage = [&cMessage]
		endif
		clear typeahead
		if !empty(m.cTitle)
			m.cResponse = MessageBox(m.cMessage, m.cOptions, m.cTitle)
		else
			m.cResponse = MessageBox(m.cMessage, m.cOptions, ALERTTITLE_LOC)
		endif
		do case
		* The strings below should not be localized
		case m.cResponse = 1
			m.cResponse = 'OK'
		case m.cResponse = 6
			m.cResponse = 'YES'
		case m.cResponse = 7
			m.cResponse = 'NO'
		case m.cResponse = 2
			m.cResponse = 'CANCEL'
		case m.cResponse = 3
			m.cResponse = 'ABORT'
		case m.cResponse = 4
			m.cResponse = 'RETRY'
		case m.cResponse = 5
			m.cResponse = 'IGNORE'
		endcase
		return m.cResponse
	ENDPROC
	
	procedure Help
		do case
		case type('_screen.ActiveForm') = 'O' .and. ;
			type('_screen.ActiveForm.HelpContextID') = 'N' .and. ;
			_screen.ActiveForm.HelpContextID <> 0
			help id (_screen.ActiveForm.HelpContextID)
		case this.iHelpContextID <> 0
			help id (this.iHelpContextID)
		otherwise
			help
		endcase
	endproc

	PROCEDURE GetOS
		DO CASE
		CASE _DOS 
			THIS.nCurrentOS = OS_DOS
		CASE _UNIX
			THIS.nCurrentOS = OS_UNIX
		CASE _MAC
			THIS.nCurrentOS = OS_MAC
		CASE ATC("Windows 3",OS(1)) # 0
			THIS.nCurrentOS = OS_W32S
		CASE ATC("Windows NT",OS(1)) # 0
			THIS.nCurrentOS = OS_NT
		OTHERWISE
			THIS.nCurrentOS = OS_WIN95
		ENDCASE
	ENDPROC

	FUNCTION JustPath
		* Returns just the pathname.
		LPARAMETERS m.filname
		LOCAL cdirsep
		cdirsep = IIF(_mac,':','\')
		m.filname = SYS(2027,ALLTRIM(UPPER(m.filname)))
		IF m.cdirsep $ m.filname
		   m.filname = SUBSTR(m.filname,1,RAT(m.cdirsep,m.filname))
		   IF RIGHT(m.filname,1) = m.cdirsep AND LEN(m.filname) > 1 ;
		            AND SUBSTR(m.filname,LEN(m.filname)-1,1) <> ':'
		         filname = SUBSTR(m.filname,1,LEN(m.filname)-1)
		   ENDIF
		   RETURN m.filname
		ELSE
		   RETURN ''
		ENDIF
	ENDFUNC
	
	FUNCTION ForceExt
		* Force filename to have a particular extension.
		LPARAMETERS m.filname,m.ext
		LOCAL m.ext
		IF SUBSTR(m.ext,1,1) = "."
		   m.ext = SUBSTR(m.ext,2,3)
		ENDIF
		m.pname = THIS.justpath(m.filname)
		m.filname = THIS.justfname(UPPER(ALLTRIM(m.filname)))
		IF AT('.',m.filname) > 0
		   m.filname = SUBSTR(m.filname,1,AT('.',m.filname)-1) + '.' + m.ext
		ELSE
		   m.filname = m.filname + '.' + m.ext
		ENDIF
		RETURN THIS.addbs(m.pname) + m.filname
	ENDFUNC
	
	FUNCTION JustFname
		* Return just the filename (i.e., no path) from "filname"
		LPARAMETERS m.filname
		LOCAL clocalfname, cdirsep
		clocalfname = SYS(2027,m.filname)
		cdirsep = IIF(_mac,':','\')
		IF RAT(m.cdirsep ,m.clocalfname) > 0
		   m.clocalfname= SUBSTR(m.clocalfname,RAT(m.cdirsep,m.clocalfname)+1,255)
		ENDIF
		IF AT(':',m.clocalfname) > 0
		   m.clocalfname= SUBSTR(m.clocalfname,AT(':',m.clocalfname)+1,255)
		ENDIF
		RETURN ALLTRIM(UPPER(m.clocalfname))
	ENDFUNC

	FUNCTION AddBS
		* Add a backslash unless there is one already there.
		LPARAMETER m.pathname
		LOCAL m.separator
		m.separator = IIF(_MAC,":","\")
		m.pathname = ALLTRIM(UPPER(m.pathname))
		IF !(RIGHT(m.pathname,1) $ '\:') AND !EMPTY(m.pathname)
		   m.pathname = m.pathname + m.separator
		ENDIF
		RETURN m.pathname
	ENDFUNC

	FUNCTION JustStem
		* Return just the stem name from "filname"
		LPARAMETERS m.filname
		IF RAT('\',m.filname) > 0
		   m.filname = SUBSTR(m.filname,RAT('\',m.filname)+1,255)
		ENDIF
		IF RAT(':',m.filname) > 0
		   m.filname = SUBSTR(m.filname,RAT(':',m.filname)+1,255)
		ENDIF
		IF AT('.',m.filname) > 0
		   m.filname = SUBSTR(m.filname,1,AT('.',m.filname)-1)
		ENDIF
		RETURN ALLTRIM(UPPER(m.filname))
	ENDFUNC

	FUNCTION justext
		* Return just the extension from "filname"
		PARAMETERS m.filname
		LOCAL m.ext
		m.filname = this.justfname(m.filname)   && prevents problems with ..\ paths
		m.ext = ""
		IF AT('.', m.filname) > 0
		   m.ext = SUBSTR(m.filname, AT('.', m.filname) + 1, 3)
		ENDIF
		RETURN UPPER(m.ext)
	ENDFUNC

	PROCEDURE GetDbcAlias
		* Takes the current DBC and gets its alias name
		* cDBC - DBC name passed if not current DBC()
		LPARAMETER cDBC
		LOCAL aDBCtmp,cGetDBC,nPos
		IF TYPE("m.cDBC") # "C"
			m.cDBC  =""
		ENDIF
		IF EMPTY(m.cDBC) AND EMPTY(DBC()) 
			RETURN ""
		ENDIF
		m.cGetDBC = IIF(EMPTY(m.cDBC),DBC(),UPPER(m.cDBC))
		DIMENSION aDBCtmp[1,2]
		=ADATA(aDBCtmp)
		m.nPos = ASCAN(aDBCtmp,m.cGetDBC)
	RETURN IIF(m.nPos = 0,"",aDBCtmp[m.nPos-1])
	ENDPROC
	
	FUNCTION TableExists
		PARAMETERS lcTableName
		LOCAL dummy, lcSQuote
		*Checks to see if a table of the same name already exists on the server	
		dummy='x'
		lcSQuote=CHR(39)
			lcSQL="select uid from sysobjects where uid = user_id() and name =" + lcSQuote + lcTableName + lcSQuote
			lcField="uid"
		RETURN this.ExecuteTempSPT(lcSQL)
	ENDFUNC
		
	FUNCTION SingleValueSPT
		PARAMETERS lcSQL, lcReturnValue, lcFieldName, llReturnedOneValue
		LOCAL lcMsg, lcErrMsg, llRetVal, lcCursor, lnOldArea, lnServerError
		* Executes a server query and sees if it return one value or not
		* If it returns one value, that value gets placed in a variable passed by reference		
		lnOldArea=select()
		lcCursor=this.UniqueCursorName("_spt")
		SELECT 0
		IF this.ExecuteTempSPT(lcSQL,@lnServerError,@lcErrMsg,lcCursor) THEN
			IF RECCOUNT(lcCursor)=0 THEN
				llReturnedOneValue= .F.
			ELSE
				lcReturnValue=&lcCursor..&lcFieldName
				llReturnedOneValue=.T.
			ENDIF
			USE
		ELSE
			lcMsg=STRTRAN(QUERY_FAILURE_LOC,"|1",LTRIM(STR(lnServerError)))
			=MESSAGEBOX(lcMsg,ICON_EXCLAMATION,TITLE_TEXT_LOC)
			this.Die
			RETURN
		ENDIF
		SELECT (lnOldArea)
		RETURN llReturnedOneValue
	ENDFUNC
	
	FUNCTION DropTable
		PARAMETERS lcTable
		LOCAL lcSQL
		lcSQL="drop table " + RTRIM(this.UserName) + "." + RTRIM(lcTable)
		lnRetVal=this.ExecuteTempSPT(lcSQL)
		RETURN lnRetVal
	ENDFUNC
	
	FUNCTION ExecuteTempSPT
		parameters lcSQL, lnServerError, lcErrMsg, lcCursor
		LOCAL nRetVal, lcMsg
		
		nRetVal=SQLEXEC(this.MasterConnHand,lcSQL)
	
		DO CASE
			*Success
			CASE nRetVal=1 
				lnServerError=0
				lcErrMsg=""
				RETURN .T.
			
			*Server error occurred
			CASE nRetVal=-1
				=AERROR(aErrArray)
				lnServerError=aErrArray[1]
				lcErrMsg=aErrArray[2]
				
				IF lnServerError=1526 AND !ISNULL(aErrArray[5])THEN
					lnServerError=aErrArray[5]
				ENDIF
				
			
			*Connection level error occurred
			CASE nRetVal=-2
				*This is trouble; continue to generate script if user wants; otherwise bail
				lcMsg=STRTRAN(CONNECT_FAILURE_LOC,"|1",LTRIM(STR(lnServerErr)))
				=MESSAGEBOX(lcMsg,ICON_EXCLAMATION,TITLE_TEXT_LOC)
	
		ENDCASE
	ENDFUNC

ENDDEFINE