<template>
<div class="root">
	<header><b>{{ blackUser.name }}</b>(黒) vs <b>{{ whiteUser.name }}</b>(白)</header>

	<div style="overflow: hidden">
		<p class="turn" v-if="!iAmPlayer && !game.isEnded">{{ '%i18n:common.reversi.turn-of%'.replace('{}', turnUser.name) }}<mk-ellipsis/></p>
		<p class="turn" v-if="logPos != logs.length">{{ '%i18n:common.reversi.past-turn-of%'.replace('{}', turnUser.name) }}</p>
		<p class="turn1" v-if="iAmPlayer && !game.isEnded && !isMyTurn">%i18n:common.reversi.opponent-turn%<mk-ellipsis/></p>
		<p class="turn2" v-if="iAmPlayer && !game.isEnded && isMyTurn" v-animate-css="{ classes: 'tada', iteration: 'infinite' }">%i18n:common.reversi.my-turn%</p>
		<p class="result" v-if="game.isEnded && logPos == logs.length">
			<template v-if="game.winner"><b>{{ game.winner.name }}</b>の勝ち{{ game.settings.isLlotheo ? ' (ロセオ)' : '' }}</template>
			<template v-else>%i18n:common.reversi.drawn%</template>
		</p>
	</div>

	<div class="board">
		<div class="labels-x" v-if="this.$store.state.settings.reversiBoardLabels">
			<span v-for="i in game.settings.map[0].length">{{ String.fromCharCode(64 + i) }}</span>
		</div>
		<div class="flex">
			<div class="labels-y" v-if="this.$store.state.settings.reversiBoardLabels">
				<div v-for="i in game.settings.map.length">{{ i }}</div>
			</div>
			<div class="cells" :style="cellsStyle">
				<div v-for="(stone, i) in o.board"
						:class="{ empty: stone == null, none: o.map[i] == 'null', isEnded: game.isEnded, myTurn: !game.isEnded && isMyTurn, can: turnUser ? o.canPut(turnUser.id == blackUser.id, i) : null, prev: o.prevPos == i }"
						@click="set(i)"
						:title="`${String.fromCharCode(65 + o.transformPosToXy(i)[0])}${o.transformPosToXy(i)[1] + 1}`">
					<img v-if="stone === true" :src="blackUser.avatarUrl" alt="">
					<img v-if="stone === false" :src="whiteUser.avatarUrl" alt="">
				</div>
			</div>
			<div class="labels-y" v-if="this.$store.state.settings.reversiBoardLabels">
				<div v-for="i in game.settings.map.length">{{ i }}</div>
			</div>
		</div>
		<div class="labels-x" v-if="this.$store.state.settings.reversiBoardLabels">
			<span v-for="i in game.settings.map[0].length">{{ String.fromCharCode(64 + i) }}</span>
		</div>
	</div>

	<p class="status"><b>{{ logPos }}ターン目</b> 黒:{{ o.blackCount }} 白:{{ o.whiteCount }} 合計:{{ o.blackCount + o.whiteCount }}</p>

	<div class="player" v-if="game.isEnded">
		<el-button-group>
			<el-button type="primary" @click="logPos = 0" :disabled="logPos == 0">%fa:angle-double-left%</el-button>
			<el-button type="primary" @click="logPos--" :disabled="logPos == 0">%fa:angle-left%</el-button>
		</el-button-group>
		<span>{{ logPos }} / {{ logs.length }}</span>
		<el-button-group>
			<el-button type="primary" @click="logPos++" :disabled="logPos == logs.length">%fa:angle-right%</el-button>
			<el-button type="primary" @click="logPos = logs.length" :disabled="logPos == logs.length">%fa:angle-double-right%</el-button>
		</el-button-group>
	</div>
</div>
</template>

<script lang="ts">
import Vue from 'vue';
import * as CRC32 from 'crc-32';
import Reversi, { Color } from '../../../../../../../games/reversi/core';
import { url } from '../../../../../config';

export default Vue.extend({
	props: ['initGame', 'connection'],

	data() {
		return {
			game: null,
			o: null as Reversi,
			logs: [],
			logPos: 0,
			pollingClock: null
		};
	},

	computed: {
		iAmPlayer(): boolean {
			if (!this.$store.getters.isSignedIn) return false;
			return this.game.user1Id == this.$store.state.i.id || this.game.user2Id == this.$store.state.i.id;
		},
		myColor(): Color {
			if (!this.iAmPlayer) return null;
			if (this.game.user1Id == this.$store.state.i.id && this.game.black == 1) return true;
			if (this.game.user2Id == this.$store.state.i.id && this.game.black == 2) return true;
			return false;
		},
		opColor(): Color {
			if (!this.iAmPlayer) return null;
			return this.myColor === true ? false : true;
		},
		blackUser(): any {
			return this.game.black == 1 ? this.game.user1 : this.game.user2;
		},
		whiteUser(): any {
			return this.game.black == 1 ? this.game.user2 : this.game.user1;
		},
		turnUser(): any {
			if (this.o.turn === true) {
				return this.game.black == 1 ? this.game.user1 : this.game.user2;
			} else if (this.o.turn === false) {
				return this.game.black == 1 ? this.game.user2 : this.game.user1;
			} else {
				return null;
			}
		},
		isMyTurn(): boolean {
			if (!this.iAmPlayer) return false;
			if (this.turnUser == null) return false;
			return this.turnUser.id == this.$store.state.i.id;
		},
		cellsStyle(): any {
			return {
				'grid-template-rows': `repeat(${ this.game.settings.map.length }, 1fr)`,
				'grid-template-columns': `repeat(${ this.game.settings.map[0].length }, 1fr)`
			};
		}
	},

	watch: {
		logPos(v) {
			if (!this.game.isEnded) return;
			this.o = new Reversi(this.game.settings.map, {
				isLlotheo: this.game.settings.isLlotheo,
				canPutEverywhere: this.game.settings.canPutEverywhere,
				loopedBoard: this.game.settings.loopedBoard
			});
			this.logs.forEach((log, i) => {
				if (i < v) {
					this.o.put(log.color, log.pos);
				}
			});
			this.$forceUpdate();
		}
	},

	created() {
		this.game = this.initGame;

		this.o = new Reversi(this.game.settings.map, {
			isLlotheo: this.game.settings.isLlotheo,
			canPutEverywhere: this.game.settings.canPutEverywhere,
			loopedBoard: this.game.settings.loopedBoard
		});

		this.game.logs.forEach(log => {
			this.o.put(log.color, log.pos);
		});

		this.logs = this.game.logs;
		this.logPos = this.logs.length;

		// 通信を取りこぼしてもいいように定期的にポーリングさせる
		if (this.game.isStarted && !this.game.isEnded) {
			this.pollingClock = setInterval(() => {
				const crc32 = CRC32.str(this.logs.map(x => x.pos.toString()).join(''));
				this.connection.send({
					type: 'check',
					crc32
				});
			}, 3000);
		}
	},

	mounted() {
		this.connection.on('set', this.onSet);
		this.connection.on('rescue', this.onRescue);
	},

	beforeDestroy() {
		this.connection.off('set', this.onSet);
		this.connection.off('rescue', this.onRescue);

		clearInterval(this.pollingClock);
	},

	methods: {
		set(pos) {
			if (this.game.isEnded) return;
			if (!this.iAmPlayer) return;
			if (!this.isMyTurn) return;
			if (!this.o.canPut(this.myColor, pos)) return;

			this.o.put(this.myColor, pos);

			// サウンドを再生する
			if (this.$store.state.device.enableSounds) {
				const sound = new Audio(`${url}/assets/reversi-put-me.mp3`);
				sound.volume = this.$store.state.device.soundVolume;
				sound.play();
			}

			this.connection.send({
				type: 'set',
				pos
			});

			this.checkEnd();

			this.$forceUpdate();
		},

		onSet(x) {
			this.logs.push(x);
			this.logPos++;
			this.o.put(x.color, x.pos);
			this.checkEnd();
			this.$forceUpdate();

			// サウンドを再生する
			if (this.$store.state.device.enableSounds && x.color != this.myColor) {
				const sound = new Audio(`${url}/assets/reversi-put-you.mp3`);
				sound.volume = this.$store.state.device.soundVolume;
				sound.play();
			}
		},

		checkEnd() {
			this.game.isEnded = this.o.isEnded;
			if (this.game.isEnded) {
				if (this.o.winner === true) {
					this.game.winnerId = this.game.black == 1 ? this.game.user1Id : this.game.user2Id;
					this.game.winner = this.game.black == 1 ? this.game.user1 : this.game.user2;
				} else if (this.o.winner === false) {
					this.game.winnerId = this.game.black == 1 ? this.game.user2Id : this.game.user1Id;
					this.game.winner = this.game.black == 1 ? this.game.user2 : this.game.user1;
				} else {
					this.game.winnerId = null;
					this.game.winner = null;
				}
			}
		},

		// 正しいゲーム情報が送られてきたとき
		onRescue(game) {
			this.game = game;

			this.o = new Reversi(this.game.settings.map, {
				isLlotheo: this.game.settings.isLlotheo,
				canPutEverywhere: this.game.settings.canPutEverywhere,
				loopedBoard: this.game.settings.loopedBoard
			});

			this.game.logs.forEach(log => {
				this.o.put(log.color, log.pos, true);
			});

			this.logs = this.game.logs;
			this.logPos = this.logs.length;

			this.checkEnd();
			this.$forceUpdate();
		}
	}
});
</script>

<style lang="stylus" scoped>
@import '~const.styl'

.root
	text-align center

	> header
		padding 8px
		border-bottom dashed 1px #c4cdd4

	> .board
		width calc(100% - 16px)
		max-width 500px
		margin 0 auto

		$label-size = 16px
		$gap = 4px

		> .labels-x
			height $label-size
			padding 0 $label-size
			display flex

			> *
				flex 1
				display flex
				align-items center
				justify-content center
				font-size 12px

				&:first-child
					margin-left -($gap / 2)

				&:last-child
					margin-right -($gap / 2)

		> .flex
			display flex

			> .labels-y
				width $label-size
				display flex
				flex-direction column

				> *
					flex 1
					display flex
					align-items center
					justify-content center
					font-size 12px

					&:first-child
						margin-top -($gap / 2)

					&:last-child
						margin-bottom -($gap / 2)

			> .cells
				flex 1
				display grid
				grid-gap $gap

				> div
					background transparent
					border-radius 6px
					overflow hidden

					*
						pointer-events none
						user-select none

					&.empty
						border solid 2px #eee

					&.empty.can
						background #eee

					&.empty.myTurn
						border-color #ddd

						&.can
							background #eee
							cursor pointer

							&:hover
								border-color darken($theme-color, 10%)
								background $theme-color

							&:active
								background darken($theme-color, 10%)

					&.prev
						box-shadow 0 0 0 4px rgba($theme-color, 0.7)

					&.isEnded
						border-color #ddd

					&.none
						border-color transparent !important

					> img
						display block
						width 100%
						height 100%

	> .graph
		display grid
		grid-template-columns repeat(61, 1fr)
		width 300px
		height 38px
		margin 0 auto 16px auto

		> div
			&:not(:empty)
				background #ccc

			> div:first-child
				background #333

			> div:last-child
				background #ccc

	> .status
		margin 0
		padding 16px 0

	> .player
		padding-bottom 32px

		> span
			display inline-block
			margin 0 8px
			min-width 70px
</style>
