<?php
if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
/*********************************************************************************
 * SugarCRM Community Edition is a customer relationship management program developed by
 * SugarCRM, Inc. Copyright (C) 2004-2013 SugarCRM Inc.
 * 
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Affero General Public License version 3 as published by the
 * Free Software Foundation with the addition of the following permission added
 * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
 * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
 * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
 * 
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU Affero General Public License along with
 * this program; if not, see http://www.gnu.org/licenses or write to the Free
 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 * 02110-1301 USA.
 * 
 * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
 * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
 * 
 * The interactive user interfaces in modified source and object code versions
 * of this program must display Appropriate Legal Notices, as required under
 * Section 5 of the GNU Affero General Public License version 3.
 * 
 * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
 * these Appropriate Legal Notices must retain the display of the "Powered by
 * SugarCRM" logo. If the display of the logo is not reasonably feasible for
 * technical reasons, the Appropriate Legal Notices must display the words
 * "Powered by SugarCRM".
 ********************************************************************************/


class CalendarUtils {

	/**
	 * Find first day of week according to user's settings
	 * @param SugarDateTime $date
	 * @return SugarDateTime $date
	 */
	static function get_first_day_of_week(SugarDateTime $date){
		$fdow = $GLOBALS['current_user']->get_first_day_of_week();
		if($date->day_of_week < $fdow)
				$date = $date->get('-7 days');
		return $date->get_day_by_index_this_week($fdow);
	}


	/**
	 * Get list of needed fields for modules
	 * @return array
	 */
	static function get_fields(){
		return array(
			'Meetings' => array(
				'name',
				'duration_hours',
				'duration_minutes',
				'status',
				'related_to',
			),
			'Calls' => array(
				'name',
				'duration_hours',
				'duration_minutes',
				'status',
				'related_to',
			),
			'Tasks' => array(
				'name',
				'status',
				'related_to',
			),
		);
	}

	/**
	 * Get array of needed time data
	 * @param SugarBean $bean
	 * @return array
	 */
	static function get_time_data(SugarBean $bean){
					$arr = array();

					$start_field = "date_start";
					$end_field = "date_end";

					if($bean->object_name == 'Task')
						$start_field = $end_field = "date_due";
					if(empty($bean->$start_field))
						return array();
					if(empty($bean->$end_field))
						$bean->$end_field = $bean->$start_field;

					$timestamp = SugarDateTime::createFromFormat($GLOBALS['timedate']->get_date_time_format(),$bean->$start_field,new DateTimeZone('UTC'))->format('U');
					$arr['timestamp'] = $timestamp;
					$arr['time_start'] = $GLOBALS['timedate']->fromTimestamp($arr['timestamp'])->format($GLOBALS['timedate']->get_time_format());
					$date_start = SugarDateTime::createFromFormat($GLOBALS['timedate']->get_date_time_format(),$bean->$start_field,new DateTimeZone('UTC'));
					$arr['ts_start'] = $date_start->get("-".$date_start->format("H")." hours -".$date_start->format("i")." minutes -".$date_start->format("s")." seconds")->format('U');
					$arr['offset'] = $date_start->format('H') * 3600 + $date_start->format('i') * 60;
					$date_end = SugarDateTime::createFromFormat($GLOBALS['timedate']->get_date_time_format(),$bean->$end_field,new DateTimeZone('UTC'));
					if($bean->object_name != 'Task')
						$date_end->modify("-1 minute");
					$arr['ts_end'] = $date_end->get("+1 day")->get("-".$date_end->format("H")." hours -".$date_end->format("i")." minutes -".$date_end->format("s")." seconds")->format('U');
					$arr['days'] = ($arr['ts_end'] - $arr['ts_start']) / (3600*24);

					return $arr;
	}


	/**
	 * Get array that will be sent back to ajax frontend
	 * @param SugarBean $bean
	 * @return array
	 */
	static function get_sendback_array(SugarBean $bean){

			if(isset($bean->parent_name) && isset($_REQUEST['parent_name']))
				$bean->parent_name = $_REQUEST['parent_name'];

			$users = array();
			if($bean->object_name == 'Call')
				$users = $bean->get_call_users();
			else if($bean->object_name == 'Meeting')
				$users = $bean->get_meeting_users();
			$user_ids = array();
			foreach($users as $u)
				$user_ids[] = $u->id;

			$field_list = CalendarUtils::get_fields();
			$field_arr = array();
			foreach($field_list[$bean->module_dir] as $field){
			    if ($field == 'related_to')
			    {
			        $focus = BeanFactory::getBean($bean->parent_type, $bean->parent_id);
			        $field_arr[$field] = $focus->name;
			    }
			    else
			    {
			        $field_arr[$field] = $bean->$field;
			    }
			}

			$date_field = "date_start";
			if($bean->object_name == 'Task')
				$date_field = "date_due";

			$arr = array(
				'access' => 'yes',
				'type' => strtolower($bean->object_name),
				'module_name' => $bean->module_dir,
				'user_id' => $GLOBALS['current_user']->id,
				'detail' => 1,
				'edit' => 1,
				'name' => $bean->name,
				'record' => $bean->id,
				'users' => $user_ids,
			);
			if(!empty($bean->repeat_parent_id))
				$arr['repeat_parent_id'] = $bean->repeat_parent_id;
			$arr = array_merge($arr,$field_arr);
			$arr = array_merge($arr,CalendarUtils::get_time_data($bean));

			return $arr;
	}

	/**
	 * Get array of repeat data
	 * @param SugarBean $bean
	 * @return array
	 */
	 static function get_sendback_repeat_data(SugarBean $bean){
	 	if ($bean->module_dir == "Meetings" || $bean->module_dir == "Calls") {
	 		if(!empty($bean->repeat_parent_id) || (!empty($bean->repeat_type) && empty($_REQUEST['edit_all_recurrences']))){
				if(!empty($bean->repeat_parent_id))
					$repeat_parent_id = $bean->repeat_parent_id;
				else
					$repeat_parent_id = $bean->id;
	 			return array("repeat_parent_id" => $repeat_parent_id);
	 		}

	 		$arr = array();
	 		if(!empty($bean->repeat_type)){
	 			$arr = array(
	 				'repeat_type' => $bean->repeat_type,
	 				'repeat_interval' => $bean->repeat_interval,
	 				'repeat_dow' => $bean->repeat_dow,
	 				'repeat_until' => $bean->repeat_until,
	 				'repeat_count' => $bean->repeat_count,
	 			);
	 		}

	 		// TODO CHECK DATETIME VARIABLE
	 		if(!empty($_REQUEST['date_start'])){
	 			$date_start = $_REQUEST['date_start'];
	 		}else
	 			$date_start = $bean->date_start;

	 		$date = SugarDateTime::createFromFormat($GLOBALS['timedate']->get_date_time_format(),$date_start);
		 	$arr = array_merge($arr,array(
		 		'current_dow' => $date->format("w"),
		 		'default_repeat_until' => $date->get("+1 Month")->format($GLOBALS['timedate']->get_date_format()),
		 	));

		 	return $arr;
		}
	 	return false;
	 }

	/**
	 * Build array of datetimes for recurring meetings
	 * @param string $date_start
	 * @param array $params
	 * @return array
	 */
	static function build_repeat_sequence($date_start,$params){

		$arr = array();

		$type = $params['type'];
		$interval = intval($params['interval']);
		if($interval < 1)
			$interval = 1;

		if(!empty($params['count'])){
			$count = $params['count'];
			if($count < 1)
				$count = 1;
		}else
			$count = 0;

		if(!empty($params['until'])){
			$until = $params['until'];
		}else
			$until = $date_start;

		if($type == "Weekly"){
			$dow = $params['dow'];
			if($dow == ""){
				return array();
			}
		}

		/** 
		 * @var SugarDateTime $start Recurrence start date.
		 */
		$start = SugarDateTime::createFromFormat($GLOBALS['timedate']->get_date_time_format(),$date_start);
		/** 
		 * @var SugarDateTime $end Recurrence end date. Used if recurrence ends by date.
		 */
		 
		if (!empty($params['until'])) {
			$end = SugarDateTime::createFromFormat($GLOBALS['timedate']->get_date_format(), $until);
			$end->modify("+1 Day");
		} else {
			$end = $start;
		}
		$current = clone $start;

		$i = 1; // skip the first iteration
		$w = $interval; // for week iteration
		$last_dow = $start->format("w");

		$limit = SugarConfig::getInstance()->get('calendar.max_repeat_count',1000);

		while($i < $count || ($count == 0 && $current->format("U") < $end->format("U"))){
			$skip = false;
			switch($type){
				case "Daily":
					$current->modify("+{$interval} Days");
					break;
				case "Weekly":
					$day_index = $last_dow;
					for($d = $last_dow + 1; $d <= $last_dow + 7; $d++){
						$day_index = $d % 7;
						if(strpos($dow,(string)($day_index)) !== false){
							break;
						}
					}
					$step = $day_index - $last_dow;
					$last_dow = $day_index;
					if($step <= 0){
						$step += 7;
						$w++;
					}
					if($w % $interval != 0)
						$skip = true;

					$current->modify("+{$step} Days");
					break;
				case "Monthly":
					$current->modify("+{$interval} Months");
					break;
				case "Yearly":
					$current->modify("+{$interval} Years");
					break;
				default:
					return array();
			}

			if($skip)
				continue;

			if(($i < $count || $count == 0 && $current->format("U") < $end->format("U"))  ){
				$arr[] = $current->format($GLOBALS['timedate']->get_date_time_format());
			}
			$i++;

			if($i > $limit + 100)
				break;
		}
		return $arr;
	}

	/**
	 * Save repeat activities
	 * @param SugarBean $bean
	 * @param array $time_arr array of datetimes
	 * @return array
	 */
	static function save_repeat_activities(SugarBean $bean,$time_arr){

		// Here we will create single big inserting query for each invitee relationship
		// rather than using relationships framework due to performance issues.
		// Relationship framework runs very slowly

		global $db;
		$id = $bean->id;
		$date_modified = $GLOBALS['timedate']->nowDb();
		$lower_name = strtolower($bean->object_name);

		$qu = "SELECT * FROM {$bean->rel_users_table} WHERE deleted = 0 AND {$lower_name}_id = '{$id}'";
		$re = $db->query($qu);
		$users_rel_arr = array();
		while($ro = $db->fetchByAssoc($re))
			$users_rel_arr[] = $ro['user_id'];
		$qu_users = "
				INSERT INTO {$bean->rel_users_table}
				(id,user_id,{$lower_name}_id,date_modified)
				VALUES
		";
		$users_filled = false;

		$qu = "SELECT * FROM {$bean->rel_contacts_table} WHERE deleted = 0 AND {$lower_name}_id = '{$id}'";
		$re = $db->query($qu);
		$contacts_rel_arr = array();
		while($ro = $db->fetchByAssoc($re))
			$contacts_rel_arr[] = $ro['contact_id'];
		$qu_contacts = "
				INSERT INTO {$bean->rel_contacts_table}
				(id,contact_id,{$lower_name}_id,date_modified)
				VALUES
		";
		$contacts_filled = false;

		$qu = "SELECT * FROM {$bean->rel_leads_table} WHERE deleted = 0 AND {$lower_name}_id = '{$id}'";
		$re = $db->query($qu);
		$leads_rel_arr = array();
		while($ro = $db->fetchByAssoc($re))
			$leads_rel_arr[] = $ro['lead_id'];
		$qu_leads = "
				INSERT INTO {$bean->rel_leads_table}
				(id,lead_id,{$lower_name}_id,date_modified)
				VALUES
		";
		$leads_filled = false;

		$arr = array();
		$i = 0;
		foreach($time_arr as $date_start){
			$clone = $bean;	// we don't use clone keyword cause not necessary
			$clone->id = "";
			$clone->date_start = $date_start;
			// TODO CHECK DATETIME VARIABLE
			$date = SugarDateTime::createFromFormat($GLOBALS['timedate']->get_date_time_format(),$date_start);
			$date = $date->get("+{$bean->duration_hours} Hours")->get("+{$bean->duration_minutes} Minutes");
			$date_end = $date->format($GLOBALS['timedate']->get_date_time_format());
			$clone->date_end = $date_end;
			$clone->recurring_source = "Sugar";
			$clone->repeat_parent_id = $id;
			$clone->update_vcal = false;
			$clone->save(false);

			if($clone->id){
				foreach($users_rel_arr as $user_id){
					if($users_filled)
						$qu_users .= ",".PHP_EOL;
					$qu_users .= "('".create_guid()."','{$user_id}','{$clone->id}','{$date_modified}')";
					$users_filled = true;
				}
				foreach($contacts_rel_arr as $contact_id){
					if($contacts_filled)
						$qu_contacts .= ",".PHP_EOL;
					$qu_contacts .= "('".create_guid()."','{$contact_id}','{$clone->id}','{$date_modified}')";
					$contacts_filled = true;
				}
				foreach($leads_rel_arr as $lead_id){
					if($leads_filled)
						$qu_leads .= ",".PHP_EOL;
					$qu_leads .= "('".create_guid()."','{$lead_id}','{$clone->id}','{$date_modified}')";
					$leads_filled = true;
				}
				if($i < 44){
					$clone->date_start = $date_start;
					$clone->date_end = $date_end;
					$arr[] = array_merge(array('id' => $clone->id),CalendarUtils::get_time_data($clone));
				}
				$i++;
			}
		}
		
		if ($users_filled) {
			$db->query($qu_users);
		}
		if ($contacts_filled) {
			$db->query($qu_contacts);
		}		
		if ($leads_filled) {
			$db->query($qu_leads);
		}
		
		vCal::cache_sugar_vcal($GLOBALS['current_user']);
		return $arr;
	}

	/**
	 * Delete recurring activities and their invitee relationships
	 * @param SugarBean $bean
	 */
	static function markRepeatDeleted(SugarBean $bean)
	{
		// we don't use mark_deleted method here because it runs very slowly
		global $db;
		$date_modified = $GLOBALS['timedate']->nowDb();
		if(!empty($GLOBALS['current_user']))
			$modified_user_id = $GLOBALS['current_user']->id;
		else
			$modified_user_id = 1;
		$lower_name = strtolower($bean->object_name);

		$qu = "SELECT id FROM {$bean->table_name} WHERE repeat_parent_id = '{$bean->id}' AND deleted = 0";
		$re = $db->query($qu);
		while( $ro = $db->fetchByAssoc($re)) {
			$id = $ro['id'];
			$date_modified = $GLOBALS['timedate']->nowDb();
			$db->query("UPDATE {$bean->table_name} SET deleted = 1, date_modified = '{$date_modified}', modified_user_id = '{$modified_user_id}' WHERE id = '{$id}'");
			$db->query("UPDATE {$bean->rel_users_table} SET deleted = 1, date_modified = '{$date_modified}' WHERE {$lower_name}_id = '{$id}'");
			$db->query("UPDATE {$bean->rel_contacts_table} SET deleted = 1, date_modified = '{$date_modified}' WHERE {$lower_name}_id = '{$id}'");
			$db->query("UPDATE {$bean->rel_leads_table} SET deleted = 1, date_modified = '{$date_modified}' WHERE {$lower_name}_id = '{$id}'");
		}
		vCal::cache_sugar_vcal($GLOBALS['current_user']);
	}

	/**
	 * check if meeting has repeat children and pass repeat_parent over to the 2nd meeting in sequence
	 * @param SugarBean $bean
	 * @param string $beanId
	 */
	static function correctRecurrences(SugarBean $bean, $beanId)
	{
		global $db;
		
		$qu = "SELECT id FROM {$bean->table_name} WHERE repeat_parent_id = '{$beanId}' AND deleted = 0 ORDER BY date_start";
		$re = $db->query($qu);

		$i = 0;
		while ($ro = $db->fetchByAssoc($re)) {
			$id = $ro['id'];
			if($i == 0){
				$new_parent_id = $id;
				$qu = "UPDATE {$bean->table_name} SET repeat_parent_id = '' AND recurring_source = '' WHERE id = '{$id}'";
			}else{
				$qu = "UPDATE {$bean->table_name} SET repeat_parent_id = '{$new_parent_id}' WHERE id = '{$id}'";
			}
			$db->query($qu);
      		$i++;
		}
	}

}
