<?php

  /*
   *  class Winr_Ags_Rets
   *
   *  wrapper class for the phrets API to communicate with RETS servers
   *
   *  this class is configured to "self init", so just calling it via a url
   *  with the appropriate "load" parameter will kick off the __construct() function
   *
   *  allowed request parameters:
   *  http://idx.flexiss.net/phrets/class.winr_ags_rets-1.2.2.php?load=(a|b|c|d|e|f|agent|office)
   *
   *  @author Dennis Williams <dennis@flexiss.net>
   *  @author Rajkumar S <rajkmr.s@nutrixtech.com>
   *  @copyright © March 2009 - Flexiss Digital Design
   *  @version 1.2.2
   *
   *  external requirements:
   *
   *  phRETS class api/documentation
   *    ./class.phrets.php
   *    http://www.troda.com/projects/phrets/docs.php

   *  adodb-lite db class/documentation
   *    ./_adodb/adodb.inc.php
   *    http://adodblite.sourceforge.net/
   *
   */
  class Winr_Ags_Rets {

    private $_rets;
    private $_db;
    private $_rs;

    private $_classDebug = false;
    private $_insertCount = 0;
    private $_updateCount = 0;
    private $_imageScaleCount = 0;
    private $_deletePropCount = 0;
    private $_deleteImageCount = 0;
    private $_photoCount = 0;
    private $_retsClassID = '';
    private $_retsClassType = '';
    private $_retsClassIDS = array('A', 'B', 'C', 'D', 'E', 'F', 'AGENT', 'OFFICE');

    //  this should eventually come from a config file, or something?
    //  these fields need to be added to the data and translation tables eventually
    private $_fieldsToSkipRegEx = array('list_0','list_84','list_113','unusedfield','room_length','room_width','room_area','room_rem','desig_nar green','list_45','list_91','LIST_92','LIST_94','LIST_54','LIST_59','list_74','list_86','list_96','list_97','list_101','list_102','LIST_111','list_112','list_117','list_120','list_121','list_127','GF20100401183654367603000000','GF20100401184140204030000000','FEAT20110110165016765894000000','GF20101203215546926447000000','GF20101203215602102494000000','GF20101203215643343824000000','GF20101203215615511014000000','GF20101203215725594534000000','FEAT20110110171311577483000000','FEAT20101206142843631509000000','DO_FRANCHISE_IDX','FEAT20101206143410523350000000');

    const DEV_EMAIL = 'dennis@flexiss.net';
    const ADMIN_EMAIL = 'dennis@flexiss.net';
    const RETS_SRV_VER = 'RETS/1.5';
    const RETS_SRV_URL = 'http://retsgw.flexmls.com:6103/rets1_4/Login';
    const RETS_SRV_USER = 'ags.rets.flexiss';
    const RETS_SRV_PASS = 'wacks-rrhagia39';
    const RETS_MLS_ID = '20081110171208613984000000';
    const RETS_MLS_ID_FIELD = 'LIST_0';
    const LISTING_FIELD_ID = 'LIST_1';
    const AGENT_FIELD_ID = 'MEMBER_0';
    const OFFICE_FIELD_ID = 'OFFICE_0';
    const LISTING_TIME_STAMP_FIELD = 'LIST_87';
    const MLS_NUM_FIELD = 'LIST_105';
    const AGENT_TIME_STAMP_FIELD = 'TIMESTAMP';
    const OFFICE_TIME_STAMP_FIELD = 'TIMESTAMP';
    const LISTING_STATUS_FIELD = 'LIST_15';
    const AGENT_OFFICE_STATUS_FIELD = 'STATUS';
    const ACTIVE_STATUS = 'Active';

    const RETS_AGS_IMG_TABLE = "`rets_to_ags_img_import`";
    const LISTING_PHOTO_TIME_STAMP_FIELD = 'LIST_134';
    const PHOTO_SMALL_KEY = 'Photo';
    const PHOTO_LARGE_KEY = 'HiRes';
    const RESIDENTIAL_LISTING_PHOTO_PATH = '/home/flexiss/public_html/idx/ags/rets/property_images';  //  no trailing slash
    const RESIDENTIAL_LISTING_PHOTO_BASE_URL = 'http://idx.flexiss.net/ags/rets/property_images';  //  no trailing slash
    const OFFICE_LISTING_PHOTO_PATH = '/home/flexiss/public_html/idx/ags/rets/office_images';  //  no trailing slash
    const OFFICE_LISTING_PHOTO_BASE_URL = 'http://idx.flexiss.net/ags/rets/office_images';  //  no trailing slash
    const AGENT_LISTING_PHOTO_PATH = '/home/flexiss/public_html/idx/ags/rets/agent_images';  //  no trailing slash
    const AGENT_LISTING_PHOTO_BASE_URL = 'http://idx.flexiss.net/ags/rets/agent_images';  //  no trailing slash

    /*
     *
     *  function __construct()
     *
     *  internal var _classDebug determines verbosity
     *  executes function _processRequest()
     *
     *  @access public
     *  @var none
     *  @return none
     *
     */
    public function __construct() {
      ini_set('display_errors', ($this->_classDebug ? 1 : 0));
      error_reporting(($this->_classDebug ? E_ALL ^ E_NOTICE : 0));
      set_time_limit(60*60);
      //ini_set('max_execution_time', 60*60);
      $this->_processRequest();
    }

    /*
     *
     *  function _loadDataClass()
     *
     *  by value of internal var _retsClassType,
     *  retrieve apprropriate class data from
     *  RETS server and load/synch with local DB
     *
     *  auto-connect local DB
     *
     *  @access private
     *  @var none
     *  @return none
     *
     */
    private function _loadDataClass() {
      if (!eregi('(AGENT|OFFICE)', $this->_retsClassType)) {  //  property
        $recordFieldID = self::LISTING_FIELD_ID;
        $timeStampField = self::LISTING_TIME_STAMP_FIELD;
      } else {  //  office/agent
        if (eregi('(OFFICE)', $this->_retsClassType)) {  //  office
          $recordFieldID = self::OFFICE_FIELD_ID;
          $timeStampField = self::OFFICE_TIME_STAMP_FIELD;
        } else {  // agent
          $recordFieldID = self::AGENT_FIELD_ID;
          $timeStampField = self::AGENT_TIME_STAMP_FIELD;
        }
      }
      $sqlTable = "`rets_to_ags_class_" . strtolower($this->_retsClassID) . "_data_import`";
      $sqlInsert = "INSERT INTO " . $sqlTable . " (%s) VALUES (%s);";
      $sqlUpdate = "UPDATE " . $sqlTable . " SET %s WHERE `" . $recordFieldID . "` = '%s';";
      $sqlTruncate = "TRUNCATE TABLE " . $sqlTable . ";";

      $recordID = ''; $timeStamp = ''; $status = '';
      $fieldBlackList = implode('|', $this->_fieldsToSkipRegEx);

      $this->_connectDB();
      if (!eregi('(AGENT|OFFICE)', $this->_retsClassID)) {  //  property search param
        $retsSearchParam = self::RETS_MLS_ID_FIELD . '=' . self::RETS_MLS_ID;
        if($this->_db->Execute($sqlTruncate) === false) {
          //  truncate failed
          $this->_exitOnError('db-sql', $this->_db->ErrorMsg() . "\n\n" . $sql);
        } else {
          //echo $sqlTruncate;
          //exit();
        }
      } else {  //  agent/office search param
        $this->_retsClassType = ucwords(strtolower($this->_retsClassType));
        $this->_retsClassID = ucwords(strtolower($this->_retsClassID));
        $retsSearchParam = self::AGENT_OFFICE_STATUS_FIELD . '=' . self::ACTIVE_STATUS;
      }
      $search = $this->_rets->Search($this->_retsClassType, $this->_retsClassID, '(' . $retsSearchParam . ')');

      //  step thru all rets records
      foreach ($search as $listing => $listingIndex) {

        //  reset loop vars
        $newTimeStamp = false;
        $newRecord = false;
        $sqlInsertFields = array();
        $sqlInsertValues = array();
        $sqlUpdates = array();

        //  load values for this rets record
        foreach ($listingIndex as $listingKey => $listingValue) {
          if (!eregi('(' . $fieldBlackList . ')', strtolower($listingKey))) {
            if ($listingKey == $recordFieldID) $recordID = $listingIndex[$listingKey];
            if ($listingKey == $timeStampField) $timeStamp = $listingIndex[$listingKey];
            if ($listingKey == self::LISTING_STATUS_FIELD) $status = $listingIndex[$listingKey];
            $sqlInsertFields[] = "`" . $listingKey . "`";
            $sqlInsertValues[] = "'" . htmlentities($listingIndex[$listingKey], ENT_QUOTES) . "'";
            $sqlUpdates[] = "`" . $listingKey . "` = '" . htmlentities($listingIndex[$listingKey], ENT_QUOTES) . "'";
          }
        }

      //if ($status == self::ACTIVE_STATUS) {  //  don't need this check
          //  check listing id existence, and/or changed timestamp
          $sql = "SELECT `" . $timeStampField . "` FROM " . $sqlTable . " WHERE `" . $recordFieldID . "` = '%s';";
          $this->_rs = $this->_db->Execute(sprintf($sql, $recordID));
          if ($this->_rs->RecordCount() == 0) {
            $newRecord = true;
          } else {
            if ($this->_rs->Fields($timeStampField) != $timeStamp) $newTimeStamp = true;
          }
          //  non-existent (new) record
          if ($newRecord) {
            //  do insert
            $sql = sprintf($sqlInsert, implode(',', $sqlInsertFields), implode(',', $sqlInsertValues));
            if($this->_db->Execute($sql) === false) {
              //  insert failed
              $this->_exitOnError('db-sql', $this->_db->ErrorMsg() . "\n\n" . $sql);
            } else {
              $this->_insertCount++;
            }
          }
          //  existing (modified) record
          if ($newTimeStamp) {
            //  do update
            $sql = sprintf($sqlUpdate, implode(',', $sqlUpdates), $recordID);
            if($this->_db->Execute($sql) === false) {
              //  update failed;
              $this->_exitOnError('db-sql', $this->_db->ErrorMsg() . "\n\n" . $sql);
            } else {
              $this->_updateCount++;
            }
          }
      //}  //  don't need this check

      }  //  end for each
    }

    /*
     *
     *  function _loadImageClass()
     *
     *  by value of internal var _retsClassType,
     *  retrieves corresponding data images from RETS
     *  server and loads reference data into local DB
     *  with image info and storage locations/urls.
     *
     *  even though this function is aware of agent/office
     *  distincitions, it is not being called/utilized
     *  (yet) by either of those two RETS data classes
     *
     *  @access private
     *  @var none
     *  @return none
     *
     */
    private function _loadImageClass() {
      switch(strtolower($this->_retsClassID)) {
        case 'agent':  //  not utilized yet
          $classPhotoPath = self::AGENT_LISTING_PHOTO_PATH;
          $classPhotoURL = self::AGENT_LISTING_PHOTO_BASE_URL;
          $classFieldID = self::AGENT_FIELD_ID;
          $classType = strtolower($this->_retsClassID);
          $classImageTimeStamp = self::LISTING_PHOTO_TIME_STAMP_FIELD;  //  no image timestamp for agents
          break;
        case 'office':  //  not utilized yet
          $classPhotoPath = self::OFFICE_LISTING_PHOTO_PATH;
          $classPhotoURL = self::OFFICE_LISTING_PHOTO_BASE_URL;
          $classFieldID = self::OFFICE_FIELD_ID;
          $classType = strtolower($this->_retsClassID);
          $classImageTimeStamp = self::LISTING_PHOTO_TIME_STAMP_FIELD;  //  no image timestamp for offices
          break;
        default:  //  all others (property)
          $classPhotoPath = self::RESIDENTIAL_LISTING_PHOTO_PATH;
          $classPhotoURL = self::RESIDENTIAL_LISTING_PHOTO_BASE_URL;
          $classFieldID = self::LISTING_FIELD_ID;
          $classType = 'property';
          $classImageTimeStamp = self::LISTING_PHOTO_TIME_STAMP_FIELD;
      }
      $sqlTable = "`rets_to_ags_class_" . strtolower($this->_retsClassID) . "_data_import`";
      //  if $classImageTimeStamp == '0000-00-00 00:00:00', then datediff function returns NULL
      $sqlWhere = " WHERE DATEDIFF(NOW(), " .  $classImageTimeStamp . ") <= 1 ";  //  1 day diff - assume last run was 1 day back
      //  temporary catch up clause for larger images
      //$sqlWhere = " WHERE DATEDIFF(NOW(), '2009-02-07') < 120 AND LIST_134 != '0000-00-00 00:00:00' ";
      //$sqlWhere = "";
      //$sqlWhere .= "OR " . $classFieldID . " NOT IN (SELECT DISTINCT (id) FROM " . self::RETS_AGS_IMG_TABLE . ")";
      $sql = 'SELECT ' . $classFieldID . ' FROM ' . $sqlTable . ' ' . $sqlWhere;
      $this->_connectDB();
      $this->_rs = $this->_db->Execute($sql);
      if ($this->_rs) {
        //  build image import data sqls
        $sqlInsert = "INSERT INTO " . self::RETS_AGS_IMG_TABLE . " VALUES ('%s', '%s', '%s', '%s', '%s', '%s')";
        $sqlUpdate = "UPDATE " . self::RETS_AGS_IMG_TABLE . " SET img_url = '%s', img_path = '%s' WHERE id = '%s' AND img_index = '%s' AND img_class = '%s' AND img_size = '%s'";
        $sqlSelect = "SELECT id, img_path FROM " . self::RETS_AGS_IMG_TABLE . " WHERE id = '%s' AND img_index = %s AND img_class = '%s' AND img_size = '%s'";
        while (!$this->_rs->EOF) {
          $retsRecordId = $this->_rs->fields[$classFieldID];
          $subDir = $retsRecordId[strlen(str_replace('000000', '', $retsRecordId)) - 1];  //  last char of listing id (0-9)
          //  get small images
          $photos = $this->_rets->GetObject($this->_retsClassType, self::PHOTO_SMALL_KEY, $retsRecordId); //args: Property , Photo, [LIST_1]
          foreach($photos as $photo) {
            if($photo['Success'] == true) {
              //  generate unique id in the image name to avoid any browser cache issue
              $uniqid = uniqid($this->_retsClassID . '_');
              //$photoName = "$subDir/{$retsRecordId}_{$photo['Object-ID']}_$uniqid.jpg";  //  [LIST_1]_(0,1,2...)_(A,B)_(Uniquid).jpg
              $photoName = (!eregi('(AGENT|OFFICE)', $this->_retsClassType) ? $subDir . '/' : '/') . $retsRecordId . '_' . $photo['Object-ID'] . '_' . $uniqid . '.jpg';
              $fp = fopen($classPhotoPath . '/' . $photoName, 'w+');
              if ($fp) {
                if (fwrite($fp, $photo['Data']) != -1) {
                  fclose($fp);
                  $rs = $this->_db->Execute(sprintf($sqlSelect, $retsRecordId, $photo['Object-ID'], $classType, 'small'));
                  if (!$rs->fields['id']) {
                    //  insert new record
                    $this->_db->Execute(sprintf($sqlInsert, $retsRecordId, $photo['Object-ID'], $classType, 'small',
                      $classPhotoURL . '/' . $photoName, $classPhotoPath . '/' . $photoName));
                  } else {
                    //  update old record
                    $this->_db->Execute(sprintf($sqlUpdate, $classPhotoURL . '/' . $photoName, $classPhotoPath . '/' . $photoName,
                    $retsRecordId, $photo['Object-ID'], $classType, 'small'));
                    //  delete old photo
                    unlink($rs->fields['img_path']);
                  }
                  $this->_photoCount++;
                } else {
                  $this->_exitOnError('io-perm', "can't write " . $classPhotoPath . '/' . $photoName);
                }
              } else {
                $this->_exitOnError('io-perm', $classPhotoPath . '/' . $photoName);
              }
            } else {
              //  error getting this image from RETS...no need to exit for this
              //$this->_exitOnError('object-error', 'Photo for id: ' . $retsRecordId);
            }
          }  //  end foreach small image
          //  get larger images
          $photos = $this->_rets->GetObject($this->_retsClassType, self::PHOTO_LARGE_KEY, $retsRecordId); //args: Property , Photo, [LIST_1]
          if (is_array($photos)) {
            foreach($photos as $photo) {
              if($photo['Success'] == true) {
                //  if image > 640, scale back down
                //$im = new Imagick();
                //$image = $photo['Data'];
                //$im->readimageblob($image);  //  read blob
                //if($im->getImageWidth($image) > 640) {
                  //$im->thumbnailImage(640, 0);  //  scale at 640 x 0 (0 height maintains aspect ratio)
                  //$photo['Data'] = $im->getimageblob();  //  replace blob
                  //$this->_imageScaleCount++;
                //}
                //  generate unique id in the image name to avoid any browser cache issue
                $uniqid = uniqid($this->_retsClassID . '_');
                //$photoName = "$subDir/{$retsRecordId}_{$photo['Object-ID']}_$uniqid.jpg";  //  [LIST_1]_(0,1,2...)_(A,B)_(Uniquid).jpg
                $photoName = (!eregi('(AGENT|OFFICE)', $this->_retsClassType) ? $subDir . '/' : '/') . $retsRecordId . '_' . $photo['Object-ID'] . '_' . $uniqid . '.jpg';
                $fp = fopen($classPhotoPath . '/' . $photoName, 'w+');
                if ($fp) {
                  if (fwrite($fp, $photo['Data']) !== FALSE ) {
                    fclose($fp);
                    $rs = $this->_db->Execute(sprintf($sqlSelect, $retsRecordId, $photo['Object-ID'], $classType, 'large'));
                    if (!$rs->fields['id']) {
                      //  insert new record
                      $this->_db->Execute(sprintf($sqlInsert, $retsRecordId, $photo['Object-ID'], $classType, 'large',
                        $classPhotoURL . '/' . $photoName, $classPhotoPath . '/' . $photoName));
                    } else {
                      //  update old record
                      $this->_db->Execute(sprintf($sqlUpdate, $classPhotoURL . '/' . $photoName, $classPhotoPath . '/' . $photoName,
                        $retsRecordId, $photo['Object-ID'], $classType, 'large'));
                      //  delete old photo
                      unlink($rs->fields['img_path']);
                    }
                    $this->_photoCount++;
                  } else {
                    $this->_exitOnError('io-perm', "can't write " . $classPhotoPath . '/' . $photoName);
                  }
                } else {
                  $this->_exitOnError('io-perm', $classPhotoPath . '/' . $photoName);
                }
              } else {
                //$this->_exitOnError('object-error', 'Photo for id: ' . $retsRecordId);
              }
            }  //  end foreach large image
          }  //  end if object
          $this->_rs->MoveNext();
        }  //  end while
      } else {
        $this->_exitOnError('db-sql', $this->_db->ErrorMsg() . "\n\n" . $sql);
      }
    }

    /*
     *
     *  function _loadDeadwoodClass()
     *
     *  removed property data where listing_id
     *    is no longer active
     *
     *  removed images where listing id
     *    is no longer active
     *
     *  @access private
     *  @var none
     *  @return none
     */
    private function _runDeadwoodClass() {
      //  step one
      //  select all ids from listing_headers
      //  for each id, if not in the RETS property tables
      //  then delete corresponding trailer table records
      //  and then the actual listing header reocrds
      $mlsNumbers = array();
      $this->_connectDB();
      $retsTable = 'rets_to_ags_class_' . strtolower($this->_retsClassID) . '_data_import';
      $sql = "select mls_no from listing_headers where mls_system = 'ags' and rets_class = '%s';";
      $this->_rs = $this->_db->Execute($sql, strtolower($this->_retsClassID));
      if (!empty($this->_rs)) {
        while (!$this->_rs->EOF) {
          $sql = 'select ' . self::MLS_NUM_FIELD . ' from ' . $retsTable . ' where ' . self::MLS_NUM_FIELD . ' = ' . $this->_rs->fields['mls_no'];
          if (!$this->_db->Execute($sql))  // not there, so collect for deletion
            $mlsNumbers[] = $this->_rs->fields['mls_no'];
          $this->_rs->MoveNext();
        }

        //  1) delete all property records
        $mlsNumberList = "'" . implode("','", $mlsNumbers) . "'";
        $sql = "delete from listing_headers where mls_no IN (" . $mlsNumberList . ");";
        if($this->_db->Execute(sprintf($sql, strtolower($this->_retsClassID))) === false) {
          //  delete failed
          $this->_exitOnError('db-sql', $this->_db->ErrorMsg() . "\n\n" . $sql);
        } else {
          $this->_deletePropCount+= $this->_db->Affected_Rows();
        }
        //  2.1) unlink image files
        $sql = "select img_path from rets_to_ags_img_import where id IN (select " . self::LISTING_FIELD_ID . " from " . $retsTable . " where " . self::MLS_NUM_FIELD . " IN (" . $mlsNumberList . "));";
        $rs = $this->_db->Execute($sql);
        if ($rs) {
          while (!$rs->EOF) {
            unlink($this->_rs['img_path']);
            $rs->MoveNext();
          }
        }

        //  2.2) delete image database records
        $sql = "delete from rets_to_ags_img_import where id IN (select " . self::LISTING_FIELD_ID . " from " . $retsTable . " where " . self::MLS_NUM_FIELD . " IN (" . $mlsNumberList . "));";
        if($this->_db->Execute($sql) === false) {
          //  delete failed
          $this->_exitOnError('db-sql', $this->_db->ErrorMsg() . "\n\n" . $sql);
        } else {
          $this->_deleteImageCount+= $this->_db->Affected_Rows();
        }
      }

      //  step two
      //  additionally, select all distinct listing_ids from
      //  RETS image table and delete if not
      //  represented in the listing_headers table

    }


    /*
     *
     *  function _connectDB()
     *
     *  via ADODB/LITE, make DB connection
     *
     *  @access private
     *  @var none
     *  @return none
     *
     */
    private function _connectDB() {
      require_once '_adodb/config.inc.php';
      require_once '_adodb/adodb.inc.php';
      $ADODB_FETCH_MODE = 'ADODB_FETCH_BOTH';
      $this->_db = ADONewConnection('mysql');
      $this->_db->debug = true;
      if(!$this->_db->Connect(DB_HOST, DB_USER, DB_PASS, DB_USE)) {
        $this->_exitOnError('db-conn');
      }
    }

    /*
     *
     *  function _connectRETS()
     *
     *  establish connection to RETS server
     *
     *  @access private
     *  @var none
     *  @return none
     *
     */
    private function _connectRETS() {
      require_once 'class.phrets.php';
      $this->_rets = new phRETS;
      $this->_rets->AddHeader('Accept', '*/*');
      $this->_rets->AddHeader('RETS-Version', self::RETS_SRV_VER);
      $this->_rets->AddHeader('User-Agent', 'PHRETS/1.0');
      $this->_rets->SetParam('cookie_file', 'phrets_cookies.txt');
      //$this->_rets->SetParam("compression_enabled", true);
      $this->_rets->SetParam('debug_mode', $this->_classDebug); // ends up in rets_debug.txt
      $this->_rets->Connect(self::RETS_SRV_URL, self::RETS_SRV_USER, self::RETS_SRV_PASS);
      if (empty($this->_rets->ch)) $this->_exitOnError('rets-conn');
    }

    /*
     *
     *  function _processRequest()
     *
     *  processing $_REQUEST parameter
     *  auto-connect RETS server and
     *  auto-execute function, _loadDataClass()
     *
     *  all requests except (AGENT|OFFICE)
     *  auto-execute second function, _loadImageClass()
     *
     *  @access private
     *  @var none
     *  @return none
     *
     */
    private function _processRequest() {
      /*  requests by class IDs
        http://idx.flexiss.net/phrets/class.winr_ags_rets-1.2.2.php?load=(a|b|c|d|e|f|agent|office)
      */
      if (!empty($_REQUEST)) {
        if (!in_array(strtoupper($_REQUEST['load']), $this->_retsClassIDS)) {
          $this->_exitOnError('req-type', strtoupper($_REQUEST['load']));
        } else {
          $this->_retsClassID = strtoupper($_REQUEST['load']);
          $this->_retsClassType = (!eregi('(AGENT|OFFICE)', $this->_retsClassID)) ? 'Property' : ucfirst($this->_retsClassID);
        }
        $this->_connectRETS();
        $this->_loadDataClass();
        if (!eregi('(AGENT|OFFICE)', $this->_retsClassID)) {
          //  get class (residential/commerical) images
          //$this->_loadImageClass();
          //if (!eregi('(b)', $this->_retsClassID)) $this->_runDeadwoodClass();
          $this->_rets->Disconnect();
          $this->_exitOnComplete('Class ' . $this->_retsClassID . ' Data w/Images Import');
        } else {
          //$this->_loadImageClass();  //  not utilized yet
          $this->_rets->Disconnect();
          $this->_exitOnComplete('Class ' . $this->_retsClassID . ' Data Import');
        }
      } else {
        $this->_exitOnError('req-miss');
      }
    }

    /*
     *
     *  function _exitOnError()
     *
     *  error processing and email alerts
     *  script terminates here
     *
     *  @access private
     *  @var (string) $type
     *    pre-defined error label
     *  @var [(string) $data]
     *    any extra formatted data for email
     *  @return none
     *
     */
    private function _exitOnError($type, $data = '') {
      $message = '';
      switch ($type) {
        case 'db-conn':
          $message = 'Database connection failed.';
          break;
        case 'db-sql':
          $message = 'Database SQL failed.' . "\n\n" . $data;
          break;
        case 'req-miss':
          $message = 'Request paramater missing.';
          break;
        case 'req-type':
          $message = 'Request paramater incorrect.' . "\n\n" . $data;
          break;
        case 'rets-conn':
          $message = 'RETS connection failed.';
          break;
        case 'io-perm':
          $message = 'File permission denied.' . "\n\n" . $data;
          break;
        case 'object-error':
          $message = 'Error getting object.' . "\n\n" . $data;
          break;
          break;
      }
      @mail(self::DEV_EMAIL, 'WINR-AGS-RETS Script Error Occurred', $message);
      exit();
    }

    /*
     *
     *  function _exitOnComplete()
     *
     *  completion processing and email alerts
     *  script terminates here
     *
     *  @access private
     *  @var (string) $classMsg
     *    class operation info executed
     *  @return none
     *
     */
    private function _exitOnComplete($classMsg) {
      @mail($this->_classDebug ? self::DEV_EMAIL : self::ADMIN_EMAIL, 'WINR-AGS-RETS Script Completed',
        $classMsg .
        "\n\nUpdate Count: " . $this->_updateCount .
        "\nInsert Count: " . $this->_insertCount .
        "\nPhoto Count: " . $this->_photoCount .
        "\nImages Scaled Count: " . $this->_imageScaleCount .
        "\nProperty Delete Count: " . $this->_deletePropCount .
        "\nImage Delete Count: " . $this->_deleteImageCount);
      exit();
    }

  }  //  end class

  //  self init
  $thisClass = new Winr_Ags_Rets();

?>