<template>
<div class="xqnhankfuuilcwvhgsopeqncafzsquya">
	<button class="go-index" v-if="selfNav" @click="goIndex">%fa:arrow-left%</button>
	<header><b><router-link :to="blackUser | userPage">{{ blackUser | userName }}</router-link></b>(%i18n:common.reversi.black%) vs <b><router-link :to="whiteUser | userPage">{{ whiteUser | userName }}</router-link></b>(%i18n:common.reversi.white%)</header>

	<div style="overflow: hidden; line-height: 28px;">
		<p class="turn" v-if="!iAmPlayer && !game.isEnded">{{ '%i18n:common.reversi.turn-of%'.replace('{}', $options.filters.userName(turnUser)) }}<mk-ellipsis/></p>
		<p class="turn" v-if="logPos != logs.length">{{ '%i18n:common.reversi.past-turn-of%'.replace('{}', $options.filters.userName(turnUser)) }}</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">
				<span>{{ '%i18n:common.reversi.won%'.replace('{}', $options.filters.userName(game.winner)) }}</span>
				<span v-if="game.surrendered != null"> (%i18n:@surrendered%)</span>
			</template>
			<template v-else>%i18n:common.reversi.drawn%</template>
		</p>
	</div>

	<div class="board">
		<div class="labels-x" v-if="this.$store.state.settings.games.reversi.showBoardLabels">
			<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.games.reversi.showBoardLabels">
				<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="black" :class="{ contrast: $store.state.settings.games.reversi.useContrastStones }">
					<img v-if="stone === false" :src="whiteUser.avatarUrl" alt="white" :class="{ contrast: $store.state.settings.games.reversi.useContrastStones }">
				</div>
			</div>
			<div class="labels-y" v-if="this.$store.state.settings.games.reversi.showBoardLabels">
				<div v-for="i in game.settings.map.length">{{ i }}</div>
			</div>
		</div>
		<div class="labels-x" v-if="this.$store.state.settings.games.reversi.showBoardLabels">
			<span v-for="i in game.settings.map[0].length">{{ String.fromCharCode(64 + i) }}</span>
		</div>
	</div>

	<p class="status"><b>{{ '%i18n:common.reversi.this-turn%'.split('{}')[0] }}{{ logPos }}{{ '%i18n:common.reversi.this-turn%'.split('{}')[1] }}</b> %i18n:common.reversi.black%:{{ o.blackCount }} %i18n:common.reversi.white%:{{ o.whiteCount }} %i18n:common.reversi.total%:{{ o.blackCount + o.whiteCount }}</p>

	<div class="actions" v-if="!game.isEnded && iAmPlayer">
		<form-button @click="surrender">%i18n:@surrender%</form-button>
	</div>

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

	<div class="info">
		<p v-if="game.settings.isLlotheo">%i18n:@is-llotheo%</p>
		<p v-if="game.settings.loopedBoard">%i18n:@looped-map%</p>
		<p v-if="game.settings.canPutEverywhere">%i18n:@can-put-everywhere%</p>
	</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: {
			type: Object,
			require: true
		},
		connection: {
			type: Object,
			require: true
		},
		selfNav: {
			type: Boolean,
			require: true
		}
	},

	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
			});
			for (const log of this.logs.slice(0, 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('check', {
					crc32: crc32
				});
			}, 3000);
		}
	},

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

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

		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('set', {
				pos: 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();
			}
		},

		onEnded(x) {
			this.game = x.game;
		},

		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();
		},

		surrender() {
			(this as any).api('games/reversi/games/surrender', {
				gameId: this.game.id
			});
		},

		goIndex() {
			this.$emit('go-index');
		}
	}
});
</script>

<style lang="stylus" scoped>
.xqnhankfuuilcwvhgsopeqncafzsquya
	text-align center

	> .go-index
		position absolute
		top 0
		left 0
		z-index 1
		width 42px
		height 42px

	> header
		padding 8px
		border-bottom dashed 1px var(--reversiGameHeaderLine)

		a
			color inherit

	> .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 var(--reversiGameEmptyCell)

					&.empty.can
						background var(--reversiGameEmptyCell)

					&.empty.myTurn
						border-color var(--reversiGameEmptyCellMyTurn)

						&.can
							background var(--reversiGameEmptyCellCanPut)
							cursor pointer

							&:hover
								border-color var(--primaryDarken10)
								background var(--primary)

							&:active
								background var(--primaryDarken10)

					&.prev
						box-shadow 0 0 0 4px var(--primaryAlpha07)

					&.isEnded
						border-color var(--reversiGameEmptyCellMyTurn)

					&.none
						border-color transparent !important

					> img
						display block
						width 100%
						height 100%

						&.contrast
							&[alt="black"]
								filter brightness(.5)

							&[alt="white"]
								filter brightness(2)

	> .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

	> .actions
		padding-bottom 16px

	> .player
		padding-bottom 32px

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

</style>
