<?php
class AddUserTransaction extends Transaction {
  /**
   * 部屋番号を指定して新しいユーザー番号を生成します。
   * ユーザーの追加が不可能な場合この関数はfalseを返します。
   * この関数が実行されると指定した部屋とそのメンバーのレコードに行レベルロックがかかります。
   * @param ChatEngine $db
   * @param integer $room_no
   * @return integer|boolean 成功した場合新しいユーザー番号、それ以外の場合false。
   */
  function _GenerateUserNumber($db, $room_no) {
    $sql = <<<SQL
SELECT
  (SELECT max_users FROM jinrou_rooms WHERE id = usr.room) AS max_users,
  SUM(usr.active_user) AS num_users,
  SUM(usr.countup) + 1 AS next_number
FROM (
  SELECT
    room,
    1 AS countup,
    IF(enabled, 1, 0) AS active_user
  FROM jinrou_users
  WHERE room = :room
) AS usr
GROUP BY usr.room
FOR UPDATE
SQL;
    if (($stmt = $db->prepare($sql)) !== false) {
      $stmt->bindValue(':room', $room_no, PDO::PARAM_INT);
      if ($stmt->execute()) {
        if ($stmt->rowCount() == 0) {
          return 1;
        }
        $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
        if (!empty($rows)) {
          extract($rows[0]);
          if ($num_users < $max_users) {
            return intval($next_number);
          }
        }
      }
    }
    return false;
  }

  /**
   * 部屋番号とログイン情報を指定して、新しいユーザーを追加します。
   * @param ChatEngine $db
   * @param int $room_id 参加する部屋のid
   * @param string $uname 追加するユーザーの名前
   * @param string $passwd 追加するユーザーのパスワード
   * @return int|bool 成功した場合追加されたユーザーのid、それ以外の場合false
   */
  function _AddUser($db, $room_id, $uname, $passwd) {
    if (!(validateText($uname, false, 1, 50) && validateText($passwd, false, 1))) {
	    return false;
    }
    $sql = <<<SQL
INSERT INTO jinrou_users (room, uname, passwd, session_id, ip_address)
VALUES (:room, :uname, MD5(:passwd), :session_id, :ip_address)
SQL;
    if (($stmt = $db->prepare($sql)) !== false) {
      $bindings = array(
        ':room' => $room_id,
        ':uname' => $uname,
        ':passwd' => $passwd,
        ':session_id' => session_id(),
        ':ip_address' => $_SERVER['REMOTE_ADDR']
      );
      if ($stmt->execute($bindings)) {
      	return intval($db->lastInsertId());
      }
    }
    return false;
  }

  /**
   * ユーザーIDを指定して、新しいプレイヤーを登録します。
   * @param ChatEngine $db
   * @param integer $user_id
   * @param integer $user_no
   * @param string $handle_name
   * @param string $profile
   * @param string $sex
   * @param string $role
   * @param integer $icon_no
   * @return integer|boolean 成功した場合は追加されたプレイヤーのID、それ以外の場合はfalse
   */
  function _AddPlayer($db, $user_id, $user_no, $handle_name, $profile, $sex, $role, $icon_no) {
    if ($user_no <= 0 || $icon_no < 0) { //アイコン番号は0(=身代わり君)がある (2011-01-18 enogu)
      return false;
    }
    else if (!validateText($handle_name, false, 1, 50) || !validateText($profile) || !validateText($role)) {
      return false;
    }
    else if ($sex != 'male' && $sex != 'female') {
      return false;
    }
    $sql = <<<SQL
INSERT INTO jinrou_players (user, user_no, handle_name, profile, sex, role, icon_no)
VALUES (:user_id, :user_no, :handle_name, :profile, :sex, :role, :icon_no)
SQL;
    $bindings = array(
      ':user_id' => $user_id,
      ':user_no' => $user_no,
      ':handle_name' => $handle_name,
      ':profile' => $profile,
      ':sex' => $sex,
      ':role' => $role,
      ':icon_no' => $icon_no
    );
    if (($stmt = $db->prepare($sql)) !== false) {
      if ($stmt->execute($bindings)) {
        return intval($db->lastInsertId());
      }
    }
    return false;
  }

  function __run($db) {
    $user_no = $this->_GenerateUserNumber($db, $this->room_no);
    if ($user_no !== false) {
      $uid = $this->_AddUser($db, $this->room_no, $this->uname, $this->passwd);
      if ($uid !== false) {
        $pid = $this->_AddPlayer(
          $db,
          $uid,
          $user_no,
          $this->handle_name,
          $this->profile,
          $this->sex,
          $this->role,
          $this->icon_no
        );
        if ($pid !== false) {
          $users = $db->GetUsersById($this->room_no, $uid);
          return $users !== false && 0 < count($users) ? array_shift($users) : false;
        }
      }
    }
    return false;
  }
}
