<?php
// Copyright 2011 Toby Zerner, Simon Zerner
// This file is part of esoTalk. Please see the included license file for usage information.

if (!defined("IN_ESOTALK")) exit;

/**
 * The settings controller handles a user's settings page and all the separate panes that are on it.
 *
 * @package esoTalk
 */
class ETSettingsController extends ETController {


/**
 * Initialize the settings controller; redirect if the user isn't logged in.
 *
 * @return void
 */
public function init()
{
	parent::init();
	if (!ET::$session->userId) {
		if ($this->responseType === RESPONSE_TYPE_DEFAULT) $this->redirect(URL(""));
		else exit;
	}
}


/**
 * A render function that will render the specified view inside of the main member "profile" view. (Except
 * on AJAX/view response types.)
 *
 * @param string $view The name of the view to render.
 * @return void
 */
public function renderProfile($view = "")
{
	if (!in_array($this->responseType, array(RESPONSE_TYPE_VIEW, RESPONSE_TYPE_AJAX))) {
		$this->data("view", $view);
		parent::render("member/profile");
	}

	else parent::render($view);
}


/**
 * View the settings page. Default to the general pane.
 *
 * @return void
 */
public function action_index()
{
	$this->action_general();
}


/**
 * Set up data and menus that are needed to render the member profile view.
 *
 * @param string $pane The name of the active pane.
 * @return array The member details.
 */
public function profile($pane = "")
{
	// Set the page title.
	$this->title = T("Settings");

	// Make a list of default member panes, and highlight the currently active one.
	$panes = ETFactory::make("menu");
	$panes->add("general", "<a href='".URL("settings/general")."'>".T("Settings")."</a>");
	$panes->add("password", "<a href='".URL("settings/password")."'>".T("Change Password or Email")."</a>");
	$panes->add("notifications", "<a href='".URL("settings/notifications")."'>".T("Notifications")."</a>");
	$panes->highlight($pane);

	// Set the member to the current user.
	$member = ET::$session->user;

	// Set up the controls and actions menus (although they will mostly be empty.)
	$controls = ETFactory::make("menu");
	$actions = ETFactory::make("menu");

	// Add a link to go back to the user's member profile.
	$actions->add("viewProfile", "<a href='".URL("member/me")."'><i class='icon-eye-open'></i> ".T("View your profile")."</a>");

	$this->trigger("initProfile", array($panes, $controls, $actions));

	// Pass along these menus to the view.
	$this->data("member", $member);
	$this->data("panes", $panes);
	$this->data("controls", $controls);
	$this->data("actions", $actions);

	return $member;
}



/**
 * Show the settings page with the general settings pane.
 *
 * @return void
 */
public function action_general()
{
	$member = $this->profile("general");

	// Construct the general settings form.
	$form = ETFactory::make("form");

	// Add the avatar section and field to the form.
	$form->addSection("avatar", T("Avatar"));
	$form->addField("avatar", "avatar", array($this, "fieldAvatar"), array($this, "saveAvatar"));

	// If there's more than 1 language installed, add the language section and field to the form.
	if (count(ET::getLanguages()) > 1) {
		$form->addSection("language", T("Forum language"));

		$form->setValue("language", ET::$session->preference("language", C("esoTalk.language")));
		$form->addField("language", "language", array($this, "fieldLanguage"), array($this, "saveLanguage"));
	}

	$form->addSection("notifications", T("Notifications"));

	// Add the "email me when I'm added to a private conversation" field.
	$form->setValue("privateAdd", ET::$session->preference("email.privateAdd"));
	$form->addField("notifications", "privateAdd", array($this, "fieldEmailPrivateAdd"), array($this, "saveEmailPreference"));

	// Add the "email me when someone replies to a conversation I have starred" field.
	$form->setValue("post", ET::$session->preference("email.post"));
	$form->addField("notifications", "post", array($this, "fieldEmailReplyToStarred"), array($this, "saveEmailPreference"));

	// Add the "email me when mentions me in a post" field.
	$form->setValue("mention", ET::$session->preference("email.mention"));
	$form->addField("notifications", "mention", array($this, "fieldEmailMention"), array($this, "saveEmailPreference"));

	// Add the "automatically star conversations I reply to" field.
	$form->setValue("starOnReply", ET::$session->preference("starOnReply"));
	$form->addField("notifications", "starOnReply", array($this, "fieldStarOnReply"), array($this, "saveBoolPreference"));

	// Add the "automatically star private conversations that I'm added to" field.
	$form->setValue("starPrivate", ET::$session->preference("starPrivate"));
	$form->addField("notifications", "starPrivate", array($this, "fieldStarPrivate"), array($this, "saveBoolPreference"));

	$form->addSection("privacy", T("Privacy"));

	// Add the "Don't allow other users to see when I am online" field.
	$form->setValue("hideOnline", ET::$session->preference("hideOnline"));
	$form->addField("privacy", "hideOnline", array($this, "fieldHideOnline"), array($this, "saveBoolPreference"));

	$this->trigger("initGeneral", array($form));

	// If the save button was clicked...
	if ($form->validPostBack("save")) {

		// Create an array of preferences to write to the database and run the form field callbacks on it.
		$preferences = array();
		$form->runFieldCallbacks($preferences);

		// If no errors occurred, we can write the preferences to the database.
		if (!$form->errorCount()) {

			if (count($preferences)) ET::$session->setPreferences($preferences);

			$this->message(T("message.changesSaved"), "success autoDismiss");
			$this->redirect(URL("settings/general"));

		}
	}

	// If the "remove avatar" button was clicked...
	elseif ($form->validPostBack("removeAvatar")) {

		// Delete the avatar file and set the member's avatarFormat to null.
		@unlink(PATH_UPLOADS."/avatars/".$member["memberId"]."_".$member["avatarTime"].".".$member["avatarFormat"]);
		ET::memberModel()->updateById($member["memberId"], array("avatarFormat" => null));

		$this->message(T("message.changesSaved"), "success autoDismiss");
		$this->redirect(URL("settings/general"));

	}

	$this->data("form", $form);
	$this->renderProfile("settings/general");
}


/**
 * Return the HTML to render the avatar field in the general settings form.
 *
 * @param ETForm $form The form object.
 * @return string
 */
public function fieldAvatar($form)
{
	return "<div class='avatarChooser'>".
		avatar(ET::$session->user).
		$form->input("avatar", "file").
		"<small>".sprintf(T("Maximum size of %s. %s."), (ET::uploader()->maxUploadSize() / (1024*1024))." MB", "JPG, GIF, PNG")."</small>".
		(ET::$session->user["avatarFormat"] ? $form->button("removeAvatar", T("Remove avatar")) : "").
		"</div>";
}


/**
 * Return the HTML to render the language field in the general settings form.
 *
 * @param ETForm $form The form object.
 * @return string
 */
public function fieldLanguage($form)
{
	$options = array();
	foreach (ET::getLanguages() as $language) $options[$language] = ET::$languageInfo[$language]["name"];
	return $form->select("language", $options);
}


/**
 * Save the contents of the language field when the general settings form is submitted.
 *
 * @param ETForm $form The form object.
 * @param string $key The name of the field that was submitted.
 * @param array $preferences An array of preferences to write to the database.
 * @return string
 */
public function saveLanguage($form, $key, &$preferences)
{
	$language = $form->getValue($key);
	if (!in_array($language, ET::getLanguages()) or $language == C("esoTalk.language")) $language = null;
	$preferences["language"] = $language;
}


/**
 * Return the HTML to render the "email me when I'm addded to a private conversation" field in the general
 * settings form.
 *
 * @param ETForm $form The form object.
 * @return string
 */
public function fieldEmailPrivateAdd($form)
{
	return "<label class='checkbox'>".$form->checkbox("privateAdd")." ".label("private")." ".T("Email me when I'm added to a private conversation")."</label>";
}


/**
 * Return the HTML to render the "email me when someone posts in a conversation I have starred" field in the general
 * settings form.
 *
 * @param ETForm $form The form object.
 * @return string
 */
public function fieldEmailReplyToStarred($form)
{
	return "<label class='checkbox'>".$form->checkbox("post")." <i class='star icon-star'></i> ".T("Email me when someone posts in a conversation I have followed")."</label>";
}


/**
 * Return the HTML to render the "email me when someone mentions me in a post" field in the general
 * settings form.
 *
 * @param ETForm $form The form object.
 * @return string
 */
public function fieldEmailMention($form)
{
	return "<label class='checkbox'>".$form->checkbox("mention")." ".T("Email me when someone mentions me in a post")."</label>";
}


/**
 * Return the HTML to render the "automatically star conversations that I reply to" field in the general
 * settings form.
 *
 * @param ETForm $form The form object.
 * @return string
 */
public function fieldStarOnReply($form)
{
	return "<label class='checkbox'>".$form->checkbox("starOnReply")." ".T("Automatically follow conversations that I reply to")."</label>";
}


/**
 * Return the HTML to render the "automatically star private conversations that I'm added to'" field in the general
 * settings form.
 *
 * @param ETForm $form The form object.
 * @return string
 */
public function fieldStarPrivate($form)
{
	return "<label class='checkbox'>".$form->checkbox("starPrivate")." ".T("Automatically follow private conversations that I'm added to")."</label>";
}


/**
 * Return the HTML to render the "don't allow other users to see when I am online" field in the general
 * settings form.
 *
 * @param ETForm $form The form object.
 * @return string
 */
public function fieldHideOnline($form)
{
	return "<label class='checkbox'>".$form->checkbox("hideOnline")." ".T("Don't allow other users to see when I am online")."</label>";
}

/**
 * Save the contents of an "email me when ..." field when the general settings form is submitted.
 *
 * @param ETForm $form The form object.
 * @param string $key The name of the field that was submitted.
 * @param array $preferences An array of preferences to write to the database.
 * @return string
 */
public function saveEmailPreference($form, $key, &$preferences)
{
	$preferences["email.".$key] = (bool)$form->getValue($key);
}


/**
 * Save the contents of a preference when the general settings form is submitted.
 *
 * @param ETForm $form The form object.
 * @param string $key The name of the field that was submitted.
 * @param array $preferences An array of preferences to write to the database.
 * @return string
 */
public function savePreference($form, $key, &$preferences)
{
	$preferences[$key] = $form->getValue($key);
}


/**
 * Save the contents of a simple checkbox field when the general settings form is submitted.
 *
 * @param ETForm $form The form object.
 * @param string $key The name of the field that was submitted.
 * @param array $preferences An array of preferences to write to the database.
 * @return string
 */
public function saveBoolPreference($form, $key, &$preferences)
{
	$preferences[$key] = (bool)$form->getValue($key);
}


/**
 * Save the contents of the avatar field when the general settings form is submitted.
 *
 * @param ETForm $form The form object.
 * @param string $key The name of the field that was submitted.
 * @param array $preferences An array of preferences to write to the database.
 * @return string
 */
public function saveAvatar($form, $key, &$preferences)
{
	if (empty($_FILES[$key]["tmp_name"])) return;

	$uploader = ET::uploader();

	try {
		// remove previous img
		$member = $this->profile("general");
		@unlink(PATH_UPLOADS."/avatars/".$member["memberId"]."_".$member["avatarTime"].".".$member["avatarFormat"]);

		// Validate and get the uploaded file from this field.
		$file = $uploader->getUploadedFile($key);
		$time = substr(md5(time()), 0, 4);

		// Save it as an image, cropping it to the configured avatar size.
		$avatar = $uploader->saveAsImage($file, PATH_UPLOADS."/avatars/".ET::$session->userId."_".$time, C("esoTalk.avatars.width"), C("esoTalk.avatars.height"), "crop");

		// Update the member's avatarFormat field to the avatar file's extension.
		ET::memberModel()->updateById(ET::$session->userId, array("avatarFormat" => pathinfo($avatar, PATHINFO_EXTENSION)));

		// Update the member's avatarFormat field to the avatar file's extension.
		ET::memberModel()->updateById(ET::$session->userId, array("avatarTime" => $time));

	} catch (Exception $e) {

		// If something went wrong up there, add the error message to the form.
		$form->error($key, $e->getMessage());

	}
}


/**
 * Show the settings page with the notifications pane.
 *
 * @param $popup bool Whether or not we are getting the contents of the notifications popup.
 * @return void
 */
public function action_notifications($popup = false)
{
	$member = $this->profile("notifications");

	// If we're getting the popup, we only want 5 notifications. Otherwise, 20.
	$limit = $popup ? 5 : 20;
	$this->data("showViewAll", $popup);

	// Get the notifications.
	$this->data("notifications", ET::activityModel()->getNotifications($limit));

	// Mark all notifications as read.
	ET::activityModel()->markNotificationsAsRead();

	$this->renderProfile("settings/notifications");
}


/**
 *
 */
public function action_notificationCheck()
{
	$this->responseType = RESPONSE_TYPE_AJAX;

	$notifications = ET::activityModel()->getNotifications(-1);

	$this->json("count", count($notifications));
	$this->notificationMessages($notifications);

	$this->render();
}


/**
 * Show the settings page with the change password or email pane.
 *
 * @return void
 */
public function action_password()
{
	$member = $this->profile("password");

	// Construct the form.
	$form = ETFactory::make("form");
	$form->action = URL("settings/password");

	// If the form was submitted...
	if ($form->validPostBack("save")) {

		$update = array();

		// Are we setting a new password?
		if ($password = $form->getValue("password")) {

			// Do the passwords entered match?
			if ($password != $form->getValue("confirm"))
				$form->error("confirm", T("message.passwordsDontMatch"));

			// The password stuff is good. Add the new password to be updated.
			else $update["password"] = $password;

		}

		// Are we setting a new email?
		if ($email = $form->getValue("email"))
			$update["email"] = $email;

		// Did they enter the correct "current password"?
		if (!ET::memberModel()->checkPassword($form->getValue("currentPassword"), ET::$session->user["password"]))
			$form->error("currentPassword", T("message.incorrectPassword"));

		// If no preliminary errors occurred, and we have stuff to update, we can go ahead and call the model.
		if (!$form->errorCount() and count($update)) {

			// Update the stuff we need to with the model.
			$model = ET::memberModel();
			$model->updateById(ET::$session->userId, $update);

			// If the model encountered errors, pass them along to the form.
			if ($model->errorCount()) $form->errors($model->errors());

			// Otherwise, show a message and redirect.
			else {
				$this->message(T("message.changesSaved"), "success autoDismiss");
				$this->redirect(URL("settings"));
			}

		}

	}

	$this->data("form", $form);
	$this->renderProfile("settings/password");
}

}
