<?php
/**
 * DBクラス
 *
 * PHP versions 5
 *
 * LICENSE: This source file is licensed under the terms of the GNU General Public License.
 *
 * @package    Magic3 Framework
 * @author     平田直毅(Naoki Hirata) <naoki@aplo.co.jp>
 * @copyright  Copyright 2006-2007 Magic3 Project.
 * @license    http://www.gnu.org/copyleft/gpl.html  GPL License
 * @version    SVN: $Id: bbs_mainThreadDb.php 657 2008-05-27 22:25:23Z fishbone $
 * @link       http://www.magic3.org
 */
require_once($gEnvManager->getDbPath() . '/baseDb.php');

class bbs_mainThreadDb extends BaseDb
{
	const MAX_LOOP_COUNT = 30;		// ループの最大階層
	
	/**
	 * すべてのカテゴリーを取得
	 *
	 * @param string	$lang				言語
	 * @param function	$callback			コールバック関数
	 * @return			true=取得、false=取得せず
	 */
	function getAllCategory($lang, $callback)
	{
		$queryStr = 'SELECT * FROM bbs_category ';
		$queryStr .=  'WHERE sr_language_id = ? AND sr_deleted = false ';
		$queryStr .=  'ORDER BY sr_sort_order';
		$this->selectLoop($queryStr, array($lang), $callback, null);
	}
	/**
	 * 指定IDのカテゴリーを取得
	 *
	 * @param string	$category			カテゴリーID
	 * @param string	$lang				言語
	 * @param array     $rows				取得レコード
	 * @return			true=取得、false=取得せず
	 */
	function getCategoryRecords($category, $lang, &$rows)
	{
		$queryStr  = 'SELECT * FROM bbs_category ';
		$queryStr .=   'WHERE sr_deleted = false ';	// 削除されていない
		$queryStr .=   'AND sr_id in (' . $category . ') ';
		$queryStr .=   'AND sr_language_id = ? ';
		$queryStr .=   'ORDER BY sr_sort_order';
		$ret = $this->selectRecords($queryStr, array($lang), $rows);
		return $ret;
	}
	/**
	 * スレッドカテゴリーをカテゴリーIDで取得
	 *
	 * @param int		$id					カテゴリーID
	 * @param string	$langId				言語ID
	 * @param array     $row				レコード
	 * @return bool							取得 = true, 取得なし= false
	 */
	function getCategoryByCategoryId($id, $langId, &$row)
	{
		$queryStr  = 'SELECT * FROM bbs_category LEFT JOIN _login_user ON sr_create_user_id = lu_id AND lu_deleted = false ';
		$queryStr .=   'WHERE sr_deleted = false ';	// 削除されていない
		$queryStr .=   'AND sr_id = ? ';
		$queryStr .=   'AND sr_language_id = ? ';
		$ret = $this->selectRecord($queryStr, array($id, $langId), $row);
		return $ret;
	}
	/**
	 * 投稿項目一覧を取得(管理用)
	 *
	 * @param int		$limit				取得する項目数
	 * @param int		$page				取得するページ(1～)
	 * @param timestamp	$startDt			期間(開始日)
	 * @param timestamp	$endDt				期間(終了日)
	 * @param array		$category			カテゴリーID
	 * @param string	$keyword			検索キーワード
	 * @param string	$lang				言語
	 * @param function	$callback			コールバック関数
	 * @return 			なし
	 */
	function searchEntryItems($limit, $page, $startDt, $endDt, $category, $keyword, $lang, $callback)
	{
		$offset = $limit * ($page -1);
		if ($offset < 0) $offset = 0;
		
		$params = array();
		$queryStr = 'SELECT * FROM bbs_thread LEFT JOIN _login_user ON se_regist_user_id = lu_id AND lu_deleted = false ';
		$queryStr .=  'WHERE se_language_id = ? '; $params[] = $lang;
		$queryStr .=    'AND se_deleted = false ';		// 削除されていない

		// 検索条件
		if (!empty($startDt)){
			$queryStr .=    'AND ? <= se_regist_dt ';
			$params[] = $startDt;
		}
		if (!empty($endDt)){
			$queryStr .=    'AND se_regist_dt < ? ';
			$params[] = $endDt;
		}
		if (!empty($category)){
			$queryStr .=    'AND se_category_id = ? ';
			$params[] = $category;		// カテゴリー
		}
		
		$queryStr .=  'ORDER BY se_root_id desc, se_sort_order limit ' . $limit . ' offset ' . $offset;
		$this->selectLoop($queryStr, $params, $callback, null);
	}
	/**
	 * 投稿項目数を取得(管理用)
	 *
	 * @param int		$limit				取得する項目数
	 * @param int		$offset				取得する先頭位置(0～)
	 * @param timestamp	$startDt			期間(開始日)
	 * @param timestamp	$endDt				期間(終了日)
	 * @param array		$category			カテゴリーID
	 * @param string	$keyword			検索キーワード
	 * @param string	$lang				言語
	 * @param function	$callback			コールバック関数
	 * @return 			なし
	 */
	function getEntryItemCount($startDt, $endDt, $category, $keyword, $lang)
	{
		$params = array();
		$queryStr = 'SELECT * FROM bbs_thread LEFT JOIN _login_user ON se_regist_user_id = lu_id AND lu_deleted = false ';
		$queryStr .=  'WHERE se_language_id = ? '; $params[] = $lang;
		$queryStr .=    'AND se_deleted = false ';		// 削除されていない
		
		// 検索条件
		if (!empty($startDt)){
			$queryStr .=    'AND ? <= se_regist_dt ';
			$params[] = $startDt;
		}
		if (!empty($endDt)){
			$queryStr .=    'AND se_regist_dt < ? ';
			$params[] = $endDt;
		}
		if (!empty($category)){
			$queryStr .=    'AND se_category_id = ? ';
			$params[] = $category;		// カテゴリー
		}
		
		return $this->selectRecordCount($queryStr, $params);
	}
	/**
	 * エントリー項目を検索
	 *
	 * @param int		$limit				取得する項目数
	 * @param int		$page				取得するページ(1～)
	 * @param string	$keyword			検索キーワード
	 * @param string	$lang				言語
	 * @param function	$callback			コールバック関数
	 * @return 			なし
	 */
	function searchEntryItemsByKeyword($limit, $page, $keyword, $lang, $callback)
	{
		$offset = $limit * ($page -1);
		if ($offset < 0) $offset = 0;
		
		$params = array();
		$queryStr = 'SELECT * FROM bbs_thread LEFT JOIN _login_user ON se_regist_user_id = lu_id AND lu_deleted = false ';
		$queryStr .=  'WHERE se_language_id = ? '; $params[] = $lang;
		$queryStr .=    'AND se_deleted = false ';		// 削除されていない

		// タイトルと記事を検索
		if (!empty($keyword)){
			$queryStr .=    'AND (se_name LIKE \'%' . $keyword . '%\' ';
			$queryStr .=    'OR se_html LIKE \'%' . $keyword . '%\') ';
		}
		
		$queryStr .=  'ORDER BY se_regist_dt desc limit ' . $limit . ' offset ' . $offset;
		$this->selectLoop($queryStr, $params, $callback, null);
	}
	
	/**
	 * エントリー項目の新規追加
	 *
	 * @param string  $id			エントリーID
	 * @param string  $lang			言語ID
	 * @param string  $name			コンテンツ名
	 * @param string  $html			HTML
	 * @param int     $status		スレッド状態(0=未設定、1=保留、2=表示、3=非表示)
	 * @param bool    $closed		終了状態
	 * @param string  $category		カテゴリーID
	 * @param int     $regUserId	投稿者ユーザID
	 * @param timestamp $regDt		投稿日時
	 * @param int     $userId		更新者ユーザID
	 * @param int     $newSerial	新規シリアル番号
	 * @return bool					true = 成功、false = 失敗
	 */
	 /*
	function addEntryItem($id, $lang, $name, $html, $status, $closed, $category, $regUserId, $regDt, $userId, &$newSerial)
	{
		$now = date("Y/m/d H:i:s");	// 現在日時
			
		// トランザクション開始
		$this->startTransaction();
		
		if ($id == 0){		// エントリーIDが0のときは、エントリーIDを新規取得
			// エントリーIDを決定する
			$queryStr = 'select max(se_id) as mid from bbs_thread ';
			$ret = $this->selectRecord($queryStr, array(), $row);
			if ($ret){
				$entryId = $row['mid'] + 1;
			} else {
				$entryId = 1;
			}
		} else {
			$entryId = $id;
		}
		
		// 前レコードの削除状態チェック
		$historyIndex = 0;
		$queryStr = 'SELECT * FROM bbs_thread ';
		$queryStr .=  'WHERE se_id = ? ';
		$queryStr .=    'AND se_language_id = ? ';
		$queryStr .=  'ORDER BY se_history_index DESC ';
		$ret = $this->selectRecord($queryStr, array($entryId, $lang), $row);
		if ($ret){
			if (!$row['se_deleted']){		// レコード存在していれば終了
				$this->endTransaction();
				return false;
			}
			$historyIndex = $row['se_history_index'] + 1;
		}
		
		// データを追加
		$queryStr = 'INSERT INTO bbs_thread ';
		$queryStr .=  '(se_id, se_language_id, se_history_index, se_name, se_html, se_root_id, se_status, se_closed, se_category_id, se_regist_user_id, se_regist_dt, se_create_user_id, se_create_dt) ';
		$queryStr .=  'VALUES ';
		$queryStr .=  '(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)';
		$this->execStatement($queryStr, array($entryId, $lang, $historyIndex, $name, $html, $entryId, $status, $closed, $category, $regUserId, $regDt, $userId, $now));
		
		// 新規のシリアル番号取得
		$queryStr = 'select max(se_serial) as ns from bbs_thread ';
		$ret = $this->selectRecord($queryStr, array(), $row);
		if ($ret) $newSerial = $row['ns'];
			
		// トランザクション確定
		$ret = $this->endTransaction();
		return $ret;
	}*/
	/**
	 * スレッド項目の更新
	 *
	 * @param int     $serial		シリアル番号
	 * @param string  $name			タイトル
	 * @param string  $html			HTML
	 * @param int     $status		スレッド状態(0=未設定、1=保留、2=表示、3=非表示)
	 * @param bool    $closed		終了状態
	 * @param string  $category		カテゴリーID
	 * @param int     $regUserId	投稿者ユーザID(0のときは更新しない)
	 * @param timestamp $regDt		投稿日時(空のときは更新しない)
	 * @param int     $userId		更新者ユーザID
	 * @param int     $newSerial	新規シリアル番号
	 * @return bool					true = 成功、false = 失敗
	 */
	function updateThreadItem($serial, $name, $html, $status, $closed, $category, $regUserId, $regDt, $userId, &$newSerial)
	{	
		$now = date("Y/m/d H:i:s");	// 現在日時
				
		// トランザクション開始
		$this->startTransaction();
		
		// 指定のシリアルNoのレコードが削除状態でないかチェック
		$historyIndex = 0;		// 履歴番号
		$queryStr  = 'select * from bbs_thread ';
		$queryStr .=   'where se_serial = ? ';
		$ret = $this->selectRecord($queryStr, array($serial), $row);
		if ($ret){		// 既に登録レコードがあるとき
			if ($row['se_deleted']){		// レコードが削除されていれば終了
				$this->endTransaction();
				return false;
			}
			$historyIndex = $row['se_history_index'] + 1;
		} else {		// 存在しない場合は終了
			$this->endTransaction();
			return false;
		}
		// 古いレコードを削除
		$queryStr  = 'UPDATE bbs_thread ';
		$queryStr .=   'SET se_deleted = true, ';	// 削除
		$queryStr .=     'se_update_user_id = ?, ';
		$queryStr .=     'se_update_dt = ? ';
		$queryStr .=   'WHERE se_serial = ?';
		$this->execStatement($queryStr, array($userId, $now, $serial));
		
		// データを追加
		if (empty($regUserId)){
			$rUserId = $row['se_regist_user_id'];
		} else {
			$rUserId = $regUserId;
		}
		if (empty($regDt)){
			$rDt = $row['se_regist_dt'];
		} else {
			$rDt = $regDt;
		}

		// 新規レコード追加		
		$queryStr = 'INSERT INTO bbs_thread ';
		$queryStr .=  '(se_id, ';
		$queryStr .=  'se_language_id, ';
		$queryStr .=  'se_history_index, ';
		$queryStr .=  'se_name, se_html, ';
		$queryStr .=  'se_status, ';
		$queryStr .=  'se_closed, ';
		$queryStr .=  'se_level, ';
		$queryStr .=  'se_max_sort_order, ';
		$queryStr .=  'se_root_id, ';
		$queryStr .=  'se_parent_id, ';
		$queryStr .=  'se_sort_order, ';
		$queryStr .=  'se_category_id, ';
		$queryStr .=  'se_regist_user_id, ';
		$queryStr .=  'se_regist_dt, ';
		$queryStr .=  'se_log_serial, ';
		$queryStr .=  'se_create_user_id, ';
		$queryStr .=  'se_create_dt) ';
		$queryStr .=  'VALUES ';
		$queryStr .=  '(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)';
		$this->execStatement($queryStr, array($row['se_id'], $row['se_language_id'], $historyIndex, $name, $html, $status, $closed, 
		$row['se_level'], $row['se_max_sort_order'], $row['se_root_id'], $row['se_parent_id'], $row['se_sort_order'],
		$category, $rUserId, $rDt, $row['se_log_serial'], $userId, $now));

		// 新規のシリアル番号取得
		$queryStr = 'select max(se_serial) as ns from bbs_thread ';
		$ret = $this->selectRecord($queryStr, array(), $row);
		if ($ret) $newSerial = $row['ns'];
		
		// トランザクション確定
		$ret = $this->endTransaction();
		return $ret;
	}

	/**
	 * エントリー項目をシリアル番号で取得
	 *
	 * @param string	$serial				シリアル番号
	 * @param array     $row				レコード
	 * @return bool							取得 = true, 取得なし= false
	 */
	function getEntryBySerial($serial, &$row)
	{
		$queryStr  = 'select *,reg.lu_name as reg_user_name from bbs_thread LEFT JOIN _login_user ON se_create_user_id = lu_id AND lu_deleted = false ';
		$queryStr .=   'LEFT JOIN _login_user as reg ON se_regist_user_id = reg.lu_id AND reg.lu_deleted = false ';
		$queryStr .=   'WHERE se_serial = ? ';
		$ret = $this->selectRecord($queryStr, array($serial), $row);
		return $ret;
	}
	/**
	 * エントリー項目のシリアル番号をエントリーIDで取得
	 *
	 * @param string	$id					エントリーID
	 * @param string	$langId				言語ID
	 * @return int							シリアル番号、取得できないときは0を返す
	 */
	function getEntrySerialNoById($id, $langId)
	{
		$serial = 0;
		$queryStr  = 'SELECT * FROM bbs_thread ';
		$queryStr .=   'WHERE se_deleted = false ';	// 削除されていない
		$queryStr .=   'AND se_id = ? ';
		$queryStr .=   'AND se_language_id = ? ';
		$ret = $this->selectRecord($queryStr, array($id, $langId), $row);
		if ($ret) $serial = $row['se_serial'];
		return $serial;
	}
	/**
	 * エントリー項目の削除
	 *
	 * @param int $serialNo			シリアルNo
	 * @param int $userId			ユーザID(データ更新者)
	 * @return						true=成功、false=失敗
	 */
	function delEntryItem($serialNo, $userId)
	{
		// トランザクション開始
		$this->startTransaction();
		
		// 指定のシリアルNoのレコードが削除状態でないかチェック
		$queryStr  = 'select * from bbs_thread ';
		$queryStr .=   'where se_deleted = false ';		// 未削除
		$queryStr .=     'and se_serial = ? ';
		$ret = $this->isRecordExists($queryStr, array($serialNo));
		// 存在しない場合は、既に削除されたとして終了
		if (!$ret){
			$this->endTransaction();
			return false;
		}
		
		// レコードを削除
		$queryStr  = 'UPDATE bbs_thread ';
		$queryStr .=   'SET se_deleted = true, ';	// 削除
		$queryStr .=     'se_update_user_id = ?, ';
		$queryStr .=     'se_update_dt = now() ';
		$queryStr .=   'WHERE se_serial = ?';
		$this->execStatement($queryStr, array($userId, $serialNo));
		
		// トランザクション確定
		$ret = $this->endTransaction();
		return $ret;
	}
	/**
	 * エントリーIDでエントリー項目を削除
	 *
	 * @param int $serial			シリアルNo
	 * @param int $userId			ユーザID(データ更新者)
	 * @return						true=成功、false=失敗
	 */
	function delEntryItemById($serial, $userId)
	{
		// トランザクション開始
		$this->startTransaction();
		
		// コンテンツIDを取得
		$queryStr  = 'select * from bbs_thread ';
		$queryStr .=   'where se_deleted = false ';		// 未削除
		$queryStr .=     'and se_serial = ? ';
		$ret = $this->selectRecord($queryStr, array($serial), $row);
		if ($ret){		// 既に登録レコードがあるとき
			if ($row['se_deleted']){		// レコードが削除されていれば終了
				$this->endTransaction();
				return false;
			}
		} else {		// 存在しない場合は終了
			$this->endTransaction();
			return false;
		}
		$entryId = $row['se_id'];
		
		// レコードを削除
		$queryStr  = 'UPDATE bbs_thread ';
		$queryStr .=   'SET se_deleted = true, ';	// 削除
		$queryStr .=     'se_update_user_id = ?, ';
		$queryStr .=     'se_update_dt = now() ';
		$queryStr .=   'WHERE se_id = ?';
		$this->execStatement($queryStr, array($userId, $entryId));
		
		// トランザクション確定
		$ret = $this->endTransaction();
		return $ret;
	}		
	/**
	 * 投稿項目一覧を取得(表示用)
	 *
	 * @param int		$limit				取得する項目数
	 * @param int		$page				取得するページ(1～)
	 * @param string		$category			カテゴリーID
	 * @param string	$lang				言語
	 * @param function	$callback			コールバック関数
	 * @return 			なし
	 */
	function getThreadList($limit, $page, $category, $lang, $callback)
	{
		$offset = $limit * ($page -1);
		if ($offset < 0) $offset = 0;
		
		$params = array();
		$queryStr = 'SELECT * FROM bbs_thread LEFT JOIN bbs_member ON se_regist_user_id = sv_login_user_id AND sv_deleted = false ';
		$queryStr .=  'WHERE se_language_id = ? '; $params[] = $lang;
		$queryStr .=    'AND se_deleted = false ';		// 削除されていない
		$queryStr .=    'AND se_status = 2 ';		// 表示する項目
		$queryStr .=    'AND se_parent_id = 0 ';		// トップ項目
		if (!empty($category)){
			$queryStr .=    'AND se_category_id = ? ';
			$params[] = $category;		// カテゴリー
		}
		
		$queryStr .=  'ORDER BY se_root_id desc limit ' . $limit . ' offset ' . $offset;
		$this->selectLoop($queryStr, $params, $callback, null);
	}
	/**
	 * 投稿項目数を取得(表示用)
	 *
	 * @param string		$category			カテゴリーID
	 * @param string	$lang				言語
	 * @return 			なし
	 */
	function getThreadCount($category, $lang)
	{
		$params = array();
		$queryStr = 'SELECT * FROM bbs_thread LEFT JOIN bbs_member ON se_regist_user_id = sv_login_user_id AND sv_deleted = false ';
		$queryStr .=  'WHERE se_language_id = ? '; $params[] = $lang;
		$queryStr .=    'AND se_deleted = false ';		// 削除されていない
		$queryStr .=    'AND se_status = 2 ';		// 表示する項目
		$queryStr .=    'AND se_parent_id = 0 ';		// トップ項目
		if (!empty($category)){
			$queryStr .=    'AND se_category_id = ? ';
			$params[] = $category;		// カテゴリー
		}
		
		return $this->selectRecordCount($queryStr, $params);
	}
	/**
	 * 参照数を取得(表示用)
	 *
	 * @param string	$threadId			カテゴリーID
	 * @param string	$lang				言語
	 * @return int							参照数
	 */
	function getThreadViewCount($threadId, $lang)
	{
		$queryStr = 'SELECT SUM(su_count) as sm FROM bbs_view_count ';
		$queryStr .=  'WHERE su_thread_id = ? ';
		$queryStr .=    'AND su_language_id = ? ';		// トップ項目
		$ret = $this->selectRecord($queryStr, array($threadId, $lang), $row);
		if ($ret){
			return $row['sm'];
		} else {
			return 0;
		}
	}
	/**
	 * 投稿項目一覧を取得(表示用)
	 *
	 * @param int		$limit				取得する項目数
	 * @param int		$page				取得するページ(1～)
	 * @param string		$thread				スレッドID
	 * @param string	$lang				言語
	 * @param function	$callback			コールバック関数
	 * @return 			なし
	 */
	function getThreadDetailList($limit, $page, $thread, $lang, $callback)
	{
		$offset = $limit * ($page -1);
		if ($offset < 0) $offset = 0;
		
		$params = array();
		$queryStr = 'SELECT * FROM bbs_thread LEFT JOIN bbs_member ON se_regist_user_id = sv_login_user_id AND sv_deleted = false ';
		$queryStr .=  'WHERE se_language_id = ? '; $params[] = $lang;
		$queryStr .=    'AND se_root_id = ? '; $params[] = $thread;
		$queryStr .=    'AND se_deleted = false ';		// 削除されていない
		$queryStr .=    'AND se_status = 2 ';		// 表示する項目
		
		$queryStr .=  'ORDER BY se_sort_order limit ' . $limit . ' offset ' . $offset;
		$this->selectLoop($queryStr, $params, $callback, null);
	}
	/**
	 * 投稿項目数を取得(表示用)
	 *
	 * @param string		$thread				スレッドID
	 * @param string	$lang				言語
	 * @return 			なし
	 */
	function getThreadDetailCount($thread, $lang)
	{
		$params = array();
		$queryStr = 'SELECT * FROM bbs_thread LEFT JOIN bbs_member ON se_regist_user_id = sv_login_user_id AND sv_deleted = false ';
		$queryStr .=  'WHERE se_language_id = ? '; $params[] = $lang;
		$queryStr .=    'AND se_root_id = ? '; $params[] = $thread;
		$queryStr .=    'AND se_deleted = false ';		// 削除されていない
		$queryStr .=    'AND se_status = 2 ';		// 表示する項目
		
		return $this->selectRecordCount($queryStr, $params);
	}
	/**
	 * スレッド情報を取得
	 *
	 * @param string	$thread				スレッドID
	 * @param string	$lang				言語ID
	 * @param array     $row				レコード
	 * @return bool							取得 = true, 取得なし= false
	 */
	function getThreadById($thread, $lang, &$row)
	{
		$queryStr = 'SELECT * FROM bbs_thread ';
		$queryStr .=  'WHERE se_deleted = false ';		// 削除されていない
		$queryStr .=    'AND se_id = ? ';
		$queryStr .=    'AND se_language_id = ? ';
		$ret = $this->selectRecord($queryStr, array($thread, $lang), $row);
		return $ret;
	}
	/**
	 * スレッドのの新規追加
	 *
	 * @param string  $id			新規のときは0
	 * @param string  $langId			言語ID
	 * @param string  $parentId		親ID(親なしのときは0)
	 * @param string  $name			タイトル名
	 * @param string  $html			HTML
	 * @param string  $category		カテゴリーID	 
	 * @param int     $logSerial	アクセスログシリアル番号
	 * @param int     $regUserId	投稿者ユーザID
	 * @param timestamp $regDt		投稿日時
	 * @param int     $userId		更新者ユーザID
	 * @param int     $newSerial	新規シリアル番号
	 * @return bool					true = 成功、false = 失敗
	 */
	function addNewThread($id, $langId, $parentId, $name, $html, $category, $logSerial, $regUserId, $regDt, $userId, &$newSerial)
	{
		$now = date("Y/m/d H:i:s");	// 現在日時
			
		// トランザクション開始
		$this->startTransaction();
		
		if ($id == 0){		// エントリーIDが0のときは、エントリーIDを新規取得
			// エントリーIDを決定する
			$queryStr = 'select max(se_id) as mid from bbs_thread ';
			$ret = $this->selectRecord($queryStr, array(), $row);
			if ($ret){
				$threadId = $row['mid'] + 1;
			} else {
				$threadId = 1;
			}
		} else {
			$threadId = $id;
		}

		// 親スレッドを取得
		if ($parentId == 0){		// スレッドIDが0のとき
			// 新規にスレッドを起こす
			$queryStr = 'INSERT INTO bbs_thread ';
			$queryStr .=  '(se_id, ';
			$queryStr .=  'se_language_id, ';
			$queryStr .=  'se_name, ';
			$queryStr .=  'se_html, ';
			$queryStr .=  'se_root_id, ';
			$queryStr .=  'se_status, ';
			$queryStr .=  'se_category_id, ';
			$queryStr .=  'se_regist_user_id, ';
			$queryStr .=  'se_regist_dt, ';
			$queryStr .=  'se_log_serial, ';
			$queryStr .=  'se_create_user_id, ';
			$queryStr .=  'se_create_dt) ';
			$queryStr .=  'VALUES ';
			$queryStr .=  '(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)';
			$this->execStatement($queryStr, array($threadId, $langId, $name, $html, $threadId, 2/*公開状態*/, $category, $regUserId, $regDt, $logSerial, $userId, $now));
		} else {
			$queryStr  = 'SELECT * FROM bbs_thread ';
			$queryStr .=   'WHERE se_deleted = false ';	// 削除されていない
			$queryStr .=   'AND se_id = ? ';
			$queryStr .=   'AND se_language_id = ? ';
			$ret = $this->selectRecord($queryStr, array($parentId, $langId), $row);
			if (!$ret){		// 見つからないときは終了
				$this->endTransaction();
				return false;
			}
			$rootId = $row['se_root_id'];
			$parentSerial = $row['se_serial'];

			// 階層レベルを求める
			$level = 1;
			$pId = $row['se_parent_id'];
			for ($i = 0; $i < self::MAX_LOOP_COUNT; $i++){
				if ($pId == 0) break;
				$queryStr  = 'SELECT * FROM bbs_thread ';
				$queryStr .=   'WHERE se_deleted = false ';	// 削除されていない
				$queryStr .=   'AND se_id = ? ';
				$queryStr .=   'AND se_language_id = ? ';
				$ret = $this->selectRecord($queryStr, array($pId, $langId), $pRow);
				if (!$ret){		// 見つからないときは終了
					$this->endTransaction();
					return false;
				}
				$pId = $pRow['se_parent_id'];
				$level++;
			}
			if ($i == self::MAX_LOOP_COUNT){		// ループ最大を超えた場合はエラー
				$this->endTransaction();
				return false;
			}
			
			// ルートスレッドを取得
			$queryStr  = 'SELECT * FROM bbs_thread ';
			$queryStr .=   'WHERE se_deleted = false ';	// 削除されていない
			$queryStr .=   'AND se_id = ? ';
			$queryStr .=   'AND se_language_id = ? ';
			$ret = $this->selectRecord($queryStr, array($rootId, $langId), $rootRow);
			if (!$ret){		// 見つからないときは終了
				$this->endTransaction();
				return false;
			}
			$rootSerial = $rootRow['se_serial'];		// ルートのシリアル番号

			// ソート順を更新
			$queryStr  = 'SELECT se_serial FROM bbs_thread ';
			$queryStr .=   'WHERE se_deleted = false ';	// 削除されていない
			$queryStr .=   'AND se_root_id = ? ';
			$queryStr .=   'AND se_language_id = ? ';
			$queryStr .=   'ORDER BY se_sort_order';
			$ret = $this->selectRecords($queryStr, array($rootId, $langId), $groupRows);
			if (!$ret){		// 見つからないときは終了
				$this->endTransaction();
				return false;
			}

			$insertOrder = -1;		// 追加する場所
			for ($i = 0; $i < count($groupRows); $i++){
				$serial = $groupRows[$i]['se_serial'];
				if ($serial == $parentSerial){
					$queryStr  = 'UPDATE bbs_thread ';
					$queryStr .=   'SET se_sort_order = ? ';	// 更新
					$queryStr .=   'WHERE se_serial = ?';
					$this->execStatement($queryStr, array($i, $serial));
					$i++;
					$insertOrder = $i;
					break;
				} else {
					$queryStr  = 'UPDATE bbs_thread ';
					$queryStr .=   'SET se_sort_order = ? ';	// 更新
					$queryStr .=   'WHERE se_serial = ?';
					$this->execStatement($queryStr, array($i, $serial));
				}
			}

			// 親スレッド以降のソート順を更新
			for (; $i < count($groupRows); $i++){
				$serial = $groupRows[$i]['se_serial'];
				$queryStr  = 'UPDATE bbs_thread ';
				$queryStr .=   'SET se_sort_order = ? ';	// 更新
				$queryStr .=   'WHERE se_serial = ?';
				$this->execStatement($queryStr, array($i + 1, $serial));			
			}
			if ($insertOrder == -1){		// エラーの場合は終了
				$this->endTransaction();
				return false;
			}
			// スレッドを追加
			$queryStr = 'INSERT INTO bbs_thread ';
			$queryStr .=  '(se_id, ';
			$queryStr .=  'se_language_id, ';
			$queryStr .=  'se_name, ';
			$queryStr .=  'se_html, ';
			$queryStr .=  'se_level, ';
			$queryStr .=  'se_root_id, ';
			$queryStr .=  'se_parent_id, ';
			$queryStr .=  'se_sort_order, ';
			$queryStr .=  'se_status, ';
			$queryStr .=  'se_category_id, ';
			$queryStr .=  'se_regist_user_id, ';
			$queryStr .=  'se_regist_dt, ';
			$queryStr .=  'se_log_serial, ';
			$queryStr .=  'se_create_user_id, ';
			$queryStr .=  'se_create_dt) ';
			$queryStr .=  'VALUES ';
			$queryStr .=  '(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)';
			$this->execStatement($queryStr, array($threadId, $langId, $name, $html, $level, $rootId, $parentId, $insertOrder, 2/*公開状態*/, $category, $regUserId, $regDt, $logSerial, $userId, $now));			
			
			// ルートスレッドの最大ソート順を更新
			$queryStr  = 'UPDATE bbs_thread ';
			$queryStr .=   'SET se_max_sort_order = ? ';	// 最大ソート順
			$queryStr .=   'WHERE se_serial = ?';
			$this->execStatement($queryStr, array(count($groupRows), $rootSerial));
		}
		// 新規のシリアル番号取得
		$queryStr = 'select max(se_serial) as ns from bbs_thread ';
		$ret = $this->selectRecord($queryStr, array(), $row);
		if ($ret) $newSerial = $row['ns'];
		
		// トランザクション確定
		$ret = $this->endTransaction();
		return $ret;
	}
	/**
	 * スレッドのビューカウントを更新
	 *
	 * @param string	$thread				スレッドID
	 * @param string	$lang				言語ID
	 * @param string	$day				日にち
	 * @param int		$hour				時間
	 * @return bool							true=成功, false=失敗
	 */
	function updateViewCount($thread, $lang, $day = null, $hour = null)
	{
		// 現在日時を取得
		if (is_null($day)) $day = date("Y/m/d");		// 日
		if (is_null($hour)) $hour = (int)date("H");		// 時間
		
		// トランザクション開始
		$this->startTransaction();
		
		// 既にレコードが作成されている場合はレコードを更新
		$queryStr  = 'SELECT * FROM bbs_view_count ';
		$queryStr .=   'WHERE su_thread_id = ? ';
		$queryStr .=     'AND su_language_id = ? ';
		$queryStr .=     'AND su_date = ? ';
		$queryStr .=     'AND su_hour = ? ';
		$ret = $this->selectRecord($queryStr, array($thread, $lang, $day, $hour), $row);
		if ($ret){
			$count = $row['su_count'];
			$count++;		// カウント数を更新
			$queryStr = 'UPDATE bbs_view_count ';
			$queryStr .=  'SET su_count = ? ';
			$queryStr .=  'WHERE su_serial = ? ';
			$this->execStatement($queryStr, array($count, $row['su_serial']));
		} else {
			$queryStr = 'INSERT INTO bbs_view_count ';
			$queryStr .=  '(su_thread_id, su_language_id, su_date, su_hour, su_count) ';
			$queryStr .=  'VALUES ';
			$queryStr .=  '(?, ?, ?, ?, ?)';
			$this->execStatement($queryStr, array($thread, $lang, $day, $hour, 1));
		}
		// トランザクション確定
		$ret = $this->endTransaction();
		return $ret;
	}
}
?>
