<template>
	<!-- change class to .master-note-edit to have it popup on the screen  -->
	<div 
		id="InputNotes" 
		class="master-note-edit full-focus" 
		@keyup.esc="close()" 
		:class="[ 'position-'+position ]" 
	>

		<!-- Main Menu  -->
		<div class="edit-menu" :class="{ 'slide-out-top':(sizeDown == true) }">

			

			<div class="edit-spacer"></div>

			<div class="menu-top-half">
				<div class="edit-button" v-on:click="close()" data-tooltip="Close" data-position="bottom center" data-inverted>
					<i class="close icon"></i>
				</div>

				<div class="edit-divide"></div>

				<div class="edit-button" v-on:click="toggleList('ul')" data-tooltip="Task List" data-position="bottom center" data-inverted :class="{'edit-active':activeToDo}">
					<i class="tasks icon"></i>
				</div>
				<div class="edit-button" v-on:click="toggleList('ol')" data-tooltip="Numbered List" data-position="bottom center" data-inverted :class="{'edit-active':activeList}">
					<i class="list ol icon"></i>
				</div>

				<div class="edit-button" v-on:click="colorpicker = true" data-tooltip="Text Color" data-position="bottom center" data-inverted :style="{'color':activeColor}">
					<i class="palette icon"></i>
				</div>

				<div class="edit-button" v-on:click="toggleBold()" data-tooltip="Bold" data-position="bottom center" data-inverted :class="{'edit-active':activeBold}">
					<i class="bold icon"></i>
				</div>

				<div class="edit-button" v-on:click="toggleItalic()" data-tooltip="Quote" data-position="bottom center" data-inverted :class="{'edit-active':activeQuote}">
					<i class="quote left icon"></i>
				</div>
				<div class="edit-button" v-on:click="modifyFont('1.4em')" data-tooltip="Title" data-position="bottom center" data-inverted :class="{'edit-active':activeTitle}">
					<i class="text height icon"></i>
				</div>
				<div class="edit-button" v-on:click="editor.increaseQuoteLevel()" data-tooltip="Indent" data-position="bottom center" data-inverted>
					<i class="indent icon"></i>
				</div>
				<div class="edit-button" v-on:click="editor.decreaseQuoteLevel()" data-tooltip="Outdent" data-position="bottom center" data-inverted>
					<i class="outdent icon"></i>
				</div>
				<div class="edit-button" v-on:click="removeFormatting()" data-tooltip="Remove Formatting" data-position="bottom center" data-inverted>
					<i class="remove format icon"></i>
				</div>
			</div>

			<div class="menu-bottom-half">
				
				<div class="edit-button" v-on:click="undoCustom()" data-tooltip="Undo" data-position="bottom center" data-inverted>
					<i class="undo icon"></i>
				</div>

				<div class="edit-divide"></div>

				<div class="edit-button" v-on:click="$router.push(`/notes/open/${noteid}/menu/colors`)" data-tooltip="Note Color" data-position="bottom center" data-inverted :style="{ 'background-color':styleObject['noteBackground'], 'color':styleObject['noteText']}">
					<i class="paint brush icon"></i>
				</div>
				<div class="edit-button" v-on:click="$router.push(`/notes/open/${noteid}/menu/tags`)" data-tooltip="Tags" data-position="bottom center" data-inverted>
					<i class="tags icon"></i>
				</div>
				<div class="edit-button" v-on:click="$router.push(`/notes/open/${noteid}/menu/images`)" data-tooltip="Images" data-position="bottom center" data-inverted>
					<i class="image icon"></i>
				</div>

				<file-upload-button 
					data-tooltip="Upload File" data-position="bottom center" data-inverted
					class="edit-button" 
					:noteId="noteid" />

				<div class="edit-divide"></div>

				<div class="edit-button" v-on:click="$router.push(`/notes/open/${noteid}/menu/options`)" data-tooltip="More Options" data-position="bottom center" data-inverted>
					<i class="tools icon"></i>
				</div>

				<div class="edit-divide"></div>

				<div class="edit-button" v-on:click="onToggleArchived()" :data-tooltip="archived == 1?'Move to main list':'Move to Archive'" data-position="bottom center" data-inverted>
					<span v-if="archived == 1"><i class="green archive icon"></i></span>
					<span v-if="archived != 1"><i class="archive icon"></i></span>
				</div>

				<div class="edit-button" v-on:click="onTogglePinned" :data-tooltip="pinned == 1?'Un-pin from top':'Pin to top'" data-position="bottom center" data-inverted>
					<span v-if="pinned == 1"><i class="green pin icon"></i></span>
					<span v-if="pinned != 1"><i class="pin icon"></i></span>
				</div>

				<!-- data-tooltip="Files on note" -->
				<div class="edit-button" v-on:click="openEditAttachment" data-tooltip="Files" data-position="bottom center" data-inverted>
					<i class="folder icon"></i>
				</div>

				<div class="edit-button">
					<i class="icons">
						<i class="grey save outline icon"></i>
						<i v-if="statusText == 'saved'" class="green small bottom left corner check icon"></i>
						<i v-if="statusText == 'saving'" class="small bottom left corner double angle up icon"></i>
					</i>
				</div>
				
			</div>

		</div>

		<div class="bottom-edit-menu"></div>

		<div class="input-container-wrapper" :class="{ 'side-menu-open':sideMenuOpen, 'size-down':(sizeDown == true),}" :style="{ 'background-color':styleObject['noteBackground'] }">

			<!-- Squire box grows -->
			<div class="note-wrapper" :style="{ 'background-color':styleObject['noteBackground'], 'color':styleObject['noteText']}">

				<!-- Loading indicator  -->
				<transition name="fade">
					<div v-if="loading || forceShowLoading" class="loading-note" :style="{ 'background-color':styleObject['noteBackground'], 'color':styleObject['noteText']}">
						<div class="loading-text">
							<loading-icon :message="loadingMessage" />
						</div>
					</div>
				</transition>

				<!-- Title input area  -->
				<textarea 
					ref="titleTextarea"
					v-on:keyup="titleResize"
					v-on:keydown="titleResize"
					@keydown.enter.exact.prevent="editor.focus(); editor.moveCursorToEnd()"
					rows="1"
					:style="{ 'background-color':styleObject['noteBackground'], 'color':styleObject['noteText']}"
					v-on:blur="save" type="text" v-model="noteTitle" placeholder="Title" class="stealth-input">
				</textarea>

				<!-- Squire Box -->
				<div id="squire-id" class="squire-box" ref="squirebox" placeholder="Note Text"></div>
				
			</div>

		</div>

		<!-- color picker -->
		<color-tooltip 
			v-if="colorpicker" 
			v-on:color="color => modifyColor(color)"
			v-on:close="colorpicker = false"
		/>

		<!-- Side slide menus for colors, tags, images and other options -->
		<side-slide-menu v-show="colors" v-on:close="colors = false" name="colors">
			<color-picker
				@changeColor="onChangeColor"
				@close="colors = false"
				:style-object="styleObject"
			/>
		</side-slide-menu>

		<side-slide-menu v-show="tags" v-on:close="tags = false" name="tags" :style-object="styleObject">
			<div class="ui basic segment">
				<note-tag-edit :noteId="noteid" :key="'tags-for-note-'+noteid"/>
			</div>
		</side-slide-menu>

		<side-slide-menu v-show="images" v-on:close="images = false" name="images" :style-object="styleObject">
			<div class="ui basic segment">
				<simple-attachment-note
					v-on:close="images = false"
					:note-id="noteid" 
					:squire-editor="editor">
				</simple-attachment-note>
			</div>
		</side-slide-menu>

		<side-slide-menu v-show="options" v-on:close="options = false" name="note-options" :style-object="styleObject">
			<div class="ui basic padded segment">
				<div class="ui grid">
					<div class="sixteen wide column">
						<h2>Additional Note Options</h2>
					</div>
					<div class="sixteen wide column">
						<div class="ui labeled icon fluid basic button" v-on:click="sortList">
							<i class="sort amount up icon"></i>
							Sort List items (Move checked to bottom)
						</div>
					</div>
					<div class="eight wide column">
						<div class="ui labeled icon fluid basic button" v-on:click="deleteCompletedListItems">
							<i class="trash icon"></i>
							Delete Checked Items
						</div>
					</div>
					<div class="eight wide column">
						<div class="ui labeled icon fluid basic button" v-on:click="uncheckAllListItems">
							<i class="list ul icon"></i>
							Uncheck all Checked items
						</div>
					</div>
					<div class="eight wide column">
						<div class="ui labeled icon fluid basic button" v-on:click="calculateMath" data-tooltip="Calculates algebra before '='">
							<i class="calculator icon"></i>
							Simple Math
						</div>
					</div>
					<div class="sixteen wide column" v-if="rawTextId > 0">
						<h2>Share Note</h2>
						<share-note-component 
							:note-id="noteid"
							:raw-text-id="rawTextId"
							:share-username="shareUsername"
						/>
					</div>
				</div>
			</div>
		</side-slide-menu>

		<!-- Show side shades if user is on desktop only -->
		<div class="full-focus-shade shade1"
			:class="{ 'slide-out-left':(sizeDown == true) }"
			v-on:click="close()"></div>
		<div class="full-focus-shade shade2" 
			:class="{ 'slide-out-right':(sizeDown == true) }"
			v-on:click="close()"></div>

	</div>
</template>

<script>

	import axios from 'axios'
	const crypto = require('crypto')
	const DiffMatchPatch = require('../../../server/helpers/DiffMatchPatch')
	
	export default {
	name: 'InputNotes',
		props: [ 'noteid', 'position', 'openMenu', 'urlData' ],
		components:{
			'note-tag-edit': () => import('@/components/NoteTagEdit.vue'),
			'color-picker': () => import('@/components/ColorPicker.vue'),
			'file-upload-button': () => import('@/components/FileUploadButton.vue'),
			// 'delete-button': () => import('@/components/NoteDeleteButtonComponent.vue'),
			'side-slide-menu': () => import('@/components/SideSlideMenuComponent.vue'),
			'simple-attachment-note': () => import('@/components/SimpleAttachmentNoteComponent.vue'),
			'share-note-component': () => import('@/components/ShareNoteComponent.vue'),

			'color-tooltip':require('@/components/TextColorTooltipComponent.vue').default,
			'nm-button':require('@/components/NoteMenuButtonComponent.vue').default,
			'loading-icon':require('@/components/LoadingIconComponent.vue').default,
		},
		data(){
			return {
				loading: true,
				forceShowLoading: true,
				loadingMessage: 'Loading Note',
				currentNoteId: 0,
				modified: false,
				noteText: '',
				noteTitle: '',
				rawTextId: 0,
				created: '',
				updated: '',
				shareUsername: null,
				diffNoteText: '',
				statusText: 'saved',
				lastNoteHash: null,
				saveDebounce: null, //Prevent save from being called numerous times quickly
				updated: 'Never',
				editDebounce: null,
				emitChangeDebounce: null,
				keyPressesCounter: 0, //Determen keys pressed between saves
				pinned: 0,
				archived: 0,
				attachmentCount: 0,
				styleObject: { 'noteText':null,'noteBackground':null, 'noteIcon':null, 'iconColor':null }, //Style object. Determines colors and badges

				sizeDown: false, //Used to animate close state

                //Settings vars
                lastVisibilityState: null,

                //All the squire settings
                editor: null,
                // pastFocusedNode: null,
                usersOnNote: 0,

                sideMenuOpen: false,
                tags: false,
                colors: false, 
                images: false,
                options: false,
                colorpicker: false,

                //active button states
                activeBold: false,
                activeQuote: false,
                activeTitle: false,
                activeList: false,
                activeToDo: false,
                activeColor: null,
			}
		},
		watch: {
			noteid:function(newVal, oldVal){

				// if(newVal == this.currentNoteId){
				// 	return
				// }

				// if(newVal == oldVal){
				// 	return
				// }
				
				// this.currentNoteId = newVal
				// this.loadNote(this.currentNoteId)
				
			},
			urlData(newVal, oldVal){

				//Handle changes in URL to 

				if(newVal.id == undefined || newVal.id != this.noteid){
					this.close()
				}

				//Reset all note menus on URL change
				this.sideMenuOpen = false
				this.colors = false
				this.tags = false
				this.options = false
				this.images = false

				//If a menu value is set, open it
				if(newVal.openMenu){
					//Only modify menu boolean if its defined
					if(typeof this[newVal.openMenu] == 'boolean'){
						this.sideMenuOpen = true
						this[newVal.openMenu] = true
					}
				}
			}
		},
		beforeMount(){
			this.$bus.$on('new_file_upload', ({noteId, imageCode}) => {
				if(this.noteid == noteId && this.editor){
					this.editor.moveCursorToEnd()
					this.editor.insertHTML(imageCode)
					this.save()
				}
			})
		},
		beforeDestroy(){

			// this.$io.emit('leave_room', this.rawTextId)

			this.$bus.$off('new_file_upload')

			document.removeEventListener('visibilitychange', this.checkForUpdatedNote)

			if(this.editor){
				this.editor.destroy()
			}
			
		},
		mounted: function() {

			setTimeout(()=>{
				this.forceShowLoading = false
			}, 500)

			document.addEventListener('visibilitychange', this.checkForUpdatedNote)

			this.$nextTick(() => {

				this.loadNote(this.noteid)
			})
		},
		methods: {
			initSquire(){
				
				//Set up squire and load note text
				this.editor = new Squire( this.$refs.squirebox, {blockTag: 'p' })
				this.setText(this.noteText)

				this.lastNoteHash = this.hashString(this.getText())
				// console.log('hash on load', this.lastNoteHash)

				//focus on open, not on mobile, it causes the keyboard to pop up, thats annoying
				if(!this.$store.getters.getIsUserOnMobile){
					this.editor.focus()
					this.editor.moveCursorToEnd()
				}

				//Change button states on editor when element is active
				//eg; Bold button turns green when on bold text
				this.editor.addEventListener('pathChange', e => {

					//Reset all button states
					this.activeBold = false
					this.activeTitle = false
					this.activeQuote = false
					this.activeList = false
					this.activeToDo = false
					this.activeColor = null

					let colors = e.path.match(/\d+/g)
					if(colors && colors.length == 3){
						this.activeColor=`rgb(${colors.join(',')})`
					}

					//@ TODO - Update this to match all elements, like color and bold
					// index of and then the specific thing might more indexOf('B'), indexOf('I'), etc

					let element = e.path.split('>').pop()
					switch (element) {
						case 'B': this.activeBold = true; break;
						case 'I': this.activeQuote = true; break;
						case 'SPAN.size[fontSize=1.4em]': this.activeTitle = true; break;
					}

					let parent = e.path.split('>').shift()
					switch (parent) {
						case 'OL': this.activeList = true; break;
						case 'UL': this.activeToDo = true; break;
					}

				})

				//Click Event - Open links when clicked in editor or toggle checks
				this.editor.addEventListener('click', e => {

					//Link clicked in editor - open link
					if(e.target.nodeName == 'A' && e.target.href){
						window.open(e.target.href)
					}

					//List Item clicked in editor - toggle link state
					if(e.target.nodeName == 'LI'){

						let el = e.target

						//Adjust ofset by 40 px
						let correction = 40

						//Determine if element was clicked or area before it, before means checkbox was clicked
						if (e.offsetX > e.target.offsetLeft  - correction) {
							//Element was clicked
						} else {

							//Will hide keyboard if clicked, much better for mobile
							this.editor.blur()

							//Area before element was clicked, they clicked the checkbox
							this.onKeyup()
							if (el.className === 'active'){
								el.className = 'inactive';
							} else {
								el.className = 'active';
							}
						}

						
					}
					
				})

				this.editor.addEventListener('keydown', event => {

					//Prevent new list items from having 
					this.$nextTick( () => {
						//Wait a moment to get item under cursor
						let selection = this.editor.getSelection()
						let container = selection.commonAncestorContainer

						//If user hit enter on a list, make sure the next list item isn't active
						if(container.nodeName == 'LI' && event.keyCode == 13 && container.classList){
							container.classList.remove('active')
						}
					})
				})

				//Bind event handlers
				this.editor.addEventListener('keyup', event => this.onKeyup(event) )

				//Show and hide additional toolbars
				this.editor.addEventListener('focus', e => {
					//Add events here if you like
				})
				this.editor.addEventListener('blur',  e => {

					this.save()
				})
			},
			//If nothing is selected, select the entire line
			selectLineIfNoSelect(){

				//Select entire line if range is not set 
				let selection = this.editor.getSelection()

				if(selection.startOffset == selection.endOffset && selection.startContainer == selection.endContainer){

					let squireRange = this.editor.createRange(
						selection.startContainer, 0, 
						selection.endContainer, selection.commonAncestorContainer.textContent.length)

					this.editor.setSelection(squireRange)
				}
			},
			removeFormatting(){
				this.selectLineIfNoSelect()
				this.editor.removeAllFormatting()
			},
			modifyFont(inSize){

				this.selectLineIfNoSelect()

				let fontInfo = this.editor.getFontInfo()
				//Toggle font size between large and normal
				if(fontInfo.size){
					this.editor.setFontSize(null)
				} else {
					this.editor.setFontSize(inSize)
				}
			},
			modifyColor(color){

				this.selectLineIfNoSelect()
				//Set color of font
				this.editor.setTextColour(color)
			},
			toggleList(type){

				//Undo list if its already a lits
				if(this.editor.hasFormat(type)){
					this.editor.removeList()
					return
				}

				if(type == 'ol'){
					this.editor.makeOrderedList()
				}
				if(type == 'ul'){
					this.editor.makeUnorderedList()
				}
			},
			toggleBold(){
				this.selectLineIfNoSelect()
				if( this.editor.hasFormat('b') ){
					this.editor.removeBold()
				} else {
					this.editor.bold()
				}
			},
			toggleItalic(){
				this.selectLineIfNoSelect()
				if( this.editor.hasFormat('i') ){
					this.editor.removeItalic()
				} else {
					this.editor.italic()
				}
			},
			undoCustom(){
				//The same as pressing CTRL + Z 
				// this.editor.focus()
				// document.execCommand("undo", false, null)
				this.editor.undo()
			},
			uncheckAllListItems(){
				//
				// Uncheck All List Items
				//

				//Close menu if user is on mobile, then sort list
				if(this.$store.getters.getIsUserOnMobile){
					this.options = false
				}

				//Fetch the container
				let container = document.getElementById('squire-id')

				Array.from( container.getElementsByClassName('active') ).forEach(item => {
					item.classList.remove('active');
				})
			},
			deleteCompletedListItems(){
				//
				// Delete Completed List Items
				//

				//Close menu if user is on mobile, then sort list
				if(this.$store.getters.getIsUserOnMobile){
					this.options = false
				}

				//Fetch the container
				let container = document.getElementById('squire-id')

				//Go through each item, on first level, look for Unordered Lists
				container.childNodes.forEach( (node) => {
					if(node.nodeName == 'UL'){

						//Create two categories, done and not done list items
						let undoneElements = document.createDocumentFragment()

						//Go through each item in each list we found
						node.childNodes.forEach( (checkListItem, index) => {

							//Skip Embedded lists, they are handled with the list item above them. Keep lists with intented items together
							if(checkListItem.nodeName == 'UL'){
								return
							}

							//Check if list item has active class
							const checkedItem = checkListItem.classList.contains('active')

							//Check if the next item is a list, Keep lists with intented items together
							let sublist = null
							if(node.childNodes[index+1] && node.childNodes[index+1].nodeName == 'UL'){
								sublist = node.childNodes[index+1]
							}

							//Push checked items and their sub lists to the done set
							if(!checkedItem){

								undoneElements.appendChild( checkListItem.cloneNode(true) )
								if(sublist){
									undoneElements.appendChild( sublist.cloneNode(true) )
								}

							}

						})

						//Remove all HTML from node, push unfinished items, then finished below them
						node.innerHTML = null
						node.appendChild(undoneElements)
						
					}
				})
			},
			sortList(){
				//
				// Sort list, checked at the bottom, unchecked at the top
				//

				//Close menu if user is on mobile, then sort list
				if(this.$store.getters.getIsUserOnMobile){
					this.options = false
				}

				//Fetch the container
				let container = document.getElementById('squire-id')

				//Go through each item, on first level, look for Unordered Lists
				container.childNodes.forEach( (node) => {
					if(node.nodeName == 'UL'){

						//Create two categories, done and not done list items
						let doneElements = document.createDocumentFragment()
						let undoneElements = document.createDocumentFragment()

						//Go through each item in each list we found
						node.childNodes.forEach( (checkListItem, index) => {

							//Skip Embedded lists, they are handled with the list item above them. Keep lists with intented items together
							if(checkListItem.nodeName == 'UL'){
								return
							}

							//Check if list item has active class
							const checkedItem = checkListItem.classList.contains('active')

							//Check if the next item is a list, Keep lists with intented items together
							let sublist = null
							if(node.childNodes[index+1] && node.childNodes[index+1].nodeName == 'UL'){
								sublist = node.childNodes[index+1]
							}

							//Push checked items and their sub lists to the done set
							if(checkedItem){

								doneElements.appendChild( checkListItem.cloneNode(true) )
								if(sublist){
									doneElements.appendChild( sublist.cloneNode(true) )
								}

							} else {

								undoneElements.appendChild( checkListItem.cloneNode(true) )
								if(sublist){
									undoneElements.appendChild( sublist.cloneNode(true) )
								}
							}

						})

						//Remove all HTML from node, push unfinished items, then finished below them
						node.innerHTML = null
						node.appendChild(undoneElements)
						node.appendChild(doneElements)
						
					}
				})
			},
			calculateMath(){
				//
				// Find math in note and calculate the outcome
				//

				//Close menu if user is on mobile, then sort list
				if(this.$store.getters.getIsUserOnMobile){
					this.options = false
				}

				//Fetch the container
				let container = document.getElementById('squire-id')

				// simple function that trys to evaluate javascript
				const shittyMath = (string) => {
					//Remove all chars but math chars
					const cleanString = String(string).replace(/[a-zA-Z\s]*/g,'')
					try {
						return Function('"use strict"; return (' + cleanString + ')')();
					} catch (error) {
						console.log('Math Error: ', string)
						return null
					}
				}

				//Go through each item, on first level, look for Unordered Lists
				container.childNodes.forEach( (node) => {

					const line = node.innerText.trim()

					// = sign exists and its the last character in the string
					if(line.indexOf('=') != -1 && (line.length-1) == line.indexOf('=')){

						//Pull out everything before the formula and try to evaluate it
						const formula = line.split('=').shift()
						const output = shittyMath(formula)

						//If its a number and didn't throw an error, update the line
						if(!isNaN(output) && output != null){

							//Since there is HTML in the line, splice in the number after the = sign
							let equalLocation = node.innerHTML.indexOf('=')
							let newLine = node.innerHTML.slice(0, equalLocation+1).trim()
							newLine += ` ${output}`
							newLine += node.innerHTML.slice(equalLocation+1).trim()

							//Slam in that new HTML with the output
							node.innerHTML = newLine
						}
					}
					
				})
			},
			setText(inText){

				this.editor.setHTML(inText)
				this.noteText = this.editor._getHTML()
				this.diffNoteText = this.editor._getHTML()
			},
			getText(){

				return this.editor.getHTML()
			},
			openEditAttachment(){

				this.$router.push('/attachments/note/'+this.currentNoteId)
			},
			onTogglePinned(){

				if(this.pinned == 0){
					this.pinned = 1
				} else {
					this.pinned = 0;
				}
				//Update last note hash, this will tell note to save next update
				this.lastNoteHash = 0
				this.save()
			},
			onToggleArchived(){

				if(this.archived == 0){
					this.archived = 1
				} else {
					this.archived = 0;
				}
				//Update last note hash, this will tell note to save next update
				this.lastNoteHash = 0
				this.save()
			},
			onChangeColor(newStyleObject){

				//Set new style object for note, page will use some styles, styles will be saved to database
				this.styleObject = newStyleObject

				this.lastNoteHash = 0 //Update hash to force note update on next save
				this.save()
			},
			loadNote(noteId){

				//Generate a random loading message
				let mod = ['Gently','Calmly','Lovingly','Quickly','','','','','','','','','','','','','']
				let doing = ['Loading','Loading','Getting','Fetching','Grabbing','Sequencing','Organizing','Untangling','Processing','Refining','Extracting','Fusing','Pruning','Expanding','Enlarging','Transfiguring','Quantizing','Ingratiating','Lumping']
				let thing = ['Note','Note','Note','Note','Data','Text','Document','Algorithm','Buffer','Client','Download','File','Frame','Graphics','Hardware','HTML','Interface','Logic','Mainframe','Memory','Media','Nodes','Network','Chaos']

				let p1 = mod[Math.floor(Math.random() * mod.length)]
				let p2 = doing[Math.floor(Math.random() * doing.length)]
				let p3 = thing[Math.floor(Math.random() * thing.length)]
				this.loadingMessage = `${p1} ${p2} ${p3}`
				
				//Component is activated with NoteId in place, lookup text with associated ID
				if(this.$store.getters.getLoggedIn){
					axios.post('/api/note/get', { 'noteId': this.noteid })
					.then(response => {

						//Block notes you don't have access to from opening
						if(response.data === false){
							this.$bus.$emit('notification', 'Error opening Note')
							this.close(true)
							return
						}

						//Set up local data
						this.currentNoteId = this.noteid
						this.rawTextId = response.data.rawTextId
						this.shareUsername = response.data.shareUsername

						this.created = response.data.created
						this.updated = response.data.updated
						this.noteTitle = ''
						if(response.data.title){
							this.noteTitle = response.data.title
						}

						this.noteText = response.data.text
						this.diffNoteText = response.data.text

						//Set up note colors
						if(response.data.color){
							this.styleObject = JSON.parse(response.data.color)
						}
						
						if(response.data.pinned != null){
							this.pinned = response.data.pinned
						}
						this.archived = response.data.archived
						this.attachmentCount = response.data.attachment_count

						this.loading = false

						this.$nextTick(() => {

							//Adjust note title size after load
							this.titleResize()
							this.setupWebSockets()
							this.initSquire()
						})

					})
					.catch(error => { this.$bus.$emit('notification', 'Failed to Open Note') })
				} else {
					console.log('Could not fetch note')
				}
			},
			diffText(){

				return

				// dont emit to one user
				if(this.usersOnNote <= 1){
					return
				}

				//Post latest diff to server, server will emit change event to all connected clients
				// clearTimeout(this.emitChangeDebounce)
				this.emitChangeDebounce = setTimeout(i => {

					//caldulate text diff
					let oldText = this.diffNoteText
					let newText = this.getText()

					if(oldText == newText){
						return
					}

					const dmp = new DiffMatchPatch.diff_match_patch()
					const diff = dmp.diff_main(oldText, newText)
					// dmp.diff_cleanupSemantic(diff)
					const patch_list = dmp.patch_make(oldText, newText, diff);
  					const patch_text = dmp.patch_toText(patch_list);


  					var patches = dmp.patch_fromText(patch_text);
  					var results = dmp.patch_apply(patches, oldText);

  					const computedText = results[0]

  					//Save computed diff text
  					this.noteText = computedText
  					this.diffNoteText = computedText

  					if(patch_text == ''){
  						return
  					}

  					// console.log(patch_text)
					this.$io.emit('note_diff', {
						id: this.rawTextId,
						diff: patch_text
					})


				}, 5)
			},
			patchText(patch_text){

				return

				//
				// Capture x,y of caret and position into string
				//

				let currentSelection = this.editor.getSelection()
				let lineText = currentSelection.startContainer.textContent
				// console.log(lineText)
				let cursorOffset = parseInt(currentSelection.startOffset) //number of characters in
				let path = this.xpath(currentSelection.commonAncestorContainer.parentElement)
				// console.log(path)

			
				//
				//Set up text to process diff
				//

				let currentText = this.editor._getHTML()
				const startingLines = (currentText.match(/<br>/g) || '').length + 1
				// console.log('1')

				const dmp = new DiffMatchPatch.diff_match_patch()
				var patches = dmp.patch_fromText(patch_text);
				var results = dmp.patch_apply(patches, currentText);
				let newText = results[0]
				// console.log('2')

				this.noteText = newText
				this.diffNoteText = newText
				// console.log('3')
				// this.editor._setHTML(newText)
				this.editor.setHTML(newText)

				// console.log('4')

				//
				// I user hasn't selected the document, we are done here
				// @TODO add code to halt execution
				//

				const endingLines = (newText.match(/<br>/g) || '').length + 1

				// if(this.pastFocusedNode != null || true){
					setTimeout( ()=>{

						var root = this.editor.getRoot()
						//Get node under current x,y on dom (may break on scroll)
						// let node = document.elementFromPoint(mouse.x, mouse.y)
						let node = this.getElementByXPath(path)

						if(node.firstChild){
							node = node.firstChild
						}

						//If the number of lines changed
						if(startingLines != endingLines){

							//Line diff may be +1 or -1 
							let lineDiff = endingLines - startingLines
							console.log('Line Diff => ', lineDiff)

							//Pull out node number from path
							var nodeNumber = path.match(/\d+/)
							let modifyNode = null
							if(nodeNumber.length == 1){
								modifyNode = parseInt(nodeNumber[0])
							}

							path = path.replace(modifyNode, modifyNode + lineDiff )
							console.log(path)
							let maybeNext = this.getElementByXPath(path)
							if(maybeNext && maybeNext.firstChild){
								maybeNext = maybeNext.firstChild
							}

							if(maybeNext && maybeNext.textContent == lineText){
								node = maybeNext
								console.log('The Node Moved!')
							}
						}

						// console.log('Targeting Node')
						// console.log(node)

						//Create and set range
						let squireRange = this.editor.createRange(node, cursorOffset)
						squireRange.collapse(true)
						this.editor.setSelection(squireRange)
						// console.log('cursor set')

					}, 20)
				// }
			},
			xpath(el) {
				//Skip things we can't use
				if (typeof el == "string") return document.evaluate(el, document, null, 0, null)
				if (!el || el.nodeType != 1) return ''

				//Anchor xpath using Ids or test-ids
				const testId = el.getAttribute('test-id')
				if (el.id) return "//*[@id='" + el.id + "']"

				//Continue to build path
				const sames = [].filter.call(el.parentNode.children, function (x) { return x.tagName == el.tagName })
				return this.xpath(el.parentNode) + '/' + el.tagName.toLowerCase() + (sames.length > 1 ? '['+([].indexOf.call(sames, el)+1)+']' : '')
			},
			getElementByXPath(xpath){

				return new XPathEvaluator()
					.createExpression(xpath)
					.evaluate(document, XPathResult.FIRST_ORDERED_NODE_TYPE) .singleNodeValue 
			},
			onKeyup(){

				this.statusText = 'modified'

				// this.diffText()

				//Each note, save after 15 seconds, focus lost or 30 characters typed.
				clearTimeout(this.editDebounce)
				this.editDebounce = setTimeout(() => {
					this.save()
				}, 15 * 1000)

				//Save after 50 keystrokes
				this.keyPressesCounter = (this.keyPressesCounter + 1)
				if(this.keyPressesCounter > 50){
					this.keyPressesCounter = 0
					this.save()
				}
			},
			save(){
				return new Promise((resolve, reject) => {
					//Clear other debounced events to prevent double calling of save
					// clearTimeout(this.editDebounce)

					// return resolve(true)

					//Don't save note if its hash doesn't change
					const currentNoteText = this.getText()
					const currentHash = this.hashString( currentNoteText )
					if( this.lastNoteHash == currentHash){
						this.statusText = 'saved'
						return resolve(true)
					}

					//If user accidentally clears note, it won't delete it
					if(currentNoteText == ''){
						return resolve(true)
					}
					
					const postData = {
						'noteId': this.currentNoteId,
						'title': this.noteTitle,
						'text': currentNoteText,
						'color': JSON.stringify(this.styleObject), //Save little json color object
						'pinned': this.pinned,
						'archived': this.archived,
						'hash': currentHash,
					}

					// console.log('Save Hash', currentHash)

					this.statusText = 'saving'
					axios.post('/api/note/update', postData).then( response => {
						this.statusText = 'saved'
						this.updated = Math.round((+new Date)/1000)
						this.modified = true

						//Update last saved note hash
						// this.lastNoteHash = this.hashString( currentNoteText )
						this.lastNoteHash = currentHash
						return resolve(true)
					})
					.catch(error => { this.$bus.$emit('notification', 'Failed to Save Note') })
				})
			},
			checkForUpdatedNote(){

				//Ignore visibility changes, handle this with socket IO
				//Just keep it always up to date if user is on note
				return

				//If user leaves page then returns to page, reload the first batch
				if(this.lastVisibilityState == 'hidden' && document.visibilityState == 'visible'){
					// console.log('Checking for note updates after visibility change.')

					const postData = { 
						noteId:this.currentNoteId, 
						text:this.getText(),
						updated: this.updated
					}

					console.log('Focus regained with note open.')
					console.log('Attempting to fix diff text. fix this. Search spleen')
					return

					axios.post('/api/note/difftext', postData)
					.then( ({data}) => {

						//Don't do anything if nothing has changed
						if(data == ''){ return }

						if(data.diffs > 0){
							//Update text and last updated time for note
							this.setText(data.updatedText)
							this.updated = data.updated
						}
					})
					.catch(error => { this.$bus.$emit('notification', 'Failed to get diff') })
				}

				//Track visibility state 
				this.lastVisibilityState = document.visibilityState
			},
			hashString(inText){

				let text = this.noteTitle + inText

				let hash = 0;
				if (text == null || text.length == 0) {
					return hash;
				}

				for (let i = 0; i < text.length; i++) {
					let char = text.charCodeAt(i);
					hash = ((hash<<5)-hash)+char;
					hash = hash & hash; // Convert to 32bit integer
				}

				return hash;
			},
			close(force = false){

				if(force){
					this.$bus.$emit('close_active_note', {
						position: this.position, noteId: this.noteid, modified: this.modified
					})
					return
				}

				this.save().then( result => {

					//If note was modified, trigger reindex on close
					if(this.modified){
						axios.post('/api/note/reindex')
					}

					this.sizeDown = true
					//This timeout allows animation to play before closing 
					setTimeout(() => {
						this.$bus.$emit('close_active_note', {
							position: this.position, noteId: this.noteid, modified: this.modified
						})
						return
					}, 300)
				})
			},
			setupWebSockets(){

				this.$io.on('new_note_text_saved', ({noteId, hash}) => {
					// console.log('Current hash', this.lastNoteHash)
					// console.log('Incoming Hash', hash)
				})

				return

				//Tell server to push this note into a room
				this.$io.emit('join_room', this.rawTextId)

				this.$io.on('update_user_count', userCount => {
					this.usersOnNote = userCount
				})
				
				//Server will hand deliver diffs from other notes to this one
				this.$io.on('incoming_diff', incomingDiffData => {
					this.patchText(incomingDiffData)
				})
			},
			titleResize(){
				//Resize the title field
				let element = this.$refs.titleTextarea
				let padding = 0

				element.style.height = 'auto';
      			element.style.height = (element.scrollHeight + padding) +'px';
			},
		}
	}
</script>

<style type="text/css" scoped>

	.full-focus-shade {
		position: fixed;
		top: 0;
		left: 0;
		right: 0;
		bottom: 0;
		background-color: var(--menu-accent);
		z-index: 999;
		cursor: pointer;
		opacity: 0.8;
	}
	.shade1 {
		left: 50%;
	}
	.shade2 {
		right: 50%;
	}

	/* squire styles */
	.input-container-wrapper {
		position: fixed;
		top: 0;
		bottom: 0;
		left: 15%;
		right: 15%;
		z-index: 1005;
		overflow-x: scroll;
		scrollbar-width: none;
	}
	.note-wrapper {
		background-color: var(--background_color);
		border: 1px solid var(--menu-accent);;
		margin: 45px 0 45px 0;
		position: relative;
	}

	/*
	
	Edit Menu Styles START
	
	*/
		.edit-menu {
			position: fixed;
			top: 0;
			left: 0;
			right: 0;
			width: 100%;
			display: block;
			background-color: var(--background_color);
			z-index: 1019;
			padding: 3px 5px;
			border: none;
			border-bottom: 1px solid var(--menu-accent);
		}
		.menu-top-half, .menu-bottom-half {
			display: inline-block;
		}
		.edit-spacer {
			width: calc(15% - 10px);
			display: inline-block;
			height: 10px;
			opacity: 0;
		}
		.edit-button {
			background-color: var(--background_color);
			color: var(--menu-text);
			display: inline-block;
			font-size: 1.4em;
			padding: 4px 1px 5px 4px;
			border-radius: 3px;
			cursor: pointer;
		}
		.edit-button:hover {
			background-color: var(--menu-accent);
		}
		.edit-active {
			background-color: #21BA45;
			color: white;
		}
		.edit-divide {
			display: inline-block;
			background-color: var(--menu-accent);
			height: 15px;
			width: 1px;
			margin: 0 1px;
			padding: 0;
		}
		@media only screen and (max-width: 740px) {
			.edit-spacer {
				display: none;
			}
		}
	/*
	
	Edit Menu Styles END
	
	*/

	.stealth-input {
		width: 100%;
		padding: 10px 15px 5px;
		background-color: rgba(255,255,255,0.1);
		border: none;
		font-size: 1.7em;
		color: var(--text_color);
		resize: none;
		overflow: hidden;
		margin: 0;

	}

	/*Settings manager styles */
	.all-settings {
		background: #221f2b;
		z-index: 99;
		flex-grow: 0;
	}
	/*End Settings manager styles */



	/* container styles change based on mobile and number of open screens */
	.master-note-edit {
		position: fixed;
		bottom: 0;
		height: 100vh;
		z-index: 1001;

		overflow-y: scroll;
		overflow-x: hidden;
	}
	.loading-note {
		position: absolute;
		top: 0;
		width: 100%;
		height: 100%;
		min-height: 300px;
		/*background: var(--background_color);*/
		/*opacity: 0.;*/
		z-index: 1;
	}
	.loading-text {
		margin: 0;
	    position: absolute;
	    top: 200px;
	    left: 50%;
	    margin-right: -50%;
	    transform: translate(-50%, -50%);
	}

	/* One note open, in the middle of the screen */
	.master-note-edit.position-0 {
		left: 50%;
		right: 0;
	}
	.master-note-edit.full-focus {
		left: 15%;
		right: 15%;
	}
	.side-menu-open {
		left: calc(50% + 10px) !important;
		right: calc(0% + 10px) !important;
	}
	@media only screen and (max-width: 740px) {
		.input-container-wrapper {
			left: 0;
			right: 0;
			top: 35px;
			bottom: 40px;
			background-color: var(--background_color);
		}
		.note-wrapper {
			margin: 0;
			border: none;
		}
		.shade1, .shade2 {
			right: 150%;
		}
		/*menu overwrites */
		.bottom-edit-menu {
			position: fixed;
			bottom: 0;
			left: 0;
			right: 0;
			width: 100%;
			display: block;
			background-color: var(--background_color);
			z-index: 1012;
			border: none;
			border-top: 1px solid var(--menu-accent);
			min-height: 40px;
		}
		.edit-menu {
			text-align: center;
		}
		.menu-bottom-half {
			z-index: 1005;
			position: fixed;
			bottom: 4px;
			left: 0;
			right: 0;
			text-align: center;
		}
	}

	/* Two Notes Open, each takes up 50% of the space */
	.master-note-edit.position-1 {
		left: 50%;
		right: 0%;
	}
	
	

	.master-note-edit.position-2 {
		left: 0%;
		right: 50%;
	}
	.master-note-edit.position-3 {
		display: inline-block;
		position: inherit;
		width: 100%;
		min-height: 200px;
		height: auto;
		box-shadow: none;
	}

	/* animations START */

		.slide-out-top {
			animation: slide-out-top 0.5s ease;
		}

		@keyframes slide-out-top {
			0% {
				top: 0;
			}
			100% {
				top: -100px;
			}
		}

		.size-down {
			animation: size-down 0.5s ease;
		}

		@keyframes size-down {
			0% {
				top: 0;
			}
			100% {
				top: 150vh;
			}
		}

		.slide-out-left {
			animation: slide-out-left 0.5s ease;
		}

		@keyframes slide-out-left {
			0% {
				left: 85%;
			}
			100% {
				left: 150%;
			}
		}

		.slide-out-right {
			animation: slide-out-right 0.5s ease;
		}

		@keyframes slide-out-right {
			0% {
				right: 85%;
			}
			100% {
				right: 150%;
			}
		}

		/* Fade out transition animation */
		.fade-enter {
			/*opacity: 0;*/
		}

		.fade-enter-active {
			/*transition: opacity 0.7s;*/
		}

		.fade-leave {
			/* opacity: 0; */
		}

		.fade-leave-active {
			transition: opacity 0.7s;
			opacity: 0;
		}
	/* animations END */

</style>