<?php

  /**
   * Subtasks class
   *
   * @package activeCollab.modules.system
   * @subpackage models
   */
  class Subtasks extends FwSubtasks {

    /**
     * Find subtasks for outline
     *
     * @param ISubtasks $parent
     * @param IUser $user
     * @param $visibility
     *
     * @return array
     */
    function findForOutline(ISubtasks $parent, IUser $user) {
      $parent_id = $parent->getId();
      $parent_type = $parent->getType();
      $can_edit_parent = $parent->canEdit($user);
      $subtask_class = 'ProjectObjectSubtask';

      $subtask_ids = DB::executeFirstColumn('SELECT id FROM ' . TABLE_PREFIX . 'subtasks WHERE parent_id = ? AND parent_type = ? AND completed_on IS NULL AND state >= ?', $parent_id, $parent_type, STATE_VISIBLE);

      if (!is_foreachable($subtask_ids)) {
        return false;
      } // if

      $subtasks = DB::execute('SELECT id, body, due_on, assignee_id, label_id, priority FROM ' . TABLE_PREFIX . 'subtasks WHERE ID IN(?) ORDER BY ISNULL(position) ASC, position, priority DESC, created_on', $subtask_ids);

      // casting
      $subtasks->setCasting(array(
        'due_on'        => DBResult::CAST_DATE,
        'start_on'      => DBResult::CAST_DATE
      ));

      $subtasks_id_prefix_pattern = '--SUBTASK-ID--';
      $routing_context = $parent->getRoutingContext();
      $routing_params = array_merge($parent->getRoutingContextParams(), array('subtask_id' => $subtasks_id_prefix_pattern));
      $view_subtask_url_pattern = Router::assemble($routing_context . '_subtask', $routing_params);
      $edit_subtask_url_pattern = Router::assemble($routing_context . '_subtask_edit', $routing_params);
      $trash_subtask_url_pattern = Router::assemble($routing_context . '_subtask_trash', $routing_params);
      $subscribe_subtask_url_pattern = Router::assemble($routing_context . '_subtask_subscribe', $routing_params);
      $unsubscribe_subtask_url_pattern = Router::assemble($routing_context . '_subtask_unsubscribe', $routing_params);
      $reschedule_subtask_url_pattern = Router::assemble($routing_context . '_subtask_reschedule', $routing_params);
      $complete_subtask_url_pattern = Router::assemble($routing_context . '_subtask_complete', $routing_params);

      // 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 = ?', $subtask_ids, $subtask_class, $user->getId());

      $results = array();
      foreach ($subtasks as $subobject) {
        $subtask_id = array_var($subobject, 'id');

        $results[] = array(
          'id'                  => $subtask_id,
          'name'                => array_var($subobject, 'body'),
          'class'               => $subtask_class,
          'priority'            => array_var($subobject, 'priority'),
          'parent_id'           => $parent_id,
          'parent_class'        => $parent_type,
          'due_on'              => array_var($subobject, 'due_on'),
          'assignee_id'         => array_var($subobject, 'assignee_id'),
          'label_id'            => array_var($subobject, 'label_id', null),
          'user_is_subscribed'  => in_array($subtask_id, $user_subscriptions_on_tasks),
          'event_names'         => array(
            'updated'             => 'subtask_updated'
          ),
          'urls'                => array(
            'view'                => str_replace($subtasks_id_prefix_pattern, $subtask_id, $view_subtask_url_pattern),
            'edit'                => str_replace($subtasks_id_prefix_pattern, $subtask_id, $edit_subtask_url_pattern),
            'trash'               => str_replace($subtasks_id_prefix_pattern, $subtask_id, $trash_subtask_url_pattern),
            'subscribe'           => str_replace($subtasks_id_prefix_pattern, $subtask_id, $subscribe_subtask_url_pattern),
            'unsubscribe'         => str_replace($subtasks_id_prefix_pattern, $subtask_id, $unsubscribe_subtask_url_pattern),
            'reschedule'          => str_replace($subtasks_id_prefix_pattern, $subtask_id, $reschedule_subtask_url_pattern),
            'complete'            => str_replace($subtasks_id_prefix_pattern, $subtask_id, $complete_subtask_url_pattern),
          ),
          'permissions'         => array(
            'can_edit'            => $can_edit_parent,
            'can_trash'           => $can_edit_parent,
          )
        );
      } // foreach

      return $results;
    } // findForOutline

    /**
     * Find all project attachments
     *
     * @param Project $project
     * @param integer $min_state
     * @return DBResult
     */
    static function findForApiByProject(Project $project, $min_state = STATE_ARCHIVED) {
      $subtasks_table = TABLE_PREFIX . 'subtasks';

      if($project->getState() >= STATE_VISIBLE) {
        $map = Subtasks::findTypeIdMapOfPotentialParents($project, $min_state);

        if($map) {
          $conditions = array();

          foreach($map as $type => $ids) {
            $conditions[] = DB::prepare('(parent_type = ? AND parent_id IN (?))', array($type, $ids));
          } // if

          $conditions = implode(' OR ', $conditions);

          $result = DB::execute("SELECT id, type, parent_type, parent_id, label_id, assignee_id, delegated_by_id, priority, body, due_on, state, created_on, created_by_id, created_by_name, created_by_email, completed_on, completed_by_id, completed_by_name, completed_by_email FROM $subtasks_table WHERE ($conditions) AND state >= ?", $min_state);

          if($result) {
            $result->setCasting(array(
              'id' => DBResult::CAST_INT,
              'parent_id' => DBResult::CAST_INT,
              'label_id' => DBResult::CAST_INT,
              'assignee_id' => DBResult::CAST_INT,
              'delegated_by_id' => DBResult::CAST_INT,
              'priority' => DBResult::CAST_INT,
              'state' => DBResult::CAST_INT,
              'created_by_id' => DBResult::CAST_INT,
              'completed_by_id' => DBResult::CAST_INT,
            ));

            return $result;
          } // if
        } // if
      } // if

      return null;
    } // findForApiByProject

    /**
     * Find type ID map of potential subtask parents in a given project
     *
     * @param Project $project
     * @param integer $min_state
     * @return array
     */
    static function findTypeIdMapOfPotentialParents(Project $project, $min_state = STATE_ARCHIVED) {
      $map = array();

      $rows = DB::execute('SELECT id, type FROM ' . TABLE_PREFIX . 'project_objects WHERE project_id = ? AND state >= ? AND type IN (?)', $project->getId(), $min_state, array('Task', 'TodoList'));
      if($rows) {
        foreach($rows as $row) {
          if(array_key_exists($row['type'], $map)) {
            $map[$row['type']][] = (integer) $row['id'];
          } else {
            $map[$row['type']] = array((integer) $row['id']);
          } // if
        } // foreach
      } // if

      EventsManager::trigger('on_extend_project_items_type_id_map', array(&$project, $min_state, &$map));

      return count($map) ? $map : null;
    } // findTypeIdMapOfPotentialParents
    
  }