/**
 * This is the box that pops up if you press ctrl+f. It handles searching through the content on the page and scrolling to matches.
 */
import React from "react";
import LoggerStore from "../../../stores/LoggerStore";

import { CtrlFSearch } from "../../../stores/CtrlFSearch";

interface IProps {
	show: boolean;
}
interface IState {
	matches: any;
	activeIndex: number;
	searchString: string;
}

export default class LoggerSearchBox extends React.Component<IProps, IState> {
	constructor(props: IProps) {
		super(props);
		this.state = {
			matches: new CtrlFSearch().getIterator(),
			activeIndex: 1,
			searchString: LoggerStore.getSearchBoxString(),
		};
		this.onKeyPress = this.onKeyPress.bind(this);
		this.scrollToNextMatch = this.scrollToNextMatch.bind(this);
		this.scrollToPreviousMatch = this.scrollToPreviousMatch.bind(this);
		this.focus = this.focus.bind(this);
		this.setSearchString = this.setSearchString.bind(this);
		this.onSearchUpdate = this.onSearchUpdate.bind(this);
		LoggerStore.setConfigSearchBoxString(this.state.searchString);
	}

	focus() {
		if (this.refs.SearchBox) {
			(this.refs.SearchBox as HTMLInputElement).focus();
		}
	}

	onKeyPress(e: React.KeyboardEvent<HTMLInputElement>) {
		if (e.key === "Enter") {
			this.scrollToNextMatch();
		}
	}

	setSearchString(e: React.ChangeEvent<HTMLInputElement>) {
		LoggerStore.setConfigSearchBoxString(e.target.value);
	}

	onSearchUpdate() {
		this.setState(
			{
				matches: LoggerStore.getSearchMatches(),
				searchString: LoggerStore.getSearchBoxString(),
			},
			() => {
				if (this.state.activeIndex === 1) {
					this.scrollToNextMatch();
				} else {
					this.state.matches.setActiveIndex(this.state.activeIndex);
				}
			}
		);
	}

	scrollToNextMatch() {
		// SearchResultNumber is X out of N matches. It's X.
		const { matches } = this.state;
		const nextMatch = matches.next();
		if (nextMatch.value !== undefined) {
			this.setState({
				activeIndex: nextMatch.searchResultNumber,
			});
			LoggerStore.setActiveConfigSearchMatch(nextMatch.value);
		}
	}

	scrollToPreviousMatch() {
		const { matches } = this.state;
		const nextMatch = matches.previous();
		this.setState({
			activeIndex: nextMatch.searchResultNumber,
		});
		LoggerStore.setActiveConfigSearchMatch(nextMatch.value);
	}

	hideSearchBox() {
		LoggerStore.hideSearchBox();
	}

	componentDidMount() {
		LoggerStore.addListener("loggerNewMessages", this.searchAgain);
		LoggerStore.addListener("showSearchBox", this.focus);
		LoggerStore.addListener("showSearchBoxChange", this.focus);
		LoggerStore.addListener("searchBoxTextChange", this.onSearchUpdate);
	}

	componentWillUnmount() {
		LoggerStore.removeListener("loggerNewMessages", this.searchAgain);
		LoggerStore.removeListener("showSearchBox", this.focus);
		LoggerStore.removeListener("showSearchBoxChange", this.focus);
		LoggerStore.removeListener("searchBoxTextChange", this.onSearchUpdate);
	}

	searchAgain() {
		LoggerStore.setConfigSearchBoxString(LoggerStore.Search.searchString);
	}

	render() {
		const classes = "fsbl-logger-searchbox";
		if (!this.props.show) {
			return null;
		}
		const numMatches = this.state.matches && this.state.matches.values ? this.state.matches.values.length : 0;
		// For when matches < 10.
		let left = "152px";
		if (numMatches >= 10) {
			left = "142px";
		} else if (numMatches >= 100) {
			left = "128px";
		}
		const matchTextStyle = {
			left,
		};

		return (
			<div className={`${classes}`}>
				<div className="search-box-input-wrapper">
					<div className="search-box-text-input">
						<input
							value={this.state.searchString}
							ref="SearchBox"
							autoFocus
							placeholder="Find string in logs"
							type="text"
							onKeyPress={this.onKeyPress}
							onChange={this.setSearchString}
						/>
						{numMatches > 0 && (
							<label className="search-box-match-text" style={matchTextStyle}>
								<span>
									{this.state.activeIndex} of {numMatches}
								</span>
							</label>
						)}
					</div>
					<div className="search-box-match-navigators">
						<span onClick={this.scrollToPreviousMatch}>&#x25B2;</span>
						<span onClick={this.scrollToNextMatch}>&#x25BC;</span>
					</div>
				</div>

				<div className="search-box-cancel-button">
					<span onClick={this.hideSearchBox}>Cancel</span>
				</div>
			</div>
		);
	}
}
