<?php
// class-post.php

class post {

	private $query;

	public function __construct() {
		$this->query = new query;
		$this->cache = new cache;
		$this->use_cache = true;
	}//construct()

	public function last_query() {
		return $this->query->last_query;
	}

	public function add_post($args = array()) {
		$session = Session::getInstance();
		$user_meta = get_user_meta($session->id);
		if(!isset($args['type'])) {
			$args['type'] = "page";
		}
		if(!isset($args['title'])) {
			$args['title'] = "New ".ucwords($args['type']);
		}
		if(!isset($args['posted_on'])) {
			$args['posted_on'] = time();
		}
		if(!isset($args['posted_by'])) {
			$args['posted_by'] = $user_meta['id'];
		}
		if(!isset($args['id'])) {
			unset($args['id']);
		}
		// db section
		if(!isset($args['db_section_id'])) {
			$add_db_section = add_db_section($user_meta);
			if($add_db_section) {
				$args['db_section_id'] = $add_db_section;
			} else $args['db_section_id'] = -1;
		}
		// db section
		$args = sanitize($args);
		if($args['type'] === "page") {
			if(!isset($args['permalink'])) {
				$args['permalink'] = $this->generate_permalink($args['title']);
			} else {
				$args['permalink'] = $this->generate_permalink($args['permalink']);
			}
		} else {
			$args['permalink'] = "";
		}

		$post_id = $this->query->insert('post', array('title', 'permalink'), array($args['title'], $args['permalink']));
		if($post_id) {
			unset($args['permalink']);
			unset($args['title']);
			$this->add_post_meta($post_id, $args);
			return $post_id;
		}	
	}

	private function add_post_meta($post_id, $args) {
		$meta_arr = array();
		foreach ($args as $meta_name => $meta_value) {
			$meta_name = strtolower($meta_name);
			array_push($meta_arr, array($post_id, $meta_name, $meta_value));
		}
		$this->query->insert('post_meta', array('post_id', 'meta_name', 'meta_value'), $meta_arr, true);
	}

	public function get_post_meta($post_id) {
		if($this->use_cache && ($cache = $this->cache->__get_cache($post_id, 'post'))) {
			return $cache;
		}
		$query = "
			SELECT DISTINCT meta_name, meta_value, title, permalink
    		FROM post_meta 
    		LEFT JOIN post ON post.id = %d
    		WHERE post_id = %d
    		ORDER BY meta_value ASC
		";

		$res = $this->query->get_results( $this->query->prepare($query, (int) $post_id, (int) $post_id), OBJECT_K );
		if(empty($res)) {
			return false;
		}
		$meta = array_map(function($v){
		    $r = htmlspecialchars_decode($v->meta_value);
		    return removeslashes($r);
		}, $res);
		$meta['permalink'] = $res['posted_on']->permalink;
		$meta['title'] = $res['posted_on']->title;
		$meta['id'] = (int) $post_id;
		if($this->use_cache)
			$this->cache->__save_new_cache($post_id, 'post', $meta);
		return $meta;
	}

	public function update_post_meta($post_id, $args) {
		$post_meta = $this->get_post_meta($post_id);
		if(!_count($post_meta))
			return false;
		$to_update = array();
		$updated = 0;
		// don't update id
		if(isset($args['id'])) {
			unset($args['id']);
		}

		// don't update type
		if(isset($args['type'])) {
			unset($args['type']);
		}

		// don't update db section id
		if(isset($args['db_section_id'])) {
			unset($args['db_section_id']);
		}

		if(!empty($args)) {
			$args = sanitize($args);
		} else return false;

		if(isset($args['title']) && $args['title'] !== $post_meta['title']) {
			array_push($to_update, 'title');
			$temp_title = $args['title'];
			unset($args['title']);
		}
		if(isset($args['permalink']) && strtolower($args['permalink']) != $post_meta['permalink']) {
			array_push($to_update, 'permalink');
			$temp_permalink = $args['permalink'];
			unset($args['permalink']);
		}

		if(!empty($to_update)) {
			$set = array();
			foreach ($to_update as $meta) {
				if($meta == 'title') {
					$set[$meta] = $temp_title;

				}
				if($meta == 'permalink') {
					$set[$meta] = $this->generate_permalink($temp_permalink);
				}
			}
			$result = $this->query->update( 'post', $set, array('id' => $post_id) );
			if($result) {
				$updated = 1;
			}
		}

		//update other meta data
		if (empty($args))
			return $updated;

		foreach ($args as $key => $value) {
			if(isset($post_meta[strtolower($key)])) {
				if ($post_meta[strtolower($key)] == $value) {
					continue;
				}
				$result = $this->query->update( 'post_meta', array('meta_value' => $value), array('post_id' => $post_id, 'meta_name' => strtolower($key)) );
				if($result) {
					$updated = 1;
				}	
			} else {
				$meta_name = strtolower($key);
				$result = $this->query->insert('post_meta', array('post_id', 'meta_name', 'meta_value'), array($post_id, $meta_name, $value));
				if($result) {
					$updated = 1;
				}
			}
		}
		if($updated) {
			$this->cache->__drop_cache($post_id, 'post');
		}
		return $updated;


	}

	public function generate_permalink($title_original) {
		$title = strtolower($title_original);
		$strip_words = array(' is ', ' and ', ' to ', ' for ', ' are ', ' a ', ' with ', ' i ', ' the ', ' my ', '(', ')', '[', ']', '{', '}', '&', '/', '|', '%');
		$title = str_replace($strip_words, '', $title);
		$sample_link = preg_replace('/\s+/', '-', $title);
		
		if($this->search_post_by_permalink($sample_link)) {
			$i = $this->get_next_link_serial($sample_link, $title_original);
			$final_link = $sample_link.'-'.$i;
		} else return $sample_link;
		while($this->search_post_by_permalink($final_link)) {
			$i++;
			$final_link = $sample_link.'-'.$i;
		}
		return $final_link;
	}

	function get_next_link_serial($sample_link, $title) {
		$link = $this->query->quick_select('post', [
					'where' => ['permalink' => $sample_link."-%", 'title' => $title],
					'order' => 'DESC',
					'order_by' => 'id',
					'limit' => 1,
					'compare' => 'LIKE'
				], OBJECT_K);
		if(_count($link)) {
			$link = array_values($link);
			$permalink_arr = explode("-", $link[0]->permalink);
			$serial = (int) end($permalink_arr);
			return $serial + 1;
		} else return 1;
	}

	public function search_post_by_permalink($permalink) {
		$result = $this->query->select('post', $where = array('permalink' => $permalink));
		$res_arr = $this->query->query_to_array($result);
		if ( !_count($res_arr)) {
			return false;
		}
		foreach ($res_arr as $key => $value) {
			return $value['id'];
		}
	}

	public function get_post_count_by_meta_data($args, $compare = 'LIKE', $id_as_key = false, $limit = 0, $offset = 0, $order_by = 'post_id', $order = 'ASC') {
		$result = $this->get_post_by_meta_data($args, $compare, $id_as_key, $limit, $offset, $order_by, $order);
		return $result ? _count($result) : 0;
	}

	public function get_post_by_meta_data($args, $compare = 'LIKE', $id_as_key = false, $limit = 0, $offset = 0, $order_by = 'post_id', $order = 'ASC') {
		// db section
		if(!isset($args['db_section_id'])) {
			$add_db_section = add_db_section();
			if($add_db_section && $args['apply_db_session']) {
				$args['db_section_id'] = [$add_db_section, -1];
			}
		}
		if(isset($args['apply_db_session'])) unset($args['apply_db_session']);
		
		// db section
		if(isset($args['_range_from'])) {
			$_range_from = $args['_range_from'];
			unset($args['_range_from']);
		} else $_range_from = false;
		if(isset($args['_range_to'])) {
			$_range_to = $args['_range_to'];
			unset($args['_range_to']);
		} else $_range_to = time();

		$num_args = _count($args);
		$return_key = $id_as_key ? OBJECT_K : OBJECT;

		if(is_array($args) && $num_args) :
			$sql = "SELECT post_id
			FROM post_meta
			WHERE ";
			if($_range_from) {
				$num_args++;
				$sql .= "( `meta_name` = 'posted_on' AND `meta_value` BETWEEN ".$_range_from." AND ".$_range_to." )"." OR ";
			}
			foreach ($args as $meta_name => $meta_value) {
				if($meta_value === "_all") {
					$num_args--;
					continue;
				}
				if(is_array($meta_value)) {
					if(in_array("_all", $meta_value)) {
						$num_args--;
						continue;
					}
				}
				if(is_array($compare)) {
					$compare = array_merge(['default' => 'LIKE'], $compare);

					if(isset($compare[$meta_name])) {
						
						if(_count($meta_value)) {
							$sql .= "( `meta_name` = '".$meta_name."' AND (";
							foreach ($meta_value as $mv) {
								$sql .= "`meta_value` ".$compare[$meta_name]." '".$mv."' OR ";
							}
							$sql = substr($sql, 0, -4);
							$sql .= ") )";
						} else {
							$sql .= "( `meta_name` = '".$meta_name."' AND (`meta_value` ".$compare[$meta_name]." '".$meta_value."') )";
						}

					} else {

						if(_count($meta_value)) {
							$sql .= "( `meta_name` = '".$meta_name."' AND (";
							foreach ($meta_value as $mv) {
								$sql .= "`meta_value` ".$compare['default']." '".$mv."' OR ";
							}
							$sql = substr($sql, 0, -4);
							$sql .= ") )";
						} else {
							if(!is_array($meta_value)) {
								$sql .= "( `meta_name` = '".$meta_name."' AND `meta_value` ".$compare['default']." '".$meta_value."' )";
							} else {
								$sql = substr($sql, 0, -4);
							}
						}

					} 
					

				} else {
					if(_count($meta_value)) {
						$sql .= "( `meta_name` = '".$meta_name."' AND (";
						foreach ($meta_value as $mv) {
							$sql .= "`meta_value` ".$compare." '".$mv."' OR ";
						}
						$sql = substr($sql, 0, -4);
						$sql .= ") )";
					} else {
						$sql .= "( `meta_name` = '".$meta_name."' AND `meta_value` ".$compare." '".$meta_value."' )";
					}
					
				}
				$sql .= " OR ";
			}
			$sql = substr($sql, 0, -4);
			$sql .= " GROUP BY `post_id`";
			$sql .= " HAVING COUNT(post_id) = ".$num_args;
			$sql .= ($order == "RAND" || $order == "RAND()") ? " ORDER BY RAND()" :" ORDER BY `".$order_by."` ".$order;
			$sql .= ($limit && $limit > 0) ? " LIMIT ".$limit : "";
			$sql .= ($offset && $offset > 0) ? " OFFSET ".$offset : "";
			$this->match = $this->query->get_results($sql, $return_key);
			$this->result = array_map(function($v){
			    return $this->get_post_meta($v->post_id);
			}, $this->match);
		endif;
		return $this->result;
	}

	public function drop_post($post_id) {
		if(is_array($post_id)) {
			$this->drop_post_by_meta_data($post_id);
			return;
		}
		$this->cache->__drop_cache($post_id, 'post');
		$this->query->delete( 'post', array('id' => $post_id));
		$this->query->delete( 'post_meta', array('post_id' => $post_id));
	}

	public function drop_post_by_meta_data($args, $compare = 'LIKE', $id_as_key = false, $limit = 0, $offset = 0, $order_by = 'post_id', $order = 'ASC') {
		$posts = $this->get_post_by_meta_data($args, $compare, $id_as_key, $limit, $offset, $order_by, $order);
		if($posts) {
			if(_count($posts)) {
				foreach ($posts as $post) {
					set_time_limit(30);
					$this->drop_post($post['id']);
				}
			}
		}
	}
}
