<?php
/*
* @package LabCMS
* @copyright (c) 2006 Alexander Levin aka Loki (loki_angel@mail.ru)
* @support http://labcms.ru
* @license http://opensource.org/licenses/gpl-license.php GNU Public License
*/

class login_forms
{
	public $avatar_width=75;
	public $avatar_height=75;
	public $types=array(	1 => 'gif',
							2 => 'jpg',
							3 => 'png');
	public $use_openid=false;
	public $max_login_length=20;
	public $validation=1;
	
	/**
	 * форма редактирования свойств пользователя
	 * 
	 * @return object    объект формы
	 */
	function userInfo()
	{
		$user=User::i()->getCurrentUser();
		$form = Factory::create(
			'HTML_QuickForm2', 
			'profile',
			'post',
			array('enctype'=>'multipart/form-data',
			'action'=>_url(false, 'edit'))
		);
		$token=$form->addElement('hidden', 'token', array('value' => User::i()->token));
		$form->addDataSource(
			Factory::create(
				'HTML_QuickForm2_DataSource_Array', 
				array(
					'email'		=> $user->email,
					'realname'	=> $user->realname,
					'website'	=> $user->website,
					'icq'		=> $user->icq
				)
			)
		);
		
		$email=$form->addElement(
			'email',
			'email',
			array('maxlength'=>50),
			array('label' => 'Email:')
		);
		$this->_addEmailRulesClientServer($email);
		$this->_addEmailRulesServer($email);
				
		$realname=$form->addElement(
			'text',
			'realname',
			null,
			array('label' => _m('Настоящее имя:'))
		);
		$website=$form->addElement(
			'text',
			'website',
			null,
			array('label' => _m('Домашняя страница:'))
		);
		$icq=$form->addElement('text', 'icq', null, array('label' => _m('ICQ:')));

		$maxfilesize=51200;
	
		$avatar=$form->addElement(
			'file',
			'avatar',
			null,
			array(
				'label' => _m('Аватар:'),
				'note'=>
					'('.$this->avatar_width.'px*'.$this->avatar_height
					.'px) &lt;'.get_formatted_filesize($maxfilesize)
			)
		);
		$avatar->addRule(
			'mimetype', _m('Данный тип файла не поддерживается'),
			array('image/gif', 'image/png', 'image/jpeg', 'image/pjpeg')
		);
		$avatar->addRule(
			'maxfilesize',
			sprintf(
				_m('Файл слишком большой. Разрешены файлы не больше %s'),
				get_formatted_filesize($maxfilesize)
			),
			$maxfilesize
		);

		if ($user->avatar) {
			$alabel='<img src="/storage/Image/avatars/'
			.$user->id.'.'.$this->types[$user->avatar].'?'.rand().'" />';
			$form->addElement(
				'checkbox',
				'del_avatar',
				null,
				array('content'=>$alabel, 'label' => _m('удалить'))
			);
		}
		$form->addElement('submit', null, array('value'=>_m('Изменить')));
		return $form;
	}
	
	/**
	 * форма изменения пароля
	 * 
	 * @return object    объект формы
	 */
	public function changePassword()
	{
		$form = Factory::create('HTML_QuickForm2', 'password', 'post', array('action'=>'#'));
		$token=$form->addElement('hidden', 'token', array('value' => User::i()->token));
		$newPassword=$form->addElement(
			'password',
			'newpass',
			null,
			array('label' => _m('Новый пароль:'))
		);
		$repPassword=$form->addElement(
			'password',
			'repass',
			null,
			array('label' => _m('Ввести повторно:'))
		);
		
		$newPassword->addRule(
			'required',
			_m('Пароль не может быть пустым'),
			null,
			$this->validation
		);
		$repPassword->addRule(
			'required',
			_m('Пароль не может быть пустым'),
			null,
			$this->validation
		);
		
		$newPassword->addRule('nonempty', _m('Пароль не может быть пустым'));
		$newPassword->addRule('eq', _m('Пароли не совпадают'), $repPassword, $this->validation);
		$repPassword->addRule('eq', ' ', $newPassword, $this->validation);
		
		$form->addElement('submit', null, array('value'=>_m('Изменить')));
		return $form;
	}

	/**
	 * форма редактирования openId
	 * 
	 * @return object    объект формы
	 */
	public function changeOpenID()
	{
		$user_id=User::i()->id;
		$form = Factory::create('HTML_QuickForm2', 'openid_tool', 'post', array('action'=>'#'));
		$token=$form->addElement('hidden', 'token', array('value'=>User::i()->token));
		
		$oids=$this->_getOpenIDs($user_id);
		if ($oids) foreach ($oids as $key=>$oid) {
			$form->addElement(
				'checkbox',
				'delopenid['.$key.']',
				null,
				array('label' => _m('удалить'), 'note'=>$oid)
			);
		}
		
		$this->addOpenIDToForm($form, _m('Добавить OpenID'));

		$form->addElement('submit', null, array('value'=>_m('Применить')));
		return $form;
	}
	
	/**
	 * форма авторизации
	 * 
	 * @return object    объект формы
	 */
	public function auth()
	{
		$form = Factory::create('HTML_QuickForm2', 'auth_form', 'post', array('action'=>'#'));
		$token=$form->addElement('hidden', 'token', array('value' => User::i()->token));
		
		$field=$form->addElement('fieldset')->setLabel(_m('Введите логин и пароль'));

		$login=$field->addElement('text', 'login', array('maxlength'=>20), array('label' =>_m('Логин:')));
		$pass=$field->addElement('password', 'pass', null, array('label' => _m('Пароль:')));

		if ($this->use_openid) {
			$openid=$this->addOpenIDToForm($form);
			$login->addRule('nonempty', _m('Нужно указать логин'), null, $this->validation)
			->or_($openid->createRule('nonempty', _m('или OpenId')));
			$login->addRule('nonempty', '', null, $this->validation)
			->and_($pass->createRule('nonempty', _m('Пароль не может быть пустым')));
		} else {
			$login->addRule('required', _m('Нужно указать логин'), null, $this->validation);
			$pass->addRule('required', _m('Пароль не может быть пустым'), null, $this->validation);
		}

		$form->addElement(
			'checkbox',
			'rememberme',
			null,
			array('content'=>'&nbsp;', 'label' => _m('Запомнить меня'))
		);
		$form->addElement('submit', null, array('value'=>_m('Отправить')));

		return $form;
	}
	
	/**
	 * форма регистрации
	 * 
	 * @return object    объект формы
	 */
	public function register()
	{
		$form = Factory::create('HTML_QuickForm2', 'register_form', 'post', array('action'=>'#'));
		$field=$form->addElement('fieldset')->setLabel(_m('Введите данные для регистрации'));

		$token=$form->addElement('hidden', 'token', array('value'=>User::i()->token));
		$login=$field->addElement(
			'text',
			config::get('core.catcher'),
			array('maxlength'=>20),
			array('label' => _m('Логин:').$this->getCatcher)
		);
		$pass=$field->addElement('password', 'pass', null, array('label' => _m('Пароль:')));
		$repass=$field->addElement(
			'password',
			'repass',
			null,
			array('label' => _m('Ввести повторно:'))
		);
		$email=$field->addElement(
			'email',
			'email',
			array('maxlength'=>50),
			array('label' => _m('Email:'))
		);
		
		if ($this->use_openid) {
			$open_id=$this->addOpenIDToForm($form);
			$open_id->addRule('nonempty', '', null, $this->validation)
				->or_($this->_addLoginRulesClientServer($login, false));
			$open_id->addRule('nonempty', '', null, $this->validation)
				->or_($pass->createRule('nonempty', _m('Пароль не может быть пустым')));
			$open_id->addRule('nonempty', '', null, $this->validation)
				->or_($repass->createRule('eq', _m('Пароли не совпадают'), $pass));
			$open_id->addRule('nonempty', '', null, $this->validation)
				->or_($this->_addEmailRulesClientServer($email, false));
			$open_id->addRule('callback', 'Ошибка OpenId', array($this, 'sendRegOpenId'));
		} else {
			$this->_addLoginRulesClientServer($login);
			$pass->addRule('nonempty', _m('Пароль не может быть пустым'));
			$repass->addRule('eq', _m('Пароли не совпадают'), $pass);
			$this->_addEmailRulesClientServer($email);
		}
		
		$this->_addLoginRulesServer($login);
		$this->_addEmailRulesServer($email);

		$form->addElement('submit', null, array('value'=>_m('Зарегистрироваться')));
		return $form;
	}
	
	/**
	 * форма восстановления пароля
	 * 
	 * @return object    объект формы
	 */
	public function lostPass()
	{
		$form = Factory::create('HTML_QuickForm2', 'recovery', 'post', array('action'=>'#'));
		$token=$form->addElement('hidden', 'token', array('value'=>User::i()->token));
		$recovery=$form->addElement(
			'text',
			'recover_info',
			null,
			array('label' => _m('Введите логин или email:'))
		);
		$recovery->addRule(
			'required',
			_m('Нужна хоть какая-то информация:)'),
			null,
			$this->validation
		);
		
		$form->addElement('submit', null, array('value'=>_m('Восстановить пароль')));
		return $form;
	}
	
	/**
	 * форма редактирования свойств пользователя
	 * 
	 * @return object    объект формы
	 */
	public function ReGetCode()
	{
		$form = Factory::create('HTML_QuickForm2', 'get_code', 'post', array('action'=>'#'));
		$token=$form->addElement('hidden', 'token', array('value'=>User::i()->token));
		$email=$form->addElement(
			'email',
			'email',
			array('maxlength'=>50),
			array('label' => _m('Введите email:'))
		);
		$form->addElement('submit', null, array('value'=>_m('Запросить код')));

		$email->addRule('required', _m('Нужно указать email'), null, $this->validation);
		$email->addRule(
			'email', _m('Сдается нам, таких email-ов не бывает'),
			null,
			$this->validation
		);
		
		return $form;
	}
	
	/**
	 * форма регистрации через openID
	 * 
	 * @return object    объект формы
	 */
	public function registerByOpenID($data)
	{
		$form = Factory::create('HTML_QuickForm2', 'register', 'post', array('action'=>'#'));
		
		if (is_array($data)) $form->addDataSource(Factory::create('HTML_QuickForm2_DataSource_Array', $data));
		$token=$form->addElement('hidden', 'token', array('value'=>User::i()->token));
		
		$openid=$form->addElement('hidden', 'openid');
		$login=$form->addElement(
			'text',
			'login',
			array('maxlength'=>20),
			array('label' => _m('Логин:'))
		);
		$email=$form->addElement(
			'email',
			'email',
			array('maxlength'=>50),
			array('label' => _m('Email:'))
		);
		$form->addElement('submit', null, array('value'=>_m('Зарегистрироваться')));

		$openid_rule=$openid->addRule(
			'callback',
			_m('Данный openID уже зарегистрирован'),
			array('callback'=>array($this, 'isOpenIdNotExists'),
			'arguments'=>array(false))
		);
		if (!$openid_rule->validate()) LabCMS::i()->error(_m('Данный openID уже зарегистрирован'));
		$client=$this->_addLoginRulesClientServer($login);
		$server=$this->_addLoginRulesServer($login);
		if ($data['login']) {
			$client->validate();
			$server->validate();
		}
		
		$server=$this->_addEmailRulesServer($email);
		$client=$this->_addEmailRulesClientServer($email);
		if ($data['email']) {
			$client->validate();
			$server->validate();
		}
		return $form;
	}
	
	/**
	 * добавление серверных правил проверки логина
	 * 
	 * @param object $login объект поля логина
	 * 
	 * @return object    объект поля логина
	 */
	protected function _addLoginRulesServer(&$login)
	{
		return 	$login->addRule(
			'callback', _m('Логин уже занят'),
			array('callback'=>array($this, 'IsLoginNotExists'),
			'arguments'=>array(false))
		);
	}

	/**
	 * добавление клиент-серверных правил проверки логина
	 * 
	 * @param object $login    объект поля логина
	 * @param boolean $required является ли поле обязательным (если разрешено OpenId, то может быть необязательным)
	 * 
	 * @return объект поля логина
	 */
	protected function _addLoginRulesClientServer(&$login, $required=true)
	{
		return $login->addRule(
			$required?'required':'nonempty',
			_m('Нужно указать логин'), null, $required?$this->validation:1
		)
		->and_(
			$login->createRule(
				'maxlength',
				sprintf(
					_m('Логин не может быть длиннее %d символов'),
					$this->max_login_length
				),
				$this->max_login_length
			)
		);
	}
	
	/**
	 * добавление серверных правил проверки email
	 * 
	 * @param object $email объект поля email
	 * 
	 * @return object    объект поля email
	 */
	protected function _addEmailRulesServer(&$email)
	{
		return $email->addRule(
			'callback',
			_m('Этот email уже используется.'),
			array('callback'=>array($this, 'isEmailNotExists'),
			'arguments'=>array(false))
		);
	}
	
	/**
	 * добавление клиент-серверных правил проверки email
	 * 
	 * @param object $email    объект поля email
	 * @param boolean $required является ли поле обязательным (если разрешено OpenId, то может быть необязательным)
	 * 
	 * @return объект поля email
	 */
	protected function _addEmailRulesClientServer(&$email, $required=true)
	{
		return $email->addRule(
			$required?'required':'nonempty',
			_m('Нужно указать email'), null,
			$required?$this->validation:1
		)
		->and_($email->createRule('maxlength', sprintf(_m('Email не может быть длиннее %d символов'), 50), 50))
		->and_(
			$email->createRule(
				'email', _m('Сдается нам, таких email-ов не бывает')
			)
		);
	}
	
	protected function getCatcher()
	{
		return '<input type="text" name="login" value="" class="catch" />';
	}
	
	/**
	 * проверяет есть ли такой логин
	 * 
	 * @param string $login логин
	 * 
	 * @return boolean  результат поиска
	 */
	public function IsLoginNotExists($login)
	{
		return (User::i()->IsLoginExists($login))?false:true;
	}
	
	/**
	 * проверяет зарегистрирован ли такой email
	 * 
	 * @param sting $email email адрес
	 * 
	 * @return boolean    результат поиска
	 */
	public function IsEmailNotExists($email)
	{
		if (
			Db::i()->selectCell(
				"SELECT COUNT(user_id) FROM ?_users
				WHERE email=? {AND user_id!=?}",
				trim($email), (User::i()->isNotGuest())?User::i()->id:DBSIMPLE_SKIP
			)
		) return false;
		else return true;
	}
	
	/**
	 * проверяет нет ли в базе такого openId идентификатора
	 * 
	 * @param string $open_id ipenid идентификатор
	 * 
	 * @return boolean    результат поиска
	 */
	public function IsOpenIdNotExists($open_id)
	{
		if (
			Db::i()->selectCell(
				"SELECT COUNT(user_id) FROM ?_openid
				WHERE openid=?",
				trim($open_id)
			)
		) return false;
		else return true;
	}
	
	/**
	 * добавляет поле openid в форму
	 * 
	 * @param object $form объект формы
	 * @param string $text заголовок группы полей
	 * 
	 * @return object    объект поля openid
	 */
	protected function addOpenIDToForm(&$form, $text=null)
	{
		if (!$text) $text=_m('или используйте OpenID');
		$field=$form->addElement('fieldset')->setLabel($text);
		return $field->addElement(
			'text',
			'openid',
			array('id'=>'openid', 'class'=>'openid_input'),
			array('label' => 'OpenID:')
		);
	}
	
	/**
	 * получает список openid текущего пользователя
	 * 
	 * @param ineger $user_id идентификатор пользователя
	 * 
	 * @return array    массив openid пользователя
	 */
	protected function _getOpenIDs($user_id)
	{
		return Db::i()->selectCol(
			"SELECT id AS ARRAY_KEY, openid
			FROM ?_openid
			WHERE user_id=?",
			$user_id
		);
	}

	/**
	 * отправляет запрос к openid провайдеру
	 * 
	 * @param string $open_id идентификатор
	 * 
	 * @return boolean если идентификатор пустой, то возвращаем true, иначе - результат отправки
	 */
	public function sendRegOpenId($open_id)
	{
		if ($open_id) {
			$oid=Factory::create('OpenId');
			$oid->returnTo=$oid->getTrustRoot()
						._url(false, 'reg_openid');
			$oid->required=array('email', 'nickname');
			return $oid->SendOpenId($open_id);
		}
		return true;
	}
}
