/**
  * Return associative array of changes that is easy to display
  *
  * @param void
  * @return array
  */
 function getVerboseChanges()
 {
     $result = array();
     if (is_foreachable($this->getChanges())) {
         foreach ($this->getChanges() as $field => $change_data) {
             list($old_value, $new_value) = $change_data;
             $log_fields = array('project_id', 'milestone_id', 'parent_id', 'name', 'body', 'priority', 'due_on');
             switch ($field) {
                 case 'project_id':
                     $old_project = Projects::findById($old_value);
                     $new_project = Projects::findById($new_value);
                     $old_project_name = instance_of($old_project, 'Project') ? $old_project->getName() : lang('unknown project');
                     $new_project_name = instance_of($new_project, 'Project') ? $new_project->getName() : lang('unknown project');
                     $result[] = lang('Moved from <span>:from</span> to <span>:to</span>', array('from' => $old_project_name, 'to' => $new_project_name));
                     break;
                 case 'milestone_id':
                     $old_milestone = Milestones::findById($old_value);
                     $new_milestone = Milestones::findById($new_value);
                     $old_milestone_name = instance_of($old_milestone, 'Milestone') ? $old_milestone->getName() : lang('-- none --');
                     $new_milestone_name = instance_of($new_milestone, 'Milestone') ? $new_milestone->getName() : lang('-- none --');
                     $result[] = lang('Moved from <span>:from</span> to <span>:to</span> milestone', array('from' => $old_milestone_name, 'to' => $new_milestone_name));
                     break;
                 case 'parent_id':
                     $old_parent = ProjectObjects::findById($old_value);
                     $new_parent = ProjectObjects::findById($new_value);
                     $old_parent_name = instance_of($old_parent, 'Category') ? $old_parent->getName() : lang('-- none --');
                     $new_parent_name = instance_of($new_parent, 'Category') ? $new_parent->getName() : lang('-- none --');
                     $result[] = lang('Moved from <span>:from</span> to <span>:to</span> category', array('from' => $old_parent_name, 'to' => $new_parent_name));
                     break;
                 case 'name':
                     $result[] = lang('Summary is changed from <span>:from</span> to <span>:to</span>', array('from' => $old_value, 'to' => $new_value));
                     break;
                 case 'body':
                     $result[] = lang('Long description is changed');
                     break;
                 case 'priority':
                     switch ($old_value) {
                         case PRIORITY_HIGHEST:
                             $old_priority = lang('Highest');
                             break;
                         case PRIORITY_HIGH:
                             $old_priority = lang('High');
                             break;
                         case PRIORITY_NORMAL:
                             $old_priority = lang('Normal');
                             break;
                         case PRIORITY_LOW:
                             $old_priority = lang('Low');
                             break;
                         case PRIORITY_LOWEST:
                             $old_priority = lang('Lowest');
                             break;
                         case PRIORITY_ONGOING:
                             $old_priority = lang('Ongoing');
                             break;
                         case PRIORITY_HOLD:
                             $old_priority = lang('Hold');
                             break;
                     }
                     // switch
                     switch ($new_value) {
                         case PRIORITY_HIGHEST:
                             $new_priority = lang('Highest');
                             break;
                         case PRIORITY_HIGH:
                             $new_priority = lang('High');
                             break;
                         case PRIORITY_NORMAL:
                             $new_priority = lang('Normal');
                             break;
                         case PRIORITY_LOW:
                             $new_priority = lang('Low');
                             break;
                         case PRIORITY_LOWEST:
                             $new_priority = lang('Lowest');
                             break;
                         case PRIORITY_ONGOING:
                             $new_priority = lang('Ongoing');
                             break;
                         case PRIORITY_HOLD:
                             $new_priority = lang('Hold');
                             break;
                     }
                     // switch
                     $result[] = lang('Priority is changed from <span>:from</span> to <span>:to</span>', array('from' => $old_priority, 'to' => $new_priority));
                     break;
                 case 'due_on':
                     require_once SMARTY_PATH . '/plugins/modifier.date.php';
                     $old_due_on = instance_of($old_value, 'DateValue') ? smarty_modifier_date($old_value, 0) : lang('-- none --');
                     $new_due_on = instance_of($new_value, 'DateValue') ? smarty_modifier_date($new_value, 0) : lang('-- none --');
                     $result[] = lang('Due date is changed from <span>:from</span> to <span>:to</span>', array('from' => $old_due_on, 'to' => $new_due_on));
                     break;
                 case 'completed_on':
                     if (instance_of($old_value, 'DateValue') && $new_value === null) {
                         $result[] = lang('Status changed to: Open');
                     } elseif ($old_value === null && instance_of($new_value, 'DateValue')) {
                         $result[] = lang('Status changed to: Completed');
                     }
                     // if
                     break;
                 case 'owner':
                     if ($new_value) {
                         $new_owner = Users::findById($new_value);
                         if (instance_of($new_owner, 'User')) {
                             $result[] = lang(':user is responsible', array('user' => $new_owner->getDisplayName()));
                         } else {
                             $result[] = lang('Owner changed (unknown user or deleted in the meantime)');
                         }
                         // if
                     } else {
                         $result[] = lang('Anyone can pick up and work on this ticket');
                     }
                     // if
                     break;
                 case 'assignees':
                     $old_assignees = array();
                     if (is_foreachable($old_value)) {
                         $old_assignees_users = Users::findByIds($old_value);
                         if (is_foreachable($old_assignees_users)) {
                             foreach ($old_assignees_users as $user) {
                                 $old_assignees[$user->getId()] = $user->getDisplayName();
                             }
                             // foreach
                         }
                         // if
                     }
                     // if
                     $new_assignees = array();
                     if (is_foreachable($new_value)) {
                         $new_assignees_users = Users::findByIds($new_value);
                         if (is_foreachable($new_assignees_users)) {
                             foreach ($new_assignees_users as $user) {
                                 $new_assignees[$user->getId()] = $user->getDisplayName();
                             }
                             // foreach
                         }
                         // if
                     }
                     // if
                     foreach ($new_assignees as $new_assignee_id => $new_assignee) {
                         if (!array_key_exists($new_assignee_id, $old_assignees)) {
                             $result[] = lang(':user has been assigned to this ticket', array('user' => $new_assignee));
                         }
                         // if
                     }
                     // foreach
                     foreach ($old_assignees as $old_assignee_id => $old_assignee) {
                         if (!array_key_exists($old_assignee_id, $new_assignees)) {
                             $result[] = lang(':user has been removed from this ticket', array('user' => $old_assignee));
                         }
                         // if
                     }
                     // foreach
                     break;
             }
             // switch
         }
         // foreach
     }
     // if
     return $result;
 }
 /**
  * Find project objects in commit message, make them links and
  * save the relations to database
  *
  * @param string $commit_message
  * @param string $commit_author
  * @param integer $revision
  * @param Repository $repository
  * @param Project $project
  * @return string
  */
 function analyze_message($commit_message, $commit_author, $revision, $repository, $project)
 {
     if (define('PURIFY_HTML') && PURIFY_HTML) {
         $commit_message = purify_html($commit_message);
         // Clean!
     }
     // if
     $pattern = '/((complete[d]*)[\\s]+)?(ticket|milestone|discussion|task)[s]*[\\s]+[#]*\\d+/i';
     if (preg_match_all($pattern, $commit_message, $matches)) {
         $i = 0;
         $search = array();
         $replace = array();
         $matches_unique = array_unique($matches['0']);
         foreach ($matches_unique as $key => $match) {
             $match_data = preg_split('/[\\s,]+/', $match, null, PREG_SPLIT_NO_EMPTY);
             // check if the object got completed by this commit
             $object_completed = false;
             if (strpos(strtolower($match_data['0']), 'complete') !== false) {
                 $object_completed = true;
                 unset($match_data['0']);
                 $match_data = array_values($match_data);
             }
             // if
             $object_class_name = $match_data['0'];
             $module_name = Inflector::pluralize($object_class_name);
             $object_id = trim($match_data['1'], '#');
             $search[$i] = $match;
             if (class_exists($module_name) && class_exists($object_class_name)) {
                 $object = null;
                 switch (strtolower($module_name)) {
                     case 'tickets':
                         $object = Tickets::findByTicketId($project, $object_id);
                         break;
                     case 'discussions':
                         $object = Discussions::findById($object_id);
                         break;
                     case 'milestones':
                         $object = Milestones::findById($object_id);
                         break;
                     case 'tasks':
                         $object = Tasks::findById($object_id);
                         break;
                 }
                 // switch
                 if (instance_of($object, $object_class_name)) {
                     $link_already_created = CommitProjectObjects::count("object_id = '" . $object->getId() . "' AND revision = '{$revision}'") > 0;
                     if (!$link_already_created) {
                         $comit_project_object = new CommitProjectObject();
                         $comit_project_object->setProjectId($object->getProjectId());
                         $comit_project_object->setObjectId($object->getId());
                         $comit_project_object->setObjectType(ucfirst($object_class_name));
                         $comit_project_object->setRepositoryId($repository->getId());
                         $comit_project_object->setRevision($revision);
                         db_begin_work();
                         $save = $comit_project_object->save();
                         if ($save && !is_error($save)) {
                             db_commit();
                         } else {
                             db_rollback();
                         }
                         // if save
                     }
                     // if
                     $replace[$i] = ($object_completed ? 'Completed ' : '') . '<a href="' . $object->getViewUrl() . '">' . $match_data['0'] . ' ' . $match_data['1'] . '</a>';
                     // set the object as completed
                     if ($object_completed && !instance_of($object, 'Discussion')) {
                         $completed_by = $repository->getMappedUser($commit_author);
                         $object->complete($completed_by);
                     }
                     // if
                 } else {
                     $replace[$i] = ($object_completed ? 'Completed ' : '') . '<a href="#" class="project_object_missing" title="' . lang('Project object does not exist in this project') . '">' . $match_data['0'] . ' ' . $match_data['1'] . '</a>';
                 }
                 // if instance_of
                 $i++;
             }
             // if module loaded
         }
         // foreach
         return str_ireplace($search, $replace, htmlspecialchars($commit_message));
         // linkify
     }
     // if preg_match
     return $commit_message;
 }
 /**
  * Return parent milestone
  *
  * @param void
  * @return Milestone
  */
 function &getMilestone()
 {
     if ($this->milestone === false) {
         $this->milestone = $this->getMilestoneId() ? Milestones::findById($this->getMilestoneId()) : null;
     }
     // if
     return $this->milestone;
 }
 /**
  * Add AC object links to commit messages
  *
  * @param string
  * @return string
  **/
 private function analyzeCommitMessage($commit_message)
 {
     $pattern = '/(ticket|milestone|discussion|task)[s]*[\\s]+[#]*(\\d+)/i';
     if (preg_match_all($pattern, $commit_message, $matches)) {
         $i = 0;
         $search = array();
         $replace = array();
         $matches_unique = array_unique($matches['0']);
         foreach ($matches_unique as $key => $match) {
             $match_data = preg_split('/[\\s,]+/', $match, null, PREG_SPLIT_NO_EMPTY);
             $object_class_name = $match_data['0'];
             $module_name = Inflector::pluralize($object_class_name);
             $object_id = trim($match_data['1'], '#');
             $search[$i] = $match;
             if (class_exists($module_name) && class_exists($object_class_name)) {
                 $object = null;
                 switch (strtolower($module_name)) {
                     case 'tickets':
                         $object = Tickets::findByTicketId($this->active_project, $object_id);
                         break;
                     case 'discussions':
                         $object = Discussions::findById($object_id);
                         break;
                     case 'milestones':
                         $object = Milestones::findById($object_id);
                         break;
                     case 'tasks':
                         $object = Tasks::findById($object_id);
                         break;
                 }
                 // switch
                 if (instance_of($object, $object_class_name)) {
                     $replace[$i] = '<a href="' . $object->getViewUrl() . '">' . $match_data['0'] . ' ' . $match_data['1'] . '</a>';
                 } else {
                     $replace[$i] = '<a href="#" class="project_object_missing" title="' . lang('Project object does not exist in this project') . '">' . $match_data['0'] . ' ' . $match_data['1'] . '</a>';
                 }
                 // if instance_of
                 $i++;
             }
             // if module loaded
         }
         // foreach
         return str_ireplace($search, $replace, htmlspecialchars($commit_message));
         // linkify
     }
     // if preg_match
     return $commit_message;
 }
 /**
  * Show and process reorder task form
  *
  * @param void
  * @return null
  */
 function reorder_tickets()
 {
     $this->wireframe->print_button = false;
     $milestone = Milestones::findById($this->request->get('milestone_id'));
     if (instance_of($milestone, 'Milestone')) {
         $milestone_id = $milestone->getId();
     } else {
         $milestone_id = null;
     }
     // if
     if (!$this->request->isSubmitted()) {
         $this->httpError(HTTP_ERR_BAD_REQUEST, null, true, true);
     }
     // if
     if (!Ticket::canManage($this->logged_user, $this->active_project)) {
         $this->httpError(HTTP_ERR_FORBIDDEN, null, true, true);
     }
     // if
     $order_data = $this->request->post('reorder_ticket');
     $ids = array_keys($order_data);
     if (is_foreachable($order_data)) {
         $x = 1;
         foreach ($order_data as $key => $value) {
             $order_data[$key] = $x;
             $x++;
         }
         // foreach
     }
     // if
     $tickets = Tickets::findByIds($ids, STATE_VISIBLE, $this->logged_user->getVisibility());
     if (is_foreachable($tickets)) {
         foreach ($tickets as $ticket) {
             $ticket->setMilestoneId($milestone_id);
             $ticket->setPosition(array_var($order_data, $ticket->getId()));
             $ticket->save();
         }
         // foreach
     }
     // if
     $this->httpOk();
 }