const React = require('react');
const { connect } = require('react-redux');
const shared = require('lib/components/shared/side-menu-shared.js');
const { Synchronizer } = require('lib/synchronizer.js');
const BaseModel = require('lib/BaseModel.js');
const Setting = require('lib/models/Setting.js');
const Folder = require('lib/models/Folder.js');
const Note = require('lib/models/Note.js');
const Tag = require('lib/models/Tag.js');
const { _ } = require('lib/locale.js');
const { themeStyle } = require('../theme.js');
const { bridge } = require('electron').remote.require('./bridge');
const Menu = bridge().Menu;
const MenuItem = bridge().MenuItem;
const InteropServiceHelper = require('../InteropServiceHelper.js');
const { substrWithEllipsis } = require('lib/string-utils');
const { ALL_NOTES_FILTER_ID } = require('lib/reserved-ids');

class SideBarComponent extends React.Component {
	constructor() {
		super();

		this.onFolderDragStart_ = (event) => {
			const folderId = event.currentTarget.getAttribute('folderid');
			if (!folderId) return;

			event.dataTransfer.setDragImage(new Image(), 1, 1);
			event.dataTransfer.clearData();
			event.dataTransfer.setData('text/x-jop-folder-ids', JSON.stringify([folderId]));
		};

		this.onFolderDragOver_ = (event) => {
			if (event.dataTransfer.types.indexOf('text/x-jop-note-ids') >= 0) event.preventDefault();
			if (event.dataTransfer.types.indexOf('text/x-jop-folder-ids') >= 0) event.preventDefault();
		};

		this.onFolderDrop_ = async (event) => {
			const folderId = event.currentTarget.getAttribute('folderid');
			const dt = event.dataTransfer;
			if (!dt) return;

			// folderId can be NULL when dropping on the sidebar Notebook header. In that case, it's used
			// to put the dropped folder at the root. But for notes, folderId needs to always be defined
			// since there's no such thing as a root note.

			if (dt.types.indexOf('text/x-jop-note-ids') >= 0) {
				event.preventDefault();

				if (!folderId) return;

				const noteIds = JSON.parse(dt.getData('text/x-jop-note-ids'));
				for (let i = 0; i < noteIds.length; i++) {
					await Note.moveToFolder(noteIds[i], folderId);
				}
			} else if (dt.types.indexOf('text/x-jop-folder-ids') >= 0) {
				event.preventDefault();

				const folderIds = JSON.parse(dt.getData('text/x-jop-folder-ids'));
				for (let i = 0; i < folderIds.length; i++) {
					await Folder.moveToFolder(folderIds[i], folderId);
				}
			}
		};

		this.onTagDrop_ = async (event) => {
			const tagId = event.currentTarget.getAttribute('tagid');
			const dt = event.dataTransfer;
			if (!dt) return;

			if (dt.types.indexOf('text/x-jop-note-ids') >= 0) {
				event.preventDefault();

				const noteIds = JSON.parse(dt.getData('text/x-jop-note-ids'));
				for (let i = 0; i < noteIds.length; i++) {
					await Tag.addNote(tagId, noteIds[i]);
				}
			}
		};

		this.onFolderToggleClick_ = async (event) => {
			const folderId = event.currentTarget.getAttribute('folderid');

			this.props.dispatch({
				type: 'FOLDER_TOGGLE',
				id: folderId,
			});
		};

		this.folderItemsOrder_ = [];
		this.tagItemsOrder_ = [];

		this.onKeyDown = this.onKeyDown.bind(this);
		this.onAllNotesClick_ = this.onAllNotesClick_.bind(this);

		this.rootRef = React.createRef();

		this.anchorItemRefs = {};

		this.state = {
			tagHeaderIsExpanded: Setting.value('tagHeaderIsExpanded'),
			folderHeaderIsExpanded: Setting.value('folderHeaderIsExpanded'),
		};
	}

	style() {
		const theme = themeStyle(this.props.theme);

		const itemHeight = 25;

		const style = {
			root: {
				backgroundColor: theme.backgroundColor2,
			},
			listItemContainer: {
				boxSizing: 'border-box',
				height: itemHeight,
				display: 'flex',
				flexDirection: 'row',
			},
			listItem: {
				fontFamily: theme.fontFamily,
				fontSize: theme.fontSize,
				textDecoration: 'none',
				color: theme.color2,
				cursor: 'default',
				opacity: 0.8,
				whiteSpace: 'nowrap',
				display: 'flex',
				flex: 1,
				alignItems: 'center',
				userSelect: 'none',
			},
			listItemSelected: {
				backgroundColor: theme.selectedColor2,
			},
			listItemExpandIcon: {
				color: theme.color2,
				cursor: 'default',
				opacity: 0.8,
				fontSize: theme.fontSize,
				textDecoration: 'none',
				paddingRight: 5,
				display: 'flex',
				alignItems: 'center',
				width: 12,
			},
			conflictFolder: {
				color: theme.colorError2,
				fontWeight: 'bold',
			},
			header: {
				height: itemHeight * 1.8,
				fontFamily: theme.fontFamily,
				fontSize: theme.fontSize * 1.16,
				textDecoration: 'none',
				boxSizing: 'border-box',
				color: theme.color2,
				paddingLeft: 8,
				display: 'flex',
				alignItems: 'center',
				userSelect: 'none',
			},
			button: {
				padding: 6,
				fontFamily: theme.fontFamily,
				fontSize: theme.fontSize,
				textDecoration: 'none',
				boxSizing: 'border-box',
				color: theme.color2,
				display: 'flex',
				alignItems: 'center',
				justifyContent: 'center',
				border: '1px solid rgba(255,255,255,0.2)',
				marginTop: 10,
				marginLeft: 5,
				marginRight: 5,
				cursor: 'default',
				userSelect: 'none',
			},
			syncReport: {
				fontFamily: theme.fontFamily,
				fontSize: Math.round(theme.fontSize * 0.9),
				color: theme.color2,
				opacity: 0.5,
				display: 'flex',
				alignItems: 'left',
				justifyContent: 'top',
				flexDirection: 'column',
				marginTop: 10,
				marginLeft: 5,
				marginRight: 5,
				marginBottom: 10,
				wordWrap: 'break-word',
			},
			noteCount: {
				paddingLeft: 5,
				opacity: 0.5,
				userSelect: 'none',
			},
		};

		style.tagItem = Object.assign({}, style.listItem);
		style.tagItem.paddingLeft = 23;
		style.tagItem.height = itemHeight;

		return style;
	}

	clearForceUpdateDuringSync() {
		if (this.forceUpdateDuringSyncIID_) {
			clearInterval(this.forceUpdateDuringSyncIID_);
			this.forceUpdateDuringSyncIID_ = null;
		}
	}

	doCommand(command) {
		if (!command) return;

		let commandProcessed = true;

		if (command.name === 'focusElement' && command.target === 'sideBar') {
			if (this.props.sidebarVisibility) {
				const item = this.selectedItem();
				if (item) {
					const anchorRef = this.anchorItemRefs[item.type][item.id];
					if (anchorRef) anchorRef.current.focus();
				} else {
					const anchorRef = this.firstAnchorItemRef('folder');
					console.info('anchorRef', anchorRef);
					if (anchorRef) anchorRef.current.focus();
				}
			}
		} else if (command.name === 'synchronize') {
			if (!this.props.syncStarted) this.sync_click();
		} else {
			commandProcessed = false;
		}

		if (commandProcessed) {
			this.props.dispatch({
				type: 'WINDOW_COMMAND',
				name: null,
			});
		}
	}

	componentWillUnmount() {
		this.clearForceUpdateDuringSync();
	}

	componentDidUpdate(prevProps) {
		if (prevProps.windowCommand !== this.props.windowCommand) {
			this.doCommand(this.props.windowCommand);
		}

		// if (shim.isLinux()) {
		// 	// For some reason, the UI seems to sleep in some Linux distro during
		// 	// sync. Cannot find the reason for it and cannot replicate, so here
		// 	// as a test force the update at regular intervals.
		// 	// https://github.com/laurent22/joplin/issues/312#issuecomment-429472193
		// 	if (!prevProps.syncStarted && this.props.syncStarted) {
		// 		this.clearForceUpdateDuringSync();

		// 		this.forceUpdateDuringSyncIID_ = setInterval(() => {
		// 			this.forceUpdate();
		// 		}, 2000);
		// 	}

		// 	if (prevProps.syncStarted && !this.props.syncStarted) this.clearForceUpdateDuringSync();
		// }
	}

	async itemContextMenu(event) {
		const itemId = event.currentTarget.getAttribute('data-id');
		if (itemId === Folder.conflictFolderId()) return;

		const itemType = Number(event.currentTarget.getAttribute('data-type'));
		if (!itemId || !itemType) throw new Error('No data on element');

		let deleteMessage = '';
		let buttonLabel = _('Remove');
		if (itemType === BaseModel.TYPE_FOLDER) {
			const folder = await Folder.load(itemId);
			deleteMessage = _('Delete notebook "%s"?\n\nAll notes and sub-notebooks within this notebook will also be deleted.', substrWithEllipsis(folder.title, 0, 32));
			buttonLabel = _('Delete');
		} else if (itemType === BaseModel.TYPE_TAG) {
			const tag = await Tag.load(itemId);
			deleteMessage = _('Remove tag "%s" from all notes?', substrWithEllipsis(tag.title, 0, 32));
		} else if (itemType === BaseModel.TYPE_SEARCH) {
			deleteMessage = _('Remove this search from the sidebar?');
		}

		const menu = new Menu();

		let item = null;
		if (itemType === BaseModel.TYPE_FOLDER) {
			item = BaseModel.byId(this.props.folders, itemId);
		}

		if (itemType === BaseModel.TYPE_FOLDER && !item.encryption_applied) {
			menu.append(
				new MenuItem({
					label: _('New sub-notebook'),
					click: () => {
						this.props.dispatch({
							type: 'WINDOW_COMMAND',
							name: 'newSubNotebook',
							activeFolderId: itemId,
						});
					},
				})
			);
		}

		menu.append(
			new MenuItem({
				label: buttonLabel,
				click: async () => {
					const ok = bridge().showConfirmMessageBox(deleteMessage, {
						buttons: [buttonLabel, _('Cancel')],
						defaultId: 1,
					});
					if (!ok) return;

					if (itemType === BaseModel.TYPE_FOLDER) {
						await Folder.delete(itemId);
					} else if (itemType === BaseModel.TYPE_TAG) {
						await Tag.untagAll(itemId);
					} else if (itemType === BaseModel.TYPE_SEARCH) {
						this.props.dispatch({
							type: 'SEARCH_DELETE',
							id: itemId,
						});
					}
				},
			})
		);

		if (itemType === BaseModel.TYPE_FOLDER && !item.encryption_applied) {
			menu.append(
				new MenuItem({
					label: _('Rename'),
					click: async () => {
						this.props.dispatch({
							type: 'WINDOW_COMMAND',
							name: 'renameFolder',
							id: itemId,
						});
					},
				})
			);

			// menu.append(
			// 	new MenuItem({
			// 		label: _("Move"),
			// 		click: async () => {
			// 			this.props.dispatch({
			// 				type: "WINDOW_COMMAND",
			// 				name: "renameFolder",
			// 				id: itemId,
			// 			});
			// 		},
			// 	})
			// );

			menu.append(new MenuItem({ type: 'separator' }));

			const InteropService = require('lib/services/InteropService.js');

			const exportMenu = new Menu();
			const ioService = new InteropService();
			const ioModules = ioService.modules();
			for (let i = 0; i < ioModules.length; i++) {
				const module = ioModules[i];
				if (module.type !== 'exporter') continue;

				exportMenu.append(
					new MenuItem({
						label: module.fullLabel(),
						click: async () => {
							await InteropServiceHelper.export(this.props.dispatch.bind(this), module, { sourceFolderIds: [itemId] });
						},
					})
				);
			}

			menu.append(
				new MenuItem({
					label: _('Export'),
					submenu: exportMenu,
				})
			);
		}

		if (itemType === BaseModel.TYPE_TAG) {
			menu.append(
				new MenuItem({
					label: _('Rename'),
					click: async () => {
						this.props.dispatch({
							type: 'WINDOW_COMMAND',
							name: 'renameTag',
							id: itemId,
						});
					},
				})
			);
		}

		menu.popup(bridge().window());
	}

	folderItem_click(folder) {
		this.props.dispatch({
			type: 'FOLDER_SELECT',
			id: folder ? folder.id : null,
		});
	}

	tagItem_click(tag) {
		this.props.dispatch({
			type: 'TAG_SELECT',
			id: tag ? tag.id : null,
		});
	}

	async sync_click() {
		await shared.synchronize_press(this);
	}

	anchorItemRef(type, id) {
		if (!this.anchorItemRefs[type]) this.anchorItemRefs[type] = {};
		if (this.anchorItemRefs[type][id]) return this.anchorItemRefs[type][id];
		this.anchorItemRefs[type][id] = React.createRef();
		return this.anchorItemRefs[type][id];
	}

	firstAnchorItemRef(type) {
		const refs = this.anchorItemRefs[type];
		if (!refs) return null;

		const n = `${type}s`;
		const item = this.props[n] && this.props[n].length ? this.props[n][0] : null;
		console.info('props', this.props[n], item);
		if (!item) return null;

		return refs[item.id];
	}

	noteCountElement(count) {
		return <div style={this.style().noteCount}>({count})</div>;
	}

	folderItem(folder, selected, hasChildren, depth) {
		let style = Object.assign({}, this.style().listItem);
		if (folder.id === Folder.conflictFolderId()) style = Object.assign(style, this.style().conflictFolder);

		const itemTitle = Folder.displayTitle(folder);

		let containerStyle = Object.assign({}, this.style().listItemContainer);
		if (selected) containerStyle = Object.assign(containerStyle, this.style().listItemSelected);

		containerStyle.paddingLeft = 8 + depth * 15;

		const expandLinkStyle = Object.assign({}, this.style().listItemExpandIcon);
		const expandIconStyle = {
			visibility: hasChildren ? 'visible' : 'hidden',
		};

		const iconName = this.props.collapsedFolderIds.indexOf(folder.id) >= 0 ? 'fa-chevron-right' : 'fa-chevron-down';
		const expandIcon = <i style={expandIconStyle} className={`fas ${iconName}`}></i>;
		const expandLink = hasChildren ? (
			<a style={expandLinkStyle} href="#" folderid={folder.id} onClick={this.onFolderToggleClick_}>
				{expandIcon}
			</a>
		) : (
			<span style={expandLinkStyle}>{expandIcon}</span>
		);

		const anchorRef = this.anchorItemRef('folder', folder.id);
		const noteCount = folder.note_count ? this.noteCountElement(folder.note_count) : '';

		return (
			<div className={`list-item-container list-item-depth-${depth}`} style={containerStyle} key={folder.id} onDragStart={this.onFolderDragStart_} onDragOver={this.onFolderDragOver_} onDrop={this.onFolderDrop_} draggable={true} folderid={folder.id}>
				{expandLink}
				<a
					ref={anchorRef}
					className="list-item"
					href="#"
					data-id={folder.id}
					data-type={BaseModel.TYPE_FOLDER}
					onContextMenu={(event) => this.itemContextMenu(event)}
					style={style}
					folderid={folder.id}
					onClick={() => {
						this.folderItem_click(folder);
					}}
					onDoubleClick={this.onFolderToggleClick_}
				>
					{itemTitle} {noteCount}
				</a>
			</div>
		);
	}

	tagItem(tag, selected) {
		let style = Object.assign({}, this.style().tagItem);
		if (selected) style = Object.assign(style, this.style().listItemSelected);

		const anchorRef = this.anchorItemRef('tag', tag.id);
		const noteCount = Setting.value('showNoteCounts') ? this.noteCountElement(tag.note_count) : '';

		return (
			<a
				className="list-item"
				href="#"
				ref={anchorRef}
				data-id={tag.id}
				data-type={BaseModel.TYPE_TAG}
				onContextMenu={(event) => this.itemContextMenu(event)}
				tagid={tag.id}
				key={tag.id}
				style={style}
				onDrop={this.onTagDrop_}
				onClick={() => {
					this.tagItem_click(tag);
				}}
			>
				{Tag.displayTitle(tag)} {noteCount}
			</a>
		);
	}

	// searchItem(search, selected) {
	// 	let style = Object.assign({}, this.style().listItem);
	// 	if (selected) style = Object.assign(style, this.style().listItemSelected);
	// 	return (
	// 		<a
	// 			className="list-item"
	// 			href="#"
	// 			data-id={search.id}
	// 			data-type={BaseModel.TYPE_SEARCH}
	// 			onContextMenu={event => this.itemContextMenu(event)}
	// 			key={search.id}
	// 			style={style}
	// 			onClick={() => {
	// 				this.searchItem_click(search);
	// 			}}
	// 		>
	// 			{search.title}
	// 		</a>
	// 	);
	// }

	makeDivider(key) {
		return <div style={{ height: 2, backgroundColor: 'blue' }} key={key} />;
	}

	makeHeader(key, label, iconName, extraProps = {}) {
		const style = this.style().header;
		const icon = <i style={{ fontSize: style.fontSize, marginRight: 5 }} className={`fas ${iconName}`} />;

		if (extraProps.toggleblock || extraProps.onClick) {
			style.cursor = 'pointer';
		}

		const headerClick = extraProps.onClick || null;
		delete extraProps.onClick;

		// check if toggling option is set.
		let toggleIcon = null;
		const toggleKey = `${key}IsExpanded`;
		if (extraProps.toggleblock) {
			const isExpanded = this.state[toggleKey];
			toggleIcon = <i className={`fas ${isExpanded ? 'fa-chevron-down' : 'fa-chevron-right'}`} style={{ fontSize: style.fontSize * 0.75, marginRight: 12, marginLeft: 5, marginTop: style.fontSize * 0.125 }}></i>;
		}
		if (extraProps.selected) {
			style.backgroundColor = this.style().listItemSelected.backgroundColor;
		}

		const ref = this.anchorItemRef('headers', key);

		return (
			<div
				ref={ref}
				style={style}
				key={key}
				{...extraProps}
				onClick={(event) => {
					// if a custom click event is attached, trigger that.
					if (headerClick) {
						headerClick(key, event);
					}
					this.onHeaderClick_(key, event);
				}}
			>
				{icon}
				<span style={{ flex: 1 }}>{label}</span>
				{toggleIcon}
			</div>
		);
	}

	selectedItem() {
		if (this.props.notesParentType === 'Folder' && this.props.selectedFolderId) {
			return { type: 'folder', id: this.props.selectedFolderId };
		} else if (this.props.notesParentType === 'Tag' && this.props.selectedTagId) {
			return { type: 'tag', id: this.props.selectedTagId };
		}

		return null;
	}

	onKeyDown(event) {
		const keyCode = event.keyCode;
		const selectedItem = this.selectedItem();

		if (keyCode === 40 || keyCode === 38) {
			// DOWN / UP
			event.preventDefault();

			const focusItems = [];

			for (let i = 0; i < this.folderItemsOrder_.length; i++) {
				const id = this.folderItemsOrder_[i];
				focusItems.push({ id: id, ref: this.anchorItemRefs['folder'][id], type: 'folder' });
			}

			for (let i = 0; i < this.tagItemsOrder_.length; i++) {
				const id = this.tagItemsOrder_[i];
				focusItems.push({ id: id, ref: this.anchorItemRefs['tag'][id], type: 'tag' });
			}

			let currentIndex = 0;
			for (let i = 0; i < focusItems.length; i++) {
				if (!selectedItem || focusItems[i].id === selectedItem.id) {
					currentIndex = i;
					break;
				}
			}

			const inc = keyCode === 38 ? -1 : +1;
			let newIndex = currentIndex + inc;

			if (newIndex < 0) newIndex = 0;
			if (newIndex > focusItems.length - 1) newIndex = focusItems.length - 1;

			const focusItem = focusItems[newIndex];

			const actionName = `${focusItem.type.toUpperCase()}_SELECT`;

			this.props.dispatch({
				type: actionName,
				id: focusItem.id,
			});

			focusItem.ref.current.focus();
		}

		if (keyCode === 9) {
			// TAB
			event.preventDefault();

			if (event.shiftKey) {
				this.props.dispatch({
					type: 'WINDOW_COMMAND',
					name: 'focusElement',
					target: 'noteBody',
				});
			} else {
				this.props.dispatch({
					type: 'WINDOW_COMMAND',
					name: 'focusElement',
					target: 'noteList',
				});
			}
		}

		if (selectedItem && selectedItem.type === 'folder' && keyCode === 32) {
			// SPACE
			event.preventDefault();

			this.props.dispatch({
				type: 'FOLDER_TOGGLE',
				id: selectedItem.id,
			});
		}

		if (keyCode === 65 && (event.ctrlKey || event.metaKey)) {
			// Ctrl+A key
			event.preventDefault();
		}
	}

	onHeaderClick_(key, event) {
		const currentHeader = event.currentTarget;
		const toggleBlock = +currentHeader.getAttribute('toggleblock');
		if (toggleBlock) {
			const toggleKey = `${key}IsExpanded`;
			const isExpanded = this.state[toggleKey];
			this.setState({ [toggleKey]: !isExpanded });
			Setting.setValue(toggleKey, !isExpanded);
		}
	}

	onAllNotesClick_() {
		this.props.dispatch({
			type: 'SMART_FILTER_SELECT',
			id: ALL_NOTES_FILTER_ID,
		});
	}

	synchronizeButton(type) {
		const style = Object.assign({}, this.style().button, { marginBottom: 5 });
		const iconName = 'fa-sync-alt';
		const label = type === 'sync' ? _('Synchronise') : _('Cancel');
		const iconStyle = { fontSize: style.fontSize, marginRight: 5 };

		if (type !== 'sync') {
			iconStyle.animation = 'icon-infinite-rotation 1s linear infinite';
		}

		const icon = <i style={iconStyle} className={`fas ${iconName}`} />;
		return (
			<a
				className="synchronize-button"
				style={style}
				href="#"
				key="sync_button"
				onClick={() => {
					this.sync_click();
				}}
			>
				{icon}
				{label}
			</a>
		);
	}

	render() {
		const style = Object.assign({}, this.style().root, this.props.style, {
			overflowX: 'hidden',
			overflowY: 'hidden',
			display: 'inline-flex',
			flexDirection: 'column',
		});

		const items = [];
		items.push(
			this.makeHeader('allNotesHeader', _('All notes'), 'fa-clone', {
				onClick: this.onAllNotesClick_,
				selected: this.props.notesParentType === 'SmartFilter' && this.props.selectedSmartFilterId === ALL_NOTES_FILTER_ID,
			})
		);

		items.push(
			this.makeHeader('folderHeader', _('Notebooks'), 'fa-book', {
				onDrop: this.onFolderDrop_,
				folderid: '',
				toggleblock: 1,
			})
		);

		if (this.props.folders.length) {
			const result = shared.renderFolders(this.props, this.folderItem.bind(this));
			const folderItems = result.items;
			this.folderItemsOrder_ = result.order;
			items.push(
				<div className="folders" key="folder_items" style={{ display: this.state.folderHeaderIsExpanded ? 'block' : 'none' }}>
					{folderItems}
				</div>
			);
		}

		items.push(
			this.makeHeader('tagHeader', _('Tags'), 'fa-tags', {
				toggleblock: 1,
			})
		);

		if (this.props.tags.length) {
			const result = shared.renderTags(this.props, this.tagItem.bind(this));
			const tagItems = result.items;
			this.tagItemsOrder_ = result.order;

			items.push(
				<div className="tags" key="tag_items" style={{ display: this.state.tagHeaderIsExpanded ? 'block' : 'none' }}>
					{tagItems}
				</div>
			);
		}

		let decryptionReportText = '';
		if (this.props.decryptionWorker && this.props.decryptionWorker.state !== 'idle' && this.props.decryptionWorker.itemCount) {
			decryptionReportText = _('Decrypting items: %d/%d', this.props.decryptionWorker.itemIndex + 1, this.props.decryptionWorker.itemCount);
		}

		let resourceFetcherText = '';
		if (this.props.resourceFetcher && this.props.resourceFetcher.toFetchCount) {
			resourceFetcherText = _('Fetching resources: %d/%d', this.props.resourceFetcher.fetchingCount, this.props.resourceFetcher.toFetchCount);
		}

		const lines = Synchronizer.reportToLines(this.props.syncReport);
		if (resourceFetcherText) lines.push(resourceFetcherText);
		if (decryptionReportText) lines.push(decryptionReportText);
		const syncReportText = [];
		for (let i = 0; i < lines.length; i++) {
			syncReportText.push(
				<div key={i} style={{ wordWrap: 'break-word', width: '100%' }}>
					{lines[i]}
				</div>
			);
		}

		const syncButton = this.synchronizeButton(this.props.syncStarted ? 'cancel' : 'sync');

		const syncReportComp = !syncReportText.length ? null : (
			<div style={this.style().syncReport} key="sync_report">
				{syncReportText}
			</div>
		);

		return (
			<div ref={this.rootRef} onKeyDown={this.onKeyDown} className="side-bar" style={style}>
				<div style={{ flex: 1, overflowX: 'hidden', overflowY: 'auto' }}>{items}</div>
				<div style={{ flex: 0 }}>
					{syncReportComp}
					{syncButton}
				</div>
			</div>
		);
	}
}

const mapStateToProps = (state) => {
	return {
		folders: state.folders,
		tags: state.tags,
		searches: state.searches,
		syncStarted: state.syncStarted,
		syncReport: state.syncReport,
		selectedFolderId: state.selectedFolderId,
		selectedTagId: state.selectedTagId,
		selectedSearchId: state.selectedSearchId,
		selectedSmartFilterId: state.selectedSmartFilterId,
		notesParentType: state.notesParentType,
		locale: state.settings.locale,
		theme: state.settings.theme,
		collapsedFolderIds: state.collapsedFolderIds,
		decryptionWorker: state.decryptionWorker,
		resourceFetcher: state.resourceFetcher,
		windowCommand: state.windowCommand,
		sidebarVisibility: state.sidebarVisibility,
		noteListVisibility: state.noteListVisibility,
	};
};

const SideBar = connect(mapStateToProps)(SideBarComponent);

module.exports = { SideBar };
