HEX
Server: Microsoft-IIS/10.0
System: Windows NT ITPWINWEBSVR22 10.0 build 20348 (Windows Server 2022) AMD64
User: www.conferencesearch.co.uk (0)
PHP: 8.3.30
Disabled: NONE
Upload Files
File: D:/web/itpartnership/radphp/rpcl/db.inc.php
<?php
/**
*  This file is part of the RPCL project
*
*  Copyright (c) 2004-2011 Embarcadero Technologies, Inc.
*
*  Checkout AUTHORS file for more information on the developers
*
*  This library is free software; you can redistribute it and/or
*  modify it under the terms of the GNU Lesser General Public
*  License as published by the Free Software Foundation; either
*  version 2.1 of the License, or (at your option) any later version.
*
*  This library 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
*  Lesser General Public License for more details.
*
*  You should have received a copy of the GNU Lesser General Public
*  License along with this library; if not, write to the Free Software
*  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
*  USA
*
*/

use_unit("classes.inc.php");
use_unit("rtl.inc.php");

define('daFail','daFail');
define('daAbort','daAbort');


/**
 * Encapsulates a table field
 *
 * This class is used to encapsulate the name of a table field and the caption
 * to be shown on data-aware component.
 *
 */
class Field extends Object
{
        private $_fieldname;
        private $_displaylabel;

        /**
        * Indicates the name of the physical column in the underlying table or query result to which a field component is bound.
        *
        * Use FieldName to specify which field in the underlying dataset the field component represents. FieldName is used when
        * displaying references to the field to users, unless a DisplayLabel has been set.
        *
        * @see getDisplayLabel()
        * @return string
        */
        function getFieldName() { return $this->_fieldname;     }
        function setFieldName($value) { $this->_fieldname=$value; }

        /**
        * Contains the text to display in the corresponding column heading of a data grid.
        *
        * Use DisplayLabel to assign column headings to a data grid. The column headings of the data grid use
        * the DisplayName property of the field whose value they represent. Setting DisplayLabel changes the
        * read-only DisplayName property from FieldName to the string specified as DisplayLabel.
        *
        * @see getFieldName()
        * @return string
        */
        function getDisplayLabel() { return $this->_displaylabel;       }
        function setDisplayLabel($value) { $this->_displaylabel=$value; }
}

/**
 * CustomConnection, a common ancestor for all Connection objects
 *
 * A connection must represent the object which through data objects (tables, queries, etc) perform
 * their operations. Components like Database inherit from CustomConnection and implement the right
 * functionality.
 *
 */
class CustomConnection extends Component
{

    protected $_datasets=null;
    protected $_fstreamedconnected=false;

    /**
    * Provides an indexed array of all active datasets for a database component.
    *
    * Use DataSets to access active datasets associated with a database component. An active dataset is one that is currently open.
    *
    * @see readClients()
    * @return Collection
    */
    function readDataSets() { return $this->_datasets; }
    function writeDataSets($value) { $this->_datasets=$value; }
    function defaultDataSets() { return null; }

    protected $_clients=null;

    /**
    * Returns the fieldnames for the table
    *
    * Use this method to get an array with the fieldnames for an specific table.
    * This method can be useful if you want to explore the structure of a table.
    *
    * @param string $tablename Table to get the fields for
    *
    * @return array Array with fieldnames for $tablename
    */
    function MetaFields($tablename)
    {
    }

    /**
    * Begins a new transaction against the database server.
    *
    * Call BeginTrans to begin a new transaction against the database server.
    *
    * Updates, insertions, and deletions that take place after a call to StartTransaction
    * are held by the server until an application calls CompleteTrans with true to commit the changes
    * or false to Rollback
    *
    * @see completeTrans()
    */
    function BeginTrans()
    {
        //To be overriden
    }

    /**
    * Permanently stores updates, insertions, and deletions of data associated with
    * the current transaction, and ends the current transactions, but
    * if false is sent in the autocomplete parameter, then a rollback is performed
    * and then Cancels all updates, insertions, and deletions for the current
    * transaction and ends the transaction.
    *
    * Call CompleteTrans to permanently store to the database server all updates,
    * insertions, and deletions of data associated with the current transaction and
    * then end the transaction. The current transaction is the last transaction
    * started by calling BeginTrans.
    *
    * If you send false on the autocomplete parameter, then it cancels all updates,
    * insertions, and deletions for the current transaction and to end the transaction.
    * The current transaction is the last transaction started by calling BeginTrans.
    *
    * @see beginTrans()
    *
    * @param bool $autocomplete If true, the transaction will be commited, if false, will be rolled back
    * @return bool
    */
    function CompleteTrans($autocomplete=true)
    {
        //To be overriden
    }



    /**
    * Send a connect event to all the datasets, both for connecting and disconnecting
    *
    * This is an internal method used to fire a dataset connect event to all attached
    * datasets.
    *
    * @see DataSet::dataEvent()
    *
    * @param $connecting boolean specifies the status of the connection
    */
    function SendConnectEvent($connecting)
    {
        for($i=0;$i<=$this->_clients->count()-1;$i++)
        {
            $client=$this->_clients->items[$i];
            if ($client->inheritsFrom('DataSet'))
            {
                $client->DataEvent(deConnectChange, $connecting);
            }
        }
    }

    /**
    * Returns a date formatted to be used on this database, depending on the type
    *
    * You must use this method to get a data formatted in a valid format depending
    * on the type of database.
    *
    * @see param(), quoteStr()
    *
    * @param string $input Date to convert
    * @return string Date converted to a valid format
    */
    function DBDate($input)
    {
        return($input);
    }

    /**
    * Sends a query to the server for optimization prior to execution.
    *
    * Call Prepare to have a remote database server allocate resources for the
    * query and to perform additional optimizations.
    *
    * If the query will only be executed once, the application does not need to
    * explicitly call Prepare. Executing an unprepared query generates these
    * calls automatically. However, if the same query is to be executed repeatedly,
    * it is more efficient to prevent these automatic calls by calling Prepare
    * explicitly.
    *
    * @param string $query SQL sentence to be prepared
    */
    function Prepare($query)
    {

    }

    /**
    * Returns a parameter formatted depending on the database type
    *
    * When writting parametrized queries, use this method to get a parameter formatted
    * in a valid format for the current database type.
    *
    * @see DBDate(), QuoteStr()
    *
    * @param string $input Parameter name
    * @return string $input converted to a valid parameter
    */
    function Param($input)
    {
        return($input);
    }

    /**
    * Quote a string depending on the database type
    *
    * When writting queries, use this method to get a string quoted in a format
    * valid for the current database type.
    *
    * @see param(), dbDate()
    *
    * @param string $input String to quote
    * @return string $input quoted with valid quotes
    */
    function QuoteStr($input)
    {
        return($input);
    }

    /**
    * Returns the clients of this database
    *
    * @see readDatasets()
    *
    * @return Collection
    */
    function readClients() { return $this->_clients; }
    function writeClients($value) { $this->_clients=$value; }
    function defaultClients() { return null; }

    protected $_onafterconnect=null;

    /**
    * Occurs after a connection is established.
    *
    * Write an OnAfterConnect event handler to take application-specific
    * actions immediately after the connection component opens a connection to
    * the remote source of database information.
    *
    * @see readConnected(), readOnBeforeConnect()
    *
    * @return mixed
    */
    function readOnAfterConnect() { return $this->_onafterconnect; }
    function writeOnAfterConnect($value) { $this->_onafterconnect=$value; }
    function defaultOnAfterConnect() { return null; }

    protected $_onbeforeconnect=null;

    /**
    * Occurs immediately before establishing a connection.
    *
    * Write a OnBeforeConnect event handler to take application-specific actions
    * before the connection component opens a connection to the remote source of
    * database information.
    *
    * @see readConnected(), readOnAfterConnect()
    *
    * @return mixed
    */
    function readOnBeforeConnect() { return $this->_onbeforeconnect; }
    function writeOnBeforeConnect($value) { $this->_onbeforeconnect=$value; }
    function defaultOnBeforeConnect() { return null; }

    protected $_oncustomconnect=null;

    function getOnCustomConnect() { return $this->_oncustomconnect; }
    function setOnCustomConnect($value) { $this->_oncustomconnect=$value; }
    function defaultOnCustomConnect() { return null; }

    protected $_onafterdisconnect=null;

    /**
    * Occurs after the connection closes.
    *
    * Write an OnAfterDisconnect event handler to take application-specific
    * actions after the connection component drops a connection.
    *
    * @see readConnected(), readOnBeforeDisconnect()
    *
    * @return mixed
    */
    function readOnAfterDisconnect() { return $this->_onafterdisconnect; }
    function writeOnAfterDisconnect($value) { $this->_onafterdisconnect=$value; }
    function defaultOnAfterDisconnect() { return null; }

    protected $_onbeforedisconnect=null;

    /**
    * Occurs immediately before the connection closes.
    *
    * Write a BeforeDisconnect event handler to take application-specific actions
    * before dropping a connection.
    *
    * @see readConnected(), readOnAfterDisconnect()
    *
    * @return mixed
    */
    function readOnBeforeDisconnect() { return $this->_onbeforedisconnect; }
    function writeOnBeforeDisconnect($value) { $this->_onbeforedisconnect=$value; }
    function defaultOnBeforeDisconnect() { return null; }

    protected $_onlogin=null;

    /**
    * Occurs when an application connects to a database.
    *
    * Write an OnLogin event handler to take specific actions when an application
    * attempts to connect to a database.
    *
    * If there is no OnLogin event handler, the current UserName and Password are the ones used
    * from the UserName and UserPassword properties.
    *
    * These values are then passed to the remote server.
    *
    * @return mixed
    */
    function readOnLogin() { return $this->_onlogin; }
    function writeOnLogin($value) { $this->_onlogin=$value; }
    function defaultOnLogin() { return null; }

        function __construct($aowner=null)
        {
                //Calls inherited constructor
                parent::__construct($aowner);

                $this->_datasets=new Collection();
                $this->_clients=new Collection();
        }

        /**
        * Opens the connection.
        *
        * Call Open to establish a connection to the remote source of database information.
        * Open sets the Connected property to true.
        *
        * @see readConnected(), close()
        */
        function Open()
        {
            $this->Connected=true;
        }


        /**
        * Closes the connection.
        *
        * Call Close to disconnect from the remote source of database information.
        * Before the connection component is deactivated, all associated datasets are
        * closed. Calling Close is the same as setting the Connected property to false.
        *
        * @see readConnected(), open()
        */
        function Close()
        {
            $this->Connected=false;
        }


        function loaded()
        {
                parent::loaded();
                if ($this->_fstreamedconnected)
                {
                    $this->Connected=true;
                }
        }

        /**
        * Determines whether a connection has been established to the remote source of data.
        *
        * Set Connected to true to open the connection. Set Connected to false to terminate the connection.
        *
        * Setting Connected to true generates a OnBeforeConnect event, calls the protected
        * DoConnect method to establish the connection, and generates an OnAfterConnect event.
        * In addition, when setting Connected to true.
        *
        * Setting Connected to false generates a OnBeforeDisconnect event, calls the protected
        * DoConnect method to drop the connection, and generates an OnAfterDisconnect event.
        *
        * When deriving custom connection components from CustomConnection, override readConnected to return
        * true when a connection is established, and override DoConnect and DoDisconnect to create and drop
        * the connection.
        *
        * @see Open(), Close()
        * @return boolean
        */
        function readConnected() { return "0"; }
        function writeConnected($value)
        {
            if (($this->ControlState & csLoading)==csLoading)
            {
                $this->_fstreamedconnected=$value;
            }
            else
            {
                if ($value == $this->readConnected())
                {
                }
                else
                {
                    if ($value)
                    {
                        $this->callEvent("onbeforeconnect",array());
                        $this->DoConnect();
                        $this->SendConnectEvent(true);
                        $this->callEvent("onafterconnect",array());
                    }
                    else
                    {
                        $this->callEvent("onbeforedisconnect",array());
                        $this->SendConnectEvent(false);
                        $this->DoDisconnect();
                        $this->callEvent("onafterdisconnect",array());
                    }
                }
            }
        }
        function defaultConnected() { return "0"; }

        /**
        * Provides the interface for a method that opens a connection.
        *
        * The Connected property uses DoConnect to establish a connection.
        * Descendant classes override the DoConnect method to establish their
        * connection as appropriate. As implemented in CustomConnection,
        * DoConnect does nothing.
        *
        * @see open(), close(), readConnected()
        */
        function DoConnect()
        {
            //Override this
        }

        /**
        * Provides the interface for a method that terminates the connection.
        *
        * The Connected property uses DoDisconnect to close a connection.
        * Descendant classes override the DoDisconnect method to drop a connection.
        * As implemented in CustomConnection, DoDisconnect does nothing.
        *
        * @see open(), close(), readConnected()
        */
        function DoDisconnect()
        {
            //Override this
        }
}


define('deFieldChange',1);
define('deRecordChange',2);
define('deDataSetChange',3);
define('deDataSetScroll',4);
define('deLayoutChange',5);
define('deUpdateRecord',6);
define('deUpdateState',7);
define('deCheckBrowseMode',8);
define('dePropertyChange',9);
define('deFieldListChange',10);
define('deFocusControl',11);
define('deParentScroll',12);
define('deConnectChange',13);
define('deReconcileError',14);
define('deDisabledStateChange',15);

define('dsInactive'    ,1);
define('dsBrowse'      ,2);
define('dsEdit'        ,3);
define('dsInsert'      ,4);
define('dsSetKey'      ,5);
define('dsCalcFields'  ,6);
define('dsFilter'      ,7);
define('dsNewValue'    ,8);
define('dsOldValue'    ,9);
define('dsCurValue'    ,10);
define('dsBlockRead'   ,11);
define('dsInternalCalc',12);
define('dsOpening'     ,13);

/**
* Exception for a DatabaseError
*
* This exception is raised whenever a data access component generates an error.
*
* @see DatabaseError
*/
class EDatabaseError extends Exception { }

/**
* Function to raise a Database Error
*
* Call DatabaseError to raise an EDatabaseError exception, using Message as the text for the exception.
* If a component is provided as the second parameter, the message is prefixed by the name of the component to help
* in interpreting the error message.
*
* Calling DatabaseError rather than creating and raising the exception directly in code reduces the overall code size of the application.
*
* @see EDatabaseError
*
* @param string $message Message of the exception to show
* @param Component $component Component is raising the exception
*/
function databaseError($message, $component=null)
{
  if ((assigned($component)) && ($component->Name != ''))
  {
    throw new EDatabaseError(sprintf('%s: %s', $component->Name, $message));
  }
  else
  {
    throw new EDatabaseError($message);
  }
}

/**
* DataSet component, base class to inherit and create dataset components
*
* A DataSet is a collection of information, organized in rows and fields, and this class
* implement the basic interface all data-aware components will use to show information.
*
* A DataSet is not attached to an specific source of information, you can, for example, create a
* DataSet that provide information from a memory array.
*
*/
class DataSet extends Component
{
        protected $_limitstart='0';
        protected $_limitcount='10';

        /**
        * Defines the starting record to filter the dataset with
        *
        * Use this property to filter the dataset and to set which is the first
        * record to be added to the set.
        *
        * @see getLimitCount()
        *
        * @return integer
        */
        function getLimitStart() { return $this->_limitstart;   }
        function setLimitStart($value) { $this->_limitstart=$value;     }
        function defaultLimitStart() { return "0"; }

        /**
        * Defines how many records will be shown
        *
        * Use this property to set how many records do you want to get on the
        * set, at max.
        *
        * @see getLimitStart()
        *
        * @return integer
        */
        function getLimitCount() { return $this->_limitcount;   }
        function setLimitCount($value) { $this->_limitcount=$value; }
        function defaultLimitCount() { return "10"; }

        /**
        * Override this method to perform the closing of the dataset
        *
        * This method is called internally by the engine to close the dataset.
        * Is not intended to be called directly the component user.
        *
        * @see Close()
        *
        */
        function internalClose() {}

        /**
        * Override this method to handle exceptions
        *
        * This method is called internally by the engine to handle an exception using
        * the dataset.
        *
        * Is not intended to be called directly the component user.
        */
        function internalHandleException() {}

        /**
        * Override this method to init field definitions. Not used.
        */
        function internalInitFieldDefs() {}

        /**
        * Override this method to perform the opening of the dataset
        *
        * This method is called internally by the engine to open the dataset.
        * Is not intended to be called directly the component user.
        *
        * @see open()
        *
        */
        function internalOpen() {}

        /**
        * Override this method to return if the cursor is open or not
        *
        * This method is called internally by the engine to determine if the cursor
        * is open or not.
        *
        * Is not intended to be called directly the component user.
        *
        * @return boolean True if cursor is open
        */
        function isCursorOpen() {}

        /**
        * This property returns an array with the field names and values
        *
        * Use Fields to access fields that make up this dataset.
        * The order of field components in Fields corresponds directly to the
        * order of columns in the table or tables underlying a dataset.
        *
        * Accessing fields with the Fields property is useful for applications that:
        *
        * Iterate over some or all fields in a dataset.
        *
        * Work with underlying tables whose internal data structure is unknown at runtime.
        *
        * If an application knows the data types of individual fields, then it can read
        * or write individual field values through the Fields property.
        *
        * @return array
        */
        function readFields() { return array(); }

        /**
        * Indicates the number of field components associated with the dataset.
        *
        * Examine FieldCount to determine the number of fields listed by the Fields property.
        *
        * @return integer
        */
        function readFieldCount() { return 0; }

        /**
        * Buffer to hold values for searching/filtering
        */
        public $fieldbuffer=array();

        protected $_recordcount=0;
        protected $_state=dsInactive;
        protected $_modified=false;
        protected $_InternalOpenComplete=false;
        protected $_DefaultFields=false;
        protected $_DisableCount=0;

        protected $_datasetfield=null;

        /**
        * Indicates the persistent DataSetField object that owns a nested dataset.
        *
        * Not used.
        *
        * @return Field
        */
        function readDataSetField() { return $this->_datasetfield; }
        function writeDataSetField($value) { $this->_datasetfield=$value; }
        function defaultDataSetField() { return null; }

        /**
        * Indicates the current operating mode of the dataset.
        *
        * Examine State to determine the current operating mode of the dataset.
        * State determines what can be done with data in a dataset, such as editing
        * existing records or inserting new ones. The dataset state constantly changes
        * as an application processes data.
        *
        * Opening a dataset changes State from dsInactive to dsBrowse. An application
        * can call Edit to put a dataset into dsEdit state, or call Insert to put a
        * dataset into dsInsert state.
        *
        * Posting or canceling edits, insertions, or deletions, changes State from
        * its current state to dsBrowse. Closing a dataset changes its state to dsInactive.
        *
        * @return enum
        */
        function readState() { return $this->_state; }
        function writeState($value) { $this->_state=$value; }
        function defaultState() { return dsInactive; }

        protected $_mastersource=null;

        protected $_masterfields=array();

        /**
        * Specifies one or more fields in a master table to link with corresponding
        * fields in this table in order to establish a master-detail relationship
        * between the tables.
        *
        * Use MasterFields after setting the MasterSource property to specify the
        * names of one or more fields to use in establishing a detail-master
        * relationship between this table and the one specified in MasterSource.
        *
        * MasterFields is an array containing one or more field names in the master table.
        *
        * Each time the current record in the master table changes, the new values in
        * those fields are used to select corresponding records in this table for display.
        *
        * @see readMasterSource()
        *
        * @return array
        */
        function readMasterFields() { return $this->_masterfields; }
        function writeMasterFields($value) { $this->_masterfields=$value; }
        function defaultMasterFields() { return array(); }

        /**
        * Specifies the name of the data source for a dataset to use as a master
        * table in establishing a detail-master relationship between this table and another one.
        *
        * Use MasterSource to specify the name of the data source component whose DataSet
        * property identifies a dataset to use as a master table in establishing a detail-master
        * relationship between this table and another one.
        *
        * Note: At design time choose an available data source from the MasterSource property�s
        * drop-down list in the Object Inspector.
        *
        * After setting the MasterSource property, specify which fields to use in the master
        * table by setting the MasterFields property. At runtime each time the current record
        * in the master table changes, the new values in those fields are used to select corresponding
        * records in this table for display.
        *
        * @see readMasterFields()
        *
        * @return DataSource
        */
        function readMasterSource() { return $this->_mastersource;   }
        function writeMasterSource($value)
        {
                $this->_mastersource=$this->fixupProperty($value);
        }

        protected $_recno=0;

        /**
        * Indicates the current record in the dataset.
        *
        * Examine RecNo to determine the record number of the current record in the dataset.
        * Applications might use this property with RecordCount to iterate through all
        * the records in a dataset, though typically record iteration is handled with calls
        * to First, Last, MoveBy, Next, and Prior.
        *
        * @see readRecKey()
        *
        * @return integer
        */
        function readRecNo() { return $this->_recno; }
        function writeRecNo($value)
        {
            if ($value!=$this->_recno)
            {
                $diff=$value-$this->_recno;
                if ($diff>0)
                {
                    $this->MoveBy($diff);
                }
                $this->_recno=$value;
            }
        }
        function defaultRecNo() { return 0; }

        protected $_reckey=array();

        /**
        * Specifies the record key for this dataset
        *
        * This property specifies the fields and values that determine
        * the key of a record.
        *
        * @see readRecNo()
        *
        * @return array
        */
        function readRecKey() { return $this->_reckey; }
        function writeRecKey($value) { $this->_reckey=$value; }
        function defaultRecKey() { return ""; }

        function serialize()
        {
                parent::serialize();

                $owner = $this->readOwner();
                if ($owner != null)
                {
                        $prefix = $owner->readNamePath().".".$this->_name.".";
                        $_SESSION[$prefix."State"] = $this->_state;
//                        $_SESSION[$prefix."FieldBuffer"] = serialize($this->fieldbuffer);
//                        if (!empty($this->_regkey))
//                        {
//                            $_SESSION[$prefix."RegKey"] = serialize($this->_regkey);
//                        }
//                        $_SESSION[$prefix."RegKey"] = serialize($this->_regkey);
//                        $_SESSION[$prefix."RecNo"] = $this->_recno;
                }
        }

        function unserialize()
        {
                parent::unserialize();
                $owner = $this->readOwner();
                if ($owner != null)
                {
                        $prefix = $owner->readNamePath().".".$this->_name.".";
                        if (isset($_SESSION[$prefix."State"])) $this->_state= $_SESSION[$prefix."State"];
//                        if (isset($_SESSION[$prefix."FieldBuffer"])) $this->fieldbuffer= unserialize($_SESSION[$prefix."FieldBuffer"]);
//                        if (isset($_SESSION[$prefix."RegKey"])) $this->_regkey= unserialize($_SESSION[$prefix."RegKey"]);
//                        if (isset($_SESSION[$prefix."RecNo"]))
//                        {
//                            $this->RecNo= $_SESSION[$prefix."RecNo"];
//                        }
                }
        }

        /**
        * Indicates whether the active record is modified.
        *
        * Check Modified to determine if the active record is modified. If Modified
        * is true, the active record is modified. If false, the active record is not modified.
        *
        * Note: In general, an application need not check the status of Modified.
        * Properties, events, and methods of TDataSet and its descendants that modify records
        * generally check this status automatically and take appropriate actions based on its value.
        *
        * @see redCanModify()
        *
        * @return boolean
        */
        function readModified() { return $this->_modified; }
        function writeModified($value) { $this->_modified=$value; }
        function defaultModified() { return false; }

        protected $_canmodify=true;

        /**
        * Indicates whether an application can insert, edit, and delete data in a table.
        *
        * Check the status of CanModify to determine if an application can modify a
        * dataset in any way. If CanModify is true, the dataset can be modified. If
        * CanModify is false, the table is read-only.
        *
        * CanModify is set automatically when an application opens a table. If the ReadOnly
        * property of a table component is true, then CanModify is set to false.
        *
        * Note: Even if CanModify is true, it is not a guarantee that a user will be able
        * to insert or update records in a table. Other factors may come in to play,
        * for example, SQL access privileges.
        *
        * @see readModified()
        *
        * @return boolean
        */
        function readCanModify() { return $this->_canmodify; }
        function writeCanModify($value) { $this->_canmodify=$value; }
        function defaultCanModify() { return true; }

        protected $_onbeforeopen=null;

        /**
        * Occurs before an application executes a request to open a dataset.
        *
        * Write a OnBeforeOpen event handler to take specific action before an
        * application opens a dataset for viewing or editing. OnBeforeOpen is
        * triggered when an application sets the Active property to true for
        * a dataset or an application calls Open.
        *
        * @see readOnAfterOpen()
        *
        * @return mixed
        */
        function readOnBeforeOpen() { return $this->_onbeforeopen; }
        function writeOnBeforeOpen($value) { $this->_onbeforeopen=$value; }
        function defaultOnBeforeOpen() { return null; }

        protected $_onafteropen=null;

        /**
        * Occurs after an application completes opening a dataset and before any data access occurs.
        *
        * Write an AfterOpen event handler to take specific action immediately after an
        * application opens the dataset. AfterOpen is called after the dataset establishes
        * access to its data and the dataset is put into dsBrowse state. For example,
        * an AfterOpen event handler might check an ini file to determine the last record
        * touched in the dataset the previous time the application ran, and position the
        * dataset at that record.
        *
        * @see readOnBeforeOpen()
        *
        * @return mixed
        */
        function readOnAfterOpen() { return $this->_onafteropen; }
        function writeOnAfterOpen($value) { $this->_onafteropen=$value; }
        function defaultOnAfterOpen() { return null; }

        protected $_onbeforeclose=null;

        /**
        * Occurs immediately before the dataset closes.
        *
        * Write a OnBeforeClose event to take specific action before an application
        * closes a dataset. Calling Close or setting the Active property to false
        * results in a call to the OnBeforeClose event handler.
        *
        * @see readOnAfterClose()
        *
        * @return mixed
        */
        function readOnBeforeClose() { return $this->_onbeforeclose; }
        function writeOnBeforeClose($value) { $this->_onbeforeclose=$value; }
        function defaultOnBeforeClose() { return null; }

        protected $_onafterclose=null;

        /**
        * Occurs after an application closes a dataset.
        *
        * Write an OnAfterClose event handler to take specific action immediately
        * after an application closes a dataset.
        *
        * OnAfterClose is called after a dataset is closed and the dataset state
        * is set to dsInactive.
        *
        * @see readOnBeforeClose()
        *
        * @return mixed
        */
        function readOnAfterClose() { return $this->_onafterclose; }
        function writeOnAfterClose($value) { $this->_onafterclose=$value; }
        function defaultOnAfterClose() { return null; }

        protected $_onbeforeinsert=null;

        /**
        * Occurs before an application enters insert mode.
        *
        * Write a OnBeforeInsert event handler to take specific action before an
        * application inserts or appends a new record. The Insert or Append method
        * generates a OnBeforeInsert method before it sets the dataset into dsInsert state.
        *
        * @see readOnAfterInsert()
        *
        * @return mixed
        */
        function readOnBeforeInsert() { return $this->_onbeforeinsert; }
        function writeOnBeforeInsert($value) { $this->_onbeforeinsert=$value; }
        function defaultOnBeforeInsert() { return null; }

        protected $_onafterinsert=null;

        /**
        * Occurs after an application inserts a new record.
        *
        * Write an OnAfterInsert event handler to take specific action immediately
        * after an application inserts a record. The Insert and Append methods generate
        * an OnAfterInsert event after inserting or appending a new record.
        *
        * @see readOnBeforeInsert()
        *
        * @return mixed
        */
        function readOnAfterInsert() { return $this->_onafterinsert; }
        function writeOnAfterInsert($value) { $this->_onafterinsert=$value; }
        function defaultOnAfterInsert() { return null; }

        protected $_onbeforeedit=null;

        /**
        * Occurs before an application enters edit mode for the active record.
        *
        * Write a OnBeforeEdit event handler to take specific action before an
        * application enables editing of the active record. For example, an
        * application that keeps a log of database edits could use the OnBeforeEdit
        * event to record the edit request, time, and user before entering edit state.
        *
        * @see readOnAfterEdit()
        *
        * @return mixed
        */
        function readOnBeforeEdit() { return $this->_onbeforeedit; }
        function writeOnBeforeEdit($value) { $this->_onbeforeedit=$value; }
        function defaultOnBeforeEdit() { return null; }

        protected $_onafteredit=null;

        /**
        * Occurs after an application starts editing a record.
        *
        * Write an OnAfterEdit event handler to take specific action immediately
        * after dataset enters edit mode. OnAfterEdit is called by Edit after it
        * enables editing of a record, recalculates calculated fields, and calls
        * the data event handler to process a record change.
        *
        * @see readOnBeforeEdit()
        *
        * @return mixed
        */
        function readOnAfterEdit() { return $this->_onafteredit; }
        function writeOnAfterEdit($value) { $this->_onafteredit=$value; }
        function defaultOnAfterEdit() { return null; }

        protected $_onbeforepost=null;

        /**
        * Occurs before an application posts changes for the active record to the database or change log.
        *
        * Write a OnBeforePost event handler to take specific action before an
        * application posts dataset changes. OnBeforePost is triggered when an
        * application calls the Post method. Post checks to make sure all required
        * fields are present, then calls OnBeforePost before posting the record.
        *
        * An application might use OnBeforePost to perform validity checks on data
        * changes before committing them. If it encountered a validity problem, it
        * could call Abort to cancel the Post operation.
        *
        * @see readOnAfterPost()
        *
        * @return mixed
        */
        function readOnBeforePost() { return $this->_onbeforepost; }
        function writeOnBeforePost($value) { $this->_onbeforepost=$value; }
        function defaultOnBeforePost() { return null; }

        protected $_onafterpost=null;

        /**
        * Occurs after an application writes the active record to the database or change log and returns to browse state.
        *
        * Write an OnAfterPost event handler to take specific action immediately
        * after an application posts a change to the active record. OnAfterPost
        * is called after a modification or insertion is made to a record.
        *
        * @see readOnBeforePost()
        *
        * @return mixed
        */
        function readOnAfterPost() { return $this->_onafterpost; }
        function writeOnAfterPost($value) { $this->_onafterpost=$value; }
        function defaultOnAfterPost() { return null; }

        protected $_onbeforecancel=null;

        /**
        * Occurs before an application executes a request to cancel changes to the active record.
        *
        * Write a OnBeforeCancel event to take specific action before an application
        * carries out a request to cancel changes. OnBeforeCancel is called by the
        * Cancel method before it cancels a dataset operation such as Edit, Insert, or Delete.
        *
        * An application might use the OnBeforeCancel event to record a user�s changes in an undo buffer.
        *
        * @see readOnAfterCancel()
        *
        * @return mixed
        */
        function readOnBeforeCancel() { return $this->_onbeforecancel; }
        function writeOnBeforeCancel($value) { $this->_onbeforecancel=$value; }
        function defaultOnBeforeCancel() { return null; }

        protected $_onaftercancel=null;

        /**
        * Occurs after an application completes a request to cancel modifications to the active record.
        *
        * Write an OnAfterCancel event handler to take specific action after an
        * application cancels changes to the active record. OnAfterCancel is called by the
        * Cancel method after it updates the current position, releases the lock on
        * the active record if necessary, and sets the dataset state to dsBrowse.
        * If an application requires additional processing before returning control to
        * a user after a Cancel event, code it in the OnAfterCancel event.
        *
        * @see readOnBeforeCancel()
        *
        * @return mixed
        */
        function readOnAfterCancel() { return $this->_onaftercancel; }
        function writeOnAfterCancel($value) { $this->_onaftercancel=$value; }
        function defaultOnAfterCancel() { return null; }

        protected $_onbeforedelete=null;

        /**
        * Occurs before an application attempts to delete the active record.
        *
        * Write a BeforeDelete event handler to take specific action before an
        * application deletes the active record. OnBeforeDelete is called by
        * Delete before it actually deletes a record.
        *
        * @see readOnAfterCancel()
        *
        * @return mixed
        */
        function readOnBeforeDelete() { return $this->_onbeforedelete; }
        function writeOnBeforeDelete($value) { $this->_onbeforedelete=$value; }
        function defaultOnBeforeDelete() { return null; }

        protected $_onafterdelete=null;

        /**
        * Occurs after an application deletes a record.
        *
        * Write an OnAfterDelete event handler to take specific action immediately
        * after an application deletes the active record in a dataset. OnAfterDelete
        * is called by Delete after it deletes the record, sets the dataset state to
        * dsBrowse, and repositions the current record.
        *
        * @see readOnBeforeDelete()
        *
        * @return mixed
        */
        function readOnAfterDelete() { return $this->_onafterdelete; }
        function writeOnAfterDelete($value) { $this->_onafterdelete=$value; }
        function defaultOnAfterDelete() { return null; }

        protected $_oncalcfields=null;

        /**
        * Occurs when an application recalculates calculated fields.
        *
        * (not used)
        *
        * @return mixed
        */
        function readOnCalcFields() { return $this->_oncalcfields; }
        function writeOnCalcFields($value) { $this->_oncalcfields=$value; }
        function defaultOnCalcFields() { return null; }

        protected $_ondeleteerror=null;

        /**
        * Not used, reserved for future use
        */
        function readOnDeleteError() { return $this->_ondeleteerror; }
        function writeOnDeleteError($value) { $this->_ondeleteerror=$value; }
        function defaultOnDeleteError() { return null; }

        protected $_filter="";

        /**
        * Specifies the text of the current filter for a dataset.
        *
        * Use Filter to specify a dataset filter. When filtering is applied to a
        * dataset, only those records that meet a filter�s conditions are available.
        * Filter describes the filter condition.
        *
        * @return string
        */
        function readFilter() { return $this->_filter; }
        function writeFilter($value)
        {
            if ($value!=$this->_filter)
            {
                //$this->Close();
                $this->_filter=$value;
                //$this->Open();
            }
        }
        function defaultFilter() { return ""; }



        protected $_onfilterrecord=null;

        /**
        * Not used, reserved for future use
        */
        function readOnFilterRecord() { return $this->_onfilterrecord; }
        function writeOnFilterRecord($value) { $this->_onfilterrecord=$value; }
        function defaultOnFilterRecord() { return null; }

        protected $_onnewrecord=null;

        /**
        * Not used, reserved for future use
        */
        function readOnNewRecord() { return $this->_onnewrecord; }
        function writeOnNewRecord($value) { $this->_onnewrecord=$value; }
        function defaultOnNewRecord() { return null; }

        protected $_onposterror=null;

        /**
        * Not used, reserved for future use
        */
        function readOnPostError() { return $this->_onposterror; }
        function writeOnPostError($value) { $this->_onposterror=$value; }
        function defaultOnPostError() { return null; }


        /**
        * Checks if an specific operation can be made, if not, calls $ErrorEvent
        * @param string $Operation Operation to perform on the dataset
        * @param string $ErrorEvent Event to call if there is any error
        */
        function checkOperation($Operation, $ErrorEvent)
        {
            $Done = false;
            do
            {
                try
                {
//                $this->UpdateCursorPos();
                  $this->$Operation();
                  $Done=true;
                }
                catch (EDatabaseError $e)
                {
                    $Action=daFail;
                    $Action=$this->callEvent($ErrorEvent, array('Exception'=>$e, 'Action'=>$Action));
                    if ($Action===null) $Action=daFail;
                    if ($Action==daFail) throw $e;
                    if ($Action==daAbort) Abort();
                }

            }
            while(!$Done);
        }

        /**
        * Used to notify attached datasets about an specific event
        * @param integer $event Event to notify
        * @param array $info Info for the event
        */
        function dataEvent($event, $info)
        {
            $NotifyDataSources = !(($this->ControlsDisabled()) || ($this->State == dsBlockRead));

            switch($event)
            {
            /*
    deFieldChange:
      begin
        if TField(Info).FieldKind in [fkData, fkInternalCalc] then
          SetModified(True);
        UpdateCalcFields;
      end;
    deFieldListChange:
      FieldList.Updated := False;
    dePropertyChange:
      FieldDefs.Updated := False;
    deCheckBrowseMode:
      CheckNestedBrowseMode;
    deDataSetChange, deDataSetScroll:
      NotifyDetails;
    deLayoutChange:
      begin
        FieldList.Updated := False;
        if ControlsDisabled then
          FEnableEvent := deLayoutChange;
      end;
    deUpdateState:
      if ControlsDisabled then
      begin
        Event := deDisabledStateChange;
        Info := Integer(State <> dsInactive);
        NotifyDataSources := True;
        FEnableEvent := deLayoutChange;
      end;
      */
      }
        /*
        if ($NotifyDataSources)
        {
            for I := 0 to FDataSources.Count - 1 do
              TDataSource(FDataSources[I]).DataEvent(Event, Info);
        }
        */
        }

        /**
        * Checks to see if the database connection is active.
        *
        * Call CheckActive to determine if the connection to a database server is active.
        * If the database connection is inactive, an DatabaseError exception is raised.
        *
        * @see databaseError()
        */
        function checkActive()
        {
            if ($this->State == dsInactive) DatabaseError(_("Cannot perform this operation on a closed dataset"), $this);
        }

        /**
        * Checks to see if the dataset can be modified.
        *
        * Call CheckCanModify to determine if the dataset can be modified.
        * If the dataset cannot be modified, an DatabaseError exception is raised.
        *
        * @see databaseError()
        */
        function checkCanModify()
        {
            if (!$this->CanModify) DatabaseError(_("Cannot modify a read-only dataset", Self));
        }

        /**
        * Indicates whether data-aware controls update their display to reflect changes to the dataset.
        *
        * Call ControlsDisabled to ascertain whether the updating of data display in data-aware
        * controls is currently disabled. If ControlsDisabled is true, controls are currently disabled.
        * ControlsDisabled is true as long as the reference count that keeps track of disabling for the
        * dataset is greater than zero. This count is incremented every time the DisableControls method
        * is called and decremented when EnableControls is called. Applications call DisableControls to
        * improve performance and prevent constant updates during automated iterations through records in
        * the dataset.
        *
        * In complex applications, when controls may be disabled multiple times by different processes, you
        * can use ControlsDisabled as a check in a procedure to reenable controls should each call to
        * DisableControls not be paired with a subsequent call to EnableControls.
        *
        * @see disableControls(), enableControls()
        *
        * @return boolean True if controls has been disabled
        */
        function controlsDisabled()
        {
            return($this->_DisableCount!=0);
        }

        /**
        * Disables data display in data-aware controls associated with the dataset.
        *
        * Call DisableControls prior to iterating through a large number of records
        * in the dataset to prevent data-aware controls from updating every time
        * the active record changes. Disabling controls speeds performance because
        * data does not need to be processed by data-aware controls.
        *
        * If controls are not already disabled, DisableControls records the current
        * state of the dataset, broadcasts the state change to all associated data-aware
        * controls and detail datasets, and increments the dataset�s disabled count variable.
        * Otherwise, DisableControls just increments the disabled count variable.
        *
        * The disabled count is used internally to determine whether to display data
        * in data-aware controls. When the disable count variable is greater than zero,
        * data is not updated.
        *
        * If the dataset is the master of a master/detail relationship, calling DisableControls
        * also disables the master/detail relationship.
        *
        * Note: Calls to DisableControls can be nested. Only when all calls to DisableControls
        * is matched to a corresponding call to EnableControls does the dataset update
        * data controls and detail datasets.
        *
        * @see ControlsDisabled(), EnableControls()
        */
        function DisableControls()
        {
            if ($this->_DisableCount == 0)
            {
                $this->_DisableState=$this->State;
                $this->_EnableEvent=deDataSetChange;
            }
            $this->_DisableCount++;
        }

        /**
        * Enable controls attached to the datasource
        *
        * Call EnableControls to permit data display in data-aware controls after
        * a prior call to DisableControls. EnableControls decrements the disabled
        * count variable for the dataset if it is not already zero. If the disable
        * count variable is zero, EnableControls updates the current state of the
        * dataset, if necessary, and then tells associated controls to re-enable display.
        *
        * @see DisableControls(), EnableControls()
        *
        */
        function EnableControls()
        {
            if ($this->_DisableCount!=0)
            {
                $this->_DisableCount--;
                if ($this->_DisableCount==0)
                {
                    if ($this->_DisableState!=$this->State) $this->DataEvent(deUpdateState, 0);
                    if (($this->_DisableState!=dsInactive) && ($this->_State != dsInactive)) $this->DataEvent($this->_EnableEvent, 0);
                }
            }
        }

        /**
        * Clear buffers associated with the dataset
        *
        * This method set the dataset buffers to the inital state, that is, recordcount
        * to 0 and bof/eof to true. The fieldbuffer is also cleared to an empty array.
        *
        */
        function clearBuffers()
        {
            $this->_recordcount = 0;
//            $this->_activerecord = 0;
//            $this->_currentrecord = -1;
            $this->_bof = true;
            $this->_eof = true;
            $this->fieldbuffer=array();
        }

        /**
        * Begins an insert/append operation
        *
        * This method is called by the dataset to start an insert or append
        * operation, it first checks the browse mode, after that, checks if the
        * dataset can be modified and finally, calls the OnBeforeInsert event
        *
        * @see insert(), append(), endInsertAppend()
        */
        function beginInsertAppend()
        {
            $this->CheckBrowseMode();
            $this->CheckCanModify();
            $this->callEvent('onbeforeinsert', array());
            $this->CheckParentState();
        }

        /**
        * Finishes an insert/append operation
        *
        * This method is called by a dataset to finish an insert or append
        * operation. It sets the dataset in insert state, calls the OnNewRecord
        * event and finally calls the OnAfterInsert.
        *
        * @see insert(), append(), endInsertAppend()
        */
        function endInsertAppend()
        {
            $this->State=dsInsert;
            try
            {
                $this->callEvent('onnewrecord',array());
            }
            catch (Exception $e)
            {
                $this->UpdateCursorPos();
                $this->FreeFieldBuffers();
                $this->State=dsBrowse;
                throw $e;
            }
            $this->_modified = false;
            $this->DataEvent(deDataSetChange, 0);
            $this->callEvent('onafterinsert',array());
        }

        function __construct($aowner=null)
        {
                //Calls inherited constructor
                parent::__construct($aowner);
        }

        /**
        * Inserts a new, empty record in the dataset.
        *
        * Call Insert to:
        *
        * 1 - Open a new, empty record in the dataset.
        * 2 - Set the active record to the new record.
        *
        * After a call to Insert, an application can allow users to enter data
        * in the fields of the record, and then post those changes to the database
        * or change log using Post.
        *
        * @see beginInsertAppend(), endInsertAppend(), append()
        */
        function insert()
        {
            $this->BeginInsertAppend();
            //OldCurrent := Bookmark;
            //MoveBuffer(FRecordCount, FActiveRecord);
            //Buffer := ActiveBuffer;
            //InitRecord(Buffer);
            //if FRecordCount = 0 then
            //SetBookmarkFlag(Buffer, bfBOF) else
            //SetBookmarkData(Buffer, Pointer(OldCurrent));
            //if FRecordCount < FBufferCount then Inc(FRecordCount);
            $this->InternalInsert();
            $this->EndInsertAppend();
        }

        /**
        * Adds a new, empty record to the end of the dataset.
        *
        * For datasets that permit editing, call Append to:
        *
        * 1 - Open a new, empty record at the end of the dataset.
        * 2 - Set the active record to the new record.
        *
        * After a call to Append, an application can enable users to enter data
        * in the fields of the record, and can then post those changes to the
        * database or change log using Post
        *
        * @see beginInsertAppend(), endInsertAppend(), insert()
        */
        function append()
        {
                $Buffer="";
                $this->BeginInsertAppend();
                $this->ClearBuffers();
                $this->InitRecord($Buffer);
                $this->_recordcount = 1;
                $this->_bof = False;
//                $this->GetPriorRecords();
                $this->InternalInsert();
                $this->EndInsertAppend();
        }

        /**
        * Cancels modifications to the active record if those changes are not yet posted.
        *
        * Call Cancel to undo modifications made to one or more fields belonging to
        * the active record. As long as those changes are not already posted, Cancel
        * returns the record to its previous state, and sets the dataset state to dsBrowse.
        *
        * Typically Cancel is used to back out of changes in response to user request, or
        * in field validation routines that back out illegal field values.
        *
        * Note: If the dataset is not in an editing state (dsEdit or dsInsert), Cancel does nothing.
        *
        * @see edit(), insert()
        */
        function cancel()
        {
            switch($this->State)
            {
                case dsEdit:
                case dsInsert:
                {
                    $this->DataEvent(deCheckBrowseMode, 0);
                    $this->callEvent("onbeforecancel",array());
//                    $DoScrollEvents = ($this->State == dsInsert);
//                    if ($DoScrollEvents) $this->DoBeforeScroll();
//                    $this->UpdateCursorPos();
                    $this->InternalCancel();
                    $this->fieldbuffer=array();
                    $this->State=dsBrowse;
                    //$this->Resync([]);
                    $this->callEvent("onaftercancel",array());
//                    if ($DoScrollEvents) $this->DoAfterScroll();
                    break;
                }
            }
        }

        /**
        * Ensures that data-aware controls and detail datasets reflect record updates.
        *
        * UpdateRecord is used internally by some dataset methods to inform data-aware
        * controls of updates and trigger an OnUpdateRecord event if updates
        * are enabled. Applications should not need to call UpdateRecord directly unless
        * they provide custom dataset methods that bypass DataSet methods.
        *
        * @see edit(), insert()
        */
        function updateRecord()
        {
            if (($this->State!=dsEdit) && ($this->State!=dsInsert) && ($this->State!=dsSetKey)) DatabaseError(_("Dataset not in edit or insert mode"), $this);
            $this->DataEvent(deUpdateRecord,0);
        }

        /**
        * Automatically posts or cancels data changes when the active record changes.
        *
        * CheckBrowseMode is used internally by many dataset methods to ensure that
        * modifications to the active record are posted when a dataset�s state is
        * dsEdit, dsInsert, or dsSetKey and a method switches to a different record.
        *
        * If State is dsEdit or dsInsert, CheckBrowseMode calls UpdateRecord, and,
        * if the Modified property for the dataset is true, calls Post. If Modified
        * is false, CheckBrowseMode calls Cancel.
        *
        * If State is dsSetKey, CheckBrowseMode calls Post.
        *
        * If State is dsInactive, CheckBrowseMode raises an exception.
        *
        * If an application uses existing dataset methods, CheckBrowseMode is always
        * called when necessary, so there is usually no need to call CheckBrowseMode directly.
        *
        * Applications that provide custom dataset routines may need to call CheckBrowseMode
        * inside those routines to guarantee that changes are posted when switching to a different record.
        *
        * @see edit(), insert(), checkActive(), dataEvent(), updateRecord(), post(), cancel()
        */
        function checkBrowseMode()
        {
            $this->CheckActive();
            $this->DataEvent(deCheckBrowseMode, 0);
            switch($this->State)
            {
                case dsEdit:
                case dsInsert:
                {
                    $this->UpdateRecord();
                    if ($this->Modified) $this->post();
                    else $this->cancel();
                    break;
                }
                case dsSetKey:
                {
                    $this->post();
                    break;
                }
            }
        }

        /**
        * Closes a dataset.
        *
        * Call Close to set the Active property of a dataset to false. When Active
        * is false, the dataset is closed; it cannot read or write data and data-aware
        * controls can�t use it to fetch data or post edits.
        *
        * An application must close the dataset before changing properties that affect the
        * status of the database or the controls that display data in an application.
        * For example, to change the DataSource property for a dataset, the dataset must
        * be closed. Closing the dataset puts it into the dsInactive state.
        *
        * @see open()
        */
        function close()
        {
            $this->Active=false;
        }

        /**
        * Deletes the active record and positions the dataset on the next record.
        *
        * Call Delete to remove the active record from the database. If the dataset
        * is inactive, Delete raises an exception. Otherwise, Delete:
        *
        * Verifies that the dataset is not empty (and raises an exception if it is).
        *
        * Calls CheckBrowseMode to post any pending changes to a prior record if necessary.
        *
        * Calls the OnBeforeDelete event handler.
        *
        * Deletes the record.
        *
        * Frees any buffers allocated for the record.
        *
        * Puts the dataset into dsBrowse mode.
        *
        * Resynchronizes the dataset to make the next undeleted record active.
        * If the record deleted was the last record in the dataset, then the previous record becomes the current record.
        *
        * Calls the AfterDelete event handler.
        *
        * @see readOnBeforeDelete(), readOnAfterDelete()
        */
        function delete()
        {
            $this->CheckActive();
            if (($this->State==dsInsert) || ($this->State==dsSetKey)) $this->Cancel();
            else
            {
                if ($this->Recordcount==0) DatabaseError(_("Cannot perform this operation on an empty dataset"), Self);
                $this->DataEvent(deCheckBrowseMode, 0);
                $this->callevent("onbeforedelete",array());
                $this->CheckOperation("InternalDelete", "ondeleteerror");
                $this->fieldbuffer=array();
                $this->State=dsBrowse;
                $this->callevent("onafterdelete",array());
            }
        }

        /**
        * Sets the parent dataset in edit state
        *
        * This is an internal method you don't need to call directly.
        *
        * @see edit()
        */
        function checkParentState()
        {
            if ($this->DataSetField != null) $this->DataSetField->DataSet->Edit();
        }

        /**
        * Enables editing of data in the dataset.
        *
        * Call Edit to permit editing of the active record in a dataset. Edit
        * determines the current state of the dataset. If the dataset is empty,
        * Edit calls Insert. Otherwise Edit:
        *
        * Calls CheckBrowseMode to post any pending changes to a prior record if necessary.
        *
        * Checks the CanModify property and raises an exception if the dataset can�t be edited.
        *
        * Calls the OnBeforeEdit event handler.
        *
        * Retrieves the record.
        *
        * Puts the dataset into dsEdit state, enabling the application or user to modify fields in the record.
        *
        * Broadcasts the state change to associated controls.
        *
        * Calls the OnAfterEdit event handler.
        *
        * Modifications will go to a buffer waiting for post()/cancel()
        *
        * @see readOnBeforeEdit(), readOnAfterEdit(), post()
        */
        function edit()
        {
            if ((($this->State==dsEdit) || ($this->State==dsInsert)))
            {
            }
            else
            {
//                if ($this->_recordcount==0) $this->Insert();
//                else
//                {
                    $this->CheckBrowseMode();
                    $this->CheckCanModify();
                    $this->callevent("onbeforeedit",array());
                    $this->CheckParentState();
                    $this->CheckOperation("InternalEdit", "onediterror");
//                    $this->GetCalcFields(ActiveBuffer);
                    $this->State=dsEdit;
                    $this->DataEvent(deRecordChange, 0);
                    $this->callevent("onafteredit",array());
//                }
            }
        }

        /**
        * Indicates the total number of records associated with the dataset.
        *
        * As implemented in DataSet, RecordCount is always 0. Ordinarily an application
        * does not access RecordCount at the DataSet level. Instead a redeclared and
        * implemented RecordCount property in a descendant class is accessed. RecordCount
        * provides a fallback property for derived dataset classes that do not reimplement
        * the property access method.
        *
        * @return integer
        */
        function readRecordCount()
        {
            return $this->_recordcount;
        }
        function defaultRecordCount() { return 0; }


        /**
        * Moves to the first record in the dataset.
        *
        * Call First to make the first record in the dataset active. First posts
        * any changes to the active record and:
        *
        * Clears the record buffers.
        *
        * Fetches the first record and makes it the active record.
        *
        * Fetches any additional records required for display, such as those needed to
        * fill out a grid control.
        *
        * Sets the Bof property to true.
        *
        * Broadcasts the record change so that data controls and linked detail sets can update.
        *
        * Note: DataSet uses internal, protected methods to reposition the active record and
        * to fetch additional records required for display. In DataSet, these internal methods are empty
        * stubs. Descendant classes implement these methods to enable the First method to work.
        *
        * @see last(), readBof(), readEof()
        */
        function first()
        {
            $this->CheckBrowseMode();
            $FReopened = false;
            /*
            if IsUniDirectional then begin
                if not BOF then begin             // Need to Close and Reopen dataset: (Midas)
                    Active := False;
                    Active := True;
                end;
                FReopened := True
            end
            else ClearBuffers;
            */
            $this->ClearBuffers();
            try
            {
                $this->InternalFirst();
                //if not FReopened then begin
                //$this->GetNextRecord();
                //$this->GetNextRecords();
                //end;
            }
            catch (Exception $e)
            {
                $this->_bof = true;
                $this->DataEvent(deDataSetChange, 0);
                throw $e;
            }

            $this->_bof = true;
            $this->DataEvent(deDataSetChange, 0);
        }

        /**
        * Performs an internal open of the dataset
        *
        * This is method called by the dataset to perform an open of the data.
        * It calls InternalOpen, a method you should implement if you are deriving
        * from Dataset.
        *
        * @see open(), readBof()
        */
        function doInternalOpen()
        {
            $this->_DefaultFields = ($this->FieldCount == 0);
            $this->InternalOpen();
            $this->_InternalOpenComplete = true;
            //$this->UpdateBufferCount();
            $this->_bof = true;
        }

        /**
        * Opens the cursor for the dataset
        *
        * This method is called to open the cursor for this dataset by calling
        * DoInternalOpen.
        *
        * @see doInternalOpen(), open()
        *
        * @param boolean $InfoQuery If true, initialize internal field defs
        */
        function openCursor($InfoQuery= False)
        {
            if ($InfoQuery) $this->InternalInitFieldDefs();
            else if ($this->State!=dsOpening) $this->DoInternalOpen();
        }

        /**
        * Finishes the open cursor operation
        *
        * This method is called when opening a cursor to complete the open operation,
        * it first calls DoInternalOpen and fires the OnAfterOpen event.
        *
        * @see DoInternalOpen(), Open(), OpenCursor()
        */
        function OpenCursorComplete()
        {
            try
            {
                if ($this->State == dsOpening) $this->DoInternalOpen();
            }
            catch(Exception $e)
            {
                if ($this->_InternalOpenComplete)
                {
                    $this->State=dsBrowse;
                    $this->callEvent("onafteropen", array());
                }
                else
                {
                    $this->State=dsInactive;
                    $this->CloseCursor();
                }
                throw $e;
            }
            if ($this->_InternalOpenComplete)
            {
                if ($this->_state==dsInactive) $this->_state=dsBrowse;
                $this->callEvent("onafteropen", array());
            }
            else
            {
                $this->State=dsInactive;
                $this->CloseCursor();
            }
        }

        /**
        * Close the cursor for this dataset
        *
        * This method is used to close the cursor attached to the dataset, it
        * calls InternalClose, a method you need to override if you are deriving
        * from Dataset.
        *
        * @see internalClose(), close()
        */
        function closeCursor()
        {
//            BlockReadSize := 0;
            $this->_InternalOpenComplete = false;
//            FreeFieldBuffers;
//            ClearBuffers;
//            SetBufListSize(0);
            $this->InternalClose();
//            FBufferCount := 0;
//            FDefaultFields := False;
        }

        /**
        * To be overriden to perform a first() operation
        *
        * This method is called when a first operation is atempted, so if you are
        * creating new types of datasets, you need to override this method.
        *
        * @see first()
        */
        function internalFirst()
        {
        }

        /**
        * To be overriden to perform a last() operation
        *
        * This method is called when a last operation is atempted, so if you are
        * creating new types of datasets, you need to override this method.
        *
        * @see last()
        */
        function internalLast()
        {
          databaseError("Last operations are not implemented for this type dataset",$this);
        }

        /**
        * To initialize the current record
        * @param array $Buffer Initial values
        *
        * @see internalInitRecord()
        */
        function initRecord($Buffer)
        {
            $this->InternalInitRecord($Buffer);
//            $this->ClearCalcFields($Buffer);
//            $this->SetBookmarkFlag($Buffer, bfInserted);
        }

        function internalInitRecord($buffer)
        {
        }

        function internalAddRecord($buffer, $append)
        {
        }

        /**
        * To be overriden to perform a delete() operation
        *
        * This method is called when a delete operation is atempted, so if you are
        * creating new types of datasets, you need to override this method.
        *
        * @see delete()
        */
        function internalDelete()
        {
        }

        /**
        * To be overriden to perform a post() operation
        *
        * This method is called when a post operation is atempted, so if you are
        * creating new types of datasets, you need to override this method.
        *
        * @see post()
        */
        function internalPost()
        {
//            $this->CheckRequiredFields();
        }

        /**
        * To be overriden to perform a cancel() operation
        *
        * This method is called when a cancel operation is atempted, so if you are
        * creating new types of datasets, you need to override this method.
        *
        * @see cancel()
        */
        function internalCancel()
        {
        }

        /**
        * To be overriden to perform a edit() operation
        *
        * This method is called when a edit operation is atempted, so if you are
        * creating new types of datasets, you need to override this method.
        *
        * @see edit()
        */
        function internalEdit()
        {
        }

        /**
        * To be overriden to perform a insert() operation
        *
        * This method is called when a insert operation is atempted, so if you are
        * creating new types of datasets, you need to override this method.
        *
        * @see insert()
        */
        function internalInsert()
        {
        }

        /**
        * To be overriden to perform a refresh() operation
        *
        * This method is called when a refresh operation is atempted, so if you are
        * creating new types of datasets, you need to override this method.
        *
        * @see refresh()
        */
        function internalRefresh()
        {
        }

        /**
        * Moves to the last record in the dataset.
        *
        * Call Last to make the last record in the dataset active.
        * Last posts any changes to the active record and
        *
        * Clears the record buffers.
        *
        * Fetches the last record and makes it the active record.
        *
        * Fetches any additional records required for display, such as those needed to fill out a grid control.
        *
        * Sets the Eof property to true.
        *
        * Broadcasts the record change so that data controls and linked detail sets can update.
        *
        *
        * Note: DataSet uses internal, protected methods to reposition the active record
        * and to fetch additional records required for display. In DataSet, these internal methods
        * are empty stubs. Descendant classes implement these methods to enable the Last method to work.
        *
        * @see internalLast(), first()
        */
        function last()
        {
            //$this->CheckBiDirectional();
            $this->CheckBrowseMode();
            $this->ClearBuffers();
            try
            {
                $this->InternalLast();
//                $this->GetPriorRecord();
//                $this->GetPriorRecords();
            }
            catch (Exception $e)
            {
                $this->_eof = true;
                $this->DataEvent(deDataSetChange, 0);
                throw $e;
            }

            $this->_eof = true;
            $this->DataEvent(deDataSetChange, 0);
        }

        /**
        * Re-fetches data from the database to update a dataset�s view of data.
        *
        * Call Refresh to ensure that an application has the latest data from a database.
        * For example, when an application turns off filtering for a dataset, it should immediately
        * call Refresh to display all records in the dataset, not just those that used to meet the filter condition.
        *
        * DataSet generates a OnBeforeRefresh event before refreshing the records and an OnAfterRefresh event afterwards.
        *
        * Warning: Dataset refresh the data by closing and reopening the cursor. This can have unintended side effects if,
        * for example, you have code in the OnBeforeClose, OnAfterClose, OnBeforeOpen, or OnAfterOpen event handlers.
        *
        * @see readActive()
        */
        function refresh()
        {
            $this->Active=false;
            $this->Active=true;
        }

        /**
        * Moves to the next record in the dataset.
        *
        * Call Next to move to the next record in the dataset, making it the
        * active record. Next posts any changes to the active record and
        *
        * Sets the Bof and Eof properties to false.
        *
        * Fetches the next record and makes it the active record.
        *
        * Fetches any additional records required for display, such as those needed to fill out a grid control.
        *
        * Sets the Eof property to true if the last record in the dataset was already active.
        *
        * Broadcasts the record change so that data controls and linked detail sets can update.
        *
        * Note: DataSet uses internal, protected methods to move the active record and
        * to fetch additional records required for display. In DataSet, these internal methods are empty stubs.
        * Descendant classes implement these methods to enable the Next method to work.
        *
        * @see prior()
        */
        function next()
        {
//            if ($this->BlockReadSize > 0) $this->BlockReadNext();
//            else
              $this->MoveBy(1);
              if (!$this->EOF) $this->fieldbuffer=$this->_rs->fields;
        }

        /**
        * Opens the dataset.
        *
        * Call Open to set the Active property for the dataset to true. When Active
        * is true, dataset can be populated with data. It can read data from a database
        * or other source (such as a provider). Depending on the CanModify property,
        * active datasets can post changes.
        *
        * Setting Active to true:
        *
        * Triggers the OnBeforeOpen event handler if one is defined for the dataset.
        *
        * Sets the dataset state to dsBrowse.
        *
        * Establishes a way to fetch data (typically by opening a cursor).
        *
        * Triggers the After Open event handler if one is defined for the dataset.
        *
        * If an error occurs during the dataset open, dataset state is set to dsInactive, and any cursor is closed.
        *
        * @see close(), readActive()
        */
        function open()
        {
            $this->Active=true;
        }

        /**
        * Implements a virtual method to write a modified record to the database or change log.
        *
        * DataSet implements a virtual method to write a modified record to the database or
        * change log. Dataset methods that change the dataset state, such as Edit, Insert, or Append,
        * or that move from one record to another, such as First, Last, Next, and Prior automatically call Post.
        *
        * Designers of custom datasets can choose whether to implement Post by writing records to the
        * database server or to an internal change log.
        *
        * @see cancel(), edit(), insert()
        */
        function post()
        {
            $this->UpdateRecord();
            switch ($this->State)
            {
                case dsEdit:
                case dsInsert:
                {
                    $this->DataEvent(deCheckBrowseMode, 0);
                    $this->callevent("onbeforepost",array());
                    $this->CheckOperation("InternalPost", "onposterror");
                    $this->fieldbuffer=array();
                    //$this->FreeFieldBuffers();
                    $this->State=dsBrowse;
                    $this->callevent("onafterpost",array());
                    break;
                }
            }
        }

        /**
        * Moves to another record relative to the active record in the dataset.
        *
        * Call MoveBy to move the active record by the number of records specified by
        * Distance. A positive value for Distance indicates forward progress through
        * the dataset, while a negative value indicates backward progress.
        *
        * MoveBy posts any changes to the active record and
        *
        * Sets the Bof and Eof properties to false.
        *
        * If Distance is positive, repeatedly fetches Distance subsequent records
        * (if possible), and makes the last record fetched active. If an attempt is
        * made to move past the end of the file, MoveBy sets Eof to true.
        *
        * If Distance is negative, repeatedly fetches the appropriate number of
        * previous records (if possible), and makes the last record fetched active.
        * If an attempt is made to move past the start of the file, MoveBy sets Bof
        * to true. If the dataset is unidirectional, the dataset raises an EDatabaseError
        * exception when MoveBy tries to fetch a prior record.
        *
        * Broadcasts information about the record change so that data-aware controls and
        * linked datasets can update.
        *
        * @param integer $distance Records to move the pointer
        *
        * @see first(), last(), prior(), next()
        */
        function moveBy($distance)
        {
            $this->_recno+=$distance;
        }

        /**
        * Moves to the previous record in the dataset.
        *
        * Call Prior to move to the previous record in the dataset, making it the
        * active record. Prior posts any changes to the active record and
        *
        * Sets the Bof and Eof properties to false.
        *
        * Fetches the previous record and makes it the active record. If the dataset
        * is unidirectional, it raises an EDatabaseError exception at this point.
        *
        * Fetches any additional records required for display, such as those needed to
        * fill out a grid control.
        *
        * Sets the Bof property to true if the first record in the dataset was already active.
        *
        * Broadcasts the record change so that data controls and linked detail sets can update.
        *
        * Note: DataSet uses internal, protected methods to move the active record and
        * to fetch additional records required for display. In DataSet, these internal
        * methods are empty stubs. Descendant classes implement these methods to enable the Prior
        * method to work.
        *
        * @see next(), moveBy()
        */
        function prior()
        {
            $this->MoveBy(-1);
        }

        protected $_active=0;

        /**
        * Specifies whether or not a dataset is open.
        *
        * Use Active to determine or set whether a dataset is populated with data.
        * When Active is false, the dataset is closed; the dataset cannot read or write
        * data and data-aware controls can not use it to fetch data or post edits.
        * When Active is true, the dataset can be populated with data. It can read data
        * from a database or other source (such as a provider). Depending on the
        * CanModify property, active datasets can post changes.
        *
        * Setting Active to true:
        *
        * Generates a OnBeforeOpen event.
        *
        * Sets the dataset state to dsBrowse.
        *
        * Establishes a way to fetch data (typically by opening a cursor).
        *
        * Generates an OnAfterOpen event.
        *
        * If an error occurs while opening the dataset, dataset state is set to
        * dsInactive, and any cursor is closed.
        *
        *
        *
        * Setting Active to false:
        *
        * 1 - Triggers a BeforeClose event.
        *
        * 2 - Sets the State property to dsInactive.
        *
        * 3 - Closes the cursor.
        *
        * 4 - Triggers an AfterClose event.
        *
        * An application must set Active to false before changing other properties
        * that affect the status of a database or the controls that display data in
        * an application.
        *
        * Note: Calling the Open method sets Active to true; calling the Close method
        * sets Active to false.
        *
        * @see open(), close(), readState()
        *
        * @return boolean
        */
        function readActive()
        {
            if (($this->readState()==dsInactive) || ($this->readState()==dsOpening) || ($this->_rs==null))
            {
                $this->_active=0;
                return(0);
            }
            else
            {
              $this->_active=true;
              return(true);
            }
        }

        protected $_fstreamedactive=false;

        function loaded()
        {
            parent::loaded();
            $this->writeMasterSource($this->_mastersource);
            if ($this->_fstreamedactive)
            {
                $this->Active=true;
            }
        }

        function writeActive($value)
        {
            if (($this->ControlState & csLoading)==csLoading)
            {
                $this->_fstreamedactive=$value;
            }
            else
            {
                if ($this->Active != $value)
                {
                    if ($value==true)
                    {
                        $this->callevent("onbeforeopen",array());
                        try
                        {
                            $this->OpenCursor();
                            if ($this->State!=dsOpening)
                            {
                                $this->OpenCursorComplete();
                            }
                            $this->_active=true;
                        }
                        catch (Exception $e)
                        {
                            if ($this->State!=dsOpening)
                            {
                                $this->OpenCursorComplete();
                            }
                            throw $e;
                        }
                    }
                    else
                    {
                        $this->_active=false;
                        $this->callevent("onbeforeclose",array());
                        $this->State=dsInactive;
                        $this->CloseCursor();
                        $this->callevent("onafterclose",array());
                    }
                }
            }
        }

        function defaultActive() { return "0"; }


        protected $_bof=false;
        protected $_eof=false;

        /**
        * Indicates whether the first record in the dataset is active.
        *
        * Test Bof (beginning of file) to determine if the dataset is positioned
        * at the first record. If Bof is true, the active record is unequivocally
        * the first row in the dataset. Bof is true when an application.
        *
        * Opens a dataset.
        *
        * Calls a dataset�s First method.
        *
        * Call a dataset�s Prior method, and the method fails because the first row is already active.
        *
        * Bof is false in all other cases.
        *
        * @see EOF(), First()
        *
        * @return boolean
        */
        function readBOF() { return $this->_bof; }
        function defaultBOF() { return false; }

        /**
        * Indicates whether a dataset is positioned at the last record.
        *
        * Test Eof (end-of-file) to determine if the active record in a dataset
        * is the last record. If Eof is true, the current record is unequivocally
        * the last row in the dataset. Eof is true when an application:
        *
        * Opens an empty dataset.
        *
        * Calls a dataset�s Last method. (Unless it is a unidirectional dataset)
        *
        * Call a dataset�s Next method, and the method fails because the current record is already the last row in the dataset.
        *
        *
        *
        * Eof is false in all other cases.
        *
        * Tip: If both Eof and Bof are true, the dataset is empty.
        *
        * @see BOF(), Last(), Next()
        *
        * @return boolean
        */
        function readEOF() { return $this->_eof; }
        function defaultEOF() { return false; }
}

/**
 * DataSource provides an interface between a dataset component and data-aware controls on a form.
 *
 * Use DataSource to
 *
 * provide a conduit between a dataset and data-aware controls on a form that enable display,
 * navigation, and editing of the data underlying the dataset.
 *
 * link two datasets in a master/detail relationship.
 *
 * All datasets must be associated with a data source component if their data is to be displayed and
 * manipulated in data-aware controls. Similarly, each data-aware control needs to be associated with
 * a data source component in order for the control to receive and manipulate data.
 *
 * Data source components also link datasets in master-detail relationships.
 */
class Datasource extends Component
{
        protected $_dataset;

        function __construct($aowner=null)
        {
                //Calls inherited constructor
                parent::__construct($aowner);
        }

        /**
        * Specifies the dataset for which the data source component serves as
        * a conduit to data-aware controls or other datasets.
        *
        * Set DataSet to the name of an existing dataset component either at
        * design time, or at runtime. By changing the value of DataSet at runtime
        * an application can effectively use the same data-aware controls to
        * display and edit data in different datasets.
        *
        *
        * Note: To link a dataset that resides in a data module to a form at
        * design-time, choose File | Use unit
        *
        * @return DataSet
        */
        function getDataSet() { return $this->_dataset; }
        function setDataSet($value)
        {
                $this->_dataset=$this->fixupProperty($value);
        }

        function loaded()
        {
                parent::loaded();
                $this->setDataSet($this->_dataset);
        }
}

class ArrayRecordSet extends Object
{
  public $fields=array();
}

class ArrayDataset extends DataSet
{
    public $array=array();
    public $_rs=null;
    public $_internalrecordcount=0;

    function __construct($aowner = null, $array=array())
    {
        parent::__construct($aowner);
        $this->_rs=new ArrayRecordSet();
        $this->array=$array;
        $this->readFields();
    }

    function readFields()
    {
      $result=array();
      $record=$this->array[$this->_recno];
      if (is_array($record))
      {
        foreach ($record as $fname=>$value)
        {
          $result[$fname]=$value;
        }
      }
      $this->_rs->fields=$result;
      return $result;
    }

    function readFieldProperties($fieldname)
    {
      return(false);
    }

    function moveBy($distance)
    {
      parent::moveBy($distance);
      $this->readFields();
    }

    function internalFirst()
    {
      $this->_recno=0;
    }

    function readEOF()
    {
      return($this->_recno>=count($this->array));
    }

    function fieldget($fieldname)
    {
    	if ($this->_rs!=null)
        {
        	if ($this->Active)
            {
            	if ((is_array($this->_rs->fields)) && (array_key_exists($fieldname,$this->_rs->fields)))
                {
                	if ($this->State==dsBrowse)
                    {
                    	return ($this->_rs->fields[$fieldname]);
                    }
                    else if (array_key_exists($fieldname,$this->fieldbuffer))
                    {
                    	return($this->fieldbuffer[$fieldname]);
                    }
                    else return('');
                }
                else if ((is_array($this->fieldbuffer)) && (array_key_exists($fieldname,$this->fieldbuffer)))
                {
                	return($this->fieldbuffer[$fieldname]);
                }
            }
        }

		throw new EPropertyNotFound($this->ClassName().'->'.$fieldname);
    }

    /**
    * Overriden to allow get field values as properties
    *
    * @param string $nm  Name of the property/field to get
    * @return mixed
    */
    function __get($nm)
    {
        try
        {
                //Try to get the property from the object
                return(parent::__get($nm));
        }
        catch (EPropertyNotFound $e)
        {
    			//If there is no such property, then try to search for a field
          return($this->fieldget($nm));
        }
    }

}


?>