/**
  * This function will return paginated result. Result is an array where first element is 
  * array of returned object and second populated pagination object that can be used for 
  * obtaining and rendering pagination data using various helpers.
  * 
  * Items and pagination array vars are indexed with 0 for items and 1 for pagination
  * because you can't use associative indexing with list() construct
  *
  * @access public
  * @param array $arguments Query argumens (@see find()) Limit and offset are ignored!
  * @param integer $items_per_page Number of items per page
  * @param integer $current_page Current page number
  * @return array
  */
 function paginate($arguments = null, $items_per_page = 10, $current_page = 1)
 {
     if (isset($this) && instance_of($this, 'ApplicationLogs')) {
         return parent::paginate($arguments, $items_per_page, $current_page);
     } else {
         return ApplicationLogs::instance()->paginate($arguments, $items_per_page, $current_page);
         //$instance =& ApplicationLogs::instance();
         //return $instance->paginate($arguments, $items_per_page, $current_page);
     }
     // if
 }
 /**
  * Used for Drag & Drop, adds objects to a member
  * @author alvaro
  */
 function add_objects_to_member()
 {
     $ids = json_decode(array_var($_POST, 'objects'));
     $mem_id = array_var($_POST, 'member');
     if (!is_array($ids) || count($ids) == 0) {
         ajx_current("empty");
         return;
     }
     $member = Members::findById($mem_id);
     try {
         DB::beginWork();
         $objects = array();
         $from = array();
         foreach ($ids as $oid) {
             /* @var $obj ContentDataObject */
             $obj = Objects::findObject($oid);
             $dim_obj_type_content = DimensionObjectTypeContents::findOne(array('conditions' => array('`dimension_id`=? AND `dimension_object_type_id`=? AND `content_object_type_id`=?', $member->getDimensionId(), $member->getObjectTypeId(), $obj->getObjectTypeId())));
             if (!$dim_obj_type_content instanceof DimensionObjectTypeContent) {
                 continue;
             }
             if (!$dim_obj_type_content->getIsMultiple() || array_var($_POST, 'remove_prev')) {
                 $db_res = DB::execute("SELECT group_concat(om.member_id) as old_members FROM " . TABLE_PREFIX . "object_members om INNER JOIN " . TABLE_PREFIX . "members m ON om.member_id=m.id WHERE m.dimension_id=" . $member->getDimensionId() . " AND om.object_id=" . $obj->getId());
                 $row = $db_res->fetchRow();
                 if (array_var($row, 'old_members') != "") {
                     $from[$obj->getId()] = $row['old_members'];
                 }
                 // remove from previous members
                 ObjectMembers::delete('`object_id` = ' . $obj->getId() . ' AND `member_id` IN (SELECT `m`.`id` FROM `' . TABLE_PREFIX . 'members` `m` WHERE `m`.`dimension_id` = ' . $member->getDimensionId() . ')');
             }
             $obj->addToMembers(array($member));
             $obj->addToSharingTable();
             $objects[] = $obj;
         }
         DB::commit();
         // add to application logs
         foreach ($objects as $object) {
             $action = array_var($from, $obj->getId()) ? ApplicationLogs::ACTION_MOVE : ApplicationLogs::ACTION_COPY;
             $log_data = (array_var($from, $obj->getId()) ? "from:" . array_var($from, $obj->getId()) . ";" : "") . "to:" . $member->getId();
             ApplicationLogs::instance()->createLog($object, $action, false, true, true, $log_data);
         }
         $lang_key = count($ids) > 1 ? 'objects moved to member success' : 'object moved to member success';
         flash_success(lang($lang_key, $member->getName()));
         if (array_var($_POST, 'reload')) {
             ajx_current('reload');
         } else {
             ajx_current('empty');
         }
     } catch (Exception $e) {
         DB::rollback();
         ajx_current("empty");
         flash_error(lang('unable to move objects'));
     }
 }
 /**
  * Mass set is_private for a given type. If $ids is present limit update only to object with given ID-s
  *
  * @param boolean $is_private
  * @param string $type
  * @parma array $ids
  * @return boolean
  */
 static function setIsPrivateForType($is_private, $type, $ids = null)
 {
     $limit_ids = null;
     if (is_array($ids)) {
         $limit_ids = array();
         foreach ($ids as $id) {
             $limit_ids[] = DB::escape($id);
         }
         // if
         $limit_ids = count($limit_ids) > 0 ? implode(',', $limit_ids) : null;
     }
     // if
     $sql = DB::prepareString('UPDATE ' . ApplicationLogs::instance()->getTableName(true) . ' SET `is_private` = ?  WHERE `rel_object_manager` = ?', array($is_private, $type));
     if ($limit_ids !== null) {
         $sql .= " AND `rel_object_id` IN ({$limit_ids})";
     }
     // if
     return DB::execute($sql);
 }
 /**
  * Return manager instance
  *
  * @access protected
  * @param void
  * @return ApplicationLogs 
  */
 function manager()
 {
     if (!$this->manager instanceof ApplicationLogs) {
         $this->manager = ApplicationLogs::instance();
     }
     return $this->manager;
 }
    /**
     * Used for Drag & Drop, adds objects to a member
     * @author alvaro
     */
    function add_objects_to_member()
    {
        $ids = json_decode(array_var($_POST, 'objects'));
        $mem_id = array_var($_POST, 'member');
        if (!is_array($ids) || count($ids) == 0) {
            ajx_current("empty");
            return;
        }
        try {
            DB::beginWork();
            if ($mem_id) {
                $user_ids = array();
                $member = Members::findById($mem_id);
                $objects = array();
                $from = array();
                foreach ($ids as $oid) {
                    /* @var $obj ContentDataObject */
                    $obj = Objects::findObject($oid);
                    if ($obj instanceof ContentDataObject && $obj->canAddToMember(logged_user(), $member, active_context())) {
                        $dim_obj_type_content = DimensionObjectTypeContents::findOne(array('conditions' => array('`dimension_id`=? AND `dimension_object_type_id`=? AND `content_object_type_id`=?', $member->getDimensionId(), $member->getObjectTypeId(), $obj->getObjectTypeId())));
                        if (!$dim_obj_type_content instanceof DimensionObjectTypeContent) {
                            continue;
                        }
                        if (!$dim_obj_type_content->getIsMultiple() || array_var($_POST, 'remove_prev')) {
                            $db_res = DB::execute("SELECT group_concat(om.member_id) as old_members FROM " . TABLE_PREFIX . "object_members om INNER JOIN " . TABLE_PREFIX . "members m ON om.member_id=m.id WHERE m.dimension_id=" . $member->getDimensionId() . " AND om.object_id=" . $obj->getId());
                            $row = $db_res->fetchRow();
                            if (array_var($row, 'old_members') != "") {
                                $from[$obj->getId()] = $row['old_members'];
                            }
                            // remove from previous members
                            ObjectMembers::delete('`object_id` = ' . $obj->getId() . ' AND `member_id` IN (SELECT `m`.`id` FROM `' . TABLE_PREFIX . 'members` `m` WHERE `m`.`dimension_id` = ' . $member->getDimensionId() . ')');
                        }
                        $obj->addToMembers(array($member));
                        $obj->addToSharingTable();
                        $objects[] = $obj;
                        if (Plugins::instance()->isActivePlugin('mail') && $obj instanceof MailContent) {
                            $conversation = MailContents::getMailsFromConversation($obj);
                            foreach ($conversation as $conv_email) {
                                if (array_var($_POST, 'attachment') && $conv_email->getHasAttachments()) {
                                    MailUtilities::parseMail($conv_email->getContent(), $decoded, $parsedEmail, $warnings);
                                    $classification_data = array();
                                    for ($j = 0; $j < count(array_var($parsedEmail, "Attachments", array())); $j++) {
                                        $classification_data["att_" . $j] = true;
                                    }
                                    MailController::classifyFile($classification_data, $conv_email, $parsedEmail, array($member), array_var($_POST, 'remove_prev'), false);
                                }
                            }
                        }
                        // if object is contact ask to add default permissions in member
                        if ($obj instanceof Contact && $obj->isUser() && can_manage_security(logged_user())) {
                            $user_ids[] = $obj->getId();
                        }
                    } else {
                        throw new Exception(lang('you dont have permissions to classify object in member', $obj->getName(), $member->getName()));
                    }
                }
                // if object is contact ask to add default permissions in member
                if (can_manage_security(logged_user()) && count($user_ids) > 0 && $member->getDimension()->getDefinesPermissions()) {
                    evt_add('ask to assign default permissions', array('user_ids' => $user_ids, 'member' => array('id' => $member->getId(), 'name' => clean($member->getName())), ''));
                }
                Hook::fire('after_dragdrop_classify', $objects, $member);
                $display_name = $member->getName();
                $lang_key = count($ids) > 1 ? 'objects moved to member success' : 'object moved to member success';
                $log_datas = array();
                $actions = array();
                // add to application logs
                foreach ($objects as $obj) {
                    $actions[$obj->getId()] = array_var($from, $obj->getId()) ? ApplicationLogs::ACTION_MOVE : ApplicationLogs::ACTION_COPY;
                    $log_datas[$obj->getId()] = (array_var($from, $obj->getId()) ? "from:" . array_var($from, $obj->getId()) . ";" : "") . "to:" . $member->getId();
                }
            } else {
                if ($dim_id = array_var($_POST, 'dimension')) {
                    $dimension = Dimensions::getDimensionById($dim_id);
                    $from = array();
                    foreach ($ids as $oid) {
                        /* @var $obj ContentDataObject */
                        $obj = Objects::findObject($oid);
                        if ($obj instanceof ContentDataObject) {
                            $db_res = DB::execute("SELECT group_concat(om.member_id) as old_members FROM " . TABLE_PREFIX . "object_members om INNER JOIN " . TABLE_PREFIX . "members m ON om.member_id=m.id WHERE m.dimension_id=" . $dim_id . " AND om.object_id=" . $obj->getId());
                            $row = $db_res->fetchRow();
                            if (array_var($row, 'old_members') != "") {
                                $from[$obj->getId()] = $row['old_members'];
                            }
                            // remove from previous members
                            ObjectMembers::delete('`object_id` = ' . $obj->getId() . ' AND `member_id` IN (
							SELECT `m`.`id` FROM `' . TABLE_PREFIX . 'members` `m` WHERE `m`.`dimension_id` = ' . $dim_id . ')');
                        }
                        $obj->addToMembers(array());
                        $obj->addToSharingTable();
                        $objects[] = $obj;
                    }
                    $display_name = $dimension->getName();
                    $lang_key = count($ids) > 1 ? 'objects removed from' : 'object removed from';
                    $log_datas = array();
                    $actions = array();
                    // add to application logs
                    foreach ($objects as $obj) {
                        $actions[$obj->getId()] = array_var($from, $obj->getId()) ? ApplicationLogs::ACTION_MOVE : ApplicationLogs::ACTION_COPY;
                        $log_datas[$obj->getId()] = array_var($from, $obj->getId()) ? "from:" . array_var($from, $obj->getId()) . ";" : "";
                    }
                }
            }
            DB::commit();
            foreach ($objects as $object) {
                ApplicationLogs::instance()->createLog($object, $actions[$object->getId()], false, true, true, $log_datas[$object->getId()]);
            }
            flash_success(lang($lang_key, $display_name));
            if (array_var($_POST, 'reload')) {
                ajx_current('reload');
            } else {
                ajx_current('empty');
            }
        } catch (Exception $e) {
            DB::rollback();
            ajx_current("empty");
            flash_error($e->getMessage());
        }
    }
	/**
	 * Used for Drag & Drop, adds objects to a member
	 * @author alvaro
	 */
	function add_objects_to_member() {
		$ids = json_decode(array_var($_POST, 'objects'));
		$mem_id = array_var($_POST, 'member');
		
		if (!is_array($ids) || count($ids) == 0) {
			ajx_current("empty");
			return;
		}
                
		$member = Members::findById($mem_id);
		
		try {
			DB::beginWork();
			
			$objects = array();
			$from = array();
			foreach ($ids as $oid) {
				/* @var $obj ContentDataObject */
				$obj = Objects::findObject($oid);
				if ($obj instanceof ContentDataObject && $obj->canAddToMember(logged_user(), $member, active_context())) {
					
					$dim_obj_type_content = DimensionObjectTypeContents::findOne(array('conditions' => array('`dimension_id`=? AND `dimension_object_type_id`=? AND `content_object_type_id`=?', $member->getDimensionId(), $member->getObjectTypeId(), $obj->getObjectTypeId())));
					if (!($dim_obj_type_content instanceof DimensionObjectTypeContent)) continue;
					if (!$dim_obj_type_content->getIsMultiple() || array_var($_POST, 'remove_prev')) {
						$db_res = DB::execute("SELECT group_concat(om.member_id) as old_members FROM ".TABLE_PREFIX."object_members om INNER JOIN ".TABLE_PREFIX."members m ON om.member_id=m.id WHERE m.dimension_id=".$member->getDimensionId()." AND om.object_id=".$obj->getId());
						$row = $db_res->fetchRow();
						if (array_var($row, 'old_members') != "") $from[$obj->getId()] = $row['old_members'];
						// remove from previous members
						ObjectMembers::delete('`object_id` = ' . $obj->getId() . ' AND `member_id` IN (SELECT `m`.`id` FROM `'.TABLE_PREFIX.'members` `m` WHERE `m`.`dimension_id` = '.$member->getDimensionId().')');
					}
					
					$obj->addToMembers(array($member));
					$obj->addToSharingTable();
					$objects[] = $obj;
					
					if ($obj->allowsTimeslots()) {
						$timeslots = $obj->getTimeslots();
						foreach ($timeslots as $timeslot) {
							$ts_mids = ObjectMembers::getMemberIdsByObject($timeslot->getId());
							// if classified then reclassify
							if (count($ts_mids)) {
								if (array_var($_POST, 'remove_prev')) {
									ObjectMembers::delete('`object_id` = ' . $timeslot->getId() . ' AND `member_id` IN (SELECT `m`.`id` FROM `'.TABLE_PREFIX.'members` `m` WHERE `m`.`dimension_id` = '.$member->getDimensionId().')');
								}
								$timeslot->addToMembers(array($member));
								$timeslot->addToSharingTable();
								$objects[] = $timeslot;
							}
						}
					}
					
					if ($obj instanceof MailContent) {
						$conversation = MailContents::getMailsFromConversation($obj);
						foreach ($conversation as $conv_email) {
							if (array_var($_POST, 'attachment') && $conv_email->getHasAttachments()) {
								MailUtilities::parseMail($conv_email->getContent(), $decoded, $parsedEmail, $warnings);
								$classification_data = array();
								for ($j=0; $j < count(array_var($parsedEmail, "Attachments", array())); $j++) {
									$classification_data["att_".$j] = true;
								}
								MailController::classifyFile($classification_data, $conv_email, $parsedEmail, array($member), array_var($_POST, 'remove_prev'));
							}
						}
					}
				} else {
					throw new Exception(lang('you dont have permissions to classify object in member', $obj->getName(), $member->getName()));
				}
			}
			
			Hook::fire('after_dragdrop_classify', $objects, $member);
			
			DB::commit();
			
			// add to application logs
			foreach ($objects as $object) {
				$action = array_var($from, $obj->getId()) ? ApplicationLogs::ACTION_MOVE : ApplicationLogs::ACTION_COPY;
				$log_data = (array_var($from, $obj->getId()) ? "from:" . array_var($from, $obj->getId()) . ";" : "") . "to:" . $member->getId();
				ApplicationLogs::instance()->createLog($object, $action, false, true, true, $log_data);
			}
			
			$lang_key = count($ids)>1 ? 'objects moved to member success' : 'object moved to member success';
			flash_success(lang($lang_key, $member->getName()));
			if (array_var($_POST, 'reload')) ajx_current('reload');
			else ajx_current('empty');
			
		} catch (Exception $e) {
			DB::rollback();
			ajx_current("empty");
			flash_error($e->getMessage());
		}
	}
 /**
 * Return manager instance
 *
 * @access protected
 * @param void
 * @return ApplicationLogs 
 */
 function manager() {
   if(!($this->manager instanceof ApplicationLogs)) $this->manager = ApplicationLogs::instance();
   return $this->manager;
 } // manager
 function popup_reminders()
 {
     ajx_current("empty");
     // extra data to send to interface
     $extra_data = array();
     // if no new popup reminders don't make useless queries
     if (GlobalCache::isAvailable()) {
         $check = GlobalCache::get('check_for_popup_reminders_' . logged_user()->getId(), $success);
         if ($success && $check == 0) {
             return;
         }
     }
     $reminders = ObjectReminders::getDueReminders("reminder_popup");
     $popups = array();
     foreach ($reminders as $reminder) {
         $context = $reminder->getContext();
         if (str_starts_with($context, "mails_in_outbox")) {
             if ($reminder->getUserId() > 0 && $reminder->getUserId() != logged_user()->getId()) {
                 continue;
             }
             preg_match('!\\d+!', $context, $matches);
             evt_add("popup", array('title' => lang("mails_in_outbox reminder"), 'message' => lang("mails_in_outbox reminder desc", $matches[0]), 'type' => 'reminder', 'sound' => 'info'));
             $reminder->delete();
             continue;
         }
         if (str_starts_with($context, "eauthfail")) {
             if ($reminder->getUserId() == logged_user()->getId()) {
                 $acc = trim(substr($context, strrpos($context, " ")));
                 evt_add("popup", array('title' => lang("failed to authenticate email account"), 'message' => lang("failed to authenticate email account desc", $acc), 'type' => 'reminder', 'sound' => 'info'));
                 $reminder->delete();
             }
             continue;
         }
         $object = $reminder->getObject();
         $type = $object->getObjectTypeName();
         $date = $object->getColumnValue($reminder->getContext());
         if (!$date instanceof DateTimeValue) {
             continue;
         }
         if ($object->isTrashed()) {
             $reminder->delete();
             continue;
         }
         // convert time to the user's locale
         $timezone = logged_user()->getTimezone();
         if ($date->getTimestamp() + 5 * 60 < DateTimeValueLib::now()->getTimestamp()) {
             // don't show popups older than 5 minutes
             //$reminder->delete();
             //continue;
         }
         if ($reminder->getUserId() == 0) {
             if (!$object->isSubscriber(logged_user())) {
                 // reminder for subscribers and user is not subscriber
                 continue;
             }
         } else {
             if ($reminder->getUserId() != logged_user()->getId()) {
                 continue;
             }
         }
         if ($context == "due_date" && $object instanceof ProjectTask) {
             if ($object->isCompleted()) {
                 // don't show popups for completed tasks
                 $reminder->delete();
                 continue;
             }
         }
         $url = $object->getViewUrl();
         $link = '<a href="#" onclick="og.openLink(\'' . $url . '\');return false;">' . clean($object->getObjectName()) . '</a>';
         evt_add("popup", array('title' => lang("{$context} {$type} reminder", clean($object->getObjectName())), 'message' => lang("{$context} {$type} reminder desc", $link, format_datetime($date)), 'type' => 'reminder', 'sound' => 'info'));
         if ($reminder->getUserId() == 0) {
             // reminder is for all subscribers, so change it for one reminder per user (except logged_user)
             // otherwise if deleted it won't notify other subscribers and if not deleted it will keep notifying
             // logged user
             $subscribers = $object->getSubscribers();
             foreach ($subscribers as $subscriber) {
                 if ($subscriber->getId() != logged_user()->getId()) {
                     $new = new ObjectReminder();
                     $new->setContext($reminder->getContext());
                     $new->setDate($reminder->getDate());
                     $new->setMinutesBefore($reminder->getMinutesBefore());
                     $new->setObject($object);
                     $new->setUser($subscriber);
                     $new->setType($reminder->getType());
                     $new->save();
                 }
             }
         }
         $reminder->delete();
     }
     // popup reminders already checked for logged user
     if (GlobalCache::isAvailable()) {
         $today_next_reminders = ObjectReminders::findAll(array('conditions' => array("`date` > ? AND `date` < ?", DateTimeValueLib::now(), DateTimeValueLib::now()->endOfDay()), 'limit' => config_option('cron reminder limit', 100)));
         if (count($today_next_reminders) == 0) {
             GlobalCache::update('check_for_popup_reminders_' . logged_user()->getId(), 0, 60 * 30);
         }
     }
     // check for member modifications
     if (isset($_POST['dims_check_date'])) {
         $dims_check_date = new DateTimeValue($_POST['dims_check_date']);
         $dims_check_date_sql = $dims_check_date->toMySQL();
         $members_log_count = ApplicationLogs::instance()->count("member_id>0 AND created_on>'{$dims_check_date_sql}'");
         if ($members_log_count > 0) {
             $extra_data['reload_dims'] = 1;
         }
     }
     ajx_extra_data($extra_data);
 }