<?php

namespace app\controllers;

use lithium\storage\Session;
use app\models\User;
use app\models\confirmKey;
use app\models\ProfilePic;
use app\models\Post;
use lithium\security\Auth;
use lithium\util\String;
use li3_flash_message\extensions\storage\FlashMessage;
use lithium\template\helper\Html;

class UsersController extends \lithium\action\Controller {
	public $secret = "marshmallows"; //I don't know why either?
	
	//Make login a public action.
	public $publicActions = array('login', 'logout', 'signup', 'confirm');

	/* User profile implementation */
	/* So, like twitter if you friend someone but they don't friend you, 
	 * You can see their posts, but they don't see yours. Furthermore, posts that start with a @username 
	 * shouldn't be shown to the user either.
	 *
	 * Now say for instance the the user isn't logged in but visits the profile of another user. It should show the users posts 
	 * that aren't set to private. this should be as easy as Posts::find('all', array('conditions' => array('level' != private)))
	 * However, we need to differentiate posts that are Hidden (posts that begin with a @username), Friends only (set by user) or 
	 * Public (by default all posts.) there should be a method that filters the new post method, that takes a post, determines
	 *  what access level it should be then passes that back to the calling method (in save?)
	 *
	 * Of course, for logged in users, we need to do a multiselect I guess, something like find posts where access level is hidden
	 * friends only, and public, ordered by date (descending) limit 20 or so (use pagination plugin)
	 *
	 * Finally, there should be an an option to make all posts private, this can be done by the postlevel() method, it can check if
	 * the user has the private option set, then if true return private for all posts :)
	  */

	public function index($username = null)
	{
		//If no username was entered, 
		if ($username == null)
		{
			//Show a user list?
			// TODO: Pagination 
			//Show a list of all users
			$users = User::all();
			return compact('users');
			//maybe we can use the endpoint hook and show a "network activity feed"
			//For example show all public posts as they get posted using ajax ?
			//Maybe we should have a route for this? /activity maybe?
		}
		//Otherwise get that user
		$user = User::find('first', array('conditions' => compact('username')));
	
		//find all posts, sort by date, order descending, limit to 20
		$feed; 

		//Dont know if php will keep counts return on the stack so I'm storing it to avoid calling it 3 times.
		$tmpCount = count($user->feed);

		//If the user has 20 or more posts then query 20, otherwise query the number of posts the user has
		$count = ($tmpCount >= 20) ? 20 : $tmpCount;

		//If the user is logged in
		$user = Auth::check('default');
		if ($user)
		{	 
			if ($user->username == $username)
			{
				$feed = $user->getPosts(array('level' => null));
				return compact($feed, $user);	
			}
			//if the user is logged in and the users are friends
			if (User::areFriend(Auth::check('default'), $user))
			{
				$feed = $user->getPosts(array('level' => null));
				return compact($feed, $user);	
			}
		} //If they aren't friend, or if the user isn't logged in it defaults to the public version (filter private posts)
		//If the user isn't logged in, then we should show a signup partial like twitter
		else
		{
			//find all non-private posts, limit 20, order descending (decending was taken care of with array_unshift btw)
			$feed = $user->getPost(array('level' => array('$ne' => "private")));
			return compact($feed, $user); 
		}
	}


    /** 
    * How this method should work: 
	* Since this network is default open like twitter, there is three types of relationships:
	* 1) Mutually Oblivious: Neither user knows each other. 
	* 2) You Follow: You follow a user and sees their non-private posts
	* 3) Friends: being friends allows you to see each others privates posts 
	* (@see app\models\post) for an example of how this works
    * 
    * Now, for now there are two types of requests: Friend requests which causes both users to automatically follow eachother
    * And follows. Follows are unidirectional and thus don't require the followees permission
    */
	public function follow($username = null)
	{
		$status;
		$message;
		if($this->request->data)
		{
			$user = Auth::check('default');
			if ($user)
			{
				$user = User::find('first', array('conditions' => array('username' => $user['username'])));
				if ($user->follow($username))
				{
					$status = true;
					
					return array('sucseeded' => true, 'message' => 'You are now following $username');
				}
			}
		}	
	}

	/**
	* Calls the user to addFriend method, then returns the status.
	* @param username The name of the user to add as a friend
	*/
	public function addfriend($username = null)
	{
		
	}

	public function reconfirm()
	{
		//Search the database for email address
		if (ConfirmKey::count(array('conditions' => array('email' => $this->request->data['email']))) != 0)
		{
			//Resend the confirmation email
		}
		else
		{
			//Show them a message
		}

		//Send a new key
	}

	public function profile($username) 
	{
		//If no username is passed in.
		if (empty($username))
		{
			$this->redirect('/');
		}
		
		//Otherwise
		else
		{
			//Find that user, and go to their profile page. 
			$user = User::find('first', array('conditions' => compact('username')));
			//$photo = (empty($user->profilepic) ? ProfilePic::create() : $user->profilepic);
			return compact('user', 'photo');
			//Render the profile layout

		}
	}

	public function post()
	{
		if ($this->request->data)
		{
			$user = Auth::check('default');
			if ($user) {
				$user = User::find($user['id']);
				$user->post($this->request->data);
			}

			/* :TODO:  Need to return a status here */
			$this->redirect('Users::feed');
		}
	}


	public function feed()
	{
		//Get the currently logged in user 
		$user = Auth::check('default');
		
		//If there is a user logged in (There should be since feed isn't a public function)
		if ($user) 
		{
			//Get that user from the database
			$user = User::find('first', array('conditions' => array('username' => $user['username'])));
			
			//Set the feed variable scope (since we are going to use it outside the loop)
			$feed;

			if (isset($user->feed)) {
			//For each post ID in $users feed,
			foreach ($user->feed as $post)
			{
				//Find the post by it's ID
				$post = Post::find($post);
				
				//If a post was found,
				if (!empty($post))
				{
					//Add it to the feed
					$feed[] = $post; 				
				}
				//Else we should remove the the ID from the users feed. 
			}
			
			/* new posts are appended to the end of the feed array, therefore new posts naturally end up at the bottom of the feed
			 * therefore, we reverse the order of the array so that new posts end up at the top of the feed.
			 * This is probably faster than doing sorting by date at the database level, though it for some reason
			 * posts don't get inserted in the right order it could cause them to come out wrong in the view */
			$feed = array_reverse($feed);

			//This renders a custom layout we use for the feed, then passes user and feed to the view for the variables. 
		}
			return compact('user', 'feed');
		}
		
	}
	/*
			If the user is valid, but not confirmed,
				tell the user they haven't confirmed,
				offer to resend the confirmation email or changed their email address. 
		*/
	public function login($location = null, $args = null)
	{
		
		if (!empty($this->request->data)) {
			$user = Auth::check('default', $this->request);
			if ($user)
			{
				$user = User::find('first', array('conditions' => array('username' => $user['username'])));
				$user->lastLogin = date('Y-m-d H:i:s', time());
				$user->save(null, array('validate' => false));
				

				//If the user hasn't confirmed their account
				if(!$user->confirmed)
				{
					//Redirect them to the confirmation page.
					return $this->redirect('Signup::confirm');
				}
				
				//If the user's account is not active they are probably banned
				if (!$user->active)
				{
					return $this->redirect('/pages/banned');
				}
				
				//If the user was trying to go somewhere, redirect them there
				$loc = Session::read('url');
				if (isset($loc))
				{
					Session::delete('url');
					return $this->redirect(array('controller' => $loc['controller'],
										  'action' => $loc['action'],
										  'args' => $loc['args']
										  ));
				}
				//Otherwise send them to the hompa				
				return $this->redirect('Users::feed');
			}
			else
			{
				FlashMessage::write('Username or Password Incorrect.');
			}
		}
	}

	//Logout
	public function logout()
	{	
		//If the user logs out
		//Clear their auth cookie
		Auth::Clear('default');

		//Redirect them to the homepage. 
		return $this->redirect('/');
	}

	public function changePassword()
	{
		//Get the user to verify their current password
		$input = $this->request->data;

		//If there is inputfrom the form
		if ($input)
		{
			//Get the user from auth
			$user = Auth::check('default');
			
			//Ensure that the passwords are the same.
			if ($input['newpass'] != $input['confirm'])
			{
				//return error
				return $this->redirect('/'); 
			} 
			else if(!empty($user) && isset($input['newpass']))
			{
				//find the user by their ID
				$user = User::find($user['_id']);

				//Set the newpassword, this triggers the hash function in ->save()

				$user->newpass = $input['newpass'];

				//Save the data
				if ($user->save(null, array('validate' => false))) {
					//Tell the user their password was updated sucsessfully
				}

				//Else there was an error, so send them away
				/* If the compare is changed to a validator
				 * returning the user object will show the error in the view.*/
				return compact('user');

			}
		}
	}

	public function settings()
	{
		//Get the user using their login information (from auth)
		$user = Auth::check('default');
		$user = User::find($user['id']);

		//If the request isn't empty
		if(!empty($this->request->data)) {
			//Foreach key/value pair in the request data
			foreach($this->request->data as $key => $value)
			{
				//TODO: Make sure to lock the schema to prevent wierd values
				$user->$key = $value;
			}

			//Save the user.
			$user->save(null, array('validate' => false));
		}
		
		return compact('user');
	}

	public function requestFriend($username = null) {
		if ($username == null)
		{
			$username = $this->request->query['username'];
		}
		//If the user isn't blocking this user, 

		//And the user doesn't have private set 

		//Send them a DM with a confirm key
		$key = confirmKey::create();
		$thisUser = auth::check('default');
		$url = \lithium\net\http\Router::match(array('controller' => 'users',
										 'action' => 'confirmFriend',
										 'args'=>array($thisUser['username'], $key->key)), null, array('absolute' => 'false')); 
		$post = Post::create(array('body' => $thisUser['username'] . " want's to be your friend. Click $url to confirm"));

		$post->directMessage($thisUser);

		return $this->redirect('users::feed');

	}

	/* Potential hack here, in theory, a user could sign up a new account 
	 * then send a direct message manually using the confirm key from the email.
	 */
	public function confirmFriend($username, $key) {
		/* Normally we could try and find the cKey, then if it doesn't exist 
		 * Do something about it, 
		 * However, ConfirmKey::validates basically counts the number of keys that 
		 * match $key, this is probably better than find since ->validates() may be a bit
		 * more efficent */

		$cKey = confirmKey::create(compact('key'));
		if ($cKey->validates())
		{
			$thisUser = Auth::check('default');
			$thisUser = User::find('first', array('conditions' => array('username' => $thisUser['username'])));
			$requestingUser = User::find('first', array('conditions' => compact('username')));
			$requestingUser->addFriend($thisUser->username);
			$thisUser->addFriend($requetingUser->username);

			//Some action here if true :TODO:
		}

		//Some action here if false
	}


	public function step2()
	{
		//Check that step1 is completed sucsessfully, 
		//Then take them to their profile in edit mode
	}
}

?>