/*
 * @file        LevelMatching.cpp
 * @brief
 *
 * レベルによるマッチング処理
 *
 * Copyright MONOBIT Inc. All rights reserved.
 */

#include "./LevelMatching.hpp"

/**
 * コンストラクタ
 */
LevelMatching::LevelMatching()
{
}

/**
 * デストラクタ
 */
LevelMatching::~LevelMatching()
{
}

/**
 * ルームの新規作成
 * 
 * @info        所有者の入室も同時に行う
 * 
 * @param       createRoomInfo          ルーム作成情報
 * @param       pCreateTableInfo        テーブル作成情報
 * 
 * @return      trueなら成功、falseなら失敗
 */
bool LevelMatching::CreateRoom( CreateRoomInfo& createRoomInfo, CreateTableInfo* pCreateTableInfo )
{
        return MatchingBase::CreateRoom( createRoomInfo, pCreateTableInfo );
}

/**
 * ルームの検索
 * 
 * @param       level_min                       レベル最小値
 * @param       level_max                       レベル最大値
 * @param       searchRoomInfoList      検索用ルーム情報リスト
 * @param       limit                           最大数
 * @param       offset                          開始オフセット
 * 
 * @return      trueなら成功、falseなら失敗
 */
bool LevelMatching::SearchRoom( uint32 level_min, uint32 level_max, SearchRoomInfoList& searchRoomInfoList, uint32 limit, uint32 offset )
{
        do{
                std::string sql;
                SqlQueryInfo sqlInfo;
                
                searchRoomInfoList.clear();
                
                // ルームの検索
                sql =
"SELECT rooms.id, rooms.max_players, rooms.curt_players, rooms.created_time"
" FROM level_rooms, rooms"
" WHERE level_rooms.level >= ?1"
" AND level_rooms.level <= ?2"
" AND rooms.id = level_rooms.room_id"
" AND rooms.curt_players < rooms.max_players"
" AND rooms.curt_players > 0"
" ORDER BY rooms.created_time"
                + SQL::LIMIT( limit, offset );
                sqlInfo.SetQuery( sql );
                sqlInfo.SetParam( 1, level_min );
                sqlInfo.SetParam( 2, level_max );
                if ( ! m_DbAgent.ExecuteQuery( sqlInfo ) ){
                        DNALOG_ERR_D( "Error Query." );
                        break;
                }
                
                // ルームなし
                if ( ! sqlInfo.IsRow() ){
                        return true;
                }
                
                // データの取得
                do{
                        SearchRoomInfo info;
                        
                        sqlInfo.GetColumnData( 0, &info.roomInfo.room_id );
                        sqlInfo.GetColumnData( 1, &info.roomInfo.max_players );
                        sqlInfo.GetColumnData( 2, &info.roomInfo.curt_players );
                        
                        uint64 createdTime;
                        sqlInfo.GetColumnData( 3, &createdTime );
                        SQL::Time2Str( createdTime, info.roomInfo.created, sizeof( info.roomInfo.created ) );
                        
                        searchRoomInfoList.push_back( info );
                }while ( sqlInfo.Next() );
                
                return true;
        }while ( false );
        
        return false;
}

/**
 * テーブル作成クエリ
 * 
 * @return      trueなら成功、falseなら失敗
 */
bool LevelMatching::QueryCreateTable()
{
        do{
                std::string sql;
                
                // マッチング用テーブルの作成
                sql =
"CREATE TABLE level_rooms ("
"room_id INTEGER"
",level INTEGER"
")";
                if ( ! m_DbAgent.ExecuteQuery( sql ) ){
                        DNALOG_ERR_D( "Error Query." );
                        break;
                }
                
                // マッチング用テーブルインデックスの作成
                // (SQLiteの場合、インデックス名はデータベースレベルでユニークにする)
                sql =
"CREATE UNIQUE INDEX level_rooms_room_id ON level_rooms( room_id )";
                if ( ! m_DbAgent.ExecuteQuery( sql ) ){
                        DNALOG_ERR_D( "Error Query." );
                        break;
                }
                sql =
"CREATE INDEX level_rooms_level ON level_rooms( level )";
                if ( ! m_DbAgent.ExecuteQuery( sql ) ){
                        DNALOG_ERR_D( "Error Query." );
                        break;
                }
                
                return MatchingBase::QueryCreateTable();
        }while ( false );
        
        return false;
}

/**
 * ルーム作成クエリ
 *
 * @param       createRoomInfo  ルーム作成情報
 * @param       pArg                    汎用引数
 *
 * @return      trueなら成功、falseなら失敗
 */
bool LevelMatching::QueryCreateRoom( CreateRoomInfo& createRoomInfo, void* pArg )
{
        do{
                std::string sql;
                SqlQueryInfo sqlInfo;
                
                CreateTableInfo* pCreateTableInfo = (CreateTableInfo*)pArg;
                if ( NULL == pCreateTableInfo ) break;
                
                if ( ! MatchingBase::QueryCreateRoom( createRoomInfo, pCreateTableInfo ) ) break;
                
                // データの登録
                sql =
"INSERT INTO level_rooms ( room_id, level ) VALUES ( ?1, ?2 )";
                sqlInfo.SetQuery( sql );
                sqlInfo.SetParam( 1, createRoomInfo.room_id );
                sqlInfo.SetParam( 2, pCreateTableInfo->level );
                if ( ! m_DbAgent.ExecuteQuery( sqlInfo ) ){
                        DNALOG_ERR_D( "Error Query." );
                        break;
                }
                
                // 更新件数チェック
                if ( 1 != m_DbAgent.GetChangeNum() ){
                        DNALOG_ERR_D( "Not Changed." );
                        break;
                }
                
                return true;
        }while ( false );
        
        return false;
}

/**
 * ルームの削除クエリ
 * 
 * @param       roomId          ルームID
 * 
 * @return      trueなら成功、falseなら失敗
 */
bool LevelMatching::QueryDeleteRoom( uint64 roomId )
{
        do{
                std::string sql;
                SqlQueryInfo sqlInfo;
                
                // データの削除
                sql =
"DELETE FROM level_rooms WHERE room_id = ?1";
                sqlInfo.SetQuery( sql );
                sqlInfo.SetParam( 1, roomId );
                if ( ! m_DbAgent.ExecuteQuery( sqlInfo ) ){
                        DNALOG_ERR_D( "Error Query." );
                        break;
                }
                
                return MatchingBase::QueryDeleteRoom( roomId );
        }while ( false );
        
        return false;
}