Merge pull request #4962 from totten/master-angular-ts
[civicrm-core.git] / CRM / Core / BAO / RecurringEntity.php
index b5b145488caed2adea70c13ea8a1dd2ab9ae9537..f214e164eed49e8b311a91399d526a9a33068eb2 100644 (file)
-<?php\r
-/*\r
- +--------------------------------------------------------------------+\r
- | CiviCRM version 4.4                                                |\r
- +--------------------------------------------------------------------+\r
- | Copyright CiviCRM LLC (c) 2004-2013                                |\r
- +--------------------------------------------------------------------+\r
- | This file is a part of CiviCRM.                                    |\r
- |                                                                    |\r
- | CiviCRM is free software; you can copy, modify, and distribute it  |\r
- | under the terms of the GNU Affero General Public License           |\r
- | Version 3, 19 November 2007 and the CiviCRM Licensing Exception.   |\r
- |                                                                    |\r
- | CiviCRM is distributed in the hope that it will be useful, but     |\r
- | WITHOUT ANY WARRANTY; without even the implied warranty of         |\r
- | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.               |\r
- | See the GNU Affero General Public License for more details.        |\r
- |                                                                    |\r
- | You should have received a copy of the GNU Affero General Public   |\r
- | License and the CiviCRM Licensing Exception along                  |\r
- | with this program; if not, contact CiviCRM LLC                     |\r
- | at info[AT]civicrm[DOT]org. If you have questions about the        |\r
- | GNU Affero General Public License or the licensing of CiviCRM,     |\r
- | see the CiviCRM license FAQ at http://civicrm.org/licensing        |\r
- +--------------------------------------------------------------------+\r
-*/\r
-\r
-/**\r
- *\r
- * @package CRM\r
- * @copyright CiviCRM LLC (c) 2004-2013\r
- * $Id$\r
- *\r
- */\r
-\r
-require_once 'packages/When/When.php';\r
-\r
-class CRM_Core_BAO_RecurringEntity extends CRM_Core_DAO_RecurringEntity {\r
-\r
-  CONST RUNNING = 1;\r
-  public $schedule = array();\r
-  public $scheduleId = NULL;\r
-  public $scheduleFormValues = array();\r
-\r
-  public $dateColumns = array();\r
-  public $overwriteColumns = array();\r
-  public $intervalDateColumns = array();\r
-  public $excludeDates = array();\r
-\r
-  public $linkedEntities = array();\r
-\r
-  public $isRecurringEntityRecord = TRUE;\r
-\r
-  protected $recursion = NULL;\r
-  protected $recursion_start_date = NULL;\r
-\r
-  public static $_entitiesToBeDeleted = array();\r
-\r
-  public static $status = NULL;\r
-\r
-  static $_recurringEntityHelper =\r
-    array(\r
-      'civicrm_event' => array(\r
-        'helper_class' => 'CRM_Event_DAO_Event',\r
-        'delete_func' => 'delete',\r
-        'pre_delete_func' => 'CRM_Event_Form_ManageEvent_Repeat::checkRegistrationForEvents'\r
-      ),\r
-      'civicrm_activity' => array(\r
-        'helper_class' => 'CRM_Activity_DAO_Activity',\r
-        'delete_func' => 'delete',\r
-        'pre_delete_func' => ''\r
-      )\r
-    );\r
-\r
-  static $_dateColumns =\r
-    array(\r
-      'civicrm_event' => array(\r
-        'dateColumns' => array('start_date'),\r
-        'excludeDateRangeColumns' => array('start_date', 'end_date'),\r
-        'intervalDateColumns' => array('end_date')\r
-      ),\r
-      'civicrm_activity' => array(\r
-        'dateColumns' => array('activity_date_time'),\r
-      )\r
-    );\r
-\r
-  static $_tableDAOMapper =\r
-    array(\r
-      'civicrm_event'       => 'CRM_Event_DAO_Event',\r
-      'civicrm_price_set_entity' => 'CRM_Price_DAO_PriceSetEntity',\r
-      'civicrm_uf_join'     => 'CRM_Core_DAO_UFJoin',\r
-      'civicrm_tell_friend' => 'CRM_Friend_DAO_Friend',\r
-      'civicrm_pcp_block'   => 'CRM_PCP_DAO_PCPBlock',\r
-      'civicrm_activity'    => 'CRM_Activity_DAO_Activity',\r
-      'civicrm_activity_contact'  => 'CRM_Activity_DAO_ActivityContact',\r
-    );\r
-\r
-  static $_updateSkipFields =\r
-    array(\r
-      'civicrm_event'       => array('start_date', 'end_date'),\r
-      'civicrm_tell_friend' => array('entity_id'),\r
-      'civicrm_pcp_block'   => array('entity_id'),\r
-      'civicrm_activity'    => array('activity_date_time'),\r
-    );\r
-\r
-  static $_linkedEntitiesInfo =\r
-    array(\r
-      'civicrm_tell_friend' => array(\r
-        'entity_id_col'    => 'entity_id',\r
-        'entity_table_col' => 'entity_table'\r
-      ),\r
-      'civicrm_price_set_entity' => array(\r
-        'entity_id_col'    => 'entity_id',\r
-        'entity_table_col' => 'entity_table',\r
-        'is_multirecord'   => TRUE,\r
-      ),\r
-      'civicrm_uf_join' => array(\r
-        'entity_id_col'    => 'entity_id',\r
-        'entity_table_col' => 'entity_table',\r
-        'is_multirecord'   => TRUE,\r
-      ),\r
-      'civicrm_pcp_block' => array(\r
-        'entity_id_col'    => 'entity_id',\r
-        'entity_table_col' => 'entity_table'\r
-      ),\r
-    );\r
-\r
-  static function getStatus() {\r
-    return self::$status;\r
-  }\r
-\r
-  static function setStatus($status) {\r
-    self::$status = $status;\r
-  }\r
-  /**\r
-   * save records in civicrm_recujrring_entity table\r
-   *\r
-   * @param array $params reference array contains the values submitted by the form\r
-   *\r
-   * @access public\r
-   * @static\r
-   *\r
-   * @return object\r
-   */\r
-  static function add(&$params) {\r
-    if (CRM_Utils_Array::value('id', $params)) {\r
-      CRM_Utils_Hook::pre('edit', 'RecurringEntity', $params['id'], $params);\r
-    }\r
-    else {\r
-      CRM_Utils_Hook::pre('create', 'RecurringEntity', NULL, $params);\r
-    }\r
-\r
-    $daoRecurringEntity = new CRM_Core_DAO_RecurringEntity();\r
-    $daoRecurringEntity->copyValues($params);\r
-    $daoRecurringEntity->find(TRUE);\r
-    $result = $daoRecurringEntity->save();\r
-\r
-    if (CRM_Utils_Array::value('id', $params)) {\r
-      CRM_Utils_Hook::post('edit', 'RecurringEntity', $daoRecurringEntity->id, $daoRecurringEntity);\r
-    }\r
-    else {\r
-      CRM_Utils_Hook::post('create', 'RecurringEntity', $daoRecurringEntity->id, $daoRecurringEntity);\r
-    }\r
-    return $result;\r
-  }\r
-\r
-  /**\r
-   * Wrapper for the function add() to add entry in recurring entity\r
-   *\r
-   * @param int $parentId Parent entity id\r
-   * @param int $entityId Child entity id\r
-   * @param String $entityTable Name of the entity table\r
-   *\r
-   * @access public\r
-   * @static\r
-   *\r
-   * @return object\r
-   */\r
-  static function quickAdd($parentId, $entityId, $entityTable) {\r
-    $params =\r
-      array(\r
-        'parent_id'    => $parentId,\r
-        'entity_id'    => $entityId,\r
-        'entity_table' => $entityTable\r
-      );\r
-    return self::add($params);\r
-  }\r
-\r
-  /**\r
-   * This function updates the mode column in the civicrm_recurring_entity table\r
-   *\r
-   * @param int $mode Mode of the entity to cascade changes across parent/child relations eg 1 - only this entity, 2 - this and the following entities, 3 - All the entity\r
-   *\r
-   * @access public\r
-   *\r
-   * @return void\r
-   */\r
-  function mode($mode) {\r
-    if ($this->entity_id && $this->entity_table) {\r
-      if ($this->find(TRUE)) {\r
-        $this->mode = $mode;\r
-      }\r
-      else {\r
-        $this->parent_id = $this->entity_id;\r
-        $this->mode = $mode;\r
-      }\r
-      $this->save();\r
-    }\r
-  }\r
-\r
-  /**\r
-   * This function generates all new entities based on object vars\r
-   *\r
-   * @return array\r
-   */\r
-  function generate() {\r
-    $this->generateRecursiveDates();\r
-\r
-    return $this->generateEntities();\r
-  }\r
-\r
-  /**\r
-   * This function builds a "When" object based on schedule/reminder params\r
-   *\r
-   * @return object When object\r
-   */\r
-  function generateRecursion() {\r
-    // return if already generated\r
-    if (is_a($this->recursion, 'When')) {\r
-      return $this->recursion;\r
-    }\r
-\r
-    if ($this->scheduleId) {\r
-      // get params by ID\r
-      $this->schedule = $this->getScheduleParams($this->scheduleId);\r
-    }\r
-    else if (!empty($this->scheduleFormValues)) {\r
-      $this->schedule = $this->mapFormValuesToDB($this->scheduleFormValues);\r
-    }\r
-\r
-    if (!empty($this->schedule)) {\r
-      $this->recursion = $this->getRecursionFromSchedule($this->schedule);\r
-    }\r
-    return $this->recursion;\r
-  }\r
-\r
-  /**\r
-   * Generate new DAOs and along with entries in civicrm_recurring_entity table\r
-   *\r
-   * @return array\r
-   */\r
-  function generateEntities() {\r
-    self::setStatus(self::RUNNING);\r
-\r
-    $newEntities  = array();\r
-    $findCriteria = array();\r
-    if (!empty($this->recursionDates)) {\r
-      if ($this->entity_id) {\r
-        $findCriteria = array('id' => $this->entity_id);\r
-\r
-        // save an entry with initiating entity-id & entity-table\r
-        if ($this->entity_table && !$this->find(TRUE)) {\r
-          $this->parent_id = $this->entity_id;\r
-          $this->save();\r
-        }\r
-      }\r
-      if (empty($findCriteria)) {\r
-        CRM_Core_Error::fatal("Find criteria missing to generate form. Make sure entity_id and table is set.");\r
-      }\r
-\r
-      $count = 0;\r
-      foreach ($this->recursionDates as $key => $dateCols) {\r
-        $newCriteria = $dateCols;\r
-        foreach ($this->overwriteColumns as $col => $val) {\r
-          $newCriteria[$col] = $val;\r
-        }\r
-        // create main entities\r
-        $obj = CRM_Core_BAO_RecurringEntity::copyCreateEntity($this->entity_table,\r
-          $findCriteria,\r
-          $newCriteria,\r
-          $this->isRecurringEntityRecord\r
-        );\r
-\r
-        if (is_a($obj, 'CRM_Core_DAO') && $obj->id) {\r
-          $newCriteria = array();\r
-          $newEntities[$this->entity_table][$count] = $obj->id;\r
-\r
-          foreach ($this->linkedEntities as $linkedInfo) {\r
-            foreach ($linkedInfo['linkedColumns'] as $col) {\r
-              $newCriteria[$col] = $obj->id;\r
-            }\r
-            // create linked entities\r
-            $linkedObj = CRM_Core_BAO_RecurringEntity::copyCreateEntity($linkedInfo['table'],\r
-              $linkedInfo['findCriteria'],\r
-              $newCriteria,\r
-              CRM_Utils_Array::value('isRecurringEntityRecord', $linkedInfo, TRUE)\r
-            );\r
-\r
-            if (is_a($linkedObj, 'CRM_Core_DAO') && $linkedObj->id) {\r
-              $newEntities[$linkedInfo['table']][$count] = $linkedObj->id;\r
-            }\r
-          }\r
-        }\r
-        $count++;\r
-      }\r
-    }\r
-\r
-    self::$status = NULL;\r
-    return $newEntities;\r
-  }\r
-\r
-  /**\r
-   * This function iterates through when object criterias and\r
-   * generates recursive dates based on that\r
-   *\r
-   * @return array array of dates\r
-   */\r
-  function generateRecursiveDates() {\r
-    $this->generateRecursion();\r
-\r
-    $recursionDates = array();\r
-    if (is_a($this->recursion, 'When')) {\r
-      $initialCount = CRM_Utils_Array::value('start_action_offset', $this->schedule);\r
-\r
-      $exRangeStart = $exRangeEnd = NULL;\r
-      if (!empty($this->excludeDateRangeColumns)) {\r
-        $exRangeStart = $this->excludeDateRangeColumns[0];\r
-        $exRangeEnd   = $this->excludeDateRangeColumns[1];\r
-      }\r
-\r
-      $count = 1;\r
-      while ($result = $this->recursion->next()) {\r
-        $skip = FALSE;\r
-        if ($result == $this->recursion_start_date) {\r
-          // skip the recursion-start-date from the list we going to generate\r
-          $skip = TRUE;\r
-        }\r
-        $baseDate = CRM_Utils_Date::processDate($result->format('Y-m-d H:i:s'));\r
-\r
-        foreach ($this->dateColumns as $col) {\r
-          $recursionDates[$count][$col] = $baseDate;\r
-        }\r
-        foreach ($this->intervalDateColumns as $col => $interval) {\r
-          $newDate = new DateTime($baseDate);\r
-          $newDate->add($interval);\r
-          $recursionDates[$count][$col] = CRM_Utils_Date::processDate($newDate->format('Y-m-d H:i:s'));\r
-        }\r
-        if ($exRangeStart) {\r
-          $exRangeStartDate = CRM_Utils_Date::processDate($recursionDates[$count][$exRangeStart], NULL, FALSE, 'Ymd');\r
-          $exRangeEndDate   = CRM_Utils_Date::processDate($recursionDates[$count][$exRangeEnd], NULL, FALSE, 'Ymd');\r
-        }\r
-\r
-        foreach ($this->excludeDates as $exDate) {\r
-          $exDate = CRM_Utils_Date::processDate($exDate, NULL, FALSE, 'Ymd');\r
-          if (!$exRangeStart) {\r
-            if ($exDate == $result->format('Ymd')) {\r
-              $skip = TRUE;\r
-              break;\r
-            }\r
-          }\r
-          else {\r
-            if (($exDate == $exRangeStartDate) ||\r
-              ($exRangeEndDate && ($exDate > $exRangeStartDate) && ($exDate <= $exRangeEndDate))\r
-            ) {\r
-              $skip = TRUE;\r
-              break;\r
-            }\r
-          }\r
-        }\r
-\r
-        if ($skip) {\r
-          unset($recursionDates[$count]);\r
-          if ($initialCount && ($initialCount > 0)) {\r
-            // lets increase the counter, so we get correct number of occurrences\r
-            $initialCount++;\r
-            $this->recursion->count($initialCount);\r
-          }\r
-          continue;\r
-        }\r
-        $count++;\r
-      }\r
-    }\r
-    $this->recursionDates = $recursionDates;\r
-\r
-    return $recursionDates;\r
-  }\r
-\r
-  /**\r
-   * This function gets all the children for a particular parent entity\r
-   *\r
-   * @param int $parentId Parent entity id\r
-   * @param string $entityTable Name of the entity table\r
-   * @param boolean $includeParent If true parent id is included in result set and vice versa\r
-   * @param int $mode 1. retrieve only one entity. 2. retrieve all future entities in the repeating set. 3. all entities in the repeating set.\r
-   * @param int $initiatorId the instance where this function is invoked from\r
-   *\r
-   * @access public\r
-   * @static\r
-   *\r
-   * @return array an array of child ids\r
-   */\r
-  static public function getEntitiesForParent($parentId, $entityTable, $includeParent = TRUE, $mode = 3, $initiatorId = NULL) {\r
-    $entities = array();\r
-    if (empty($parentId) || empty($entityTable)) {\r
-      return $entities;\r
-    }\r
-\r
-    if (!$initiatorId) {\r
-      $initiatorId = $parentId;\r
-    }\r
-\r
-    $queryParams = array(\r
-      1 => array($parentId,    'Integer'),\r
-      2 => array($entityTable, 'String'),\r
-      3 => array($initiatorId, 'Integer'),\r
-    );\r
-\r
-    if (!$mode) {\r
-      $mode = CRM_Core_DAO::singleValueQuery("SELECT mode FROM civicrm_recurring_entity WHERE entity_id = %3 AND entity_table = %2", $queryParams);\r
-    }\r
-\r
-    $query = "SELECT *\r
-      FROM civicrm_recurring_entity\r
-      WHERE parent_id = %1 AND entity_table = %2";\r
-    if (!$includeParent) {\r
-      $query .= " AND entity_id != " . ($initiatorId ? "%3" : "%1");\r
-    }\r
-\r
-    if ($mode == '1') { // MODE = SINGLE\r
-      $query .= " AND entity_id = %3";\r
-    }\r
-    else if ($mode == '2') { // MODE = FUTURE\r
-      $recurringEntityID = CRM_Core_DAO::singleValueQuery("SELECT id FROM civicrm_recurring_entity WHERE entity_id = %3 AND entity_table = %2", $queryParams);\r
-      if ($recurringEntityID) {\r
-        $query .= $includeParent ? " AND id >= %4" : " AND id > %4";\r
-        $query .= " ORDER BY id ASC"; // FIXME: change to order by dates\r
-        $queryParams[4] = array($recurringEntityID, 'Integer');\r
-      }\r
-      else {\r
-        // something wrong, return empty\r
-        return array();\r
-      }\r
-    }\r
-\r
-    $dao = CRM_Core_DAO::executeQuery($query, $queryParams);\r
-    while ($dao->fetch()) {\r
-      $entities["{$dao->entity_table}_{$dao->entity_id}"]['table'] = $dao->entity_table;\r
-      $entities["{$dao->entity_table}_{$dao->entity_id}"]['id'] = $dao->entity_id;\r
-    }\r
-    return $entities;\r
-  }\r
-\r
-  /**\r
-   * This function when passed an entity id checks if it has parent and\r
-   * returns all other entities that are connected to same parent.\r
-   *\r
-   * @param int $entityId entity id\r
-   * @param string $entityTable Entity table name\r
-   * @param boolean $includeParent Include parent in result set\r
-   * @param int $mode 1. retrieve only one entity. 2. retrieve all future entities in the repeating set. 3. all entities in the repeating set.\r
-   *\r
-   * @access public\r
-   * @static\r
-   *\r
-   * @return array array of connected ids\r
-   */\r
-  static public function getEntitiesFor($entityId, $entityTable, $includeParent = TRUE, $mode = 3) {\r
-    $parentId = self::getParentFor($entityId, $entityTable);\r
-    if ($parentId) {\r
-      return self::getEntitiesForParent($parentId, $entityTable, $includeParent, $mode, $entityId);\r
-    }\r
-    return array();\r
-  }\r
-\r
-  /**\r
-   * This function gets the parent for the entity id passed to it\r
-   *\r
-   * @param int $entityId entity ID\r
-   * @param string $entityTable Entity table name\r
-   * @param boolean $includeParent Include parent in result set\r
-   *\r
-   * @access public\r
-   * @static\r
-   *\r
-   * @return int unsigned $parentId Parent ID\r
-   */\r
-  static public function getParentFor($entityId, $entityTable, $includeParent = TRUE) {\r
-    if (empty($entityId) || empty($entityTable)) {\r
-      return NULL;\r
-    }\r
-\r
-    $query = "\r
-      SELECT parent_id\r
-      FROM civicrm_recurring_entity\r
-      WHERE entity_id = %1 AND entity_table = %2";\r
-    if (!$includeParent) {\r
-      $query .= " AND parent_id != %1";\r
-    }\r
-    $parentId =\r
-      CRM_Core_DAO::singleValueQuery($query,\r
-        array(\r
-          1 => array($entityId, 'Integer'),\r
-          2 => array($entityTable, 'String'),\r
-        )\r
-      );\r
-    return $parentId;\r
-  }\r
-\r
-  /**\r
-   * This function copies the information from parent entity and creates other entities with same information\r
-   *\r
-   * @param string $entityTable Entity table name\r
-   * @param array $fromCriteria array of all the fields & values on which basis to copy\r
-   * @param array $newParams  array of all the fields & values to be copied besides the other fields\r
-   * @param boolean $createRecurringEntity if to create a record in recurring_entity table\r
-   *\r
-   * @access public\r
-   * @static\r
-   *\r
-   * @return object\r
-   */\r
-  static public function copyCreateEntity($entityTable, $fromCriteria, $newParams, $createRecurringEntity = TRUE) {\r
-    $daoName = self::$_tableDAOMapper[$entityTable];\r
-    if (!$daoName) {\r
-      CRM_Core_Error::fatal("DAO Mapper missing for $entityTable.");\r
-    }\r
-    $newObject = CRM_Core_DAO::copyGeneric($daoName, $fromCriteria, $newParams);\r
-\r
-    if (is_a($newObject, 'CRM_Core_DAO') && $newObject->id && $createRecurringEntity) {\r
-      $object = new $daoName( );\r
-      foreach ($fromCriteria as $key => $value) {\r
-        $object->$key = $value;\r
-      }\r
-      $object->find(TRUE);\r
-\r
-      CRM_Core_BAO_RecurringEntity::quickAdd($object->id, $newObject->id, $entityTable);\r
-    }\r
-    return $newObject;\r
-  }\r
-\r
-  /**\r
-   * This function acts as a listener to dao->update whenever there is an update,\r
-   * and propagates any changes to all related entities present in recurring entity table\r
-   *\r
-   * @param object $event An object of /Civi/Core/DAO/Event/PostUpdate containing dao object that was just updated\r
-   *\r
-   * @access public\r
-   * @static\r
-   *\r
-   * @return void\r
-   */\r
-  static public function triggerUpdate($event) {\r
-    // if DB version is earlier than 4.6 skip any processing\r
-    static $currentVer = NULL;\r
-    if (!$currentVer) {\r
-      $currentVer = CRM_Core_BAO_Domain::version();\r
-    }\r
-    if (version_compare($currentVer, '4.6.alpha1') < 0) {\r
-      return;\r
-    }\r
-\r
-    static $processedEntities = array();\r
-    $obj =& $event->object;\r
-    if (empty($obj->id) || empty($obj->__table)) {\r
-      return FALSE;\r
-    }\r
-    $key = "{$obj->__table}_{$obj->id}";\r
-\r
-    if (array_key_exists($key, $processedEntities)) {\r
-      // already processed\r
-      return NULL;\r
-    }\r
-\r
-    // get related entities\r
-    $repeatingEntities = self::getEntitiesFor($obj->id, $obj->__table, FALSE, NULL);\r
-    if (empty($repeatingEntities)) {\r
-      // return if its not a recurring entity parent\r
-      return NULL;\r
-    }\r
-    // mark being processed\r
-    $processedEntities[$key] = 1;\r
-\r
-    // to make sure we not copying to source itself\r
-    unset($repeatingEntities[$key]);\r
-\r
-    foreach($repeatingEntities as $key => $val) {\r
-      $entityID = $val['id'];\r
-      $entityTable = $val['table'];\r
-\r
-      $processedEntities[$key] = 1;\r
-\r
-      if (array_key_exists($entityTable, self::$_tableDAOMapper)) {\r
-        $daoName  = self::$_tableDAOMapper[$entityTable];\r
-\r
-        $skipData = array();\r
-        if (array_key_exists($entityTable, self::$_updateSkipFields)) {\r
-          $skipFields = self::$_updateSkipFields[$entityTable];\r
-          foreach ($skipFields as $sfield) {\r
-            $skipData[$sfield] = NULL;\r
-          }\r
-        }\r
-\r
-        $updateDAO = CRM_Core_DAO::cascadeUpdate($daoName, $obj->id, $entityID, $skipData);\r
-        CRM_Core_DAO::freeResult();\r
-      }\r
-      else {\r
-        CRM_Core_Error::fatal("DAO Mapper missing for $entityTable.");\r
-      }\r
-    }\r
-    // done with processing. lets unset static var.\r
-    unset($processedEntities);\r
-  }\r
-\r
-  /**\r
-   * This function acts as a listener to dao->save,\r
-   * and creates entries for linked entities in recurring entity table\r
-   *\r
-   * @param object $event An object of /Civi/Core/DAO/Event/PostUpdate containing dao object that was just inserted\r
-   *\r
-   * @access public\r
-   * @static\r
-   *\r
-   * @return void\r
-   */\r
-  static public function triggerInsert($event) {\r
-    $obj =& $event->object;\r
-    if (!array_key_exists($obj->__table, self::$_linkedEntitiesInfo)) {\r
-      return FALSE;\r
-    }\r
-\r
-    // if DB version is earlier than 4.6 skip any processing\r
-    static $currentVer = NULL;\r
-    if (!$currentVer) {\r
-      $currentVer = CRM_Core_BAO_Domain::version();\r
-    }\r
-    if (version_compare($currentVer, '4.6.alpha1') < 0) {\r
-      return;\r
-    }\r
-\r
-    static $processedEntities = array();\r
-    if (empty($obj->id) || empty($obj->__table)) {\r
-      return FALSE;\r
-    }\r
-    $key = "{$obj->__table}_{$obj->id}";\r
-\r
-    if (array_key_exists($key, $processedEntities)) {\r
-      // already being processed. Exit recursive calls.\r
-      return NULL;\r
-    }\r
-\r
-    if (self::getStatus() == self::RUNNING) {\r
-      // if recursion->generate() is doing some work, lets not intercept\r
-      return NULL;\r
-    }\r
-\r
-    // mark being processed\r
-    $processedEntities[$key] = 1;\r
-\r
-    // get related entities for table being saved\r
-    $hasaRecurringRecord = self::getParentFor($obj->id, $obj->__table);\r
-\r
-    if (empty($hasaRecurringRecord)) {\r
-      // check if its a linked entity\r
-      if (array_key_exists($obj->__table, self::$_linkedEntitiesInfo) &&\r
-        !CRM_Utils_Array::value('is_multirecord', self::$_linkedEntitiesInfo[$obj->__table])) {\r
-        $linkedDAO = new self::$_tableDAOMapper[$obj->__table]();\r
-        $linkedDAO->id = $obj->id;\r
-        if ($linkedDAO->find(TRUE)) {\r
-          $idCol = self::$_linkedEntitiesInfo[$obj->__table]['entity_id_col'];\r
-          $tableCol = self::$_linkedEntitiesInfo[$obj->__table]['entity_table_col'];\r
-\r
-          $pEntityID    = $linkedDAO->$idCol;\r
-          $pEntityTable = $linkedDAO->$tableCol;\r
-\r
-          // find all parent recurring entity set\r
-          $pRepeatingEntities = self::getEntitiesFor($pEntityID, $pEntityTable);\r
-\r
-          if (!empty($pRepeatingEntities)) {\r
-            // for each parent entity in the set, find out a similar linked entity,\r
-            // if doesn't exist create one, and also create entries in recurring_entity table\r
-\r
-            foreach($pRepeatingEntities as $key => $val) {\r
-              if (array_key_exists($key, $processedEntities)) {\r
-                // this graph is already being processed\r
-                return NULL;\r
-              }\r
-              $processedEntities[$key] = 1;\r
-            }\r
-\r
-            // start with first entry with just itself\r
-            CRM_Core_BAO_RecurringEntity::quickAdd($obj->id, $obj->id, $obj->__table);\r
-\r
-            foreach($pRepeatingEntities as $key => $val) {\r
-              $rlinkedDAO = new self::$_tableDAOMapper[$obj->__table]();\r
-              $rlinkedDAO->$idCol = $val['id'];\r
-              $rlinkedDAO->$tableCol = $val['table'];\r
-              if ($rlinkedDAO->find(TRUE)) {\r
-                CRM_Core_BAO_RecurringEntity::quickAdd($obj->id, $rlinkedDAO->id, $obj->__table);\r
-              }\r
-              else {\r
-                // linked entity doesn't exist. lets create them\r
-                $newCriteria = array(\r
-                  $idCol    => $val['id'],\r
-                  $tableCol => $val['table']\r
-                );\r
-                $linkedObj = CRM_Core_BAO_RecurringEntity::copyCreateEntity($obj->__table,\r
-                  array('id' => $obj->id),\r
-                  $newCriteria,\r
-                  TRUE\r
-                );\r
-                if ($linkedObj->id) {\r
-                  CRM_Core_BAO_RecurringEntity::quickAdd($obj->id, $linkedObj->id, $obj->__table);\r
-                }\r
-              }\r
-            }\r
-          }\r
-        }\r
-      }\r
-    }\r
-\r
-    // done with processing. lets unset static var.\r
-    unset($processedEntities);\r
-  }\r
-\r
-  /**\r
-   * This function acts as a listener to dao->delete, and deletes an entry from recurring_entity table\r
-   *\r
-   * @param object $event An object of /Civi/Core/DAO/Event/PostUpdate containing dao object that was just deleted\r
-   *\r
-   * @access public\r
-   * @static\r
-   *\r
-   * @return void\r
-   */\r
-  static public function triggerDelete($event) {\r
-    $obj =& $event->object;\r
-\r
-    // if DB version is earlier than 4.6 skip any processing\r
-    static $currentVer = NULL;\r
-    if (!$currentVer) {\r
-      $currentVer = CRM_Core_BAO_Domain::version();\r
-    }\r
-    if (version_compare($currentVer, '4.6.alpha1') < 0) {\r
-      return;\r
-    }\r
-\r
-    static $processedEntities = array();\r
-    if (empty($obj->id) || empty($obj->__table) || !$event->result) {\r
-      return FALSE;\r
-    }\r
-    $key = "{$obj->__table}_{$obj->id}";\r
-\r
-    if (array_key_exists($key, $processedEntities)) {\r
-      // already processed\r
-      return NULL;\r
-    }\r
-\r
-    // mark being processed\r
-    $processedEntities[$key] = 1;\r
-\r
-    $parentID = self::getParentFor($obj->id, $obj->__table);\r
-    if ($parentID) {\r
-      CRM_Core_BAO_RecurringEntity::delEntity($obj->id, $obj->__table, TRUE);\r
-    }\r
-  }\r
-\r
-  /**\r
-   * This function deletes main entity and related linked entities from recurring-entity table\r
-   *\r
-   * @param int $entityId Entity id\r
-   * @param string $entityTable Name of the entity table\r
-   *\r
-   * @access public\r
-   * @static\r
-   *\r
-   * @return boolean|object Returns either boolean value or CRM_Core_DAO_RecurringEntity object\r
-   */\r
-  static public function delEntity($entityId, $entityTable, $isDelLinkedEntities = FALSE) {\r
-    if (empty($entityId) || empty($entityTable)) {\r
-      return FALSE;\r
-    }\r
-    $dao = new CRM_Core_DAO_RecurringEntity();\r
-    $dao->entity_id = $entityId;\r
-    $dao->entity_table = $entityTable;\r
-    if ($dao->find(TRUE)) {\r
-      // make sure its not a linked entity thats being deleted\r
-      if ($isDelLinkedEntities && !array_key_exists($entityTable, self::$_linkedEntitiesInfo)) {\r
-        // delete all linked entities from recurring entity table\r
-        foreach (self::$_linkedEntitiesInfo as $linkedTable => $linfo) {\r
-          $daoName = self::$_tableDAOMapper[$linkedTable];\r
-          if (!$daoName) {\r
-            CRM_Core_Error::fatal("DAO Mapper missing for $linkedTable.");\r
-          }\r
-\r
-          $linkedDao = new $daoName();\r
-          $linkedDao->$linfo['entity_id_col'] = $entityId;\r
-          $linkedDao->$linfo['entity_table_col'] = $entityTable;\r
-          $linkedDao->find();\r
-          while ($linkedDao->fetch()) {\r
-            CRM_Core_BAO_RecurringEntity::delEntity($linkedDao->id, $linkedTable, FALSE);\r
-          }\r
-        }\r
-      }\r
-      // delete main entity\r
-      return $dao->delete();\r
-    }\r
-    return FALSE;\r
-  }\r
-\r
-  /**\r
-   * This function maps values posted from form to civicrm_action_schedule columns\r
-   *\r
-   * @param array $formParams and array of form values posted\r
-   *\r
-   * @return array\r
-   */\r
-  function mapFormValuesToDB($formParams = array()) {\r
-    $dbParams = array();\r
-    if (CRM_Utils_Array::value('used_for', $formParams)) {\r
-      $dbParams['used_for'] = $formParams['used_for'];\r
-    }\r
-\r
-    if (CRM_Utils_Array::value('entity_id', $formParams)) {\r
-      $dbParams['entity_value'] = $formParams['entity_id'];\r
-    }\r
-\r
-    if (CRM_Utils_Array::value('repetition_start_date', $formParams)) {\r
-      if (CRM_Utils_Array::value('repetition_start_date_display', $formParams)) {\r
-        $repetitionStartDate = $formParams['repetition_start_date_display'];\r
-      }\r
-      else {\r
-        $repetitionStartDate = $formParams['repetition_start_date'];\r
-      }\r
-      if (CRM_Utils_Array::value('repetition_start_date_time', $formParams)) {\r
-        $repetitionStartDate = $repetitionStartDate . " " . $formParams['repetition_start_date_time'];\r
-      }\r
-      $repetition_start_date = new DateTime($repetitionStartDate);\r
-      $dbParams['start_action_date'] = CRM_Utils_Date::processDate($repetition_start_date->format('Y-m-d H:i:s'));\r
-    }\r
-\r
-    if (CRM_Utils_Array::value('repetition_frequency_unit', $formParams)) {\r
-      $dbParams['repetition_frequency_unit'] = $formParams['repetition_frequency_unit'];\r
-    }\r
-\r
-    if (CRM_Utils_Array::value('repetition_frequency_interval', $formParams)) {\r
-      $dbParams['repetition_frequency_interval'] = $formParams['repetition_frequency_interval'];\r
-    }\r
-\r
-    //For Repeats on:(weekly case)\r
-    if ($formParams['repetition_frequency_unit'] == 'week') {\r
-      if (CRM_Utils_Array::value('start_action_condition', $formParams)) {\r
-        $repeats_on = CRM_Utils_Array::value('start_action_condition', $formParams);\r
-        $dbParams['start_action_condition'] = implode(",", array_keys($repeats_on));\r
-      }\r
-    }\r
-\r
-    //For Repeats By:(monthly case)\r
-    if ($formParams['repetition_frequency_unit'] == 'month') {\r
-      if ($formParams['repeats_by'] == 1) {\r
-        if (CRM_Utils_Array::value('limit_to', $formParams)) {\r
-          $dbParams['limit_to'] = $formParams['limit_to'];\r
-        }\r
-      }\r
-      if ($formParams['repeats_by'] == 2) {\r
-        if (CRM_Utils_Array::value('entity_status_1', $formParams) && CRM_Utils_Array::value('entity_status_2', $formParams)) {\r
-          $dbParams['entity_status'] = $formParams['entity_status_1']." ".$formParams['entity_status_2'];\r
-        }\r
-      }\r
-    }\r
-\r
-    //For "Ends" - After:\r
-    if ($formParams['ends'] == 1) {\r
-      if (CRM_Utils_Array::value('start_action_offset', $formParams)) {\r
-        $dbParams['start_action_offset'] = $formParams['start_action_offset'];\r
-      }\r
-    }\r
-\r
-    //For "Ends" - On:\r
-    if ($formParams['ends'] == 2) {\r
-      if (CRM_Utils_Array::value('repeat_absolute_date', $formParams)) {\r
-        $dbParams['absolute_date'] = CRM_Utils_Date::processDate($formParams['repeat_absolute_date']);\r
-      }\r
-    }\r
-    return $dbParams;\r
-  }\r
-\r
-  /**\r
-   * This function gets all the columns of civicrm_action_schedule table based on id(primary key)\r
-   *\r
-   * @param int $scheduleReminderId primary key of civicrm_action_schedule table\r
-   *\r
-   * @access public\r
-   * @static\r
-   *\r
-   * @return object\r
-   */\r
-  static public function getScheduleReminderDetailsById($scheduleReminderId) {\r
-    $query = "SELECT *\r
-      FROM civicrm_action_schedule WHERE 1";\r
-    if ($scheduleReminderId) {\r
-      $query .= "\r
-        AND id = %1";\r
-    }\r
-    $dao = CRM_Core_DAO::executeQuery($query,\r
-      array(\r
-        1 => array($scheduleReminderId, 'Integer')\r
-      )\r
-    );\r
-    $dao->fetch();\r
-    return $dao;\r
-  }\r
-\r
-  /**\r
-   * This function is a wrapper of getScheduleReminderDetailsById function\r
-   *\r
-   * @param int $scheduleReminderId primary key of civicrm_action_schedule table\r
-   *\r
-   * @return array\r
-   */\r
-  function getScheduleParams($scheduleReminderId) {\r
-    $scheduleReminderDetails = array();\r
-    if ($scheduleReminderId) {\r
-      //Get all the details from schedule reminder table\r
-      $scheduleReminderDetails = self::getScheduleReminderDetailsById($scheduleReminderId);\r
-      $scheduleReminderDetails = (array) $scheduleReminderDetails;\r
-    }\r
-    return $scheduleReminderDetails;\r
-  }\r
-\r
-  /**\r
-   * This function takes criterias saved in civicrm_action_schedule table\r
-   * and creates recursion rule\r
-   *\r
-   * @param array $scheduleReminderDetails array of repeat criterias saved in civicrm_action_schedule table\r
-   *\r
-   * @return object When object\r
-   */\r
-  function getRecursionFromSchedule($scheduleReminderDetails = array()) {\r
-    $r = new When();\r
-    //If there is some data for this id\r
-    if ($scheduleReminderDetails['repetition_frequency_unit']) {\r
-      if ($scheduleReminderDetails['start_action_date']) {\r
-        $currDate = date('Y-m-d H:i:s', strtotime($scheduleReminderDetails['start_action_date']));\r
-      }\r
-      else {\r
-        $currDate = date("Y-m-d H:i:s");\r
-      }\r
-      $start = new DateTime($currDate);\r
-      $this->recursion_start_date = $start;\r
-      if ($scheduleReminderDetails['repetition_frequency_unit']) {\r
-        $repetition_frequency_unit = $scheduleReminderDetails['repetition_frequency_unit'];\r
-        if ($repetition_frequency_unit == "day") {\r
-          $repetition_frequency_unit = "dai";\r
-        }\r
-        $repetition_frequency_unit = $repetition_frequency_unit.'ly';\r
-        $r->recur($start, $repetition_frequency_unit);\r
-      }\r
-\r
-      if ($scheduleReminderDetails['repetition_frequency_interval']) {\r
-        $r->interval($scheduleReminderDetails['repetition_frequency_interval']);\r
-      }\r
-      else {\r
-        $r->errors[] = 'Repeats every: is a required field';\r
-      }\r
-\r
-      //week\r
-      if ($scheduleReminderDetails['repetition_frequency_unit'] == 'week') {\r
-        if ($scheduleReminderDetails['start_action_condition']) {\r
-          $startActionCondition = $scheduleReminderDetails['start_action_condition'];\r
-          $explodeStartActionCondition = explode(',', $startActionCondition);\r
-          $buildRuleArray = array();\r
-          foreach($explodeStartActionCondition as $key => $val) {\r
-            $buildRuleArray[] = strtoupper(substr($val, 0, 2));\r
-          }\r
-          $r->wkst('MO')->byday($buildRuleArray);\r
-        }\r
-      }\r
-\r
-      //month\r
-      if ($scheduleReminderDetails['repetition_frequency_unit'] == 'month') {\r
-        if ($scheduleReminderDetails['entity_status']) {\r
-          $startActionDate = explode(" ", $scheduleReminderDetails['entity_status']);\r
-          switch ($startActionDate[0]) {\r
-          case 'first':\r
-            $startActionDate1 = 1;\r
-            break;\r
-          case 'second':\r
-            $startActionDate1 = 2;\r
-            break;\r
-          case 'third':\r
-            $startActionDate1 = 3;\r
-            break;\r
-          case 'fourth':\r
-            $startActionDate1 = 4;\r
-            break;\r
-          case 'last':\r
-            $startActionDate1 = -1;\r
-            break;\r
-          }\r
-          $concatStartActionDateBits = $startActionDate1.strtoupper(substr($startActionDate[1], 0, 2));\r
-          $r->byday(array($concatStartActionDateBits));\r
-        }\r
-        else if ($scheduleReminderDetails['limit_to']) {\r
-          $r->bymonthday(array($scheduleReminderDetails['limit_to']));\r
-        }\r
-      }\r
-\r
-      //Ends\r
-      if ($scheduleReminderDetails['start_action_offset']) {\r
-        if ($scheduleReminderDetails['start_action_offset'] > 30) {\r
-          $r->errors[] = 'Occurrences should be less than or equal to 30';\r
-        }\r
-        $r->count($scheduleReminderDetails['start_action_offset']);\r
-      }\r
-\r
-      if (CRM_Utils_Array::value('absolute_date', $scheduleReminderDetails)) {\r
-        $absoluteDate = CRM_Utils_Date::setDateDefaults($scheduleReminderDetails['absolute_date']);\r
-        $endDate = new DateTime($absoluteDate[0].' '.$absoluteDate[1]);\r
-        $endDate->modify('+1 day');\r
-        $r->until($endDate);\r
-      }\r
-\r
-      if (!$scheduleReminderDetails['start_action_offset'] && !$scheduleReminderDetails['absolute_date']) {\r
-        $r->errors[] = 'Ends: is a required field';\r
-      }\r
-    }\r
-    else {\r
-      $r->errors[] = 'Repeats: is a required field';\r
-    }\r
-    return $r;\r
-  }\r
-\r
-\r
-  /**\r
-   * This function gets time difference between the two datetime object\r
-   *\r
-   * @param DateTime $startDate Start Date\r
-   * @param DateTime $endDate End Date\r
-   *\r
-   * @access public\r
-   * @static\r
-   *\r
-   * @return object DateTime object which contain time difference\r
-   */\r
-  static public function getInterval($startDate, $endDate) {\r
-    if ($startDate && $endDate) {\r
-      $startDate = new DateTime($startDate);\r
-      $endDate   = new DateTime($endDate);\r
-      return $startDate->diff($endDate);\r
-    }\r
-  }\r
-\r
-  /**\r
-   * This function gets all columns from civicrm_action_schedule on the basis of event id\r
-   *\r
-   * @param int $entityId Entity ID\r
-   * @param string $used_for Specifies for which entity type it's used for\r
-   *\r
-   * @access public\r
-   * @static\r
-   *\r
-   * @return object\r
-   */\r
-  public static function getReminderDetailsByEntityId($entityId, $used_for) {\r
-    if ($entityId) {\r
-      $query = "\r
-        SELECT *\r
-        FROM   civicrm_action_schedule\r
-        WHERE  entity_value = %1";\r
-      if ($used_for) {\r
-        $query .= " AND used_for = %2";\r
-      }\r
-      $params = array(\r
-        1 => array($entityId, 'Integer'),\r
-        2 => array($used_for, 'String')\r
-      );\r
-      $dao = CRM_Core_DAO::executeQuery($query, $params);\r
-      $dao->fetch();\r
-    }\r
-    return $dao;\r
-  }\r
-\r
-  /**\r
-   * Update mode column in civicrm_recurring_entity table for event related tabs\r
-   *\r
-   * @param int $entityId event id\r
-   * @param string $linkedEntityTable Linked entity table name for this event\r
-   * @return array\r
-   */\r
-  public static function updateModeLinkedEntity($entityId, $linkedEntityTable, $mainEntityTable) {\r
-    $result = array();\r
-    if ( $entityId && $linkedEntityTable && $mainEntityTable ) {\r
-      if (CRM_Utils_Array::value($linkedEntityTable, self::$_tableDAOMapper)) {\r
-        $dao = self::$_tableDAOMapper[$linkedEntityTable];\r
-      }\r
-      else {\r
-        CRM_Core_Session::setStatus('Could not update mode for linked entities');\r
-        return;\r
-      }\r
-      $entityTable = $linkedEntityTable;\r
-      $params = array(\r
-                      'entity_id' => $entityId,\r
-                      'entity_table' => $mainEntityTable\r
-                    );\r
-      $defaults = array();\r
-      CRM_Core_DAO::commonRetrieve($dao, $params, $defaults);\r
-      if (CRM_Utils_Array::value('id', $defaults)) {\r
-        $result['entityId'] = $defaults['id'];\r
-        $result['entityTable'] = $entityTable;\r
-      }\r
-    }\r
-    return $result;\r
-  }\r
-}\r
+<?php
+/*
+ +--------------------------------------------------------------------+
+ | CiviCRM version 4.6                                                |
+ +--------------------------------------------------------------------+
+ | Copyright CiviCRM LLC (c) 2004-2014                                |
+ +--------------------------------------------------------------------+
+ | This file is a part of CiviCRM.                                    |
+ |                                                                    |
+ | CiviCRM is free software; you can copy, modify, and distribute it  |
+ | under the terms of the GNU Affero General Public License           |
+ | Version 3, 19 November 2007 and the CiviCRM Licensing Exception.   |
+ |                                                                    |
+ | CiviCRM 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 Affero General Public License for more details.        |
+ |                                                                    |
+ | You should have received a copy of the GNU Affero General Public   |
+ | License and the CiviCRM Licensing Exception along                  |
+ | with this program; if not, contact CiviCRM LLC                     |
+ | at info[AT]civicrm[DOT]org. If you have questions about the        |
+ | GNU Affero General Public License or the licensing of CiviCRM,     |
+ | see the CiviCRM license FAQ at http://civicrm.org/licensing        |
+ +--------------------------------------------------------------------+
+ */
+
+/**
+ *
+ * @package CRM
+ * @copyright CiviCRM LLC (c) 2004-2014
+ * $Id$
+ *
+ */
+
+require_once 'packages/When/When.php';
+
+class CRM_Core_BAO_RecurringEntity extends CRM_Core_DAO_RecurringEntity {
+
+  const RUNNING = 1;
+  public $schedule = array();
+  public $scheduleId = NULL;
+  public $scheduleFormValues = array();
+
+  public $dateColumns = array();
+  public $overwriteColumns = array();
+  public $intervalDateColumns = array();
+  public $excludeDates = array();
+
+  public $linkedEntities = array();
+
+  public $isRecurringEntityRecord = TRUE;
+
+  protected $recursion = NULL;
+  protected $recursion_start_date = NULL;
+
+  public static $_entitiesToBeDeleted = array();
+
+  public static $status = NULL;
+
+  static $_recurringEntityHelper
+    = array(
+      'civicrm_event' => array(
+        'helper_class' => 'CRM_Event_DAO_Event',
+        'delete_func' => 'delete',
+        'pre_delete_func' => 'CRM_Event_Form_ManageEvent_Repeat::checkRegistrationForEvents',
+      ),
+      'civicrm_activity' => array(
+        'helper_class' => 'CRM_Activity_DAO_Activity',
+        'delete_func' => 'delete',
+        'pre_delete_func' => '',
+      ),
+    );
+
+  static $_dateColumns
+    = array(
+      'civicrm_event' => array(
+        'dateColumns' => array('start_date'),
+        'excludeDateRangeColumns' => array('start_date', 'end_date'),
+        'intervalDateColumns' => array('end_date'),
+      ),
+      'civicrm_activity' => array(
+        'dateColumns' => array('activity_date_time'),
+      ),
+    );
+
+  static $_tableDAOMapper
+    = array(
+      'civicrm_event' => 'CRM_Event_DAO_Event',
+      'civicrm_price_set_entity' => 'CRM_Price_DAO_PriceSetEntity',
+      'civicrm_uf_join' => 'CRM_Core_DAO_UFJoin',
+      'civicrm_tell_friend' => 'CRM_Friend_DAO_Friend',
+      'civicrm_pcp_block' => 'CRM_PCP_DAO_PCPBlock',
+      'civicrm_activity' => 'CRM_Activity_DAO_Activity',
+      'civicrm_activity_contact' => 'CRM_Activity_DAO_ActivityContact',
+    );
+
+  static $_updateSkipFields
+    = array(
+      'civicrm_event' => array('start_date', 'end_date'),
+      'civicrm_tell_friend' => array('entity_id'),
+      'civicrm_pcp_block' => array('entity_id'),
+      'civicrm_activity' => array('activity_date_time'),
+    );
+
+  static $_linkedEntitiesInfo
+    = array(
+      'civicrm_tell_friend' => array(
+        'entity_id_col' => 'entity_id',
+        'entity_table_col' => 'entity_table',
+      ),
+      'civicrm_price_set_entity' => array(
+        'entity_id_col' => 'entity_id',
+        'entity_table_col' => 'entity_table',
+        'is_multirecord' => TRUE,
+      ),
+      'civicrm_uf_join' => array(
+        'entity_id_col' => 'entity_id',
+        'entity_table_col' => 'entity_table',
+        'is_multirecord' => TRUE,
+      ),
+      'civicrm_pcp_block' => array(
+        'entity_id_col' => 'entity_id',
+        'entity_table_col' => 'entity_table',
+      ),
+    );
+
+  public static function getStatus() {
+    return self::$status;
+  }
+
+  public static function setStatus($status) {
+    self::$status = $status;
+  }
+
+  /**
+   * Save records in civicrm_recujrring_entity table
+   *
+   * @param array $params
+   *   Reference array contains the values submitted by the form .
+   *
+   *
+   * @return object
+   */
+  public static function add(&$params) {
+    if (CRM_Utils_Array::value('id', $params)) {
+      CRM_Utils_Hook::pre('edit', 'RecurringEntity', $params['id'], $params);
+    }
+    else {
+      CRM_Utils_Hook::pre('create', 'RecurringEntity', NULL, $params);
+    }
+
+    $daoRecurringEntity = new CRM_Core_DAO_RecurringEntity();
+    $daoRecurringEntity->copyValues($params);
+    $daoRecurringEntity->find(TRUE);
+    $result = $daoRecurringEntity->save();
+
+    if (CRM_Utils_Array::value('id', $params)) {
+      CRM_Utils_Hook::post('edit', 'RecurringEntity', $daoRecurringEntity->id, $daoRecurringEntity);
+    }
+    else {
+      CRM_Utils_Hook::post('create', 'RecurringEntity', $daoRecurringEntity->id, $daoRecurringEntity);
+    }
+    return $result;
+  }
+
+  /**
+   * Wrapper for the function add() to add entry in recurring entity
+   *
+   * @param int $parentId
+   *   Parent entity id .
+   * @param int $entityId
+   *   Child entity id .
+   * @param string $entityTable
+   *   Name of the entity table .
+   *
+   *
+   * @return object
+   */
+  public static function quickAdd($parentId, $entityId, $entityTable) {
+    $params
+      = array(
+        'parent_id' => $parentId,
+        'entity_id' => $entityId,
+        'entity_table' => $entityTable,
+      );
+    return self::add($params);
+  }
+
+  /**
+   * This function updates the mode column in the civicrm_recurring_entity table
+   *
+   * @param int $mode
+   *   Mode of the entity to cascade changes across parent/child relations eg 1 - only this entity, 2 - this and the following entities, 3 - All the entity .
+   *
+   *
+   * @return void
+   */
+  public function mode($mode) {
+    if ($this->entity_id && $this->entity_table) {
+      if ($this->find(TRUE)) {
+        $this->mode = $mode;
+      }
+      else {
+        $this->parent_id = $this->entity_id;
+        $this->mode = $mode;
+      }
+      $this->save();
+    }
+  }
+
+  /**
+   * This function generates all new entities based on object vars
+   *
+   * @return array
+   */
+  public function generate() {
+    $this->generateRecursiveDates();
+
+    return $this->generateEntities();
+  }
+
+  /**
+   * This function builds a "When" object based on schedule/reminder params
+   *
+   * @return object
+   *   When object
+   */
+  public function generateRecursion() {
+    // return if already generated
+    if (is_a($this->recursion, 'When')) {
+      return $this->recursion;
+    }
+
+    if ($this->scheduleId) {
+      // get params by ID
+      $this->schedule = $this->getScheduleParams($this->scheduleId);
+    }
+    elseif (!empty($this->scheduleFormValues)) {
+      $this->schedule = $this->mapFormValuesToDB($this->scheduleFormValues);
+    }
+
+    if (!empty($this->schedule)) {
+      $this->recursion = $this->getRecursionFromSchedule($this->schedule);
+    }
+    return $this->recursion;
+  }
+
+  /**
+   * Generate new DAOs and along with entries in civicrm_recurring_entity table
+   *
+   * @return array
+   */
+  public function generateEntities() {
+    self::setStatus(self::RUNNING);
+
+    $newEntities = array();
+    $findCriteria = array();
+    if (!empty($this->recursionDates)) {
+      if ($this->entity_id) {
+        $findCriteria = array('id' => $this->entity_id);
+
+        // save an entry with initiating entity-id & entity-table
+        if ($this->entity_table && !$this->find(TRUE)) {
+          $this->parent_id = $this->entity_id;
+          $this->save();
+        }
+      }
+      if (empty($findCriteria)) {
+        CRM_Core_Error::fatal("Find criteria missing to generate form. Make sure entity_id and table is set.");
+      }
+
+      $count = 0;
+      foreach ($this->recursionDates as $key => $dateCols) {
+        $newCriteria = $dateCols;
+        foreach ($this->overwriteColumns as $col => $val) {
+          $newCriteria[$col] = $val;
+        }
+        // create main entities
+        $obj = CRM_Core_BAO_RecurringEntity::copyCreateEntity($this->entity_table,
+          $findCriteria,
+          $newCriteria,
+          $this->isRecurringEntityRecord
+        );
+
+        if (is_a($obj, 'CRM_Core_DAO') && $obj->id) {
+          $newCriteria = array();
+          $newEntities[$this->entity_table][$count] = $obj->id;
+
+          foreach ($this->linkedEntities as $linkedInfo) {
+            foreach ($linkedInfo['linkedColumns'] as $col) {
+              $newCriteria[$col] = $obj->id;
+            }
+            // create linked entities
+            $linkedObj = CRM_Core_BAO_RecurringEntity::copyCreateEntity($linkedInfo['table'],
+              $linkedInfo['findCriteria'],
+              $newCriteria,
+              CRM_Utils_Array::value('isRecurringEntityRecord', $linkedInfo, TRUE)
+            );
+
+            if (is_a($linkedObj, 'CRM_Core_DAO') && $linkedObj->id) {
+              $newEntities[$linkedInfo['table']][$count] = $linkedObj->id;
+            }
+          }
+        }
+        $count++;
+      }
+    }
+
+    self::$status = NULL;
+    return $newEntities;
+  }
+
+  /**
+   * This function iterates through when object criterias and
+   * generates recursive dates based on that
+   *
+   * @return array
+   *   array of dates
+   */
+  public function generateRecursiveDates() {
+    $this->generateRecursion();
+
+    $recursionDates = array();
+    if (is_a($this->recursion, 'When')) {
+      $initialCount = CRM_Utils_Array::value('start_action_offset', $this->schedule);
+
+      $exRangeStart = $exRangeEnd = NULL;
+      if (!empty($this->excludeDateRangeColumns)) {
+        $exRangeStart = $this->excludeDateRangeColumns[0];
+        $exRangeEnd = $this->excludeDateRangeColumns[1];
+      }
+
+      $count = 1;
+      while ($result = $this->recursion->next()) {
+        $skip = FALSE;
+        if ($result == $this->recursion_start_date) {
+          // skip the recursion-start-date from the list we going to generate
+          $skip = TRUE;
+        }
+        $baseDate = CRM_Utils_Date::processDate($result->format('Y-m-d H:i:s'));
+
+        foreach ($this->dateColumns as $col) {
+          $recursionDates[$count][$col] = $baseDate;
+        }
+        foreach ($this->intervalDateColumns as $col => $interval) {
+          $newDate = new DateTime($baseDate);
+          $newDate->add($interval);
+          $recursionDates[$count][$col] = CRM_Utils_Date::processDate($newDate->format('Y-m-d H:i:s'));
+        }
+        if ($exRangeStart) {
+          $exRangeStartDate = CRM_Utils_Date::processDate($recursionDates[$count][$exRangeStart], NULL, FALSE, 'Ymd');
+          $exRangeEndDate = CRM_Utils_Date::processDate($recursionDates[$count][$exRangeEnd], NULL, FALSE, 'Ymd');
+        }
+
+        foreach ($this->excludeDates as $exDate) {
+          $exDate = CRM_Utils_Date::processDate($exDate, NULL, FALSE, 'Ymd');
+          if (!$exRangeStart) {
+            if ($exDate == $result->format('Ymd')) {
+              $skip = TRUE;
+              break;
+            }
+          }
+          else {
+            if (($exDate == $exRangeStartDate) ||
+              ($exRangeEndDate && ($exDate > $exRangeStartDate) && ($exDate <= $exRangeEndDate))
+            ) {
+              $skip = TRUE;
+              break;
+            }
+          }
+        }
+
+        if ($skip) {
+          unset($recursionDates[$count]);
+          if ($initialCount && ($initialCount > 0)) {
+            // lets increase the counter, so we get correct number of occurrences
+            $initialCount++;
+            $this->recursion->count($initialCount);
+          }
+          continue;
+        }
+        $count++;
+      }
+    }
+    $this->recursionDates = $recursionDates;
+
+    return $recursionDates;
+  }
+
+  /**
+   * This function gets all the children for a particular parent entity
+   *
+   * @param int $parentId
+   *   Parent entity id .
+   * @param string $entityTable
+   *   Name of the entity table .
+   * @param bool $includeParent
+   *   If true parent id is included in result set and vice versa .
+   * @param int $mode
+   *   1. retrieve only one entity. 2. retrieve all future entities in the repeating set. 3. all entities in the repeating set. .
+   * @param int $initiatorId
+   *   The instance where this function is invoked from .
+   *
+   *
+   * @return array
+   *   an array of child ids
+   */
+  static public function getEntitiesForParent($parentId, $entityTable, $includeParent = TRUE, $mode = 3, $initiatorId = NULL) {
+    $entities = array();
+    if (empty($parentId) || empty($entityTable)) {
+      return $entities;
+    }
+
+    if (!$initiatorId) {
+      $initiatorId = $parentId;
+    }
+
+    $queryParams = array(
+      1 => array($parentId, 'Integer'),
+      2 => array($entityTable, 'String'),
+      3 => array($initiatorId, 'Integer'),
+    );
+
+    if (!$mode) {
+      $mode = CRM_Core_DAO::singleValueQuery("SELECT mode FROM civicrm_recurring_entity WHERE entity_id = %3 AND entity_table = %2", $queryParams);
+    }
+
+    $query = "SELECT *
+      FROM civicrm_recurring_entity
+      WHERE parent_id = %1 AND entity_table = %2";
+    if (!$includeParent) {
+      $query .= " AND entity_id != " . ($initiatorId ? "%3" : "%1");
+    }
+
+    // MODE = SINGLE
+    if ($mode == '1') {
+      $query .= " AND entity_id = %3";
+    }
+    // MODE = FUTURE
+    elseif ($mode == '2') {
+      $recurringEntityID = CRM_Core_DAO::singleValueQuery("SELECT id FROM civicrm_recurring_entity WHERE entity_id = %3 AND entity_table = %2", $queryParams);
+      if ($recurringEntityID) {
+        $query .= $includeParent ? " AND id >= %4" : " AND id > %4";
+        $query .= " ORDER BY id ASC"; // FIXME: change to order by dates
+        $queryParams[4] = array($recurringEntityID, 'Integer');
+      }
+      else {
+        // something wrong, return empty
+        return array();
+      }
+    }
+
+    $dao = CRM_Core_DAO::executeQuery($query, $queryParams);
+    while ($dao->fetch()) {
+      $entities["{$dao->entity_table}_{$dao->entity_id}"]['table'] = $dao->entity_table;
+      $entities["{$dao->entity_table}_{$dao->entity_id}"]['id'] = $dao->entity_id;
+    }
+    return $entities;
+  }
+
+  /**
+   * This function when passed an entity id checks if it has parent and
+   * returns all other entities that are connected to same parent.
+   *
+   * @param int $entityId
+   *   Entity id .
+   * @param string $entityTable
+   *   Entity table name .
+   * @param bool $includeParent
+   *   Include parent in result set .
+   * @param int $mode
+   *   1. retrieve only one entity. 2. retrieve all future entities in the repeating set. 3. all entities in the repeating set. .
+   *
+   *
+   * @return array
+   *   array of connected ids
+   */
+  static public function getEntitiesFor($entityId, $entityTable, $includeParent = TRUE, $mode = 3) {
+    $parentId = self::getParentFor($entityId, $entityTable);
+    if ($parentId) {
+      return self::getEntitiesForParent($parentId, $entityTable, $includeParent, $mode, $entityId);
+    }
+    return array();
+  }
+
+  /**
+   * This function gets the parent for the entity id passed to it
+   *
+   * @param int $entityId
+   *   Entity ID .
+   * @param string $entityTable
+   *   Entity table name .
+   * @param bool $includeParent
+   *   Include parent in result set .
+   *
+   *
+   * @return int
+   *   unsigned $parentId Parent ID
+   */
+  static public function getParentFor($entityId, $entityTable, $includeParent = TRUE) {
+    if (empty($entityId) || empty($entityTable)) {
+      return NULL;
+    }
+
+    $query = "
+      SELECT parent_id
+      FROM civicrm_recurring_entity
+      WHERE entity_id = %1 AND entity_table = %2";
+    if (!$includeParent) {
+      $query .= " AND parent_id != %1";
+    }
+    $parentId
+      = CRM_Core_DAO::singleValueQuery($query,
+        array(
+          1 => array($entityId, 'Integer'),
+          2 => array($entityTable, 'String'),
+        )
+      );
+    return $parentId;
+  }
+
+  /**
+   * This function copies the information from parent entity and creates other entities with same information
+   *
+   * @param string $entityTable
+   *   Entity table name .
+   * @param array $fromCriteria
+   *   Array of all the fields & values on which basis to copy .
+   * @param array $newParams
+   *   Array of all the fields & values to be copied besides the other fields .
+   * @param bool $createRecurringEntity
+   *   If to create a record in recurring_entity table .
+   *
+   *
+   * @return object
+   */
+  static public function copyCreateEntity($entityTable, $fromCriteria, $newParams, $createRecurringEntity = TRUE) {
+    $daoName = self::$_tableDAOMapper[$entityTable];
+    if (!$daoName) {
+      CRM_Core_Error::fatal("DAO Mapper missing for $entityTable.");
+    }
+    $newObject = CRM_Core_DAO::copyGeneric($daoName, $fromCriteria, $newParams);
+
+    if (is_a($newObject, 'CRM_Core_DAO') && $newObject->id && $createRecurringEntity) {
+      $object = new $daoName();
+      foreach ($fromCriteria as $key => $value) {
+        $object->$key = $value;
+      }
+      $object->find(TRUE);
+
+      CRM_Core_BAO_RecurringEntity::quickAdd($object->id, $newObject->id, $entityTable);
+    }
+    return $newObject;
+  }
+
+  /**
+   * This function acts as a listener to dao->update whenever there is an update,
+   * and propagates any changes to all related entities present in recurring entity table
+   *
+   * @param object $event
+   *   An object of /Civi/Core/DAO/Event/PostUpdate containing dao object that was just updated .
+   *
+   *
+   * @return void
+   */
+  static public function triggerUpdate($event) {
+    // if DB version is earlier than 4.6 skip any processing
+    static $currentVer = NULL;
+    if (!$currentVer) {
+      $currentVer = CRM_Core_BAO_Domain::version();
+    }
+    if (version_compare($currentVer, '4.6.alpha1') < 0) {
+      return;
+    }
+
+    static $processedEntities = array();
+    $obj =& $event->object;
+    if (empty($obj->id) || empty($obj->__table)) {
+      return FALSE;
+    }
+    $key = "{$obj->__table}_{$obj->id}";
+
+    if (array_key_exists($key, $processedEntities)) {
+      // already processed
+      return NULL;
+    }
+
+    // get related entities
+    $repeatingEntities = self::getEntitiesFor($obj->id, $obj->__table, FALSE, NULL);
+    if (empty($repeatingEntities)) {
+      // return if its not a recurring entity parent
+      return NULL;
+    }
+    // mark being processed
+    $processedEntities[$key] = 1;
+
+    // to make sure we not copying to source itself
+    unset($repeatingEntities[$key]);
+
+    foreach ($repeatingEntities as $key => $val) {
+      $entityID = $val['id'];
+      $entityTable = $val['table'];
+
+      $processedEntities[$key] = 1;
+
+      if (array_key_exists($entityTable, self::$_tableDAOMapper)) {
+        $daoName = self::$_tableDAOMapper[$entityTable];
+
+        $skipData = array();
+        if (array_key_exists($entityTable, self::$_updateSkipFields)) {
+          $skipFields = self::$_updateSkipFields[$entityTable];
+          foreach ($skipFields as $sfield) {
+            $skipData[$sfield] = NULL;
+          }
+        }
+
+        $updateDAO = CRM_Core_DAO::cascadeUpdate($daoName, $obj->id, $entityID, $skipData);
+        CRM_Core_DAO::freeResult();
+      }
+      else {
+        CRM_Core_Error::fatal("DAO Mapper missing for $entityTable.");
+      }
+    }
+    // done with processing. lets unset static var.
+    unset($processedEntities);
+  }
+
+  /**
+   * This function acts as a listener to dao->save,
+   * and creates entries for linked entities in recurring entity table
+   *
+   * @param object $event
+   *   An object of /Civi/Core/DAO/Event/PostUpdate containing dao object that was just inserted .
+   *
+   *
+   * @return void
+   */
+  static public function triggerInsert($event) {
+    $obj =& $event->object;
+    if (!array_key_exists($obj->__table, self::$_linkedEntitiesInfo)) {
+      return FALSE;
+    }
+
+    // if DB version is earlier than 4.6 skip any processing
+    static $currentVer = NULL;
+    if (!$currentVer) {
+      $currentVer = CRM_Core_BAO_Domain::version();
+    }
+    if (version_compare($currentVer, '4.6.alpha1') < 0) {
+      return;
+    }
+
+    static $processedEntities = array();
+    if (empty($obj->id) || empty($obj->__table)) {
+      return FALSE;
+    }
+    $key = "{$obj->__table}_{$obj->id}";
+
+    if (array_key_exists($key, $processedEntities)) {
+      // already being processed. Exit recursive calls.
+      return NULL;
+    }
+
+    if (self::getStatus() == self::RUNNING) {
+      // if recursion->generate() is doing some work, lets not intercept
+      return NULL;
+    }
+
+    // mark being processed
+    $processedEntities[$key] = 1;
+
+    // get related entities for table being saved
+    $hasaRecurringRecord = self::getParentFor($obj->id, $obj->__table);
+
+    if (empty($hasaRecurringRecord)) {
+      // check if its a linked entity
+      if (array_key_exists($obj->__table, self::$_linkedEntitiesInfo) &&
+        !CRM_Utils_Array::value('is_multirecord', self::$_linkedEntitiesInfo[$obj->__table])
+      ) {
+        $linkedDAO = new self::$_tableDAOMapper[$obj->__table]();
+        $linkedDAO->id = $obj->id;
+        if ($linkedDAO->find(TRUE)) {
+          $idCol = self::$_linkedEntitiesInfo[$obj->__table]['entity_id_col'];
+          $tableCol = self::$_linkedEntitiesInfo[$obj->__table]['entity_table_col'];
+
+          $pEntityID = $linkedDAO->$idCol;
+          $pEntityTable = $linkedDAO->$tableCol;
+
+          // find all parent recurring entity set
+          $pRepeatingEntities = self::getEntitiesFor($pEntityID, $pEntityTable);
+
+          if (!empty($pRepeatingEntities)) {
+            // for each parent entity in the set, find out a similar linked entity,
+            // if doesn't exist create one, and also create entries in recurring_entity table
+
+            foreach ($pRepeatingEntities as $key => $val) {
+              if (array_key_exists($key, $processedEntities)) {
+                // this graph is already being processed
+                return NULL;
+              }
+              $processedEntities[$key] = 1;
+            }
+
+            // start with first entry with just itself
+            CRM_Core_BAO_RecurringEntity::quickAdd($obj->id, $obj->id, $obj->__table);
+
+            foreach ($pRepeatingEntities as $key => $val) {
+              $rlinkedDAO = new self::$_tableDAOMapper[$obj->__table]();
+              $rlinkedDAO->$idCol = $val['id'];
+              $rlinkedDAO->$tableCol = $val['table'];
+              if ($rlinkedDAO->find(TRUE)) {
+                CRM_Core_BAO_RecurringEntity::quickAdd($obj->id, $rlinkedDAO->id, $obj->__table);
+              }
+              else {
+                // linked entity doesn't exist. lets create them
+                $newCriteria = array(
+                  $idCol => $val['id'],
+                  $tableCol => $val['table'],
+                );
+                $linkedObj = CRM_Core_BAO_RecurringEntity::copyCreateEntity($obj->__table,
+                  array('id' => $obj->id),
+                  $newCriteria,
+                  TRUE
+                );
+                if ($linkedObj->id) {
+                  CRM_Core_BAO_RecurringEntity::quickAdd($obj->id, $linkedObj->id, $obj->__table);
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+
+    // done with processing. lets unset static var.
+    unset($processedEntities);
+  }
+
+  /**
+   * This function acts as a listener to dao->delete, and deletes an entry from recurring_entity table
+   *
+   * @param object $event
+   *   An object of /Civi/Core/DAO/Event/PostUpdate containing dao object that was just deleted .
+   *
+   *
+   * @return void
+   */
+  static public function triggerDelete($event) {
+    $obj =& $event->object;
+
+    // if DB version is earlier than 4.6 skip any processing
+    static $currentVer = NULL;
+    if (!$currentVer) {
+      $currentVer = CRM_Core_BAO_Domain::version();
+    }
+    if (version_compare($currentVer, '4.6.alpha1') < 0) {
+      return;
+    }
+
+    static $processedEntities = array();
+    if (empty($obj->id) || empty($obj->__table) || !$event->result) {
+      return FALSE;
+    }
+    $key = "{$obj->__table}_{$obj->id}";
+
+    if (array_key_exists($key, $processedEntities)) {
+      // already processed
+      return NULL;
+    }
+
+    // mark being processed
+    $processedEntities[$key] = 1;
+
+    $parentID = self::getParentFor($obj->id, $obj->__table);
+    if ($parentID) {
+      CRM_Core_BAO_RecurringEntity::delEntity($obj->id, $obj->__table, TRUE);
+    }
+  }
+
+  /**
+   * This function deletes main entity and related linked entities from recurring-entity table
+   *
+   * @param int $entityId
+   *   Entity id
+   * @param string $entityTable
+   *   Name of the entity table
+   *
+   *
+   * @return bool|CRM_Core_DAO_RecurringEntity
+   */
+  static public function delEntity($entityId, $entityTable, $isDelLinkedEntities = FALSE) {
+    if (empty($entityId) || empty($entityTable)) {
+      return FALSE;
+    }
+    $dao = new CRM_Core_DAO_RecurringEntity();
+    $dao->entity_id = $entityId;
+    $dao->entity_table = $entityTable;
+    if ($dao->find(TRUE)) {
+      // make sure its not a linked entity thats being deleted
+      if ($isDelLinkedEntities && !array_key_exists($entityTable, self::$_linkedEntitiesInfo)) {
+        // delete all linked entities from recurring entity table
+        foreach (self::$_linkedEntitiesInfo as $linkedTable => $linfo) {
+          $daoName = self::$_tableDAOMapper[$linkedTable];
+          if (!$daoName) {
+            CRM_Core_Error::fatal("DAO Mapper missing for $linkedTable.");
+          }
+
+          $linkedDao = new $daoName();
+          $linkedDao->$linfo['entity_id_col'] = $entityId;
+          $linkedDao->$linfo['entity_table_col'] = $entityTable;
+          $linkedDao->find();
+          while ($linkedDao->fetch()) {
+            CRM_Core_BAO_RecurringEntity::delEntity($linkedDao->id, $linkedTable, FALSE);
+          }
+        }
+      }
+      // delete main entity
+      return $dao->delete();
+    }
+    return FALSE;
+  }
+
+  /**
+   * This function maps values posted from form to civicrm_action_schedule columns
+   *
+   * @param array $formParams
+   *   And array of form values posted .
+   *
+   * @return array
+   */
+  public function mapFormValuesToDB($formParams = array()) {
+    $dbParams = array();
+    if (CRM_Utils_Array::value('used_for', $formParams)) {
+      $dbParams['used_for'] = $formParams['used_for'];
+    }
+
+    if (CRM_Utils_Array::value('entity_id', $formParams)) {
+      $dbParams['entity_value'] = $formParams['entity_id'];
+    }
+
+    if (CRM_Utils_Array::value('repetition_start_date', $formParams)) {
+      if (CRM_Utils_Array::value('repetition_start_date_display', $formParams)) {
+        $repetitionStartDate = $formParams['repetition_start_date_display'];
+      }
+      else {
+        $repetitionStartDate = $formParams['repetition_start_date'];
+      }
+      if (CRM_Utils_Array::value('repetition_start_date_time', $formParams)) {
+        $repetitionStartDate = $repetitionStartDate . " " . $formParams['repetition_start_date_time'];
+      }
+      $repetition_start_date = new DateTime($repetitionStartDate);
+      $dbParams['start_action_date'] = CRM_Utils_Date::processDate($repetition_start_date->format('Y-m-d H:i:s'));
+    }
+
+    if (CRM_Utils_Array::value('repetition_frequency_unit', $formParams)) {
+      $dbParams['repetition_frequency_unit'] = $formParams['repetition_frequency_unit'];
+    }
+
+    if (CRM_Utils_Array::value('repetition_frequency_interval', $formParams)) {
+      $dbParams['repetition_frequency_interval'] = $formParams['repetition_frequency_interval'];
+    }
+
+    //For Repeats on:(weekly case)
+    if ($formParams['repetition_frequency_unit'] == 'week') {
+      if (CRM_Utils_Array::value('start_action_condition', $formParams)) {
+        $repeats_on = CRM_Utils_Array::value('start_action_condition', $formParams);
+        $dbParams['start_action_condition'] = implode(",", array_keys($repeats_on));
+      }
+    }
+
+    //For Repeats By:(monthly case)
+    if ($formParams['repetition_frequency_unit'] == 'month') {
+      if ($formParams['repeats_by'] == 1) {
+        if (CRM_Utils_Array::value('limit_to', $formParams)) {
+          $dbParams['limit_to'] = $formParams['limit_to'];
+        }
+      }
+      if ($formParams['repeats_by'] == 2) {
+        if (CRM_Utils_Array::value('entity_status_1', $formParams) && CRM_Utils_Array::value('entity_status_2', $formParams)) {
+          $dbParams['entity_status'] = $formParams['entity_status_1'] . " " . $formParams['entity_status_2'];
+        }
+      }
+    }
+
+    //For "Ends" - After:
+    if ($formParams['ends'] == 1) {
+      if (CRM_Utils_Array::value('start_action_offset', $formParams)) {
+        $dbParams['start_action_offset'] = $formParams['start_action_offset'];
+      }
+    }
+
+    //For "Ends" - On:
+    if ($formParams['ends'] == 2) {
+      if (CRM_Utils_Array::value('repeat_absolute_date', $formParams)) {
+        $dbParams['absolute_date'] = CRM_Utils_Date::processDate($formParams['repeat_absolute_date']);
+      }
+    }
+    return $dbParams;
+  }
+
+  /**
+   * This function gets all the columns of civicrm_action_schedule table based on id(primary key)
+   *
+   * @param int $scheduleReminderId
+   *   Primary key of civicrm_action_schedule table .
+   *
+   *
+   * @return object
+   */
+  static public function getScheduleReminderDetailsById($scheduleReminderId) {
+    $query = "SELECT *
+      FROM civicrm_action_schedule WHERE 1";
+    if ($scheduleReminderId) {
+      $query .= "
+        AND id = %1";
+    }
+    $dao = CRM_Core_DAO::executeQuery($query,
+      array(
+        1 => array($scheduleReminderId, 'Integer'),
+      )
+    );
+    $dao->fetch();
+    return $dao;
+  }
+
+  /**
+   * wrapper of getScheduleReminderDetailsById function
+   *
+   * @param int $scheduleReminderId
+   *   Primary key of civicrm_action_schedule table .
+   *
+   * @return array
+   */
+  public function getScheduleParams($scheduleReminderId) {
+    $scheduleReminderDetails = array();
+    if ($scheduleReminderId) {
+      //Get all the details from schedule reminder table
+      $scheduleReminderDetails = self::getScheduleReminderDetailsById($scheduleReminderId);
+      $scheduleReminderDetails = (array) $scheduleReminderDetails;
+    }
+    return $scheduleReminderDetails;
+  }
+
+  /**
+   * This function takes criterias saved in civicrm_action_schedule table
+   * and creates recursion rule
+   *
+   * @param array $scheduleReminderDetails
+   *   Array of repeat criterias saved in civicrm_action_schedule table .
+   *
+   * @return object
+   *   When object
+   */
+  public function getRecursionFromSchedule($scheduleReminderDetails = array()) {
+    $r = new When();
+    //If there is some data for this id
+    if ($scheduleReminderDetails['repetition_frequency_unit']) {
+      if ($scheduleReminderDetails['start_action_date']) {
+        $currDate = date('Y-m-d H:i:s', strtotime($scheduleReminderDetails['start_action_date']));
+      }
+      else {
+        $currDate = date("Y-m-d H:i:s");
+      }
+      $start = new DateTime($currDate);
+      $this->recursion_start_date = $start;
+      if ($scheduleReminderDetails['repetition_frequency_unit']) {
+        $repetition_frequency_unit = $scheduleReminderDetails['repetition_frequency_unit'];
+        if ($repetition_frequency_unit == "day") {
+          $repetition_frequency_unit = "dai";
+        }
+        $repetition_frequency_unit = $repetition_frequency_unit . 'ly';
+        $r->recur($start, $repetition_frequency_unit);
+      }
+
+      if ($scheduleReminderDetails['repetition_frequency_interval']) {
+        $r->interval($scheduleReminderDetails['repetition_frequency_interval']);
+      }
+      else {
+        $r->errors[] = 'Repeats every: is a required field';
+      }
+
+      //week
+      if ($scheduleReminderDetails['repetition_frequency_unit'] == 'week') {
+        if ($scheduleReminderDetails['start_action_condition']) {
+          $startActionCondition = $scheduleReminderDetails['start_action_condition'];
+          $explodeStartActionCondition = explode(',', $startActionCondition);
+          $buildRuleArray = array();
+          foreach ($explodeStartActionCondition as $key => $val) {
+            $buildRuleArray[] = strtoupper(substr($val, 0, 2));
+          }
+          $r->wkst('MO')->byday($buildRuleArray);
+        }
+      }
+
+      //month
+      if ($scheduleReminderDetails['repetition_frequency_unit'] == 'month') {
+        if ($scheduleReminderDetails['entity_status']) {
+          $startActionDate = explode(" ", $scheduleReminderDetails['entity_status']);
+          switch ($startActionDate[0]) {
+            case 'first':
+              $startActionDate1 = 1;
+              break;
+
+            case 'second':
+              $startActionDate1 = 2;
+              break;
+
+            case 'third':
+              $startActionDate1 = 3;
+              break;
+
+            case 'fourth':
+              $startActionDate1 = 4;
+              break;
+
+            case 'last':
+              $startActionDate1 = -1;
+              break;
+          }
+          $concatStartActionDateBits = $startActionDate1 . strtoupper(substr($startActionDate[1], 0, 2));
+          $r->byday(array($concatStartActionDateBits));
+        }
+        elseif ($scheduleReminderDetails['limit_to']) {
+          $r->bymonthday(array($scheduleReminderDetails['limit_to']));
+        }
+      }
+
+      //Ends
+      if ($scheduleReminderDetails['start_action_offset']) {
+        if ($scheduleReminderDetails['start_action_offset'] > 30) {
+          $r->errors[] = 'Occurrences should be less than or equal to 30';
+        }
+        $r->count($scheduleReminderDetails['start_action_offset']);
+      }
+
+      if (CRM_Utils_Array::value('absolute_date', $scheduleReminderDetails)) {
+        $absoluteDate = CRM_Utils_Date::setDateDefaults($scheduleReminderDetails['absolute_date']);
+        $endDate = new DateTime($absoluteDate[0] . ' ' . $absoluteDate[1]);
+        $endDate->modify('+1 day');
+        $r->until($endDate);
+      }
+
+      if (!$scheduleReminderDetails['start_action_offset'] && !$scheduleReminderDetails['absolute_date']) {
+        $r->errors[] = 'Ends: is a required field';
+      }
+    }
+    else {
+      $r->errors[] = 'Repeats: is a required field';
+    }
+    return $r;
+  }
+
+
+  /**
+   * This function gets time difference between the two datetime object
+   *
+   * @param DateTime $startDate
+   *   Start Date .
+   * @param DateTime $endDate
+   *   End Date .
+   *
+   *
+   * @return object
+   *   DateTime object which contain time difference
+   */
+  static public function getInterval($startDate, $endDate) {
+    if ($startDate && $endDate) {
+      $startDate = new DateTime($startDate);
+      $endDate = new DateTime($endDate);
+      return $startDate->diff($endDate);
+    }
+  }
+
+  /**
+   * This function gets all columns from civicrm_action_schedule on the basis of event id
+   *
+   * @param int $entityId
+   *   Entity ID .
+   * @param string $used_for
+   *   Specifies for which entity type it's used for .
+   *
+   *
+   * @return object
+   */
+  public static function getReminderDetailsByEntityId($entityId, $used_for) {
+    if ($entityId) {
+      $query = "
+        SELECT *
+        FROM   civicrm_action_schedule
+        WHERE  entity_value = %1";
+      if ($used_for) {
+        $query .= " AND used_for = %2";
+      }
+      $params = array(
+        1 => array($entityId, 'Integer'),
+        2 => array($used_for, 'String'),
+      );
+      $dao = CRM_Core_DAO::executeQuery($query, $params);
+      $dao->fetch();
+    }
+    return $dao;
+  }
+
+  /**
+   * Update mode column in civicrm_recurring_entity table for event related tabs
+   *
+   * @param int $entityId
+   *   Event id .
+   * @param string $linkedEntityTable
+   *   Linked entity table name for this event .
+   * @return array
+   */
+  public static function updateModeLinkedEntity($entityId, $linkedEntityTable, $mainEntityTable) {
+    $result = array();
+    if ($entityId && $linkedEntityTable && $mainEntityTable) {
+      if (CRM_Utils_Array::value($linkedEntityTable, self::$_tableDAOMapper)) {
+        $dao = self::$_tableDAOMapper[$linkedEntityTable];
+      }
+      else {
+        CRM_Core_Session::setStatus('Could not update mode for linked entities');
+        return NULL;
+      }
+      $entityTable = $linkedEntityTable;
+      $params = array(
+        'entity_id' => $entityId,
+        'entity_table' => $mainEntityTable,
+      );
+      $defaults = array();
+      CRM_Core_DAO::commonRetrieve($dao, $params, $defaults);
+      if (CRM_Utils_Array::value('id', $defaults)) {
+        $result['entityId'] = $defaults['id'];
+        $result['entityTable'] = $entityTable;
+      }
+    }
+    return $result;
+  }
+
+}