<?php

  /**
   * Calendar manager class
   *
   * @package activeCollab.modules.calendar
   * @subpackage calendar
   */
  class Calendar {
  
    // ---------------------------------------------------
    //  URL Sections
    // ---------------------------------------------------
    
    /**
     * Return dashboard calendar URL
     *
     * @return string
     */
    static function getDashboardCalendarUrl() {
      return Router::assemble('dashboard_calendar');
    } // getDashboardCalendarUrl
    
    /**
     * Return dashboard month URL
     *
     * @param integer $year
     * @param integer $month
     * @return string
     */
    static function getDashboardMonthUrl($year, $month) {
      return Router::assemble('dashboard_calendar_month', array(
    	  'year' => $year,
        'month' => $month
    	));
    } // getDashboardMonthUrl
    
    /**
     * Return dashboard calendar day URL
     *
     * @param integer $year
     * @param integer $month
     * @param integer $day
     * @return string
     */
    static function getDashboardDayUrl($year, $month, $day) {
    	return Router::assemble('dashboard_calendar_day', array(
    	  'year' => $year,
        'month' => $month,
        'day' => $day
    	));
    } // getDashboardDayUrl
    
    /**
     * Get project section URL
     *
     * @param ProjectObject $project
     * @return string
     */
    static function getProjectCalendarUrl(Project $project) {
    	return Router::assemble('project_calendar', array('project_slug' => $project->getSlug()));
    } // getProjectCalendarUrl
    
    /**
     * Return project month URL
     *
     * @param Project $project
     * @param integer $year
     * @param integer $month
     * @return string
     */
    static function getProjectMonthUrl(Project $project, $year, $month) {
      return Router::assemble('project_calendar_month', array(
        'project_slug' => $project->getSlug(),
        'year' => $year,
        'month' => $month,
      ));
    } // getProjectMonthUrl
    
    /**
     * Return project day URL
     *
     * @param Project $project
     * @param integer $year
     * @param integer $month
     * @param integer $day
     * @return string
     */
    static function getProjectDayUrl(Project $project, $year, $month, $day) {
      return Router::assemble('project_calendar_day', array(
        'project_slug' => $project->getSlug(),
        'year' => $year,
        'month' => $month,
        'day' => $day
      ));
    } // getProjectDayUrl
    
    /**
     * Return user profile calendar URL
     *
     * @param User $user
     * @return string
     */
    static function getProfileCalendarUrl($user) {
      return Router::assemble('profile_calendar', array(
        'user_id' => $user->getId(),
        'company_id' => $user->getCompanyId(),
      ));
    } // getProfileCalendarUrl
    
    /**
     * Return user profile month URL
     *
     * @param User $user
     * @param integer $year
     * @param integer $month
     * @return string
     */
    static function getProfileMonthUrl($user, $year, $month) {
      return Router::assemble('profile_calendar_month', array(
        'user_id' => $user->getId(),
        'company_id' => $user->getCompanyId(),
        'year' => $year,
        'month' => $month,
      ));
    } // getProfileMonthUrl
    
    /**
     * Return user profile day URL
     *
     * @param User $user
     * @param integer $year
     * @param integer $month
     * @param integer $day
     * @return string
     */
    static function getProfileDayUrl($user, $year, $month, $day) {
      return Router::assemble('profile_calendar_day', array(
        'user_id' => $user->getId(),
        'company_id' => $user->getCompanyId(),
        'year' => $year,
        'month' => $month,
        'day' => $day,
      ));
    } // getProfileDayUrl
    
    // ---------------------------------------------------
    //  Extractors
    // ---------------------------------------------------
    
    /**
     * Return data for active projects
     *
     * @param User $user
     * @param integer $month
     * @param integer $year
     * @param boolean $bordering_months
     * @return array
     */
    static function getActiveProjectsData($user, $month, $year, $bordering_months = false) {
    	$filter = $user->projects()->getVisibleTypesFilter(Project::STATUS_ACTIVE, get_completable_project_object_types());
    	
    	if($filter) {
    	  $filter .= DB::prepare(' AND (state >= ? AND visibility >= ?)', array(STATE_VISIBLE, $user->getMinVisibility()));
    	  return Calendar::getMonthData($month, $year, $filter, false, $bordering_months ? ConfigOptions::getValueFor('time_first_week_day', $user) : false);
    	} // if
    	
    	return null;
    } // getActiveProjectsData
    
    /**
     * Return day data for active projects
     *
     * @param User $user
     * @param DateValue $day
     * @return array
     */
    static function getActiveProjectsDayData($user, $day) {
      $filter = $user->projects()->getVisibleTypesFilter(Project::STATUS_ACTIVE, get_completable_project_object_types());
    	
    	if($filter) {
    	  $filter .= DB::prepare(' AND (state >= ? AND visibility >= ?)', array(STATE_VISIBLE, $user->getMinVisibility()));
    	  return Calendar::getDayData($day, $filter);
    	} // if
    	
    	return null;
    } // getActiveProjectsData
    
    /**
     * Return project data ready for rendering
     *
     * @param User $user
     * @param Project $project
     * @param integer $month
     * @param integer $year
     * @return array
     */
    static function getProjectData($user, $project, $month, $year) {
      $filter = $user->projects()->getVisibleTypesFilterByproject($project, get_completable_project_object_types());
    	
    	if($filter) {
    	  $filter .= DB::prepare(' AND (state >= ? AND visibility >= ?)', array(STATE_VISIBLE, $user->getMinVisibility()));
    	  return Calendar::getMonthData($month, $year, $filter);
    	} else {
    	  return null;
    	} // if
    } // getProjectData
    
    /**
     * Return project day data
     *
     * @param User $user
     * @param Project $project
     * @param DateValue $day
     * @return array
     */
    static function getProjectDayData($user, $project, $day) {
    	$filter = $user->projects()->getVisibleTypesFilterByproject($project, get_completable_project_object_types());
    	
    	if($filter) {
    	  $filter .= DB::prepare(' AND (state >= ? AND visibility >= ?)', array(STATE_VISIBLE, $user->getMinVisibility()));
    	  return Calendar::getDayData($day, $filter);
    	} else {
    	  return null;
    	} // if
    } // getProjectDayData
    
    /**
     * Return user for a given user
     *
     * This can be viewed only by project manager so type filter is not
     * necessery
     *
     * @param User $user
     * @param integer $month
     * @param integer $year
     * @param boolean $bordering_months
     * @returnay
     */
    static function getUserData($user, $month, $year, $bordering_months = false) {
    	$objects_table = TABLE_PREFIX . 'project_objects';
      $assignments_table = TABLE_PREFIX . 'assignments';
      
      return Calendar::getMonthData($month, $year, DB::prepare("(($assignments_table.user_id = ?) OR ($objects_table.assignee_id = ?))", array($user->getId(), $user->getId())), true, ConfigOptions::getValueFor('time_first_week_day', $user));
    } // getUserData
    
    /**
     * Return user day data
     *
     * @param User $user
     * @param DateValue $day
     * @return array
     */
    static function getUserDayData($user, $day) {
    	$objects_table = TABLE_PREFIX . 'project_objects';
      $assignments_table = TABLE_PREFIX . 'assignments';
      
      return Calendar::getDayData($day, DB::prepare("(($assignments_table.user_id = ?) OR ($objects_table.assignee_id = ?))", array($user->getId(), $user->getId())), true);
    } // getUserData
    
    /**
     * Prepare project data for a given month
     *
     * @param integer $month
     * @param integer $year
     * @param mixed $additional_conditions
     * @param boolean $include_assignments_table
     * @param boolean $first_week_day - if $first_week_day === false, function will return data for exactly that month, and if $first_week_day !== false
     * 																	function will return data from beginning of work week of first day of that month up until the last work day of the
     * 																	work week in which is last month day
     * @return array
     */
    static function getMonthData($month, $year, $additional_conditions, $include_assignments_table = false, $first_week_day = FALSE) {
      $first_day = DateTimeValue::beginningOfMonth($month, $year);
      $last_day = DateTimeValue::endOfMonth($month, $year);
      
      if ($first_week_day !== FALSE) {
      	$first_day = $first_day->beginningOfWeek($first_week_day);
      	$last_day = $last_day->endOfWeek($first_week_day);
      } // if
      
			$current_day = clone $first_day;
			do {
				$result[$current_day->getYear() . '-' . $current_day->getMonth() . '-' . $current_day->getDay()] = array();
				$current_day->advance(60 * 60 * 24);
			} while ($last_day->getTimestamp() > $current_day->getTimestamp());
      
      $objects_table = TABLE_PREFIX . 'project_objects';
      $assignments_table = TABLE_PREFIX . 'assignments';

      $conditions = DB::prepare("$objects_table.due_on BETWEEN ? AND ? AND $objects_table.state >= ?", array($first_day, $last_day, STATE_VISIBLE));
      if($additional_conditions) {
        $conditions .= " AND $additional_conditions";
      } // if
      // If we don't have user ID-s filter we can exclude assignments table
      $tables = $include_assignments_table ? "$objects_table LEFT JOIN $assignments_table ON ($objects_table.id = $assignments_table.parent_id)" : $objects_table;
      
      $objects = ProjectObjects::findBySQL("SELECT DISTINCT $objects_table.* FROM $tables WHERE $conditions ORDER BY type, due_on");
      if(is_foreachable($objects)) {
        foreach($objects as $object) {
          $due_on = $object->getDueOn();
          if($due_on instanceof DateValue) {
            $result[$due_on->getYear() . '-' . $due_on->getMonth() . '-' . $due_on->getDay()][] = $object;
          } // if
        } // foreach
      } // if
      
      return $result;
    } // getMonthData
    
    /**
     * Return data for a given day
     *
     * @param DateValue $day
     * @param string $additional_conditions
     * @param boolean $include_assignments_table
     * @return array
     */
    static function getDayData($day, $additional_conditions, $include_assignments_table = false) {
      $objects_table = TABLE_PREFIX . 'project_objects';
      $assignments_table = TABLE_PREFIX . 'assignments';
      
      $conditions = DB::prepare("$objects_table.due_on = ?", array($day));
      if($additional_conditions) {
        $conditions .= " AND $additional_conditions";
      } // if
      
      // If we don't have user ID-s filter we can exclude assignments table
      $tables = $include_assignments_table ? "$objects_table LEFT JOIN $assignments_table ON ($objects_table.id = $assignments_table.parent_id)" : $objects_table;
      
      return ProjectObjects::findBySQL("SELECT DISTINCT $objects_table.* FROM $tables WHERE $conditions ORDER BY priority DESC");
    } // getDayData
    
  }