<?php
class WP_Tickets_Manager {

	public function __construct() {

		/* Actions */
		add_action( 'restrict_manage_posts', array( $this, 'filterTickets' ) );
		add_action( 'manage_tickets_posts_custom_column', array( $this, 'customColumnContent' ), 10, 2 );
		add_action( 'wpas_tickets_purge', array( $this, 'autoCloseTickets' ) );	// Close old tickets
		add_action( 'before_delete_post', array( $this, 'deleteAttachment' ), 10 );
		add_action( 'before_delete_post', array( $this, 'deleteHistory' ), 10 );
		add_action( 'in_admin_footer', array( $this, 'addNoteForm' ), 10 );

		/* Filters */
		add_filter( 'parse_query', array( $this, 'taxonomy_filter_post_type_request' ) );
		add_filter( 'manage_edit-tickets_columns', array( $this, 'customizeColumns' ) );
		add_filter( 'pre_get_posts', array( $this, 'restrictTickets' ) );
		// add_filter( 'manage_edit-tickets_sortable_columns', array( $this, 'sortableColumns' ) );

	}

	/**
	 * Filters tickets
	 *
	 * This function will filter the tickets in the
	 * admin screen based on a given taxonomy.
	 * 
	 * @return [type] [description]
	 */
	public function filterTickets() {

		global $typenow;

		if( $typenow != 'tickets' )
			return;

		$post_types = get_post_types( array( '_builtin' => false ) );

		if( in_array( $typenow, $post_types ) ) {

			$filters = get_object_taxonomies( $typenow );

			foreach ( $filters as $tax_slug ) {
				$tax_obj = get_taxonomy( $tax_slug );

				$args = array(
					'show_option_all' => __( 'Show All ' . $tax_obj->label ),
					'taxonomy' 	  	  => $tax_slug,
					'name' 		  	  => $tax_obj->name,
					'orderby' 	  	  => 'name',
					'hierarchical' 	  => $tax_obj->hierarchical,
					'show_count' 	  => false,
					'hide_empty' 	  => true
				);

				if( isset($_GET[$tax_slug]) )
					$args['selected'] = $_GET[$tax_slug];

				wp_dropdown_categories( $args );
			}
		}
	}

	/**
	 * Add note form
	 *
	 * Form used to add a private note to a ticket
	 *
	 * @since 2.0.0
	 */
	public function addNoteForm() {

		global $post;

		if( isset( $_GET['action'] ) && 'edit' == $_GET['action'] && 'tickets' == $post->post_type ) {

			?>
			<div id="wpas-note-modal" style="display:none">

				<div class="wpas-modal-inner">

					<h2><?php _e( 'Add a private note to this ticket', 'wpas' ); ?></h2>
					<p><?php _e( 'This note will only be seen by you and other agents. Clients will not see private notes.', 'wpas' ); ?></p>
					
					<form method="post" action="<?php echo admin_url( "post.php?post=$post->ID&action=edit" ); ?>" id="wpas-new-note">
						<textarea name="wpas_note"  rows="10" required></textarea>
						<input type="hidden" name="post_id" value="<?php echo $post->ID; ?>">
						<?php wp_nonce_field( 'add_note', '_wpas_note_nonce', false, true );

						/* get the roles */
						global $wp_roles;

						/* Prepare the empty users list */
						$users = array();

						/* Parse the roles */
						foreach( $wp_roles->roles as $role => $data ) {

							/* Check if current role can edit tickets */
							if( array_key_exists( 'edit_ticket', $data['capabilities'] ) ) {

								/* Get users with current role */
								$usrs = new WP_User_Query( array( 'role' => $role ) );

								/* Save users in global array */
								$users = array_merge( $users, $usrs->get_results() );
							}
						}
						?>

							<div class="cf">

								<input type="submit" class="button button-primary wpas-pl" value="<?php _e( 'Add Note', 'wpas' ); ?>">

								<?php if( count( $users ) > 1 ): ?>

									<div class="wpas-pr">

										<label for="wpas-new-agent"><?php _e( 'Transfer ticket to: ', 'wpas' ); ?></label>

										<select name="wpas_agent" id="wpas-new-agent">
											<?php
											foreach( $users as $usr => $data ) {

												if( get_current_user_id() !=  $data->ID ) {
													?><option value="<?php echo $data->ID; ?>"><?php echo $data->data->display_name; ?></option><?php
												}
											}
											?>
										</select>

										<input type="submit" class="button button-secondary" name="add_transfer" value="<?php _e( 'Add Note &amp; Transfer', 'wpas' ); ?>">
									</div>

								<?php endif; ?>

							</div>

					</form>

				</div>
			</div>
			<?php

		}

	}

	/**
	 * [wpas_taxonomy_filter_post_type_request description]
	 * @param  (object) $query The main WP query
	 * @return [type]        [description]
	 */
	public function taxonomy_filter_post_type_request( $query ) {

		global $pagenow, $typenow;

		if( 'edit.php' == $pagenow ) {

			$filters = get_object_taxonomies( $typenow );

			foreach ( $filters as $tax_slug ) {

				$var = &$query->query_vars[$tax_slug];

				if( $var ) {
					$term = get_term_by( 'id', $var, $tax_slug );
					$var = $term->slug;
				}
			}
		}
	}

	/**
	 * Customize the edit screen columns
	 * 
	 * @param  (array) $columns List of columns to display
	 * @return (array) $new List of columns updated
	 */
	public function customizeColumns( $columns ) {

		$new = array();

		foreach( $columns as $id => $label ) {

			if( 'taxonomy-state' == $id )
				continue;

			if( $id == 'date' ) {

				$new['replies'] = __('Replies', 'wpas');

			}

			$new[$id] = $label;

			if( $id == 'date' ) {

				$new['ticket_age'] = __( 'Age', 'wpas' );

			}

			if( $id == 'title' ) {
				$new['author'] = __('Client', 'wpas');
			}

			if( $id == 'cb' ) {
				$new['status'] 	 = __('Status', 'wpas');
				$new['priority'] = __('Priority', 'wpas');
				$new['taxonomy-state'] = $columns['taxonomy-state'];
				$new['reply_needed'] = __( 'Reply', 'wpas' );
				if( wpas_get_option('envato_check') == 'yes' )
					$new['envato'] 	 = __('Envato', 'wpas');
			}
		}

		unset( $new['taxonomy-status'] );
		unset( $new['taxonomy-priority'] );
		return $new;
	}

	/**
	 * Manage custom columns content
	 * 
	 * @param  (string) $column ID of current column
	 * @param  (numeric) $post_id ID of the current post
	 * @return (string) Content to display in current column
	 */
	function customColumnContent( $column, $post_id ) {

		global $post;

		switch( $column ) {

			/* If displaying the 'duration' column. */
			case 'replies' :
				$args = array(
					'numberposts'		=>	-1,
					'post_type'			=>	'ticket_reply',
					'post_parent'		=>	$post->ID,
					'post_status'		=>	'inherit'
				);

				$replies = get_posts( $args );

				echo '<span class="badge badge-inverse">'.count($replies).'</span>';
			break;

			case 'status':

				/* Get the status */
				$status  	  = get_the_terms( $post->ID, 'status' );

				if( $status ) {

					$label = array(
						'wpas-open'  => __( 'Open', 'wpas' ),
						'wpas-close' => __( 'Closed', 'wpas' )
					);

					foreach( $status as $s ) {

						$status = $s->name;
						$slug 	= $s->slug;
						$sid 	= explode('-', $slug);
						$sid 	= $sid[1];
					}

					/* Get the current tag color */
					$status_color = wpas_get_option( 'status_'.$sid.'_color', false );

					$out = '<a href="'.admin_url( 'edit.php?post_type=tickets' ).'&amp;status='.$s->term_id.'" class="label"';
					if( $status_color ) { $out .= ' style="background-color:'.$status_color.';"'; }
					$out .= '>' . $label[$slug] . '</a>';

					echo $out;
				}
			break;

			case 'ticket_age':

				/* Now let's check the post status */
				$status = get_the_terms( $post->ID, 'status' );

				/* Extract the status from the array */
				if( $status ) {
					foreach($status as $s) {
						$status = $s->slug;
					}
				}

				/* Chech if ticket is open */
				if( $status != 'wpas-open' )
					return;

				/* Prepare the new object */
				$latest = new WP_Query(  array(
					'posts_per_page'	=>	1,
					'orderby'			=>	'post_date',
					'order'				=>	'DESC',
					'post_type'			=>	'ticket_reply',
					'post_parent'		=>	$post->ID,
					'post_status'		=>	'inherit'
					)
				);

				/**
				* We check when was the last reply (if there was a reply).
				* Then, we compute the ticket age and if it is considered as 
				* old, we display an informational tag.
				*/
				if( empty( $latest->posts ) ) {

					/* We get the post date */
					$created = strtotime( $post->post_date );

				} else {

					/* We get the post date */
					$created = strtotime( $latest->post->post_date );

				}

				/* Get the age limit */
				$limit = wpas_get_option( 'days_old', 10 );

				/* We compute the ticket max age */
				$old = strtotime( '+' . $limit . ' days', $created );

				/* If the ticket is considered as old, we show it instead of the status */
				if( is_numeric( $limit ) && strtotime('now') > $old ) {

					/* Get the tag color */
					$old_color = wpas_get_option( 'status_old_color', '#dd9933' );

					/* Tell the user the ticket is old */
					echo '<span class="label" style="background-color:' . $old_color . ';">' . __( 'Old', 'wpas' ) . '</span> ';

				}


			break;

			case 'reply_needed':

				/* Now let's check the post status */
				$status  = get_the_terms( $post->ID, 'status' );

				/* Extract the status from the array */
				if( $status ) {
					foreach($status as $s) {
						$status = $s->slug;
					}
				}

				/* Chech if ticket is open */
				if( $status != 'wpas-open' )
					return;

				/* We will save authors and their role for later use */
				$authors = array();

				/* Prepare the new object */
				$latest = new WP_Query(  array(
					'posts_per_page'	=>	1,
					'orderby'			=>	'post_date',
					'order'				=>	'DESC',
					'post_type'			=>	'ticket_reply',
					'post_parent'		=>	$post->ID,
					'post_status'		=>	'inherit'
					)
				);

				if( empty( $latest->posts ) ) {

					if( !user_can( $post->post_author, 'edit_ticket' ) )
						echo '<span title="'.__('You need to reply to this ticket', 'wpas').'" class="label label-default">&#9733;</span>';

				} else {

					$see  = wpas_get_option( 'admins_see_all' );
					$last = $latest->post_count-1;

					if( 'yes' == $see ) {


						if( !user_can( $latest->posts[$last]->post_author, 'edit_ticket' ) )
							echo '<span title="'.__('You need to reply to this ticket', 'wpas').'" class="label label-default">&#9733;</span>';

					} else {
						
						if( $latest->posts[$last]->post_author != get_current_user_id() )
							echo '<span title="'.__('You need to reply to this ticket', 'wpas').'" class="label label-default">&#9733;</span>';

					}

				}

			break;

			case 'priority':
				$priorities  = get_the_terms( $post->ID, 'priority' );

				if( $priorities ) {

					foreach($priorities as $p) {
						$priority = $p->name;
						$pid 	  = $p->term_id;
					}

					$prio_opts  = get_option('taxonomy_'.$pid);

					if( isset($prio_opts['color']) ) {
						$prio_color = $prio_opts['color'];
					} else {
						$prio_color = '';
					}

					if( isset($prio_opts['font_color']) ) {
						$prio_font = $prio_opts['font_color'];
					} else {
						$prio_font = '';
					}
				}

				if( $priorities ): ?><a href="<?php echo admin_url( "edit.php?post_type=tickets" ); ?>&amp;priority=<?php echo $pid; ?>" class="label label-default priority-<?php echo $p->slug; ?>" style="background-color: <?php echo $prio_color; ?>; color: <?php echo $prio_font; ?>;" title="<?php echo $priority; ?>"><?php echo $priority; ?></a><?php endif;

			break;

			case 'envato':
				if( wpas_verify_envato_purchase( $post->ID ) ) {
						echo '<img src="' . WPAS_URL . '/images/envato-logo.png" alt="Envato Verified" width="20" />';
				}
			break;

			/* Just break out of the switch statement for everything else. */
			default :
				break;
		}
	}

	/**
	 * We prevent the agents from seeing
	 * other agents tickets. This also
	 * applies to admins if the option
	 * is enabled.
	 *
	 * @param (object) $query The page's main query
	 * @return (object) Updated query
	 */
	public function restrictTickets($query) {

		global $pagenow, $current_user, $user_ID;

		if( current_user_can( 'administrator' ) && wpas_get_option( 'admins_see_all', 'no' ) == 'yes' )
			return;

		if( is_admin() && isset( $_GET['post_type'] ) && 'tickets' == $_GET['post_type'] ) {

			if( $query->query_vars['post_type'] == 'tickets' ) {

				$query->query_vars['meta_key'] 	 = WPAS_PREFIX.'assignee';
				$query->query_vars['meta_value'] = $current_user->data->ID;

				/* Fix wrong post count */
				add_filter( "views_edit-tickets", array( $this, 'fixPostCount' ) );
			}
		}

		return $query;
	}

	/**
	 * Fix wrong post count
	 *
	 * Fix wrong post count when plugin is set
	 * to only show the current user's tickets.
	 *
	 * @link http://wordpress.stackexchange.com/questions/49154/hide-other-users-posts-in-admin-panel
	 */
	public function fixPostCount( $views ) {

		global $current_user, $wp_query;

		unset( $views['mine'] );

		$types = array(
			array( 'status' => NULL ),
			array( 'status' => 'publish' ),
			array( 'status' => 'draft' ),
			// array( 'status' => 'pending' ),
			array( 'status' => 'trash' )
		);
		foreach( $types as $type ) {
			$query = array(
				'post_type'   => 'tickets',
				'post_status' => $type['status'],
				'meta_key'    => WPAS_PREFIX.'assignee',
				'meta_value'  => $current_user->data->ID
			);

			$result = new WP_Query($query);

			if( isset($wp_query->query_vars['post_status']) ):
				if( $type['status'] == NULL ):
					$class = ($wp_query->query_vars['post_status'] == NULL) ? ' class="current"' : '';
					$views['all'] = sprintf(__('<a href="%s" %s>All <span class="count">(%d)</span></a>', 'all'), admin_url('edit.php?post_type=tickets'), $class, $result->found_posts);
				elseif( $type['status'] == 'publish' ):
					$class = ($wp_query->query_vars['post_status'] == 'publish') ? ' class="current"' : '';
					$views['publish'] = sprintf(__('<a href="%s" %s>Published <span class="count">(%d)</span></a>', 'publish'), admin_url('edit.php?post_status=publish&post_type=tickets'), $class, $result->found_posts);
				elseif( $type['status'] == 'draft' ):
					$class = ($wp_query->query_vars['post_status'] == 'draft') ? ' class="current"' : '';
					$views['draft'] = sprintf(__('<a href="%s" %s>Draft'. ((sizeof($result->posts) > 1) ? "s" : "") .' <span class="count">(%d)</span></a>', 'draft'), admin_url('edit.php?post_status=draft&post_type=tickets'), $class, $result->found_posts);
				/*elseif( $type['status'] == 'pending' ):
					$class = ($wp_query->query_vars['post_status'] == 'pending') ? ' class="current"' : '';
					$views['pending'] = sprintf(__('<a href="%s"'. $class .'>Pending <span class="count">(%d)</span></a>', 'pending'),
						admin_url('edit.php?post_status=pending&post_type=tickets'),
						$result->found_posts);*/
				elseif( $type['status'] == 'trash' ):
					$class = ($wp_query->query_vars['post_status'] == 'trash') ? ' class="current"' : '';
					$views['trash'] = sprintf(__('<a href="%s" %s>Trash <span class="count">(%d)</span></a>', 'trash'), admin_url('edit.php?post_status=trash&post_type=tickets'), $class, $result->found_posts);
				endif;
			endif;
		}
		return $views;
	}

	/**
	 * Delete tickets attachments
	 * 
	 * @param  (numeric) $id The current post ID
	 */
	public function deleteAttachment( $id ) {

		if( !current_user_can( 'delete_posts' ) )
			return;

		$attachments = get_post_meta( $id, WPAS_PREFIX . 'attachments', true );

		if( $attachments != '' ) {

			foreach( $attachments as $attach => $values ) {

				if( !isset( $values['uploader'] ) || 'fineuploader' == $values['uploader'] )
					unlink( ABSPATH . 'wp-content/uploads/wpas_attachments/' . $values['file'] );

			}

		}

		/* Then delete all other attachments */
		$args = array(
			'posts_per_page'	=>	-1,
			'post_type'			=>	array( 'ticket_reply' ),
			'post_parent'		=>	$id,
			'post_status'		=>	array( 'inherit', 'private', 'trash' )
		);

		$replies = new WP_Query( $args );

		if( !empty( $replies->posts ) ) {

			foreach( $replies->posts as $key => $post ) {

				$attachments = get_post_meta( $post->ID, WPAS_PREFIX . 'attachments', true );

				if( $attachments != '' ) {

					foreach( $attachments as $attach => $values ) {

						if( !isset( $values['uploader'] ) || 'fineuploader' == $values['uploader'] )
							unlink( ABSPATH . 'wp-content/uploads/wpas_attachments/' . $values['file'] );

					}

				}

			}

		}

	}

	/**
	 * Delete the ticket history
	 * 
	 * @param  (integer) $id
	 * @since 2.0.6
	 */
	public function deleteHistory( $id ) {

		$args = array(
			'posts_per_page'	=>	-1,
			'post_type'			=>	array( 'ticket_history', 'ticket_reply', 'ticket_status', 'ticket_note' ),
			'post_parent'		=>	$id,
			'post_status'		=>	array( 'inherit', 'private', 'trash' )
		);

		$history = new WP_Query( $args );

		if( !empty( $history->posts ) ) {

			foreach( $history->posts as $post ) {

				wp_delete_post( $post->ID, true );

			}

		}

	}

	/**
	 * TODO
	 *
	 * Delete all related posts when a ticket is deleted.
	 */
	function deleteRelatedPosts( $id ) {
		$p = get_posts(  array(
			'numberposts'		=>	999,
			'post_parent'		=>	$id)
		);

		foreach( $p as $post ) {
			wp_delete_post( $post->ID, true );
		}
	}

	// Make these columns sortable
	public function sortableColumns() {

	  return array(
	    'priority' => 'priority',
	  );

	}

	/**
	 * Automatically close an old ticket
	 *
	 * The function checks if the ticket is unanswered by the client and if it is considered as old.
	 * If so, a notification is sent to the client before closing and then the ticket is closed a few days later.
	 *
	 * @since 2.0.0
	 */
	public function autoCloseTickets() {

		/* Check if auto close feature is enabled */
		if( 'no' == wpas_get_option( 'automatically_close', 'no' ) )
			return;

		/* Get mendatory values */
		$limit 		= wpas_get_option( 'days_old', 10 );
		$reminder 	= wpas_get_option( 'remider_before_closing', 10 );
		$diff 		= $limit-$reminder;
		$exclude 	= wpas_get_option( 'auto_close_exclude_state' );

		$args = array(
			'post_type' 	 => 'tickets',
			'posts_per_page' => -1,
			'tax_query' 	 => array(
				array(
					'taxonomy'  => 'status',
					'field' 	=> 'slug',
					'terms' 	=> 'wpas-open'
				)
			)
		);

		$tickets = new WP_Query( $args );

		/* Iterate through the open tickets */
		if( !empty( $tickets->posts ) ) {

			foreach( $tickets->posts as $ticket ) {

				/* We use this to skip certain tickets */
				$skip = false;

				$states = get_the_terms( $ticket->ID, 'state' );

				if( !is_wp_error( $state ) ) {

					foreach( $states as $state ) {

						if( $exclude == $state->slug )
							$skip = true;

					}

				}

				/* We skip (or not) this ticket */
				if( $skip )
					continue;

				/* Check the latest reply */
				$reply = new WP_Query(  array(
					'posts_per_page'	=>	-1,
					'orderby'			=>	'post_date',
					'order'				=>	'DESC',
					'post_type'			=>	'ticket_reply',
					'post_parent'		=>	$ticket->ID,
					'post_status'		=>	'inherit'
					)
				);

				/* Did the agent post last? */
				if( !isset( $reply->post ) || $ticket->post_author == $reply->post->post_author )
					continue;

				/* We get the post date */
				$created = get_the_time( 'Y-m-d', $ticket->ID );
				// printf( 'post %s created %s will reach limit on %s', $ticket->ID, $created, date( 'Y-m-d', strtotime( "$created +$diff days" ) ) );

				/* Set the e-mail notification class */
				$email = new WPAS_Email_Notification();

				/* Do we need to send a notification? */
				if( strtotime( 'now' ) > strtotime( "$created +$diff days" ) ) {

					$sent = get_post_meta( $ticket->ID, '_wpas_reminder_sent', true );

					if( 'yes' != $sent ) {

						/* Notify client */
						$email->sendNotification( $ticket->ID, 'ticket_will_close' );

						/* Add a post meta to remember we already sent the notification */
						update_post_meta( $ticket->ID, '_wpas_reminder_sent', 'yes' );

					}

				}

				/* Do we need to close the ticket? */
				if( strtotime( 'now' ) >= strtotime( "$created +$limit days" ) ) {

					global $wpas_submit;

					/* Close the ticket */
					wp_set_object_terms( $ticket->ID, 'wpas-close', 'status', false );
					
					/* Log history */
					$wpas_submit->LogTicketHistory( $ticket->ID, 'close-auto', 'inherit', 'ticket_status', array( 'wpautop' => false, 'user' => wpas_get_option( 'default_assignee' ) ) );
					
					/* Notify client */
					$email->sendNotification( $ticket->ID, 'ticket_was_closed' );

				}

			}

		}

	}

}

$wpas_manager = new WP_Tickets_Manager();