<?php

require_once dirname(__FILE__) . '/../../../../../include/chatengine/chatengine.php';
require_once CHEN_DIR.'/chatroom_class.php';
require_once CHEN_DIR.'/chatuser_class.php';
require_once CHEN_DIR.'/../room_class.php';
require_once CHEN_DIR.'/../user_class.php';
require_once CHEN_DIR.'/transaction.php';
require_once CHEN_DIR.'/transaction/add_room.php';
require_once CHEN_DIR.'/transaction/add_user.php';

$_SERVER['REMOTE_ADDR'] = '127.0.0.1';
session_start();

/**
 * Test class for ChatEngine.
 * Generated by PHPUnit on 2010-12-12 at 04:10:03.
 */
class ChatEngineTest extends PHPUnit_Framework_TestCase {

	/**
	 * @var ChatEngine
	 */
	protected $object;

	/**
	 * Sets up the fixture, for example, opens a network connection.
	 * This method is called before a test is executed.
	 */
	protected function setUp() {
		$this->object = new ChatEngine('localhost', 'jinrou', 'grayran', 'satorituri');
        $this->object->beginTransaction();
	}

	/**
	 * Tears down the fixture, for example, closes a network connection.
	 * This method is called after a test is executed.
	 */
	protected function tearDown() {
      $this->object->rollBack();
	}

	protected final function validateColumn($column, $type, $null = false, $key = null, $default = null, $extra=null) {
		$this->assertNotNull($column);
		$this->assertEquals($type, $column['Type']);
		$this->assertEquals($null ? 'YES' : 'NO', $column['Null']);
		$this->assertEquals(isset($key) ? $key : '', $column['Key']);
		$this->assertEquals(isset($default) ? $default : '', $column['Default']);
		$this->assertEquals(isset($extra) ? $extra : '', $column['Extra']);
	}

	/**
	 */
	public function testCreateRoomsTable() {
		$result = $this->object->CreateRoomsTable();
		$this->assertTrue($result);
		//テーブル構造の検証
		$stmt = $this->object->query('SHOW COLUMNS FROM jinrou_rooms');
		$this->assertNotSame(false, $stmt, print_r($this->object->errorInfo(), true));
		foreach($stmt->fetchAll(PDO::FETCH_ASSOC) as $column) {
			$field = $column['Field'];
			$$field = $column;
		}
		$this->validateColumn($id, 'int(11)', false, 'PRI', null, 'auto_increment');
		$this->validateColumn($name, 'varchar(255)');
		$this->validateColumn($comment, 'varchar(255)');
		$this->validateColumn($is_active, 'tinyint(4)', false, null, '1');
		$this->validateColumn($internal_time, 'int(11)', false, null, '0');
		$this->validateColumn($max_users, 'tinyint(4)');
		$this->validateColumn($builder_ip, 'varchar(50)');
		$this->validateColumn($game_option, 'text');
		$this->validateColumn($option_role, 'text');
		$this->validateColumn($built_time, 'datetime');
		$this->validateColumn($last_updated_time, 'timestamp', false, null, 'CURRENT_TIMESTAMP', 'on update CURRENT_TIMESTAMP');
	}

	/**
	 */
	public function testCreateTalkTable() {
		$result = $this->object->CreateTalkTable();
		$this->assertTrue($result);
		//テーブル構造の検証
		$stmt = $this->object->query('SHOW COLUMNS FROM jinrou_talk');
		$this->assertNotSame(false, $stmt, print_r($this->object->errorInfo(), true));
		foreach($stmt->fetchAll(PDO::FETCH_ASSOC) as $column) {
			$field = $column['Field'];
			$$field = $column;
		}
		$this->validateColumn($id, 'bigint(20)', false, 'PRI', null, 'auto_increment');
		$this->validateColumn($room, 'int(11)');
		$this->validateColumn($player, 'int(11)');
		$this->validateColumn($internal_time, 'int(11)', false, 'MUL');
		$this->validateColumn($posted_time, 'timestamp', false, null, 'CURRENT_TIMESTAMP');
		$this->validateColumn($channel, 'char(10)');
		$this->validateColumn($type, 'char(10)');
		$this->validateColumn($volume, 'varchar(50)');
		$this->validateColumn($sentence, 'text');
	}

    public function testCreateIndicatorTable() {
    	$result = $this->object->CreateIndicatorTable();
		$this->assertTrue($result);
		//テーブル構造の検証
		$stmt = $this->object->query('SHOW COLUMNS FROM jinrou_indicator');
		$this->assertNotSame(false, $stmt, print_r($this->object->errorInfo(), true));
		foreach($stmt->fetchAll(PDO::FETCH_ASSOC) as $column) {
			$field = $column['Field'];
			$$field = $column;
		}
		$this->validateColumn($id, 'bigint(20)', false, 'PRI', null, 'auto_increment');
		$this->validateColumn($room, 'int(11)');
		$this->validateColumn($internal_time, 'int(11)', false, 'MUL');
		$this->validateColumn($posted_time, 'timestamp', false, null, 'CURRENT_TIMESTAMP');
		$this->validateColumn($channel, 'char(10)');
		$this->validateColumn($type, 'char(10)');
		$this->validateColumn($sentence, 'text');
    }

	/**
	 */
	public function testCreateUserTable() {
		$result = $this->object->CreateUserTable();
		$this->assertTrue($result);
		//テーブル構造の検証
		$stmt = $this->object->query('SHOW COLUMNS FROM jinrou_users');
		$this->assertNotSame(false, $stmt, print_r($this->object->errorInfo(), true));
		foreach($stmt->fetchAll(PDO::FETCH_ASSOC) as $column) {
			$field = $column['Field'];
			$$field = $column;
		}
		$this->validateColumn($id, 'int(11)', false, 'PRI', null, 'auto_increment');
		$this->validateColumn($room, 'int(11)', false, 'MUL');
		$this->validateColumn($uname, 'varchar(50)');
		$this->validateColumn($passwd, 'char(32)');
		$this->validateColumn($enabled, 'tinyint(4)', false, null, '1');
		$this->validateColumn($session_id, 'char(32)', false, 'UNI');
		$this->validateColumn($ip_address, 'varchar(50)');
	}

	/**
	 */
	public function testCreatePlayerTable() {
		$result = $this->object->CreatePlayerTable();
		$this->assertTrue($result);
		//テーブル構造の検証
		$stmt = $this->object->query('SHOW COLUMNS FROM jinrou_players');
		$this->assertNotSame(false, $stmt, print_r($this->object->errorInfo(), true));
		foreach($stmt->fetchAll(PDO::FETCH_ASSOC) as $column) {
			$field = $column['Field'];
			$$field = $column;
		}
		$this->validateColumn($id, 'bigint(20)', false, 'PRI', null, 'auto_increment');
		$this->validateColumn($created_time, 'datetime');
		$this->validateColumn($user, 'int(11)', false, 'MUL');
		$this->validateColumn($user_no, 'tinyint(4)');
		$this->validateColumn($handle_name, 'varchar(50)');
		$this->validateColumn($profile, 'text');
		$this->validateColumn($last_words, 'text', true);
		$this->validateColumn($sex, "enum('male','female')");
		$this->validateColumn($live, "enum('live','dead','drop','kick')", false, null, 'live');
		$this->validateColumn($role, 'text');
		$this->validateColumn($icon_no, 'int(11)');
	}

	private function validateOpenedRoom($opened, $room, $uid, $loginExpected) {
		$this->assertEquals($room->name, $opened->name);
		$this->assertEquals($room->comment, $opened->comment);
		$this->assertNotNull($opened->last_alarm_type, 'アラーム情報が正しく取得されませんでした');
		$this->assertNotNull($opened->last_alarm_time, 'アラーム情報が正しく取得されませんでした');
		$this->assertNotNull($opened->last_alarm_itime, 'アラーム情報が正しく取得されませんでした');
		$this->assertNotNull($opened->last_alarm_message, 'アラーム情報が正しく取得されませんでした');
        if ($loginExpected) {
			$this->assertEquals($uid, $opened->login_user);
			$this->assertType('Room', $opened);
        }
        else {
			$this->assertEquals(0, $opened->login_user);
			$this->assertType('ChatRoom', $opened);
        }
	}

	/**
	 * @dataProvider dp_testLogin
	 */
	public function testLogin($uname, $passwd, $testUname, $testPasswd, $loginExpected) {
        $add_room = new AddRoomTransaction();
        $room = $add_room->_CreateRoom($this->object, 'testOpenRoom', 'この部屋は自動テストツールによって生成されました', 17, '', '');
		$this->assertNotSame(false, $room, 'CreateRoom='.print_r($this->object->errorInfo(), true));
        $add_room->_AddAlarm($this->object, $room);
        $add_user = new AddUserTransaction();
		$uid = $add_user->_AddUser($this->object, $room->id, $uname, $passwd);
        $pid = $add_user->_AddPlayer($this->object, $uid, 2, $uname, $passwd, 'male', '', 1);
		$this->assertNotSame(false, $uid, 'Join='.print_r($this->object->errorInfo(), true));
		$result = $this->object->Login($room->id, $testUname, $testPasswd);
        $this->assertTrue($result, 'ログイン処理に失敗しました:'.print_r($this->object->errorInfo(), true));
        if ($loginExpected) {
        	$this->assertNotNull($this->object->currentUser, 'ログインに失敗しました'.$this->object->errorText());
			$this->validateOpenedRoom($this->object->currentRoom, $room, $uid, true);
        }
        else {
        	$this->assertNull($this->object->currentUser, 'ログインに失敗しませんでした');
			$this->validateOpenedRoom($this->object->currentRoom, $room, $uid, false);
        }
	}
	public static function dp_testLogin() {
		return array(
		    array('test','testpasswd','test','testpasswd',true),
		    array('test','testpasswd','test','testpasswwd',false),
		    array('test','testpasswd','tes','testpasswd',false),
		);
	}

	/**
	 * @todo Implement testReopenRoom().
	 */
	public function testAutoLogin() {
        $add_room = new AddRoomTransaction();
		$room = $add_room->_CreateRoom($this->object, 'testReopenRoom', 'この部屋は自動テストツールによって生成されました', 17, '', '');
		$this->assertNotSame(false, $room, 'CreateRoom='.$this->object->errorText());
        $add_room->_AddAlarm($this->object, $room);
        $add_user = new AddUserTransaction();
		$uid = $add_user->_AddUser($this->object, $room->id, 'test', 'testpasswd');
        $pid = $add_user->_AddPlayer($this->object, $uid, 2, 'テスト', 'testAutoLoginメソッド用のユーザーです', 'male', '', 1);
		$this->assertNotSame(false, $uid, 'Join='.$this->object->errorText());
		$result = $this->object->Login($room->id);
        $this->assertTrue($result, 'ログイン処理に失敗しました'.print_r($this->object->errorInfo(), true));
        $this->assertNotNull($this->object->currentUser, 'ログインに失敗しました'.$this->object->errorText());
		$this->validateOpenedRoom($this->object->currentRoom, $room, $uid, true);
		$this->object->exec("UPDATE jinrou_users SET session_id = MD5(session_id) WHERE id = {$uid}");
		$result = $this->object->Login($room->id);
        $this->assertTrue($result, 'ログイン処理に失敗しました'.print_r($this->object->errorInfo(), true));
        $this->assertNull($this->object->currentUser, 'ログインが失敗しませんでした');
		$this->validateOpenedRoom($this->object->currentRoom, $room, $uid, false);
	}

	public function testGetUsersById() {
        $add_room = new AddRoomTransaction();
		$room = $add_room->_CreateRoom($this->object, 'testOpenRoom', 'この部屋は自動テストツールによって生成されました', 17, '', '');
        $add_user = new AddUserTransaction();
		// Remove the following lines when you implement this test.
		$this->markTestIncomplete(
			'This test has not been implemented yet.'
		);
	}

	/**
	 * @todo Implement testGetActiveRooms().
	 */
	public function testGetActiveRooms() {
		// Remove the following lines when you implement this test.
		$this->markTestIncomplete(
			'This test has not been implemented yet.'
		);
	}

	/**
	 * @todo Implement testGetClosedRooms().
	 */
	public function testGetClosedRooms() {
		// Remove the following lines when you implement this test.
		$this->markTestIncomplete(
			'This test has not been implemented yet.'
		);
	}

}
