/**
  * Find all tasks in project, and prepare them for objects list
  *
  * @param Project $project
  * @param User $user
  * @param int $state
  * @return array
  */
 static function findForObjectsList(Project $project, User $user, $state = STATE_VISIBLE)
 {
     $result = array();
     $today = strtotime(date('Y-m-d'));
     $tasks = DB::execute("SELECT o.id, o.name,\r\n\t\t\t\t\t\to.category_id,\r\n\t\t\t\t\t\to.milestone_id,\r\n\t\t\t\t\t\to.completed_on,\r\n\t\t\t\t\t\to.integer_field_1 as task_id,\r\n\t\t\t\t\t\to.label_id,\r\n\t\t\t\t\t\to.assignee_id,\r\n\t\t\t\t\t\to.priority,\r\n\t\t\t\t\t\to.delegated_by_id,\r\n\t\t\t\t\t\to.state,\r\n\t\t\t\t\t\to.visibility,\r\n\t\t\t\t\t\to.created_on,\r\n\t\t\t\t\t\to.updated_on,\r\n\t\t\t\t\t\to.due_on,\r\n\t\t\t\t\t\trec.tracked_time\r\n\t\t\t\t\tFROM " . TABLE_PREFIX . "project_objects o \r\n\t\t\t\t\tLEFT JOIN (SELECT parent_id, sum(value) tracked_time FROM " . TABLE_PREFIX . "time_records WHERE state = ? GROUP BY(parent_id)) rec ON(o.id=rec.parent_id)\r\n\t\t\t\t\tWHERE o.type = 'Task' AND o.project_id = ? AND o.state = ? AND o.visibility >= ? ORDER BY o.id DESC", $state, $project->getId(), $state, $user->getMinVisibility());
     if (is_foreachable($tasks)) {
         $task_url = Router::assemble('project_task', array('project_slug' => $project->getSlug(), 'task_id' => '--TASKID--'));
         $project_id = $project->getId();
         $labels = Labels::getIdDetailsMap('AssignmentLabel');
         foreach ($tasks as $task) {
             list($total_subtasks, $open_subtasks) = ProjectProgress::getObjectProgress(array('project_id' => $project_id, 'object_type' => 'Task', 'object_id' => $task['id']));
             $taskObj = new Task($task['id']);
             $result[] = array('id' => $task['id'], 'name' => $task['name'], 'project_id' => $project_id, 'category_id' => $task['category_id'], 'milestone_id' => $task['milestone_id'], 'task_id' => $task['task_id'], 'is_completed' => $task['completed_on'] ? 1 : 0, 'permalink' => str_replace('--TASKID--', $task['task_id'], $task_url), 'label_id' => $task['label_id'], 'label' => $task['label_id'] ? $labels[$task['label_id']] : null, 'assignee_id' => $task['assignee_id'], 'priority' => $task['priority'], 'delegated_by_id' => $task['delegated_by_id'], 'total_subtasks' => $total_subtasks, 'open_subtasks' => $open_subtasks, 'estimated_time' => $taskObj->tracking()->canAdd($user) && $taskObj->tracking()->getEstimate() ? $taskObj->tracking()->getEstimate()->getValue() : 0, 'tracked_time' => $taskObj->tracking()->canAdd($user) ? $task['tracked_time'] : 0, 'is_favorite' => Favorites::isFavorite(array('Task', $task['id']), $user), 'is_archived' => $task['state'] == STATE_ARCHIVED ? 1 : 0, 'visibility' => $task['visibility'], 'created_on' => $task['created_on'] ? $task['created_on'] : $task['updated_on'], 'updated_on' => $task['updated_on'], 'has_attachments' => $taskObj->attachments()->has() ? true : false, 'due_on' => $task['due_on'] ? $task['due_on'] : lang('No due date set'));
         }
         // foreach
     }
     // if
     return $result;
 }
 function index()
 {
     parent::index();
     $milestones_t = Milestones::findAllByProject($this->active_project);
     $tasks_t = Tasks::findByProject($this->active_project, $this->logged_user);
     $milestones = array();
     $tasks = array();
     // voglio il task non categorizzato che inizia prima di tutti, quindi setto questo nel futuro
     $first_task_time = new DateValue(time() + time());
     $trovato = false;
     if (is_foreachable($tasks_t)) {
         foreach ($tasks_t as $task) {
             $res = array();
             $res['id'] = $task->getTaskId();
             $res['name'] = $task->getName();
             $task->complete()->describe($this->logged_user, true, true, $completion_description);
             $task_description = $task->describe($this->logged_user, true, true);
             $res['is_completed'] = $completion_description['is_completed'];
             $res['completed_on'] = $completion_description['completed_on'];
             $res['due_on'] = $completion_description['due_on'];
             // non è sempre settato
             $res['milestone_id'] = $task_description['milestone_id'] ? $task_description['milestone_id'] : 0;
             $res['created_on_d'] = $task->getCreatedOn()->getDay();
             $res['created_on_m'] = $task->getCreatedOn()->getMonth() - 1;
             $res['created_on_y'] = $task->getCreatedOn()->getYear();
             // La data di inizio non è sempre presente. Quindi se non c'è, prendo la data di creazione del task.
             // Inoltre questo campo dipende dal modulo TaskPlus
             if (AngieApplication::isModuleLoaded('tasks_plus') && TaskPlus::getStartOn($task)) {
                 $start_on = TaskPlus::getStartOn($task);
             } else {
                 $start_on = $task->getCreatedOn();
             }
             $res['start_on_d'] = $start_on->getDay();
             $res['start_on_m'] = $start_on->getMonth() - 1;
             //javascript merda parte da Gennaio = 0
             $res['start_on_y'] = $start_on->getYear();
             // giorni in più
             $days = 60 * 60 * 24 * 15;
             //15 giorni in più
             if ($completion_description['is_completed']) {
                 $completion_date = $completion_description['completed_on'];
             } else {
                 if ($completion_description['due_on']) {
                     // non è completata ma ha data di fine settata
                     $completion_date = $completion_description['due_on'];
                 } else {
                     if (!$completion_description['due_on']) {
                         // non è completata e non ha data di fine settata
                         $completion_date = $start_on->advance($days, false);
                         // (data_inizio || data_creazione) + 15 giorni
                     }
                 }
             }
             $res['finish_on_d'] = $completion_date->getDay();
             $res['finish_on_m'] = $completion_date->getMonth() - 1;
             //javascript merda parte da Gennaio = 0
             $res['finish_on_y'] = $completion_date->getYear();
             $res['durata'] = $start_on->daysBetween($completion_date) * 8;
             //giorni_differenza * ore_lavorative
             if ($res['is_completed']) {
                 $res['percent_completion'] = 100;
             } else {
                 list($total_subtasks, $open_subtasks) = ProjectProgress::getObjectProgress($task);
                 $completed_subtasks = $total_subtasks - $open_subtasks;
                 if ($open_subtasks) {
                     $res['percent_completion'] = ceil($completed_subtasks / $total_subtasks * 100);
                 } else {
                     $res['percent_completion'] = 0;
                 }
             }
             $tasks[] = $res;
             if ($res['milestone_id'] == 0 && $first_task_time->getTimestamp() > $start_on->getTimestamp()) {
                 $first_task_time = $start_on;
                 $trovato = false;
             }
         }
     }
     if ($trovato) {
         //Aggiungo la milestone per tasks non categorizzati
         $milestones[0]['id'] = 0;
         $milestones[0]['name'] = lang("Uncategorized");
         $milestones[0]['start_on_d'] = $first_task_time->getDay();
         $milestones[0]['start_on_m'] = $first_task_time->getMonth() - 1;
         $milestones[0]['start_on_y'] = $first_task_time->getYear();
         $milestones[0]['durata'] = 1;
     }
     if (is_foreachable($milestones_t)) {
         foreach ($milestones_t as $milestone) {
             $res = array();
             $res['id'] = $milestone->getId();
             $res['name'] = $milestone->getName();
             $res['start_on_d'] = $milestone->getStartOn()->getDay();
             $res['start_on_m'] = $milestone->getStartOn()->getMonth() - 1;
             //javascript merda parte da Gennaio = 0
             $res['start_on_y'] = $milestone->getStartOn()->getYear();
             $res['durata'] = ($milestone->getDueOn()->getTimestamp() - $milestone->getStartOn()->getTimestamp()) / (60 * 60 * 24) * 8;
             //giorni * ore lavorative
             $milestones[] = $res;
         }
     }
     $this->smarty->assign(array('milestones' => $milestones, 'tasks' => $tasks));
 }
    /**
     * Find tasks for outline
     *
     * @param Project $project
     * @param User $user
     * @param int $state
     * @return array
     */
    static function findForOutline(Project $project, User $user, $state = STATE_VISIBLE)
    {
        $today = strtotime(date('Y-m-d'));
        $task_ids = DB::executeFirstColumn('SELECT id 
				FROM ' . TABLE_PREFIX . 'project_objects 
				WHERE project_id = ? 
				AND type = ? 
				AND state >= ? 
				AND visibility >= ? 
				AND completed_on IS NULL', $project->getId(), 'Task', $state, $user->getMinVisibility());
        if (!is_foreachable($task_ids)) {
            return false;
        }
        // if
        $tasks = DB::execute('SELECT o.id, 
				o.integer_field_1 AS task_id, 
				o.name, 
				o.body, 
				o.due_on, 
				o.date_field_1 AS start_on, 
				o.assignee_id, 
				o.priority, 
				o.visibility, 
				o.created_by_id, 
				o.label_id, 
				o.milestone_id,
				o.category_id, 
				o.completed_on, 
				o.delegated_by_id, 
				o.state, 
				o.created_on, 
				o.updated_on,
				o.due_on,
				u.first_name,
				u.last_name 
				FROM ' . TABLE_PREFIX . 'project_objects o LEFT JOIN ' . TABLE_PREFIX . 'users u ON(o.assignee_id=u.id) 
				WHERE o.ID IN(?) ORDER BY ' . self::$task_order_by . ' ' . self::$task_sort_by, $task_ids);
        // casting
        // 		$tasks->setCasting(array(
        // 				'due_on'        => DBResult::CAST_DATE,
        // 				'start_on'      => DBResult::CAST_DATE
        // 		));
        $tasks_id_prefix_pattern = '--TASK-ID--';
        $task_url_params = array('project_slug' => $project->getSlug(), 'task_id' => $tasks_id_prefix_pattern);
        $view_task_url_pattern = Router::assemble('project_task', $task_url_params);
        $edit_task_url_pattern = Router::assemble('project_task_edit', $task_url_params);
        $trash_task_url_pattern = Router::assemble('project_task_trash', $task_url_params);
        $subscribe_task_url_pattern = Router::assemble('project_task_subscribe', $task_url_params);
        $unsubscribe_task_url_pattern = Router::assemble('project_task_unsubscribe', $task_url_params);
        $reschedule_task_url_pattern = Router::assemble('project_task_reschedule', $task_url_params);
        $tracking_task_url_pattern = Router::assemble('project_task_tracking', $task_url_params);
        // can_manage_tasks
        $can_manage_tasks = $user->projects()->getPermission('task', $project) >= ProjectRole::PERMISSION_MANAGE;
        // all assignees
        $user_assignments_on_tasks = DB::executeFirstColumn('SELECT parent_id FROM ' . TABLE_PREFIX . 'assignments WHERE parent_id IN (?) AND parent_type = ? AND user_id = ?', $task_ids, 'Task', $user->getId());
        // all subscriptions
        $user_subscriptions_on_tasks = DB::executeFirstColumn('SELECT parent_id FROM ' . TABLE_PREFIX . 'subscriptions WHERE parent_id IN (?) AND parent_type = ? AND user_id = ?', $task_ids, 'Task', $user->getId());
        // other assignees
        $other_assignees = array();
        $raw_other_assignees = DB::execute('SELECT user_id, parent_id FROM ' . TABLE_PREFIX . 'assignments WHERE parent_type = ? AND parent_id IN (?)', 'Task', $task_ids);
        foreach ($raw_other_assignees as $raw_assignee) {
            if (!is_array($other_assignees[$raw_assignee['parent_id']])) {
                $other_assignees[$raw_assignee['parent_id']] = array();
            }
            // if
            $other_assignees[$raw_assignee['parent_id']][] = array('id' => $raw_assignee['user_id']);
        }
        // foreach
        // expenses & time
        $expenses = array();
        $time = array();
        $estimates = array();
        if (AngieApplication::isModuleLoaded('tracking')) {
            $raw_expenses = DB::execute('SELECT parent_id, SUM(value) as expense FROM ' . TABLE_PREFIX . 'expenses WHERE parent_id IN (?) AND parent_type = ? GROUP BY parent_id', $task_ids, 'Task');
            if (is_foreachable($raw_expenses)) {
                foreach ($raw_expenses as $raw_expense) {
                    $expenses[$raw_expense['parent_id']] = $raw_expense['expense'];
                }
                // if
            }
            // if
            $raw_time = DB::execute('SELECT parent_id, SUM(value) as time FROM ' . TABLE_PREFIX . 'time_records WHERE parent_id IN (?) AND parent_type = ? GROUP BY parent_id', $task_ids, 'Task');
            if (is_foreachable($raw_time)) {
                foreach ($raw_time as $raw_single_time) {
                    $time[$raw_single_time['parent_id']] = $raw_single_time['time'];
                }
                // foreach
            }
            // if
            $raw_estimates = DB::execute('SELECT parent_id, value, job_type_id FROM (SELECT * FROM ' . TABLE_PREFIX . 'estimates WHERE parent_id IN (?) AND parent_type = ? ORDER BY created_on DESC) as estimates_inverted GROUP BY parent_id', $task_ids, 'Task');
            if (is_foreachable($raw_estimates)) {
                foreach ($raw_estimates as $raw_estimate) {
                    $estimates[$raw_estimate['parent_id']] = array('value' => $raw_estimate['value'], 'job_type_id' => $raw_estimate['job_type_id']);
                }
                // foreach
            }
            // if
        }
        // if
        $task_url = Router::assemble('project_task', array('project_slug' => $project->getSlug(), 'task_id' => '--TASKID--'));
        $project_id = $project->getId();
        $labels = Labels::getIdDetailsMap('AssignmentLabel');
        $results = array();
        foreach ($tasks as $subobject) {
            $task_id = array_var($subobject, 'id');
            $task_task_id = array_var($subobject, 'task_id');
            list($total_subtasks, $open_subtasks) = ProjectProgress::getObjectProgress(array('project_id' => $project_id, 'object_type' => 'Task', 'object_id' => $subobject['id']));
            $results[] = array('id' => $task_id, 'task_id' => $task_task_id, 'name' => array_var($subobject, 'name'), 'body' => array_var($subobject, 'body'), 'priority' => array_var($subobject, 'priority'), 'milestone_id' => array_var($subobject, 'milestone_id', null), 'class' => 'Task', 'start_on' => array_var($subobject, 'start_on'), 'assignee_id' => array_var($subobject, 'assignee_id'), 'other_assignees' => array_var($other_assignees, $task_id, null), 'label_id' => array_var($subobject, 'label_id', null), 'label' => $subobject['label_id'] ? $labels[$subobject['label_id']] : null, 'project_id' => $project_id, 'category_id' => $subobject['category_id'], 'is_completed' => $subobject['completed_on'] ? 1 : 0, 'permalink' => str_replace('--TASKID--', $subobject['task_id'], $task_url), 'priority' => self::$priority_map[$subobject['priority']], 'delegated_by_id' => $subobject['delegated_by_id'], 'total_subtasks' => $total_subtasks, 'open_subtasks' => $open_subtasks, 'is_favorite' => Favorites::isFavorite(array('Task', $task_id), $user), 'is_archived' => $subobject['state'] == STATE_ARCHIVED ? 1 : 0, 'visibility' => $subobject['visibility'], 'created_on' => $subobject['created_on'] ? $subobject['created_on'] : $subobject['updated_on'], 'updated_on' => $subobject['updated_on'], 'assignee_name' => $subobject['first_name'] . " " . $subobject['last_name'], 'due_on' => $subobject['due_on'] ? $subobject['due_on'] : lang('No due date set'), 'stato' => $subobject['due_on'] ? $subobject['due_on'] >= $today ? 'orario' : 'ritardo' : 'not_set', 'user_is_subscribed' => in_array($task_id, $user_subscriptions_on_tasks), 'object_time' => array_var($time, $task_id, 0), 'object_expenses' => array_var($expenses, $task_id, 0), 'estimate' => array_var($estimates, $task_id, null), 'event_names' => array('updated' => 'task_updated'), 'urls' => array('view' => str_replace($tasks_id_prefix_pattern, $task_task_id, $view_task_url_pattern), 'edit' => str_replace($tasks_id_prefix_pattern, $task_task_id, $edit_task_url_pattern), 'trash' => str_replace($tasks_id_prefix_pattern, $task_task_id, $trash_task_url_pattern), 'subscribe' => str_replace($tasks_id_prefix_pattern, $task_task_id, $subscribe_task_url_pattern), 'unsubscribe' => str_replace($tasks_id_prefix_pattern, $task_task_id, $unsubscribe_task_url_pattern), 'reschedule' => str_replace($tasks_id_prefix_pattern, $task_task_id, $reschedule_task_url_pattern), 'tracking' => str_replace($tasks_id_prefix_pattern, $task_task_id, $tracking_task_url_pattern)), 'permissions' => array('can_edit' => can_edit_project_object($subobject, $user, $project, $can_manage_tasks, $user_assignments_on_tasks), 'can_trash' => can_trash_project_object($subobject, $user, $project, $can_manage_tasks, $user_assignments_on_tasks)));
        }
        // foreach
        return $results;
    }