note
	description : "simple application execution"
	date        : "$Date: 2018-02-02 14:04:16 -0800 (Fri, 02 Feb 2018) $"
	revision    : "$Revision: 101350 $"

class
	APPLICATION_EXECUTION

inherit
	WSF_WEBSOCKET_EXECUTION
		redefine
			initialize
		end

	WEB_SOCKET_EVENT_I
		redefine
			on_timer
		end

	LOGIN_WITH_GITHUB_CONSTANTS


create
	make

feature -- Basic operations

	initialize
	local
		env : EXECUTION_ENVIRONMENT
		do
			Precursor
			create env
 			if attached env.item ("TEST_COMPUTER") as test then
				 create database.make("http://localhost:11004")
			else
	 			create database.make("http://localhost:7474")
			end

        end

	execute
		local
			s: STRING
			dt: HTTP_DATE
			shutdown_command :  WEBSOCKET_SERVER_SHUTDOWN_COMMAND
			l_github_service: LOGIN_WITH_GITHUB_SERVICE
			mesg: WSF_RESPONSE_MESSAGE
 		do
 			create shutdown_command
 			shutdown_command.shutdown_server (Current)

			execute_oauth_session_filter

 			-- To send a response we need to setup, the status code and
 			-- the response headers.
			if request.path_info.same_string_general ("/favicon.ico") then
				response.put_header ({HTTP_STATUS_CODE}.not_found, <<["Content-Length", "0"]>>)
			elseif request.path_info.same_string_general ("/svg.js") then
				create {WSF_FILE_RESPONSE} mesg.make_with_content_type ({HTTP_MIME_TYPES}.text_javascript ,"svg.js")
				response.send (mesg)
			elseif request.path_info.same_string_general ("/svg.draggy.js") then
				create {WSF_FILE_RESPONSE} mesg.make_with_content_type ({HTTP_MIME_TYPES}.text_javascript ,"svg.draggy.js")
				response.send (mesg)
			elseif request.path_info.same_string_general ("/svg.connectable.js") then
				create {WSF_FILE_RESPONSE} mesg.make_with_content_type ({HTTP_MIME_TYPES}.text_javascript ,"svg.connectable.js")
				response.send (mesg)
			else

				if request.path_info.same_string_general ("/test") then
					if is_test then
						s := websocket_test_html (request.server_name, request.server_port)
						response.put_header ({HTTP_STATUS_CODE}.ok, <<["Content-Type", "text/html"], ["Content-Length", s.count.out]>>)
						response.set_status_code ({HTTP_STATUS_CODE}.ok)
						response.header.put_content_type_text_html
						response.header.put_content_length (s.count)
						if request.is_keep_alive_http_connection then
							response.header.put_connection_keep_alive
						end
						response.put_string (s)
					end
				elseif request.has_execution_variable ("user") and then attached {STRING_32}request.execution_variable ("user") as user and then (user.is_equal ("andersoxie") or user.is_equal ("LouiseBSharp")  or user.is_equal ("GabijaBSharp")) then
--				if request.has_execution_variable ("user")  then
					-- Authenticated case
					if request.path_info.same_string_general ("/Logout.html") then
						handle_logout (request, response)
					else

						if request.path_info.same_string_general ("/app") then
							s := websocket_app_html (request.server_name, request.server_port)
						elseif request.path_info.same_string_general ("/admin") and request.has_execution_variable ("user") and then attached {STRING_32}request.execution_variable ("user") as adminuser and then (adminuser.is_equal ("andersoxie")) then
							s := websocket_admin_html (request.server_name, request.server_port)
						else
				 			s := "Hello World!"
							if attached {STRING_32}request.execution_variable ("user") as user2 then
								s.append (user2)
							end
							create dt.make_now_utc
							s.append (" (UTC time is " + dt.rfc850_string + ").")
							s.append ("<p><h1><a href=%"/app%">BSharp AB ToDo</a></h1></p>")
						end
						response.put_header ({HTTP_STATUS_CODE}.ok, <<["Content-Type", "text/html"], ["Content-Length", s.count.out]>>)
						response.set_status_code ({HTTP_STATUS_CODE}.ok)
						response.header.put_content_type_text_html
						response.header.put_content_length (s.count)
						if request.is_keep_alive_http_connection then
							response.header.put_connection_keep_alive
						end
						response.put_string (s)
					end
				else
					-- Not Authenticated case
                    l_github_service := github_service (request)

					-- URI /login_with_github
					if request.path_info.same_string_general ("/login_with_github") then
						handle_login_with_github (request, response)

					elseif
						-- URI /login_with_github_callback
						l_github_service /= Void and then
						request.path_info.same_string_general (l_github_service.callback_uri_path)
					then
						handle_login_with_github_callback (request, response)
					else
			 			s := "Hello World!"

						if attached request.execution_variable ("user") as user then
							s.append (user.tagged_out)
						end


						create dt.make_now_utc
						s.append (" (UTC time is " + dt.rfc850_string + ").")
						s.append ("<p><h1><a href=%"/login_with_github%">Login with GitHub</a></h1></p>")

						response.put_header ({HTTP_STATUS_CODE}.ok, <<["Content-Type", "text/html"], ["Content-Length", s.count.out]>>)
						response.set_status_code ({HTTP_STATUS_CODE}.ok)
						response.header.put_content_type_text_html
						response.header.put_content_length (s.count)
						if request.is_keep_alive_http_connection then
							response.header.put_connection_keep_alive
						end
						response.put_string (s)

					end


				end
			end
		end

	execute_oauth_session_filter
                       -- Filter the request to set the current user if the oauth tokens exists.
 		do
			if
				attached {WSF_STRING} request.cookie (oauth_session_token) as l_roc_auth_session_token and then
				attached {WSF_STRING} request.cookie (oauth_user_login) as l_user
			then
				request.set_execution_variable ("user", l_user.value)
 			end
 		end

 	handle_login_with_github (req: WSF_REQUEST; res: WSF_RESPONSE)
 		local
 			l_github_service: LOGIN_WITH_GITHUB_SERVICE
 		do
			l_github_service := github_service (req)
			if l_github_service /= Void then
				l_github_service.set_error_procedure (agent handle_login_error)
				l_github_service.process_login (req, res)
 			else
 				handle_login_error (req, res, "Internal error! Set Github settings in %"github.ini%".")
 			end
 		end

	handle_login_with_github_callback (req: WSF_REQUEST; res: WSF_RESPONSE)
		local
			l_github_service: LOGIN_WITH_GITHUB_SERVICE
	 	do
	 		l_github_service := github_service (req)
	 		if l_github_service = void then
	 			handle_login_error (req, res, "Internal error (please set Github settings!)")
	 		else
	 			l_github_service.set_error_procedure (agent handle_login_error)
	 			l_github_service.process_oauth_callback (req, res,
	 				agent (i_req: WSF_REQUEST; i_res: WSF_RESPONSE; i_access_token: OAUTH_TOKEN; i_user: READABLE_STRING_GENERAL)
						local
	 						l_cookie: WSF_COOKIE
	 						conv: UTF_CONVERTER
	 						dt: DATE_TIME
	 						l_expires_in: INTEGER
	 					do
							if i_access_token.expires_in = 0 then
								l_expires_in := 3600
							else
								l_expires_in := i_access_token.expires_in
							end
							create dt.make_now_utc
							dt.second_add (l_expires_in)

							create l_cookie.make ({LOGIN_WITH_GITHUB_CONSTANTS}.oauth_session_token, i_access_token.token)
							l_cookie.set_max_age (l_expires_in)
							l_cookie.set_expiration_date (dt)
							l_cookie.set_path ("/")
							i_res.add_cookie (l_cookie)

							create l_cookie.make ({LOGIN_WITH_GITHUB_CONSTANTS}.oauth_user_login, conv.utf_32_string_to_utf_8_string_8 (i_user))
							l_cookie.set_max_age (l_expires_in)
							l_cookie.set_expiration_date (dt)
							l_cookie.set_path ("/")
							i_res.add_cookie (l_cookie)
							compute_response_redirect (i_req, i_res, i_req.absolute_script_url ("/app"))
	 					end
	 				)
	 		end
		end

		handle_logout (req: WSF_REQUEST; res: WSF_RESPONSE)
			local
				l_cookie: WSF_COOKIE
			do
				if
					attached {WSF_STRING} req.cookie ({LOGIN_WITH_GITHUB_CONSTANTS}.oauth_session_token) as l_cookie_token
				then
					req.unset_execution_variable ("user")
						-- Logout OAuth
					create l_cookie.make ({LOGIN_WITH_GITHUB_CONSTANTS}.oauth_session_token, "")
					l_cookie.set_path ("/")
					invalidate_cookie (l_cookie)
					res.add_cookie (l_cookie)

						-- Logout OAuth
					create l_cookie.make ({LOGIN_WITH_GITHUB_CONSTANTS}.oauth_user_login, "")
					l_cookie.set_path ("/")
					invalidate_cookie (l_cookie)
					res.add_cookie (l_cookie)

					req.unset_execution_variable ("user")
				end
				compute_response_redirect (req, res, req.absolute_script_url (""))
			end

	invalidate_cookie (a_cookie: WSF_COOKIE)
		do
			a_cookie.set_value ("") -- Remove data for security
			a_cookie.set_expiration_date (create {DATE_TIME}.make_from_epoch (0)) -- expiration in the past!
			a_cookie.set_max_age (0) -- Instructs the user-agent to delete the cookie
		end

 	compute_response_redirect (req: WSF_REQUEST; res: WSF_RESPONSE; a_url: STRING)
 		do
 			res.redirect_now (a_url)
 		end

	handle_login_error (req: WSF_REQUEST; res: WSF_RESPONSE; a_error_message: READABLE_STRING_GENERAL)
 		local
-- 			err: ERROR_PAGE
			msg: WSF_HTML_PAGE_RESPONSE
		do
--	   		create err.make (req.absolute_script_url (""), a_error_message, Void)
--	   		if attached err.representation as str then
--	   			compute_response_get (req, res, str)
--			else
	 			create msg.make
				msg.set_body (msg.html_encoded_string (a_error_message.to_string_32))
				res.send (msg)
--		   	end
		end

 	facebook__service (req: WSF_REQUEST): detachable LOGIN_WITH_FACEBOOK_SERVICE
 		local
 			l_setup: LOGIN_WITH_FACEBOOK_SETUP
		do
			create l_setup.make_from_path (create {PATH}.make_from_string ("facebook.ini"))
			if l_setup.is_valid then
				create Result.make (l_setup, "/login_with_facebook_callback", req)
			end
		end

		github_service (req: WSF_REQUEST): detachable LOGIN_WITH_GITHUB_SERVICE
	 		local
	 			l_setup: LOGIN_WITH_GITHUB_SETUP
			do
				create l_setup.make_from_path (create {PATH}.make_from_string ("github.ini"))
				if l_setup.is_valid then
					create Result.make (l_setup, "/login_with_github_callback", req)
				end
			end

feature -- Implementation

	database: NEO4J_DATABASE

	write_debug_message (ws: WEB_SOCKET;message : STRING)
	local
		env : EXECUTION_ENVIRONMENT
	do
		create env
		if attached env.item ("TEST_COMPUTER") as test then
				ws.send (Text_frame,message )
		end
	end

	is_test:BOOLEAN
	local
		env : EXECUTION_ENVIRONMENT
	once
		create env
		if attached env.item ("TEST_COMPUTER") as test then
				Result := true
		end
	end



feature -- Websocket execution

	new_websocket_handler (ws: WEB_SOCKET): WEB_SOCKET_HANDLER
		do
			create Result.make (ws, Current)
		end

feature -- Websocket execution

	on_open (ws: WEB_SOCKET)
		do
			initialize_commands
			set_timer_delay (1) -- Orginal was 1 second
--			ws.socket.set_timeout_ns(1000000000)




			if attached ws.request.cookie ({LOGIN_WITH_GITHUB_CONSTANTS}.oauth_user_login) as user2 then
				write_debug_message (ws, "You are: "  + user2.string_representation )
			end



			ws.put_error ("Connecting")
			write_debug_message (ws, "Hello, this is a simple demo with Websocket using Eiffel. (/help for more information).%N")

			-- Send filter to user
			create_project_filter (ws)
			create_status_filter (ws)
			create_date_filter(ws)

		end

	on_binary (ws: WEB_SOCKET; a_message: READABLE_STRING_8)
		do
			ws.send (Binary_frame, a_message)
		end

	on_text (ws: WEB_SOCKET; a_message: READABLE_STRING_8)
		local
			i: INTEGER
			cmd_name: READABLE_STRING_8
		do

			if attached ws.request.cookie ({LOGIN_WITH_GITHUB_CONSTANTS}.oauth_user_login) as user2 then
				write_debug_message (ws, "You are: "  + user2.string_representation )
			end

			if a_message.starts_with_general ("/") then
				from
					i := 1
				until
					i >= a_message.count or else a_message[i + 1].is_space
				loop
					i := i + 1
				end
				cmd_name := a_message.substring (2, i)
				if attached command (cmd_name) as cmd then
					cmd (ws, a_message.substring (i + 1, a_message.count))
				else
					write_debug_message (ws, "Error: unknown command '/" + cmd_name + "'!%N")
				end
			else
					-- Echo the message for testing.
				write_debug_message (ws, a_message)
			end
		end

	on_close (ws: WEB_SOCKET)
			-- Called after the WebSocket connection is closed.
		do
			ws.put_error ("Connection closed")
		end

	on_timer (ws: WEB_SOCKET)
			-- <Precursor>.
			-- If ever the file ".stop" exists, stop gracefully the connection.
		local
			fut: FILE_UTILITIES
			f: RAW_FILE
		do
			if fut.file_exists (".stop") then
				ws.send_text ("End of the communication ...%N")
				ws.send_connection_close ("")
--				create f.make_with_name (".stop") -- Can not delete until all connections are closed.
--				f.delete

			end
		end

feature -- Command

	initialize_commands
		do



			register_command (agent on_list_this_project_command, "list_this_project", "List tasks in a specific project, concidering the status folter only")

			register_command (agent on_setnostartdate_command, "setnostartdate", "")
			register_command (agent on_unsetnostartdate_command, "unsetnostartdate", "")
			register_command (agent on_setnoenddate_command, "setnoenddate", "")
			register_command (agent on_unsetnoenddate_command, "unsetnoenddate", "")

			register_command (agent on_search_task_summary_command, "search_task_summary", "Search for string in summary of task")


			register_command (agent on_set_filter_inbox_command, "setfilterinbox", "Inbox shall be included when filtering")
			register_command (agent on_unset_filter_inbox_command, "unsetfilterinbox", "Inbox shall NOT be included when filtering")

			register_command (agent on_connect_tasks, "connecttasks", "Make a task a subtask to another task")
			register_command (agent on_clean_test_data_DB, "cleantestDB", "Clean test data from DB")
			register_command (agent on_add_user_command, "adduser", "Create necessary data in database to handle a new user")
			register_command (agent on_set_filter_date_command, "updatefilterdate", "Set start and end date filters")
			register_command (agent on_unset_filter_status_command, "unsetfilterstatus", "Remove status from filter")
			register_command (agent on_set_filter_status_command, "setfilterstatus", "Filter status")
			register_command (agent on_unset_filter_project_command, "unsetfilterproject", "Remove projet from filter")
			register_command (agent on_set_filter_project_command, "setfilterproject", "Filter project")
			register_command (agent on_update_task_command, "updatetask", "Update task")
			register_command (agent on_edit_task_command, "edittask", "Edit task")
			register_command (agent on_update_project_command, "updateproject", "Update project")
			register_command (agent on_edit_project_command, "editproject", "Edit project")
			register_command (agent on_filter_tasks_command, "newfiltertasks", "Filter tasks to the selected subset")
			register_command (agent on_connect_task_to_project, "connecttasktoproject", "Task related to project")
			register_command (agent on_remove_connection_between_task_and_project, "on_remove_connection_between_task_and_project", "Task removed from project")
			register_command (agent on_task_deleted_command, "taskdeleted", "Task deleted")
			register_command (agent on_project_deleted_command, "projectdeleted", "Project deleted")
			register_command (agent on_task_done_command, "taskdone", "Task done")
			register_command (agent on_task_undone_command, "taskundone", "Task undone")
			register_command (agent on_list_tasks_command, "listtasks", "List tasks")
			register_command (agent on_list_tasks_without_project_command, "listtaskswithoutproject", "List tasks")
			register_command (agent on_list_projects_command, "listprojects", "List tasks")
			register_command (agent on_create_task_command, "createtask", "Create a new task in DB")
			register_command (agent on_create_project_command, "createproject", "Create a new project in DB")
			register_command (agent on_time_command, "time", "Return the server UTC time.")
			register_command (agent on_shutdown_command, "shutdown", "Shutdown the service (ends the websocket).")
		end

	register_command (a_cmd: attached like command; a_name: READABLE_STRING_8; a_description: READABLE_STRING_8)
		local
			tb: like commands
		do
			tb := commands
			if tb = Void then
				create tb.make_caseless (1)
				commands := tb
			end
			tb.force ([a_cmd, a_name, a_description], a_name)
		end

	commands: detachable STRING_TABLE [TUPLE [cmd: attached like command; name, description: READABLE_STRING_8]]

	command (a_name: READABLE_STRING_GENERAL): detachable PROCEDURE [TUPLE [ws: WEB_SOCKET; args: detachable READABLE_STRING_GENERAL]]
		do
			if
				attached commands as tb and then
				attached tb.item (a_name) as d
			then
				Result := d.cmd
			end
		end



	on_time_command (ws: WEB_SOCKET; args: detachable READABLE_STRING_GENERAL)
		do
			ws.send_text ("Server time is " + (create {HTTP_DATE}.make_now_utc).string)
		end

	on_add_user_command (ws: WEB_SOCKET; args: detachable READABLE_STRING_GENERAL)
		local
			l_table :HTML_TABLE
			database_response : STRING
			new_user : USER_DATA
		do
			if attached args as a then
				create new_user.make_from_json (a.to_string_8)
				database.add_user (new_user.user)
			end
		end


	on_clean_test_data_DB (ws: WEB_SOCKET; args: detachable READABLE_STRING_GENERAL)
		do
			if is_test then
				database.clean_db("testuserBSharpAB")
			end -- TODO Take care of responses from database
		end




	on_connect_tasks (ws: WEB_SOCKET; args: detachable READABLE_STRING_GENERAL)
		local
			l_table :HTML_TABLE
			database_response : STRING
			tasks : CONNECT_TASKS_DATA
			env : EXECUTION_ENVIRONMENT
		do
			if attached args as a then
				create env
				env.sleep (1000000000)-- Sleep one second to make sure that the new subtasks is created before we try to connect them. TODO: Use one call from weboage to both create the new task and connect it to parent task.
				create tasks.make_from_json (a.to_string_8)
				database_response := database.connect_tasks (tasks.task_uid, tasks.subtask_uid)
			end
		end

	on_connect_task_to_project (ws: WEB_SOCKET; args: detachable READABLE_STRING_GENERAL)
		local
			l_table :HTML_TABLE
			database_response : STRING
			task_and_project : CONNECT_TASK_TO_PROJECT_DATA
		do
			if attached args as a then
				create task_and_project.make_from_json (a.to_string_8)
				database_response := database.connect_task_to_project ( task_and_project.project_uid, task_and_project.task_uid)
			end
		end

	on_remove_connection_between_task_and_project (ws: WEB_SOCKET; args: detachable READABLE_STRING_GENERAL)
		local
			l_table :HTML_TABLE
			database_response : STRING
			task_and_project : CONNECT_TASK_TO_PROJECT_DATA
		do
			if attached args as a then
				create task_and_project.make_from_json (a.to_string_8)
				database_response := database.remove_connection_between_task_and_project ( task_and_project.project_uid, task_and_project.task_uid)
			end
		end

	on_create_task_command (ws: WEB_SOCKET; args: detachable READABLE_STRING_GENERAL)
		local
			html_tbl : STRING
			database_response : STRING
			task : TASK_DATA
			user : STRING
		do
			if attached args as a then
				if attached ws.request.cookie ({LOGIN_WITH_GITHUB_CONSTANTS}.oauth_user_login) as u then
					user := u.string_representation
				elseif is_test then
					user := "testuserBSharpAB"
				end
				if attached user then
					create task.make_from_json (a.to_string_8)
					database_response := database.create_task ( user.string_representation, task.summary, task.uid)
				end -- TODO Take care of if we do not get any user
			end
		end


	on_set_filter_date_command (ws: WEB_SOCKET; args: detachable READABLE_STRING_GENERAL)
		local
			html_tbl : STRING
			database_response : STRING
			datefilter : FILTER_DATE_DATA
		do
			if attached args as a then
				if attached ws.request.cookie ({LOGIN_WITH_GITHUB_CONSTANTS}.oauth_user_login) as user then
					create datefilter.make_from_json (a.to_string_8)
					database_response := database.set_filter_date( user.string_representation, datefilter)
				end
			end
		end

	on_setnostartdate_command (ws: WEB_SOCKET; args: detachable READABLE_STRING_GENERAL)
		local
			database_response : STRING
		do
			if attached ws.request.cookie ({LOGIN_WITH_GITHUB_CONSTANTS}.oauth_user_login) as user then
				database_response := database.set_filter_nostartdate(user.string_representation)
			end
		end

	on_unsetnostartdate_command (ws: WEB_SOCKET; args: detachable READABLE_STRING_GENERAL)
		local
			database_response : STRING
		do
			if attached ws.request.cookie ({LOGIN_WITH_GITHUB_CONSTANTS}.oauth_user_login) as user then
				database_response := database.unset_filter_nostartdate(user.string_representation)
			end
		end

	on_setnoenddate_command (ws: WEB_SOCKET; args: detachable READABLE_STRING_GENERAL)
		local
			database_response : STRING
		do
			if attached ws.request.cookie ({LOGIN_WITH_GITHUB_CONSTANTS}.oauth_user_login) as user then
				database_response := database.set_filter_noenddate(user.string_representation)
			end
		end

	on_unsetnoenddate_command (ws: WEB_SOCKET; args: detachable READABLE_STRING_GENERAL)
		local
			database_response : STRING
		do
			if attached ws.request.cookie ({LOGIN_WITH_GITHUB_CONSTANTS}.oauth_user_login) as user then
				database_response := database.unset_filter_noenddate(user.string_representation)
			end
		end

	on_set_filter_inbox_command (ws: WEB_SOCKET; args: detachable READABLE_STRING_GENERAL)
		local
			html_tbl : STRING
			database_response : STRING
		do
			if attached args as a then
				if attached ws.request.cookie ({LOGIN_WITH_GITHUB_CONSTANTS}.oauth_user_login) as user then
					database_response := database.set_filter_inbox(user.string_representation)
				end
			end
		end

	on_unset_filter_inbox_command (ws: WEB_SOCKET; args: detachable READABLE_STRING_GENERAL)
		local
			html_tbl : STRING
			database_response : STRING
		do
			if attached args as a then
				if attached ws.request.cookie ({LOGIN_WITH_GITHUB_CONSTANTS}.oauth_user_login) as user then
					database_response := database.unset_filter_inbox ( user.string_representation)
				end
			end
		end




	on_update_task_command (ws: WEB_SOCKET; args: detachable READABLE_STRING_GENERAL)
		local
			html_tbl : STRING
			database_response : STRING
			task : TASK_DATA
		do
			if attached args as a then
				create task.make_from_json (a.to_string_8)
				database.update_task (task)
			end
		end

	on_update_project_command (ws: WEB_SOCKET; args: detachable READABLE_STRING_GENERAL)
		local
			html_tbl : STRING
			project : PROJECT_DATA
		do
			if attached args as a then
				create project.make_from_json (a.to_string_8)
				database.update_project( project.project_name, project.uid)
			end

			-- TODO Add ensure that database is updated by checking that it is updated.
		end



	on_edit_task_command (ws: WEB_SOCKET; args: detachable READABLE_STRING_GENERAL)
		local
			html_tbl : STRING
			l_div :HTML_DIV
			button_div : HTML_DIV
			database_response : STRING
			database_response_subtasks : STRING
			database_response_parenttasks : STRING
			task_to_be_edited : UID_DATA
			startdate : STRING
			starttime : STRING
			startdate_and_time : STRING
			enddate : STRING
			endtime : STRING
			enddate_and_time : STRING
			ul_group_of_projects: HTML_UL
			ul_group_of_subtasks: HTML_UL
			checked_projects : ARRAYED_LIST[STRING]
			inbox_checked : STRING
			user : STRING
			edit_button : HTML_BUTTON
			l_table :HTML_TABLE
			result_from_db : NEO4J_ANSWER
			result_without_escaped_characters : STRING
		do
			if attached args as a then
				create task_to_be_edited.make_from_json (a.to_string_8)
				if attached ws.request.cookie ({LOGIN_WITH_GITHUB_CONSTANTS}.oauth_user_login) as u then
					user := u.string_representation
				elseif is_test then
					user := "testuserBSharpAB"
				end
				if attached user then

					database_response := database.edit_task( task_to_be_edited.uid)

					-- TODO: Filter subtasks according to filter settings.
					database_response_subtasks := database.get_subtasks (task_to_be_edited.uid)
					database_response_parenttasks := database.get_parent_task( task_to_be_edited.uid)

					if database_response.count > 1  then
						create result_from_db.make_from_json(database_response)
						create l_div
						l_div.set_style ("margin:3px;")

						across result_from_db.column_data as ic_row loop

-- Edit summay
--							l_div.add_content (l_div.new_input)
--							l_div.last_new_input.set_value (ic_row.item[3])
--							l_div.last_new_input.set_id ("edit-summary")
--							l_div.last_new_input.set_type ("text")
--							l_div.last_new_input.set_style ("margin:3px;width:100%%;")


	-- Edit summary (new)
							l_div.add_content (l_div.new_textarea)
							l_div.last_new_textarea.set_text_content (ic_row.item[3])
							l_div.last_new_textarea.set_id ("edit-summary")
							l_div.last_new_textarea.set_attribute_manual ("maxlength", "1200", false )
							l_div.last_new_textarea.set_style ("margin:3px;width:100%%;")
							l_div.last_new_textarea.set_rows ("1")


	-- Edit start time

							l_div.add_content (l_div.new_br)
							l_div.add_content (l_div.new_input)

	-- Needed to separate date and time since if one of them was not set nothing was stored. And not setting a time is ok.

							startdate_and_time :=  ic_row.item[4]
							if startdate_and_time.count = 4 or startdate_and_time.count = 0 then -- "null" from database if not exist.
								startdate := ""
								starttime := ""
							else
								startdate := startdate_and_time.substring (1, 10)
								if startdate_and_time.count > 12 then
									starttime := startdate_and_time.substring (12, 16 )
								else
									starttime := ""
								end
							end
							l_div.last_new_input.set_value (startdate)
							l_div.last_new_input.set_id ("edit-start-date")
							l_div.last_new_input.set_type ("date")
							l_div.last_new_input.set_attribute_manual ("onchange", "edit_start_date_change(event)", true )
							l_div.last_new_input.set_style ("margin:3px;")

							l_div.add_content (l_div.new_br)
							l_div.add_content (l_div.new_input)
							l_div.last_new_input.set_value (starttime)
							l_div.last_new_input.set_id ("edit-start-time")
							l_div.last_new_input.set_type ("time")
							if startdate.count = 0  then -- Should not be able to set time when no date is set.
								l_div.last_new_input.set_attribute_manual_key_only ("disabled")
							end
							l_div.last_new_input.set_style ("margin:3px;")

	-- Edit end time

							l_div.add_content (l_div.new_br)
							l_div.add_content (l_div.new_input)

	-- Needed to separate date and time since if one of them was not set nothing was stored. And not setting a time is ok.

							enddate_and_time :=  ic_row.item[5]
							if enddate_and_time.count = 4 or enddate_and_time.count = 0 then -- "null" from database if not exist.
								enddate := ""
								endtime := ""
							else
								enddate := enddate_and_time.substring (1, 10)
								if enddate_and_time.count > 12 then
									endtime := enddate_and_time.substring (12, 16 )
								else
									endtime := ""
								end
							end
							l_div.last_new_input.set_value (enddate)
							l_div.last_new_input.set_id ("edit-end-date")
							l_div.last_new_input.set_type ("date")
							l_div.last_new_input.set_attribute_manual ("onchange", "edit_end_date_change(event)", true )
							l_div.last_new_input.set_style ("margin:3px;")

							l_div.add_content (l_div.new_br)
							l_div.add_content (l_div.new_input)
							l_div.last_new_input.set_value (endtime)
							l_div.last_new_input.set_id ("edit-end-time")
							l_div.last_new_input.set_type ("time")

							if enddate.count = 0  then -- Should not be able to set time when no date is set.
								l_div.last_new_input.set_attribute_manual_key_only ("disabled")
							end
							l_div.last_new_input.set_style ("margin:3px;")
	-- Edit notes
							l_div.add_content (l_div.new_br)
							l_div.add_content (l_div.new_textarea)
							l_div.last_new_textarea.set_text_content (ic_row.item[6])
							l_div.last_new_textarea.set_id ("edit-notes")
							l_div.last_new_textarea.set_attribute_manual ("maxlength", "1200", false )
							l_div.last_new_textarea.set_style ("margin:3px;width:100%%;")
-- create subtask
							l_div.add_content (l_div.new_input)
							l_div.last_new_input.set_id ("create_subtask")
							l_div.last_new_input.set_type ("text")
							l_div.last_new_input.set_style ("margin:3px;width:100%%;")
							l_div.last_new_input.set_attribute_manual ("placeholder", "Add a subtask", true )
							l_div.last_new_input.set_attribute_manual ("onkeydown", "create_subtask()", true )



	-- OK button
							button_div := l_div.new_div
							l_div.add_content (button_div)

							button_div.set_class_names ("row")

							button_div.add_content (button_div.new_br)

							button_div.add_content (button_div.new_div)
							button_div.last_new_div.set_style("width:25%%;text-align:center;")
							button_div.last_new_div.set_class_names("col-xs-1")

							button_div.last_new_div.add_content (button_div.new_button)
							button_div.last_new_button.set_on_click ("update_task(this)")
							button_div.last_new_button.set_id(ic_row.item.first)
							button_div.last_new_button.set_text_content ("OK")
							button_div.last_new_button.set_class_names ("btn class_edit_task")
							button_div.last_new_button.set_style ("text-align:center;")

	-- Apply button

							button_div.add_content (button_div.new_div)
							button_div.last_new_div.set_style("width:25%%;text-align:center;")
							button_div.last_new_div.set_class_names("col-xs-1")

							button_div.last_new_div.add_content (button_div.new_button)
							button_div.last_new_button.set_on_click ("apply_task(this)")
							button_div.last_new_button.set_id(ic_row.item.first)
							button_div.last_new_button.set_text_content ("Apply")
							button_div.last_new_button.set_class_names ("btn class_edit_task")
							button_div.last_new_button.set_style ("text-align:center;")


	-- Cancel button



							button_div.add_content (button_div.new_div)
							button_div.last_new_div.set_style("width:25%%;text-align:center;")
							button_div.last_new_div.set_class_names("col-xs-1")

							button_div.last_new_div.add_content (button_div.new_button)
							button_div.last_new_button.set_on_click ("cancel_update_task(this)")
							button_div.last_new_button.set_id(ic_row.item.first)
							button_div.last_new_button.set_text_content ("Cancel")
							button_div.last_new_button.set_class_names ("btn")
							button_div.last_new_button.set_style ("text-align:center;")
	--						button_div.last_new_button.set_style ("text-align:center;width:60%%;")


	-- Delete button						

							button_div.add_content (button_div.new_div)
							button_div.last_new_div.set_style("width:25%%;text-align:center;")
							button_div.last_new_div.set_class_names("col-xs-1")

							button_div.last_new_div.add_content (button_div.new_button)
							button_div.last_new_button.set_on_click ("task_deleted(this)")
							button_div.last_new_button.set_id(ic_row.item.first)
							button_div.last_new_button.set_text_content ("Delete")
							button_div.last_new_button.set_class_names ("btn")
							button_div.last_new_button.set_style ("text-align:center;")
	--						button_div.last_new_button.set_style ("text-align:center;width:60%%;")
						end

-- List parenttasks

						if database_response_parenttasks.count > 1  then
							create result_from_db.make_from_json (database_response_parenttasks)
							create l_table
							l_table.set_attribute_manual ("class", "table table-striped table-sm ", true)

							l_table.add_content (l_table.new_tr)
							l_table.last_new_tr.add_content (l_table.new_td)
							l_table.last_new_td.add_text_content ("Parents")
							l_table.last_new_td.set_colspan ("2")
							l_table.last_new_td.set_style ("background-color:lightblue;text-align:center;")


							l_div.add_content (l_table)
							across result_from_db.column_data as row loop
								l_table.add_content (l_table.new_tr)
								l_table.last_new_tr.add_content (l_table.new_td)

								l_table.last_new_td.add_content (l_table.new_input)
								l_table.last_new_input.set_type ("checkbox")
								l_table.last_new_input.set_id (row.item[1])-- This is the UID

								if row.item[2].is_equal ("done") then
									l_table.last_new_input.set_attribute_manual_key_only ("checked")
								end

								l_table.last_new_input.set_on_click ("task_done(this)")


								l_table.last_new_td.add_content (l_table.new_label)
								l_table.last_new_label.set_id (row.item[1])-- This is the UID
								l_table.last_new_label.set_text_content (row.item[3])
								l_table.last_new_label.set_on_click ("edit_task(this)")

							end

						end

-- List subtasks

						if database_response_subtasks.count > 1  then
							create result_from_db.make_from_json(database_response_subtasks)
							create l_table
							l_table.set_attribute_manual ("class", "table table-striped table-sm ", true)


							l_table.add_content (l_table.new_tr)
							l_table.last_new_tr.add_content (l_table.new_td)
							l_table.last_new_td.add_text_content ("Subtasks")
							l_table.last_new_td.set_colspan ("2")
							l_table.last_new_td.set_style ("background-color:lightblue;text-align:center;")



							l_div.add_content (l_table)
							across result_from_db.column_data as row loop
								l_table.add_content (l_table.new_tr)
								l_table.last_new_tr.add_content (l_table.new_td)

								l_table.last_new_td.add_content (l_table.new_input)
								l_table.last_new_input.set_type ("checkbox")
								l_table.last_new_input.set_id (row.item[1])-- This is the UID

								if row.item[2].is_equal ("done") then
									l_table.last_new_input.set_attribute_manual_key_only ("checked")
								end

								l_table.last_new_input.set_on_click ("task_done(this)")


								l_table.last_new_td.add_content (l_table.new_label)
								l_table.last_new_label.set_id (row.item[1])-- This is the UID
								l_table.last_new_label.set_text_content (row.item[3])
								l_table.last_new_label.set_on_click ("edit_task(this)")

							end

						end






	-- List projects that one can connect to. Reuses Drag & Drop that I made earlier. Note that this are affected immediately and is not connected to the buttons above.


		-- Get the projects that refers to the task. Those should be checked when presenting the filter.
						database_response := database.get_projects_that_refers_to_the_task ( user.string_representation, task_to_be_edited.uid)
						create checked_projects.make (10)
						checked_projects.compare_objects
						if database_response.count > 1  then
							create result_from_db.make_from_json (database_response)
							across result_from_db.column_data as row loop
								checked_projects.force ( row.item[1])
							end
						end	-- TODO Handle that the database query does not return anything.

						database_response := database.get_list_of_projects (user.string_representation)

						if database_response.count > 1  then
							create result_from_db.make_from_json (database_response)


							create ul_group_of_projects
							l_div.add_content (ul_group_of_projects)

							across result_from_db.column_data as row loop
								ul_group_of_projects.add_content (ul_group_of_projects.new_input)
								ul_group_of_projects.last_new_input.set_type ("checkbox")
								ul_group_of_projects.last_new_input.set_style ("height:calc(1.5rem + 2px);width:10%%")  -- TODO Slightly better size of checkbox but the text need to be aligned and larger
								ul_group_of_projects.last_new_input.set_id (row.item.first)-- This is the UID
								if checked_projects.has (row.item.first) then
									ul_group_of_projects.last_new_input.set_attribute_manual_key_only ("checked")
								end
								ul_group_of_projects.last_new_input.set_text_content (row.item[2])
								ul_group_of_projects.last_new_input.set_on_click ("connect_this_task_to_project(this)")
								ul_group_of_projects.add_content (ul_group_of_projects.new_br)

							end
						end	-- TODO Handle that the database query does not return anything.
						-- Replace Neo4j special characteres with html versions of them.

						result_without_escaped_characters := database.replace_escaped_characters(l_div.html_out)
						ws.send_text ("edittask" + result_without_escaped_characters)
					end
				end
			end
		end



	on_edit_project_command (ws: WEB_SOCKET; args: detachable READABLE_STRING_GENERAL)
		local
			html_tbl : STRING
			l_div :HTML_DIV
			button_div : HTML_DIV
			database_response : STRING
			project_to_be_edited : UID_DATA
			startdate : STRING
			starttime : STRING
			startdate_and_time : STRING
			enddate : STRING
			endtime : STRING
			enddate_and_time : STRING
			result_from_db : NEO4J_ANSWER
		do
			if attached args as a then
				create project_to_be_edited.make_from_json (a.to_string_8)

				database_response := database.edit_project( project_to_be_edited.uid)

				if database_response.count > 1  then
					create result_from_db.make_from_json (database_response)
					create l_div
					l_div.set_style ("margin:3px;")


					across result_from_db.column_data as ic_row loop


--						l_div.add_content (l_div.new_input)
--						l_div.last_new_input.set_value (ic_row.item[2])
--						l_div.last_new_input.set_id ("edit-name")
--						l_div.last_new_input.set_type ("text")
--						l_div.last_new_input.set_style ("margin:3px;width:100%%;")


-- Edit project name (new)
						l_div.add_content (l_div.new_textarea)
						l_div.last_new_textarea.set_text_content (ic_row.item[2])
						l_div.last_new_textarea.set_id ("edit-name")
						l_div.last_new_textarea.set_attribute_manual ("maxlength", "100", false )
						l_div.last_new_textarea.set_style ("margin:3px;width:100%%;")
						l_div.last_new_textarea.set_rows ("1")



						l_div.add_content (l_div.new_br)

-- Update button
						button_div := l_div.new_div
						l_div.add_content (button_div)

						button_div.set_class_names ("row")

						button_div.add_content (button_div.new_br)

						button_div.add_content (button_div.new_div)
						button_div.last_new_div.set_style("width:33%%;text-align:center;")
						button_div.last_new_div.set_class_names("col-xs-1")

						button_div.last_new_div.add_content (button_div.new_button)
						button_div.last_new_button.set_on_click ("update_project(this)")
						button_div.last_new_button.set_id(ic_row.item.first)
						button_div.last_new_button.set_text_content ("Update")
						button_div.last_new_button.set_class_names ("btn class_edit_task")
						button_div.last_new_button.set_style ("text-align:center;")

-- Cancel button

						button_div.add_content (button_div.new_div)
						button_div.last_new_div.set_style("width:33%%;text-align:center;")
						button_div.last_new_div.set_class_names("col-xs-1")

						button_div.last_new_div.add_content (button_div.new_button)
						button_div.last_new_button.set_on_click ("cancel_update_project(this)")
						button_div.last_new_button.set_id(ic_row.item.first)
						button_div.last_new_button.set_text_content ("Cancel")
						button_div.last_new_button.set_class_names ("btn")
						button_div.last_new_button.set_style ("text-align:center;")

-- Delete button						

						button_div.add_content (button_div.new_div)
						button_div.last_new_div.set_style("width:33%%;text-align:center;")
						button_div.last_new_div.set_class_names("col-xs-1")

						button_div.last_new_div.add_content (button_div.new_button)
						button_div.last_new_button.set_on_click ("project_deleted(this)")
						button_div.last_new_button.set_id(ic_row.item.first)
						button_div.last_new_button.set_text_content ("Delete")
						button_div.last_new_button.set_class_names ("btn")
						button_div.last_new_button.set_style ("text-align:center;")

					end
					ws.send_text ("edittask" + database.replace_escaped_characters(l_div.html_out))
				end
			end
		end



	on_create_project_command (ws: WEB_SOCKET; args: detachable READABLE_STRING_GENERAL)
		local
			html_tbl : STRING
			l_table :HTML_TABLE
			database_response : STRING
			project : PROJECT_DATA
			user : STRING
		do
			if attached args as a then
				if attached ws.request.cookie ({LOGIN_WITH_GITHUB_CONSTANTS}.oauth_user_login) as u then
					user := u.string_representation
				elseif is_test then
					user := "testuserBSharpAB"
				end
				if attached user then
					create project.make_from_json (a.to_string_8)
					database.create_project( user.string_representation, project.project_name, project.uid)

				end  -- TODO Take care of that I do not get any user
			end
		end


	on_set_filter_status_command (ws: WEB_SOCKET; args: detachable READABLE_STRING_GENERAL)
		local
			html_tbl : STRING
			l_table :HTML_TABLE
			database_response : STRING
			status : UID_DATA
		do
			if attached args as a then
				if attached ws.request.cookie ({LOGIN_WITH_GITHUB_CONSTANTS}.oauth_user_login) as user then
					create status.make_from_json (a.to_string_8)
					database_response := database.add_status_to_filter(user.string_representation, status.uid)
				end  -- TODO Take care of that I do not get any user
			end
		end

	on_unset_filter_status_command (ws: WEB_SOCKET; args: detachable READABLE_STRING_GENERAL)
		local
			html_tbl : STRING
			l_table :HTML_TABLE
			database_response : STRING
			status : UID_DATA
		do
			if attached args as a then
				if attached ws.request.cookie ({LOGIN_WITH_GITHUB_CONSTANTS}.oauth_user_login) as user then
					create status.make_from_json (a.to_string_8)
					database_response := database.remove_status_from_filter( user.string_representation, status.uid)
				end  -- TODO Take care of that I do not get any user
			end
		end

	on_set_filter_project_command (ws: WEB_SOCKET; args: detachable READABLE_STRING_GENERAL)
		local
			html_tbl : STRING
			l_table :HTML_TABLE
			database_response : STRING
			project : UID_DATA
		do
			if attached args as a then
				if attached ws.request.cookie ({LOGIN_WITH_GITHUB_CONSTANTS}.oauth_user_login) as user then
					create project.make_from_json (a.to_string_8)
					database_response := database.add_project_to_filter ( user.string_representation, project.uid )
				end  -- TODO Take care of that I do not get any user

			end
		end

	on_unset_filter_project_command (ws: WEB_SOCKET; args: detachable READABLE_STRING_GENERAL)
		local
			html_tbl : STRING
			l_table :HTML_TABLE
			database_response : STRING
			project : UID_DATA
		do
			if attached args as a then
				if attached ws.request.cookie ({LOGIN_WITH_GITHUB_CONSTANTS}.oauth_user_login) as user then
					create project.make_from_json (a.to_string_8)
					database_response := database.remove_project_from_filter( User.string_representation, project.uid)
				end  -- TODO Take care of that I do not get any user
			end
		end

	on_task_done_command (ws: WEB_SOCKET; args: detachable READABLE_STRING_GENERAL)
		local
			html_tbl : STRING
			l_table :HTML_TABLE
			database_response : STRING
			task_done : UID_DATA
		do
			if attached args as a then
				create task_done.make_from_json (a.to_string_8)
				database_response := database.set_task_to_done (task_done.uid)
			end
		end

	on_task_deleted_command (ws: WEB_SOCKET; args: detachable READABLE_STRING_GENERAL)
		local
			html_tbl : STRING
			l_table :HTML_TABLE
			database_response : STRING
			task_deleted : UID_DATA
		do
			if attached args as a then
				create task_deleted.make_from_json (a.to_string_8)
				database.set_task_deleted( task_deleted.uid)
			end
		end

	on_project_deleted_command (ws: WEB_SOCKET; args: detachable READABLE_STRING_GENERAL)
		local
			html_tbl : STRING
			l_table :HTML_TABLE
			project_deleted : UID_DATA
		do
			if attached args as a then
				create project_deleted.make_from_json (a.to_string_8)
				database.set_project_deleted( project_deleted.uid)
			end
		end




	on_task_undone_command (ws: WEB_SOCKET; args: detachable READABLE_STRING_GENERAL)
		local
			html_tbl : STRING
			l_table :HTML_TABLE
			database_response : STRING
			task_undone : UID_DATA
		do
			if attached args as a then
				create task_undone.make_from_json (a.to_string_8)
				database_response := database.undo_task(task_undone.UID)
			end
		end



	create_project_filter (ws: WEB_SOCKET) -- TODO Only calculate the HTML and do not send it. Furthermore, divide it into the menu and the projects to make it possible to reuse it.
		local
			main_text :HTML_TEXT
			ul_group_of_projects : HTML_UL
			database_response : STRING
			checked_projects : ARRAYED_LIST[STRING]
			inbox_checked : STRING
			project_button : HTML_BUTTON
			drop_down_caret : HTML_BUTTON
			span_caret : HTML_SPAN
			result_from_db : NEO4J_ANSWER
		do

			if attached ws.request.cookie ({LOGIN_WITH_GITHUB_CONSTANTS}.oauth_user_login) as user then



-- Get inbox filter. Might be that I can combine this question with the next.

				database_response := database.get_filter_if_inbox_is_included(user.string_representation)
				create inbox_checked.make_empty
				if database_response.count > 1  then
					create result_from_db.make_from_json (database_response)
					across result_from_db.column_data as ic_row loop
						 inbox_checked :=  ic_row.item[1]
					end
				end	-- TODO Handle that the database query does not return anything.

-- Get the projects that is included in the filter. Those should be checked when presenting the filter.
				database_response := database.get_filter_projects_included(user.string_representation)
				create checked_projects.make (10)
				checked_projects.compare_objects
				if database_response.count > 1  then
					create result_from_db.make_from_json (database_response)
					across result_from_db.column_data as ic_row loop
						checked_projects.force ( ic_row.item[1])
					end
				end	-- TODO Handle that the database query does not return anything.

				database_response := database.get_list_of_projects ( user.string_representation )

				if database_response.count > 1  then
					create result_from_db.make_from_json (database_response)
					create main_text



					create drop_down_caret
					main_text.add_content (drop_down_caret)
					drop_down_caret.set_type ("button")
					drop_down_caret.set_class_names ("btn dropdown-toggle")
					drop_down_caret.set_attribute_manual ("data-toggle", "dropdown", true)
					drop_down_caret.set_text_content ("Project")
					drop_down_caret.set_style ("text-align:center;") -- TODO Does not help to center them

					create span_caret
					drop_down_caret.add_content (span_caret)
					span_caret.set_class_names ("caret")


					create ul_group_of_projects
					main_text.add_content (ul_group_of_projects)
					ul_group_of_projects.set_class_names ("dropdown-menu")
					ul_group_of_projects.set_attribute_manual ("role", "menu", true)
					ul_group_of_projects.set_style ("background-color:lightgrey;")




-- Take care of "project" Inbox since that is all tasks that has no project associated with it.

					ul_group_of_projects.add_content (ul_group_of_projects.new_li)
					ul_group_of_projects.last_new_li.add_content (ul_group_of_projects.new_input)
					ul_group_of_projects.last_new_input.set_type ("checkbox")
					ul_group_of_projects.last_new_input.set_id ("Inbox")
--					ul_group_of_projects.last_new_input.set_class_names ("form-control form-control-sm")
					ul_group_of_projects.last_new_input.set_style ("height:calc(1.5rem + 2px);width:10%%") -- TODO Slightly better size of checkbox but the text need to be aligned and larger

					if inbox_checked.same_string ("true") then
						ul_group_of_projects.last_new_input.set_attribute_manual_key_only ("checked")
					end
					ul_group_of_projects.last_new_input.set_text_content ("Inbox")
					ul_group_of_projects.last_new_input.set_on_click ("filter_inbox_check(this)")





					across result_from_db.column_data as ic_row loop
						ul_group_of_projects.add_content (ul_group_of_projects.new_li)
						ul_group_of_projects.last_new_li.add_content (ul_group_of_projects.new_input)
						ul_group_of_projects.last_new_input.set_type ("checkbox")
						ul_group_of_projects.last_new_input.set_style ("height:calc(1.5rem + 2px);width:10%%")  -- TODO Slightly better size of checkbox but the text need to be aligned and larger
						ul_group_of_projects.last_new_input.set_id (ic_row.item.first)-- This is the UID
						if checked_projects.has (ic_row.item.first) then
							ul_group_of_projects.last_new_input.set_attribute_manual_key_only ("checked")
						end
						ul_group_of_projects.last_new_input.set_text_content (ic_row.item[2])
						ul_group_of_projects.last_new_input.set_on_click ("filter_project_check(this)")

					end
					ws.send_text ("filter" + database.replace_escaped_characters(main_text.html_out))
				end	-- TODO Handle that the database query does not return anything.
			end  -- TODO Take care of that I do not get any user
		end

	create_status_filter (ws: WEB_SOCKET)
		local
			database_response : STRING
			item : STRING
			avaiable_statuses : ARRAY[STRING]
			checked_status : ARRAYED_LIST[STRING]

			main_text :HTML_TEXT
			ul_group_of_status : HTML_UL
			status_button : HTML_BUTTON
			drop_down_caret : HTML_BUTTON
			span_caret : HTML_SPAN
			result_from_db : NEO4J_ANSWER
		do
			if attached ws.request.cookie ({LOGIN_WITH_GITHUB_CONSTANTS}.oauth_user_login) as user then

				database_response := database.status_filter (user.string_representation)
				create checked_status.make (10)
				checked_status.compare_objects
				if database_response.count > 1  then
					create result_from_db.make_from_json (database_response)
					across result_from_db.column_data as ic_row loop
						checked_status.force ( ic_row.item[1])
					end
				end	-- TODO Handle that the database query does not return anything.

				avaiable_statuses  := << "working", "done", "created", "deleted" >>
	--			database_response := database.send_command_to_database ("{  %"statements%" : [ {    %"statement%" : %"MATCH (n:PROJECT) RETURN n.UID, n.name%"  } ]}")

	--			if database_response.count > 1  then
	--				make_from_json (database_response)
					create main_text

					create drop_down_caret
					main_text.add_content (drop_down_caret)
					drop_down_caret.set_type ("button")
					drop_down_caret.set_class_names ("btn dropdown-toggle")
					drop_down_caret.set_attribute_manual ("data-toggle", "dropdown", true)
					drop_down_caret.set_text_content ("Status")
					drop_down_caret.set_style ("text-align:center;") -- TODO Does not help to center them


					create span_caret
					drop_down_caret.add_content (span_caret)
					span_caret.set_class_names ("caret")

					create ul_group_of_status
					main_text.add_content (ul_group_of_status)
					ul_group_of_status.set_class_names ("dropdown-menu")
					ul_group_of_status.set_attribute_manual ("role", "menu", true)
					ul_group_of_status.set_style ("background-color:lightgrey;")


					across avaiable_statuses as ic_status loop
						ul_group_of_status.add_content (ul_group_of_status.new_li)
						ul_group_of_status.last_new_li.add_content (ul_group_of_status.new_input)
						ul_group_of_status.last_new_input.set_type ("checkbox")
						ul_group_of_status.last_new_input.set_style ("height:calc(1.5rem + 2px);width:10%%") -- TODO Slightly better size of checkbox but the text need to be aligned and larger						
						ul_group_of_status.last_new_input.set_id ( ic_status.item)
						ul_group_of_status.last_new_input.set_text_content (ic_status.item)
						ul_group_of_status.last_new_input.set_on_click ("filter_status_check(this)")
						if checked_status.has (ic_status.item) then
							ul_group_of_status.last_new_input.set_attribute_manual_key_only ("checked")
						end

					end
					ws.send_text ("filter_status" + main_text.html_out)
	--			end

				-- TODO Handle that the database query does not return anything.
			end  -- TODO Take care of that I do not get any user
		end

	create_date_filter (ws: WEB_SOCKET)
		local
			l_div :HTML_DIV
			database_response : STRING
			item : STRING
			startdate_and_time : STRING
			startdate : STRING
			starttime :STRING
			enddate_and_time : STRING
			enddate : STRING
			endtime :STRING


			main_text :HTML_TEXT
			ul_group_of_date : HTML_UL
			date_button : HTML_BUTTON
			drop_down_caret : HTML_BUTTON
			span_caret : HTML_SPAN

			result_from_db : NEO4J_ANSWER


		do
			if attached ws.request.cookie ({LOGIN_WITH_GITHUB_CONSTANTS}.oauth_user_login) as user then


				database_response := database.get_filter_information(user.string_representation)

				if database_response.count > 1  then
					create result_from_db.make_from_json (database_response)

					across result_from_db.column_data as ic_row loop

						create main_text

						create drop_down_caret
						main_text.add_content (drop_down_caret)
						drop_down_caret.set_type ("button")
						drop_down_caret.set_class_names ("btn dropdown-toggle")
						drop_down_caret.set_attribute_manual ("data-toggle", "dropdown", true)
						drop_down_caret.set_text_content ("Date")
						drop_down_caret.set_style ("text-align:center;") -- TODO Does not help to center them

						create span_caret
						drop_down_caret.add_content (span_caret)
						span_caret.set_class_names ("caret")

						create ul_group_of_date
						main_text.add_content (ul_group_of_date)
						ul_group_of_date.set_class_names ("dropdown-menu")
						ul_group_of_date.set_attribute_manual ("role", "menu", true)
						ul_group_of_date.set_style ("background-color:lightgrey;")


-- Edit start date filter

-- Needed to separate date and time since if one of them was not set nothing was stored. And not setting a time is ok.

						startdate_and_time := ic_row.item[1]
						if startdate_and_time.count = 4 or startdate_and_time.count = 0 then -- "null" from database if not exist.
							startdate := ""
							starttime := ""
						else
							startdate := startdate_and_time.substring (1, 10)
							if startdate_and_time.count > 12 then
								starttime := startdate_and_time.substring (12, 16 )
							else
								starttime := ""
							end
						end


						ul_group_of_date.add_content (ul_group_of_date.new_label)
						ul_group_of_date.last_new_label.set_text_content ("Start before")
						ul_group_of_date.add_content (ul_group_of_date.new_br)
						ul_group_of_date.add_content (ul_group_of_date.new_input)

						ul_group_of_date.last_new_input.set_value (startdate)
						ul_group_of_date.last_new_input.set_id ("edit-filter-start-date")
						ul_group_of_date.last_new_input.set_type ("date")
						ul_group_of_date.last_new_input.set_attribute_manual ("onchange", "edit_filter_start_date_change(event)", true )

						ul_group_of_date.add_content (ul_group_of_date.new_input)
						ul_group_of_date.last_new_input.set_value (starttime)
						ul_group_of_date.last_new_input.set_id ("edit-filter-start-time")
						ul_group_of_date.last_new_input.set_type ("time")
						ul_group_of_date.last_new_input.set_attribute_manual ("onchange", "edit_filter_start_date_change(event)", true )
						if startdate.count = 0  then -- Should not be able to set time when no date is set.
							ul_group_of_date.last_new_input.set_attribute_manual_key_only ("disabled")
						end

-- Edit end date filter
						ul_group_of_date.add_content (ul_group_of_date.new_br)
-- Needed to separate date and time since if one of them was not set nothing was stored. And not setting a time is ok.

						enddate_and_time := ic_row.item[2]
						if enddate_and_time.count = 4 or enddate_and_time.count = 0 then -- "null" from database if not exist.
							enddate := ""
							endtime := ""
						else
							enddate := enddate_and_time.substring (1, 10)
							if enddate_and_time.count > 12 then
								endtime := enddate_and_time.substring (12, 16 )
							else
								endtime := ""
							end
						end

						ul_group_of_date.add_content (ul_group_of_date.new_label)
						ul_group_of_date.last_new_label.set_text_content ("End before")
						ul_group_of_date.add_content (ul_group_of_date.new_br)

						ul_group_of_date.add_content (ul_group_of_date.new_input)

						ul_group_of_date.last_new_input.set_value (enddate)
						ul_group_of_date.last_new_input.set_id ("edit-filter-end-date")
						ul_group_of_date.last_new_input.set_type ("date")
						ul_group_of_date.last_new_input.set_attribute_manual ("onchange", "edit_filter_end_date_change(event)", true )

						ul_group_of_date.add_content (ul_group_of_date.new_input)
						ul_group_of_date.last_new_input.set_value (endtime)
						ul_group_of_date.last_new_input.set_id ("edit-filter-end-time")
						ul_group_of_date.last_new_input.set_type ("time")
						ul_group_of_date.last_new_input.set_attribute_manual ("onchange", "edit_filter_end_date_change(event)", true )
						if enddate.count = 0  then -- Should not be able to set time when no date is set.
							ul_group_of_date.last_new_input.set_attribute_manual_key_only ("disabled")
						end



-- No start data checkbox

						ul_group_of_date.add_content (ul_group_of_date.new_li)
						ul_group_of_date.last_new_li.add_content (ul_group_of_date.new_input)
						ul_group_of_date.last_new_input.set_type ("checkbox")
						ul_group_of_date.last_new_input.set_style ("height:calc(1.5rem + 2px);width:10%%") -- TODO Slightly better size of checkbox but the text need to be aligned and larger						
						ul_group_of_date.last_new_input.set_id ( "No_start_date")
						ul_group_of_date.last_new_input.set_text_content ("No start date")
						ul_group_of_date.last_new_input.set_on_click ("filter_no_start_date_check(this)")
						if ic_row.item[3].same_string ("true") then
							ul_group_of_date.last_new_input.set_attribute_manual_key_only ("checked")
						end


-- No end date checkbox
						ul_group_of_date.add_content (ul_group_of_date.new_li)
						ul_group_of_date.last_new_li.add_content (ul_group_of_date.new_input)
						ul_group_of_date.last_new_input.set_type ("checkbox")
						ul_group_of_date.last_new_input.set_style ("height:calc(1.5rem + 2px);width:10%%") -- TODO Slightly better size of checkbox but the text need to be aligned and larger						
						ul_group_of_date.last_new_input.set_id ( "No_end_date")
						ul_group_of_date.last_new_input.set_text_content ("No end date")
						ul_group_of_date.last_new_input.set_on_click ("filter_no_end_date_check(this)")
						if ic_row.item[4].same_string ("true") then
							ul_group_of_date.last_new_input.set_attribute_manual_key_only ("checked")
						end


						ws.send_text ("filter_date" + main_text.html_out)

					end
				end  -- TODO Take care of that I do not get any user
			end
		end


	on_list_projects_command (ws: WEB_SOCKET; args: detachable READABLE_STRING_GENERAL)
		local
			l_table :HTML_TABLE
			database_response : STRING
			edit_button : HTML_BUTTON
			user : STRING
			result_from_db : NEO4J_ANSWER
		do
			if attached ws.request.cookie ({LOGIN_WITH_GITHUB_CONSTANTS}.oauth_user_login) as u then
				user := u.string_representation
			elseif is_test then
				user := "testuserBSharpAB"
			end
			if attached user then

				database_response := database.get_list_of_projects(user.string_representation)

				if database_response.count > 1  then
					create result_from_db.make_from_json (database_response)
					create l_table
					l_table.set_attribute_manual ("class", "table table-striped table-sm", true)
					l_table.add_content(l_table.new_tr)

					across result_from_db.column_data as ic_row loop
						l_table.add_content (l_table.new_tr)

						across ic_row.item as ic_column loop
							if ic_column.item = ic_row.item[2] then -- Do not add UID
								l_table.last_new_tr.add_content (l_table.new_td)
								l_table.last_new_tr.set_id ("test_list_project")
								l_table.last_new_td.set_id (ic_row.item.first)-- This is the UID
								l_table.last_new_td.set_attribute_manual ("ondragover", "allowDrop(event)", false)
								l_table.last_new_td.set_attribute_manual ("ondrop", "drop(event)", false)




								l_table.last_new_td.add_content (l_table.new_div)
								l_table.last_new_div.set_attribute_manual ("class", "mytooltip", false)
								l_table.last_new_div.add_content (l_table.new_span)
								l_table.last_new_div.set_id (ic_row.item.first)

								create edit_button
								edit_button.set_text_content ("Edit")
								edit_button.set_on_click ("edit_project(this)")
								edit_button.set_id (ic_row.item.first)

--								if user.string_representation.is_equal ("andersoxie") then -- Keep this to have it when debugging
--									l_table.last_new_span.add_text_content ( "UID: " + ic_row.item.first + "<br> Project name: " + ic_row.item[2]  +  "<br>" + edit_button.html_out)
--								else
									l_table.last_new_span.add_text_content ( "Project name: " + ic_row.item[2]  +  "<br>" + edit_button.html_out)
--								end

								l_table.last_new_span.set_attribute_manual("class", "mytooltiptext", false)
								l_table.last_new_div.set_text_content (ic_column.item)




							end
						end
					end
					ws.send_text ("projectlist" + database.replace_escaped_characters( l_table.html_out))
				end
			end  -- TODO Take care of that I do not get any user
		end

	on_filter_tasks_command (ws: WEB_SOCKET; args: detachable READABLE_STRING_GENERAL)
		local
			database_response : STRING
			startdate : STRING
			include_inbox : BOOLEAN
			nostartdate : BOOLEAN
			noenddate : BOOLEAN


			user: STRING
			result_from_db : NEO4J_ANSWER
		do


			if attached ws.request.cookie ({LOGIN_WITH_GITHUB_CONSTANTS}.oauth_user_login) as u then
				user := u.string_representation
			elseif is_test then
				user := "testuserBSharpAB"
			end
			if attached user then
				database_response := database.get_filter_information(user)
				startdate := ""


				if database_response.count > 1  then
					create result_from_db.make_from_json  (database_response)
					across result_from_db.column_data as ic_row loop
						startdate := ic_row.item.first
						if ic_row.item[3].same_string("true") then
							nostartdate := true
						end
						if ic_row.item[4].same_string("true") then
							noenddate := true
						end
						if ic_row.item[5].same_string("true") then
							include_inbox := true
						end
					end
				end

-- Always include tasks that have passed end date

				create result_from_db.make_empty
				database_response := database.get_late_tasks(user)
				if database_response.count > 1  then
					result_from_db.make_from_json  (database_response)
				end


				if include_inbox then
					if nostartdate then
						database_response := database.get_inbox_according_to_filter_no_start_date_set (user)
					else
						if startdate.count > 1 then
							database_response := database.get_inbox_according_to_filter_date_filter_set (user)
						else
							database_response := database.get_inbox_according_to_filter_date_filter_not_set (user)
						end
					end
					if database_response.count > 1  then
						result_from_db.make_from_json  (database_response)
					end
				end

				if nostartdate then
					database_response := database.get_tasks_with_current_filter_with_no_start_date_set(user)
				else
					if startdate.count > 1 then
						database_response := database.get_tasks_with_current_filter_but_start_date_set(user)
					else
						database_response := database.get_tasks_with_current_filter_but_start_date_not_set(user)
					end
				end
				if database_response.count > 1  then
					result_from_db.make_from_json  (database_response)
				end
				send_task_list (ws, result_from_db, user )
			end  -- TODO Take care of that I do not get any user
		end

	send_task_list (ws: WEB_SOCKET; result_from_db: NEO4J_ANSWER; user: STRING)
		local
			l_table :HTML_TABLE
			edit_button : HTML_BUTTON
			current_project : STRING
			do

					create l_table
					l_table.set_attribute_manual ("class", "table table-striped table-sm ", true)
					current_project := ""
					across result_from_db.column_data as ic_row loop
						if ic_row.item.count > 6 then -- Then we get a project name in ic_row.item[7]
							if not current_project.is_equal (ic_row.item[7]) then
								-- Add a project Heading
								l_table.add_content (l_table.new_tr)
								l_table.last_new_tr.add_content (l_table.new_td)
								l_table.last_new_td.add_text_content (ic_row.item[7])
								l_table.last_new_td.set_colspan ("2")
								l_table.last_new_td.set_style ("background-color:lightblue;text-align:center;")
								current_project := ic_row.item[7]
								if ic_row.item.count > 7 then -- Then we get a project uid in ic_row.item[8]
									l_table.last_new_td.set_on_click ("list_this_project(this)")
									l_table.last_new_td.set_id (ic_row.item[8])
								end
							end
						end
						l_table.add_content (l_table.new_tr)
						l_table.last_new_tr.set_id ("test_send_task_list")
						l_table.last_new_tr.add_content (l_table.new_td)
						l_table.last_new_td.add_content (l_table.new_input)
						l_table.last_new_input.set_type ("checkbox")
						l_table.last_new_input.set_id (ic_row.item.first)-- This is the UID

						if ic_row.item[3].is_equal ("done") then
							l_table.last_new_input.set_attribute_manual_key_only ("checked")
						end

						l_table.last_new_input.set_on_click ("task_done(this)")

						across ic_row.item as ic_column loop
							if ic_column.item = ic_row.item[2] then -- Do not add UID
								l_table.last_new_tr.add_content (l_table.new_td)



								l_table.last_new_td.add_content (l_table.new_div)
								l_table.last_new_div.set_attribute_manual ("class", "mytooltip", false)
								l_table.last_new_div.add_content (l_table.new_span)
								l_table.last_new_div.set_id (ic_row.item.first)

								create edit_button
								edit_button.set_text_content ("Edit")
								edit_button.set_on_click ("edit_task(this)")
								edit_button.set_id (ic_row.item.first)

--								notes := ic_row.item[6]
--								if notes.count > 40 then
--									notes := notes.substring (1, 40)
--								end
--								if user.is_equal ("andersoxie") then -- Keep this to have it when debugging
--									l_table.last_new_span.add_text_content ( "UID: " + ic_row.item.first + "<br> Start date: " + ic_row.item[4]  + "<br> End date: " + ic_row.item[5] + "<br> Notes: " + ic_row.item[6] + "<br>" + edit_button.html_out)
--								else
									l_table.last_new_span.add_text_content ( " Start date: " + ic_row.item[4]  + "<br> End date: " + ic_row.item[5] + "<br>" + edit_button.html_out)
--								end

								l_table.last_new_span.set_attribute_manual("class", "mytooltiptext", false)
								l_table.last_new_div.set_text_content (ic_column.item)
								l_table.last_new_div.set_on_click ("edit_task(this)")
						-- Create a drag source
								l_table.last_new_div.set_attribute_manual ("draggable", "true", false)
								l_table.last_new_div.set_attribute_manual ("ondragstart", "drag(event)", false)

							end
						end
					end
					ws.send_text ("tasklist" +  database.replace_escaped_characters( l_table.html_out))
		end



	on_list_tasks_without_project_command (ws: WEB_SOCKET; args: detachable READABLE_STRING_GENERAL) -- e.g. "Inbox"
		local
			user : STRING
			result_from_db : NEO4J_ANSWER
		do
			if attached ws.request.cookie ({LOGIN_WITH_GITHUB_CONSTANTS}.oauth_user_login) as u then
				user := u.string_representation
			elseif is_test then
				user := "testuserBSharpAB"
			end
			if attached user then
				-- TODO the limit is set to 4 levels deep. Is that enough. What happens if I put only a "*". Probaly performace problems . I tried with this "[*1..4:INCLUDES]" but that did not work
				create result_from_db.make_from_json (database.list_tasks_without_project (user.string_representation))
				send_task_list (ws, result_from_db, user.string_representation)
			end -- TODO Take care of if no user. Or we might take care of that before calling this feature.
		end

	on_list_this_project_command (ws: WEB_SOCKET; args: detachable READABLE_STRING_GENERAL)
		local
			project_uid : UID_DATA
			result_from_db : NEO4J_ANSWER
		do
			if attached args as a then
				if attached ws.request.cookie ({LOGIN_WITH_GITHUB_CONSTANTS}.oauth_user_login) as user then
					create project_uid.make_from_json (a.to_string_8)
					create result_from_db.make_from_json (database.get_tasks_within_a_specific_project_concidering_status_filter_only (user.string_representation, project_uid.uid))
					send_task_list (ws, result_from_db, user.string_representation)
				end  -- TODO Take care of that I do not get any user
			end
		end

	on_list_tasks_command (ws: WEB_SOCKET; args: detachable READABLE_STRING_GENERAL) -- e.g. all tasks
		local
			db_answer : NEO4J_ANSWER
		do

			if attached ws.request.cookie ({LOGIN_WITH_GITHUB_CONSTANTS}.oauth_user_login) as user then
				create db_answer.make_from_json( database.list_all_tasks(user.string_representation))
				send_task_list (ws, db_answer, user.string_representation)
			end -- TODO Take care of if we do not get a user.
		end


		on_search_task_summary_command  (ws: WEB_SOCKET; args: detachable READABLE_STRING_GENERAL)
		local
			db_answer : NEO4J_ANSWER
			user : STRING
			search_for : SEARCH_DATA
		do
			if attached args as a then
				if attached ws.request.cookie ({LOGIN_WITH_GITHUB_CONSTANTS}.oauth_user_login) as u then
					user := u.string_representation
				elseif is_test then
					user := "testuserBSharpAB"
				end
				if attached user then
					create search_for.make_from_json (a.to_string_8)
					create db_answer.make_from_json( database.list_all_tasks_search_summary (user.string_representation, search_for.search_string))
					send_task_list (ws, db_answer, user.string_representation)
				end -- TODO Take care of if we do not get a user.
			end
		end




	on_shutdown_command (ws: WEB_SOCKET; args: detachable READABLE_STRING_GENERAL)
		local
			f: RAW_FILE
		do
			ws.send_text ("Active connection will end soon.%N")
			create f.make_create_read_write (".stop")
			f.put_string ("stop%N")
			f.close
		end

feature -- HTML Resource				

	javascript_socket_code : STRING
	do
		Result := "[

		function connect(){

				var host = "##WSSCHEME##://##HOSTNAME##:##PORTNUMBER##/app";

				try{

					socket = new WebSocket(host);
					message('<p class="event">Socket Status: '+socket.readyState);
					socket.onopen = function(){
							$('#myModal').css( "display", "none");
							message('<p class="event">Socket Status: '+socket.readyState+' (open)');
							initiate();
						}
					socket.onmessage = function(msg){
							data(msg.data);
						}
					socket.onclose = function(){
							message('<p class="event">Socket Status: '+socket.readyState+' (Closed)');
							connection_lost();
						}
				} catch(exception){
					message('<p>Error'+exception);
				}
		}



		]"
	end

	websocket_test_html (a_host: STRING; a_port: INTEGER): STRING
		do




			-- Using this to create Responsivenes: https://www.w3schools.com/bootstrap4/bootstrap_get_started.asp
			Result := "[


<!DOCTYPE html>
<html  lang="en">

<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">

<!-- jQuery library -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<script type="text/javascript">

	var socket;
	var test_case_number;

$(document).ready(function() {

]"

+ javascript_socket_code  +

 "[
 
 
 		connect();
 		start_test();
 
 });
 
 	function message(msg){
		$('#testLog').append(msg+'</p>' );
	}//End message()

 	function start_test(){
		$('#testLog').append(' Start testing!' );
	}//End message()

	function initiate() {

			test_case_number = 1;

			// Create 3 projects
			var data_to_send = { project_name : "Project 1" }
			try{
				data_to_send.UID  = "Project1GUID";
				socket.send('/createproject ' +   JSON.stringify( data_to_send ) );
			} catch(exception){
				message('<p class="warning">');
			}
			var data_to_send = { project_name : "Project 2" }
			try{
				data_to_send.UID  = "Project2GUID";
				socket.send('/createproject ' +   JSON.stringify( data_to_send ) );
			} catch(exception){
				message('<p class="warning">');
			}
			var data_to_send = { project_name : "Project 3" }
			try{
				data_to_send.UID  = "Project3GUID";
				socket.send('/createproject ' +   JSON.stringify( data_to_send ) );
			} catch(exception){
				message('<p class="warning">');
			}


			// Create 3 tasks
			var data_to_send = { summary : "Task 1 Summary" }
			data_to_send.notes = "Task 1 Notes Lomg note to detect error in substring of noteszzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz";
			try{
				data_to_send.UID  = "Task1GUID";
				data_to_send.startdate = "";
				data_to_send.enddate = "";
				socket.send('/createtask ' +  JSON.stringify( data_to_send ) );
			} catch(exception){
				message('<p class="warning">');
			}

			var data_to_send = { summary : "Task 2 Summary" }
			data_to_send.notes = "Task 2 Notes";
			try{
				data_to_send.UID  = "Task2GUID";
				data_to_send.startdate = "";
				data_to_send.enddate = "";
				socket.send('/createtask ' +  JSON.stringify( data_to_send ) );
			} catch(exception){
				message('<p class="warning">');
			}

			var data_to_send = { summary : "Task 3 Summary" }
			data_to_send.notes = "Task 3 Notes";
			try{
				data_to_send.UID  = "Task3GUID";
				data_to_send.startdate = "";
				data_to_send.enddate = "";
				socket.send('/createtask ' +  JSON.stringify( data_to_send ) );
			} catch(exception){
				message('<p class="warning">');
			}

		 	// List tasks

			try{
				socket.send('/listtaskswithoutproject');
			} catch(exception){
				message('<p class="warning">');
			}



	}

	function test_case2(){
		$('#testLog').append('test case 2 started');
		test_case_number = 2;


		try{
			socket.send('/listprojects');
		} catch(exception){
			message('<p class="warning">');
		}


	}

// Test assigning a task to a project.

	function test_case3(){
		$('#testLog').append('test case 3 started');
		test_case_number = 3;
	
		var data_to_send = { task_UID : "" }


		data_to_send.task_UID  = "Task1GUID";
		data_to_send.project_UID  = "Project1GUID";

		try{
			socket.send('/connecttasktoproject ' + JSON.stringify( data_to_send ) );
		} catch(exception){
			message('<p class="warning">');
		}
		
		
		// Then list tasks without project and then it should not include Task 1
		
		
		
		$('#testLog').empty();	
		
		
		try{
			socket.send('/listtaskswithoutproject ');
		} catch(exception){
			message('<p class="warning">');
		}
		
		
	}

	function test_case4(){
		$('#testLog').append('test case 4 started');
		test_case_number = 4;




	}


	function clean_db(){
		$('#testLog').append('Removing test data from DB');

		try{
			socket.send('/cleantestDB');
		} catch(exception){
			message('<p class="warning">');
		}
	}

	function data(msg_data){  // TODO Duplicated from standard page Might need to create special methods for each reply to avoid that I change in one place but not in the other.
		if ( msg_data.indexOf ("taskcreated") == 0 ) {
			$('#testLog').append('<p>' + msg_data.substring(11) + '</p>' );
		} else if ( msg_data.indexOf ("listtaskswithoutproject") == 0 ) {
			$('#testLog').append(msg_data.substring(23));

		} else if ( msg_data.indexOf ("tasklist") == 0 ) {
			$('#testLog').append(msg_data.substring(8));

			if (test_case_number == 1) {
				// Add button to make it possble to coninue after the test is verified.
				$('#testLog').append('  <button id="start_test_case_2" onclick="test_case2()">test_case2</button>');

			}

			if (test_case_number == 3) {
				// Add button to make it possble to coninue after the test is verified.
				$('#testLog').append('  <button id="start_test_case_4" onclick="test_case4()">test_case4</button>');

			}


//			try{
//				socket.send('/listprojects');
//			} catch(exception){
//				message('<p class="warning">');
//			}
		} else if ( msg_data.indexOf ("projectlist") == 0 ) { // This is the second data we get after connecting. Then send a new question directly
			$('#testLog').append(msg_data.substring(11));


			if (test_case_number == 2) {
				// Add button to make it possble to coninue after the test is verified.
				$('#testLog').append('  <button id="start_test_case_3" onclick="test_case3()">test_case3</button>');

			}





//			var summary = $('#create_task_summary').val();
//			var data_to_send = { summary : "" }
//			data_to_send.notes = "";

//			try{

//				data_to_send.UID  = "my_test_task_guid"; //generateQuickGuid();
//				data_to_send.summary = "summary";
//				data_to_send.startdate = "";
//				data_to_send.enddate = "";
//				socket.send('/createtask ' +  JSON.stringify( data_to_send ) );
//			} catch(exception){
//				message('<p class="warning">');
//			}





		} else if ( msg_data.indexOf ("filter_status") == 0 ) {
			$('#testLog').append(msg_data.substring(13));
		} else if ( msg_data.indexOf ("filter_date") == 0 ) {
			$('#testLog').append(msg_data.substring(11));
		} else if ( msg_data.indexOf ("filter") == 0 ) {
			$('#testLog').append(msg_data.substring(6));
		} else if ( msg_data.indexOf ("edittask") == 0 ) {
			$('#testLog').append(msg_data.substring(8));
		} else {
			$('#testLog').append('<p>' + msg_data + '</p>' );
		}
	}//End data()



</script>
 </head>
 <title>BSharp ToDo</title>

<body>
Test page

	<div id="testLog"  ></div>

	<button id="clean_db" onclick="clean_db()">Clean DB</button>

</body>
</html>
			]"



				Result.replace_substring_all ("##HOSTNAME##", a_host)
				Result.replace_substring_all ("##PORTNUMBER##", a_port.out)
				if request.is_https then
					Result.replace_substring_all ("##HTTPSCHEME##", "https")
					Result.replace_substring_all ("##WSSCHEME##", "wss")
				else
					Result.replace_substring_all ("##HTTPSCHEME##", "http")
					Result.replace_substring_all ("##WSSCHEME##", "ws")
				end
		end

	websocket_app_html (a_host: STRING; a_port: INTEGER): STRING
		do

			-- Using this to create Responsivnes: https://www.w3schools.com/bootstrap4/bootstrap_get_started.asp
			Result := "[
<!DOCTYPE html>
<html  lang="en">

<style>
.mytooltip {
    position: relative;
    display: inline-block;
    border-bottom: 1px dotted black;
}

.mytooltip .mytooltiptext {
    visibility: hidden;
    
    background-color: black;
    color: #fff;
    text-align: center;
    border-radius: 6px;
    padding: 5px 5px;
    position: absolute;
    z-index: 1;
    bottom: 100%;
    left: 0%;
    margin-left: -50px;
    
    /* Fade in tooltip - takes 2 second to go from 0% to 100% opac: */
    opacity: 0;
    transition: opacity 2s;
}

.mytooltip:hover .mytooltiptext {
    visibility: visible;
    opacity: 1;
}




/* from https://www.w3schools.com/howto/tryit.asp?filename=tryhow_css_modal */
/* The Modal (background) */
.mymodal {
    display: none; /* Hidden by default */
    position: fixed; /* Stay in place */
    z-index: 2; /* Sit on top */
    padding-top: 10px; /* Location of the box */
    left: 0;
    top: 0;
    width: 100%; /* Full width */
    height: 100%; /* Full height */
    overflow: auto; /* Enable scroll if needed */
    background-color: rgb(0,0,0); /* Fallback color */
    background-color: rgba(0,0,0,0.4); /* Black w/ opacity */
}

/* Modal Content */
.mymodal-content {
    background-color: #fefefe;
    margin: auto;
    padding: 20px;
    border: 1px solid #888;
    width: 98%;
}

/* The Modal (background) */
.mymodalProjects {
    display: none; /* Hidden by default */
    position: fixed; /* Stay in place */
    z-index: 1; /* Sit on top */
    padding-top: 10px; /* Location of the box */
    left: 0;
    top: 0;
    width: 100%; /* Full width */
    height: 100%; /* Full height */
    overflow: auto; /* Enable scroll if needed */
    background-color: rgb(0,0,0); /* Fallback color */
    background-color: rgba(0,0,0,0.4); /* Black w/ opacity */
}

/* ModalProjects Content */
.mymodalProjects-content {
    background-color: #fefefe;
    margin: auto;
    padding: 20px;
    border: 1px solid #888;
    width: 80%;
}



</style>
<head>
<meta charset="utf-8"> 
<meta name="viewport" content="width=device-width, initial-scale=1.0">

<!-- https://fontawesome.com/  used for Icons-->

<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.5.0/css/all.css" integrity="sha384-B4dIYHKNBt8Bc12p+WXckhzcICo0wtJAoU8YZTY5qE0Id1GSseTk6S+L3BlXeVIU" crossorigin="anonymous">

<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="##HTTPSCHEME##://maxcdn.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css">

<!-- jQuery library -->
<script src="##HTTPSCHEME##://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<!-- Popper JS -->
<script src="##HTTPSCHEME##://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js"></script>


<!-- Latest compiled JavaScript -->
<script src="##HTTPSCHEME##://maxcdn.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js"></script>

<script type="text/javascript" src="svg.js"> </script>
<script type="text/javascript" src="svg.draggy.js"></script>
<script type="text/javascript" src="svg.connectable.js"></script>

<script type="text/javascript">

	var socket;
	
$(document).ready(function() {


]"

+ javascript_socket_code  +

 "[


	$('#disconnect').click(function(){
		socket.close();
	});


	$('#list_tasks_button').click(function(){

		try{
			socket.send('/listtasks');
		} catch(exception){
			message('<p class="warning">');
		}

	});

	$('#listtaskswithoutproject_button').click(function(){

		try{
			socket.send('/listtaskswithoutproject');
		} catch(exception){
			message('<p class="warning">');
		}

	});

	$('#list_projects_button').click(function(){

		try{
			socket.send('/listprojects');
		} catch(exception){
			message('<p class="warning">');
		}

	});


	$('#new_filter_button').click(function(){


		try{
			socket.send('/newfiltertasks ');
		} catch(exception){
			message('<p class="warning">');
		}

	});



	if (!("WebSocket" in window)){
		$('#chatLog, input, button, #examples').fadeOut("fast");
		$('<p>You need a browser that supports WebSockets. How about <a href="http://www.google.com/chrome">Google Chrome</a>?</p>').appendTo('#todocontainer');
	}else{
		//The user has WebSockets
		connect();
	}
	
	
	if (SVG.supported) {
//  var draw = SVG('drawing')
//  var rect = draw.rect(100, 100)
draw = SVG('svg_demo').size(1000, 1000)
var nested = draw.nested()



var rect = draw.rect(100, 100).attr({ fill: '#f06' })

//rect.draggy();

var ellipse = nested.ellipse(75, 50).fill('#101').move(20, 20)
var line = nested.line(0, 0, 100, 150).stroke({ width: 1 })
var text = nested.plain('Lorem ipsum dolor sit amet consectetur.').attr({ visibility:'hidden' }).id('tooltip')
text.move(20,20).font({ fill: '#f06', family: 'Inconsolata' })

//nested.draggy();

var circle1 = draw.circle(100).fill('#101').move(20, 20).id('myid1');

var circle2 = draw.circle(150).fill('#111').move(40, 20).id('myid2').attr({onmouseout:'HideTooltip(evt)', onmousemove: 'ShowTooltip(evt)' });

nested.move(100,100)


var links = draw.group();
var markers = draw.group();


var g1 = draw.group().draggy();
var g2 = draw.group().draggy();
//g1.add(rect);
//g2.add(ellipse);
g1.add(circle1);
g2.add(circle2);

    g1.connectable({
        container: links,
        markers: markers
    }, g2).setLineColor("#5D4037");


//var a_set = draw.select('myid1', g2);

var a_set = SVG.get('myid1').fill('#771');

//a_set.first().fill('#701');


var element = SVG.get('myid2').fill('#ff6')


draw_task_graphic_part(300,300, nested);

} else {
  alert('SVG not supported')
}


});

var draw
function ShowTooltip(evt) {

	message (evt.target.id);
	message (evt.currentTarget.id);
    var tooltip = document.getElementById('tooltip');
    tooltip.setAttribute("visibility", "visible");
}

function HideTooltip(evt) {
	message (evt.target.id);
    var tooltip = document.getElementById('tooltip');
    tooltip.setAttribute("visibility", "hidden");
}

	function draw_task_graphic_part (x,y, parent) {
		var my_nested = parent.nested()

	// Add UID as CSS-selector to the top graphics of the new task
	// Nest it below the parent (if parent exists)

	// add also events for moving and collapsing and expaning children etc

		var rect = my_nested.circle(50, 50).attr({ fill: 'lightblue', class: 'mytooltip' }).move(x,y)


		var text = my_nested.plain('My summary').move(x+5,y+15)

	}

	function draw_task (task_uid, parent_uid) {
		// if no parent found  then draw it as a top node



		// Draw directly at the top level and let the user move it. (Long term we can save the position and use that next time it is drawn)
		//else draw it below the parent
// 		get_parent_tasks coordinates
// 		Draw directly below and let the user adjust if needed.
//       draw_task_graphics()

	}


	function initiate () {
		socket.send('/newfiltertasks ');
	}

// TODO I had to "duplicate" this code since it does not seem possible to call the connect function in the readydoc part.

	]"

+ javascript_socket_code  +

 "[
	
	
	
	function create_task(){
		if (event.keyCode === 13) {
			var summary = $('#create_task_summary').val();
			var data_to_send = { summary : "" }
			var edit_data_to_send = { UID : "" }
			data_to_send.notes = "";

			if(summary==""){
				message('<p class="warning">Please enter a summary');
				return ;
			}

			try{

				data_to_send.UID  = generateQuickGuid();
				data_to_send.summary = summary;
				data_to_send.startdate = "";
				data_to_send.enddate = "";
				socket.send('/createtask ' +  JSON.stringify( data_to_send ) );
				
				edit_data_to_send.UID  = data_to_send.UID;
				socket.send('/edittask ' + JSON.stringify( edit_data_to_send ) );
				
			} catch(exception){
				message('<p class="warning">');
			}
			$('#create_task_summary').val("");
		}
		if (event.keyCode === 222 && event.ctrlKey && event.shiftKey) {
			show_logging_etc();
		}
		
	}

	function create_subtask(){
		if (event.keyCode === 13) {
			var summary = $('#create_subtask').val();
			var data_to_send = { summary : "" }
			var edit_data_to_send = { UID : "" }
			data_to_send.notes = "";

			if(summary==""){
				message('<p class="warning">Please enter a summary');
				return ;
			}

			try{

				data_to_send.UID  = generateQuickGuid();
				data_to_send.summary = summary;
				data_to_send.startdate = "";
				data_to_send.enddate = "";

				var x = document.getElementsByClassName("class_edit_task");

				var connect_data_to_send = { task_UID : "" }

				connect_data_to_send.task_UID  = x[0].id;
				connect_data_to_send.subtask_UID  = data_to_send.UID;

				socket.send('/createtask ' +  JSON.stringify( data_to_send ) );
				socket.send('/connecttasks ' + JSON.stringify( connect_data_to_send ) );

				edit_data_to_send.UID  = data_to_send.UID;
				socket.send('/edittask ' + JSON.stringify( edit_data_to_send ) );
				
				
				
			} catch(exception){
				message('<p class="warning">');
			}
		}
	}



	function search_task_summary(){
		if (event.keyCode === 13) {
			var search_string = $('#search_task_summary').val();
			var data_to_send = { search_string : "" }

			if(search_string==""){
				message('<p class="warning">Please enter a summary');
				return ;
			}

			try{
				data_to_send.search_string = search_string;
				socket.send('/search_task_summary ' +  JSON.stringify( data_to_send ) );
			} catch(exception){
				message('<p class="warning">');
			}
			$('#search_task_summary').val("");
		}
	}














	function create_project(){
		if (event.keyCode === 13) {
			var project_name = $('#create_project_name').val();
			var data_to_send = { project_name : "" }
			if(project_name==""){
				message('<p class="warning">Please enter a project name');
				return ;
			}

			try{
				data_to_send.UID  = generateQuickGuid();
				data_to_send.project_name = project_name;
				socket.send('/createproject ' +   JSON.stringify( data_to_send ) );
			} catch(exception){
				message('<p class="warning">');
			}
			$('#create_project_name').val("");
		}
	}

	function list_this_project (element){
		var data_to_send = { UID : "" }
		data_to_send.UID  = element.id;
		try{
				socket.send('/list_this_project ' + JSON.stringify( data_to_send ) );
		} catch(exception){
			message('<p class="warning">');
		}
	}


	function task_done(element) {
		var data_to_send = { UID : "" }
		data_to_send.UID  = element.id;

		try{
			if (element.checked) {
				socket.send('/taskdone ' + JSON.stringify( data_to_send ) );
			} else {
				socket.send('/taskundone ' + JSON.stringify( data_to_send ) );
			}
		} catch(exception){
			message('<p class="warning">');
		}

	}

	function task_deleted(element) {
		var data_to_send = { UID : "" }
		data_to_send.UID  = element.id;

		try{
			socket.send('/taskdeleted ' + JSON.stringify( data_to_send ) );
			$('#myModal').css( "display", "none");
		} catch(exception){
			message('<p class="warning">');
		}

	}

	function project_deleted(element) {
		var data_to_send = { UID : "" }
		data_to_send.UID  = element.id;

		try{
			socket.send('/projectdeleted ' + JSON.stringify( data_to_send ) );
			$('#myModal').css( "display", "none");
		} catch(exception){
			message('<p class="warning">');
		}

	}
	
	function filter_project_check(element) {
		var data_to_send = { UID : "" }
		data_to_send.UID  = element.id;

		try{
			if (element.checked) {
				socket.send('/setfilterproject ' + JSON.stringify( data_to_send ) );
			} else {
				socket.send('/unsetfilterproject ' + JSON.stringify( data_to_send ) );
			}
		} catch(exception){
			message('<p class="warning">');
		}

	}

	function filter_inbox_check(element) {
		try{
			if (element.checked) {
				socket.send('/setfilterinbox ');
			} else {
				socket.send('/unsetfilterinbox ');
			}
		} catch(exception){
			message('<p class="warning">');
		}

	}


	function filter_no_start_date_check(element) {
		try{
			if (element.checked) {
				socket.send('/setnostartdate '  );
			} else {
				socket.send('/unsetnostartdate ' );
			}
		} catch(exception){
			message('<p class="warning">');
		}

	}

	function filter_no_end_date_check(element) {
		try{
			if (element.checked) {
				socket.send('/setnoenddate '  );
			} else {
				socket.send('/unsetnoenddate ' );
			}
		} catch(exception){
			message('<p class="warning">');
		}

	}




	function filter_status_check(element) {
		var data_to_send = { UID : "" }
		data_to_send.UID  = element.id;

		try{
			if (element.checked) {
				socket.send('/setfilterstatus ' + JSON.stringify( data_to_send ) );
			} else {
				socket.send('/unsetfilterstatus ' + JSON.stringify( data_to_send ) );
			}
		} catch(exception){
			message('<p class="warning">');
		}

	}

	function connection_lost() {
		try{

			$('#edittask').empty();
			$('#edittask').append('  <button id="list_tasks_button" onclick="reconnect()">Connect</button>');
			$('#myModal').css( "display", "block");
		} catch(exception){
			message('<p class="warning">');
		}
	}

	function reconnect (){
		try{
			connect();
		} catch(exception){
			message('<p class="warning">');
		}
	}


	function edit_task(element) {
		var data_to_send = { UID : "" }

		try{
			data_to_send.UID  = element.id;
			socket.send('/edittask ' + JSON.stringify( data_to_send ) );
			
		} catch(exception){
			message('<p class="warning">');
		}
	}


	function edit_project(element) {
		var data_to_send = { UID : "" }

		try{
			data_to_send.UID  = element.id;
			socket.send('/editproject ' + JSON.stringify( data_to_send ) );

		} catch(exception){
			message('<p class="warning">');
		}
	}

	function update_task(element) {
	
		apply_task(element)
		$('#myModal').css( "display", "none");


	}

	function apply_task(element) {
		var data_to_send = { summary : "" }

		try{
			data_to_send.UID  = element.id;
			data_to_send.summary = $('#edit-summary').val();
			data_to_send.notes = $('#edit-notes').val();
			if ($('#edit-start-time').val() == "" ){
				data_to_send.startdate = $('#edit-start-date').val();
			} else {
				data_to_send.startdate = $('#edit-start-date').val() + "T" + $('#edit-start-time').val();
			}

			if ($('#edit-end-time').val() == "" ){
				data_to_send.enddate = $('#edit-end-date').val();
			} else {
				data_to_send.enddate = $('#edit-end-date').val() + "T" + $('#edit-end-time').val();
			}

			socket.send('/updatetask ' +  JSON.stringify( data_to_send ) );
		} catch(exception){
			message('<p class="warning">');
		}

	}




	function update_project(element) {
		var data_to_send = { project_name : "" }

		try{
			data_to_send.UID  = element.id;
			data_to_send.project_name = $('#edit-name').val();

			socket.send('/updateproject ' +  JSON.stringify( data_to_send ) );
			$('#myModal').css( "display", "none");

		} catch(exception){
			message('<p class="warning">');
		}

	}

	function cancel_update_task(element) {
		$('#myModal').css( "display", "none");
	}

	function cancel_update_projects(element) {
		$('#myModalProjects').css( "display", "none");
	}

//TODO Might have one cancel update funtion instead since I try to resuse the same modal dialog.

	function cancel_update_project(element) {
		$('#myModal').css( "display", "none");
	}

	function show_logging_etc() {
		$('#chatLog').css( "display", "block");
		$('#diconnectButton').css( "display", "block");
	}


	function edit_filter_start_date_change (element) {
		var startdate = ""


		startdate = $('#edit-filter-start-date').val() ;
		if (startdate == "" ) {
			document.getElementById("edit-filter-start-time").disabled = true;
			document.getElementById("edit-filter-start-time").value = "";
		}	else  {
			document.getElementById("edit-filter-start-time").disabled = false;
		}

		var data_to_send = { startdate : "" }

		try{
			if ($('#edit-filter-start-time').val() == "" ){
				data_to_send.startdate = $('#edit-filter-start-date').val();
			} else {
				data_to_send.startdate = $('#edit-filter-start-date').val() + "T" + $('#edit-filter-start-time').val();
			}

			if ($('#edit-filter-end-time').val() == "" ){
				data_to_send.enddate = $('#edit-filter-end-date').val();
			} else {
				data_to_send.enddate = $('#edit-filter-end-date').val() + "T" + $('#edit-filter-end-time').val();
			}


			socket.send('/updatefilterdate ' +  JSON.stringify( data_to_send ) );
		} catch(exception){
			message('<p class="warning">');
		}


	}


	function edit_filter_end_date_change (element) {
		var enddate = ""

		enddate = $('#edit-filter-end-date').val() ;
		if (enddate == "" ) {
			document.getElementById("edit-filter-end-time").disabled = true;
			document.getElementById("edit-filter-end-time").value = "";
		}	else  {
			document.getElementById("edit-filter-end-time").disabled = false;
		}

		var data_to_send = { startdate : "" }

		try{
			if ($('#edit-filter-start-time').val() == "" ){
				data_to_send.startdate = $('#edit-filter-start-date').val();
			} else {
				data_to_send.startdate = $('#edit-filter-start-date').val() + "T" + $('#edit-filter-start-time').val();
			}

			if ($('#edit-filter-end-time').val() == "" ){
				data_to_send.enddate = $('#edit-filter-end-date').val();
			} else {
				data_to_send.enddate = $('#edit-filter-end-date').val() + "T" + $('#edit-filter-end-time').val();
			}


			socket.send('/updatefilterdate ' +  JSON.stringify( data_to_send ) );
		} catch(exception){
			message('<p class="warning">');
		}

	}
	
	function edit_start_date_change (element) {
		var startdate = ""


		startdate = $('#edit-start-date').val() ;
		if (startdate == "" ) {
			document.getElementById("edit-start-time").disabled = true;
			document.getElementById("edit-start-time").value = "";
		}	else  {
			document.getElementById("edit-start-time").disabled = false;
		}
	}

	function edit_end_date_change (element) {
		var enddate = ""


		enddate = $('#edit-end-date').val() ;
		if (enddate == "" ) {
			document.getElementById("edit-end-time").disabled = true;
			document.getElementById("edit-end-time").value = "";
		}	else  {
			document.getElementById("edit-end-time").disabled = false;
		}
	}

	
	function message(msg){
		$('#chatLog').append(msg+'</p>' );
	}//End message()

	function data(msg_data){
		if ( msg_data.indexOf ("taskcreated") == 0 ) {
			$('#chatLog').append('<p>' + msg_data.substring(11) + '</p>' );
		} else if ( msg_data.indexOf ("listtaskswithoutproject") == 0 ) {
			$('#listtaskswithoutproject').empty();
			$('#listtaskswithoutproject').append(msg_data.substring(23));
		} else if ( msg_data.indexOf ("tasklist") == 0 ) {
			$('#tasklist').empty();
			$('#tasklist').append(msg_data.substring(8));
		} else if ( msg_data.indexOf ("projectlist") == 0 ) {
			$('#editprojects').empty();
			$('#editprojects').append('<input id="create_project_name" type="text" placeholder="Add a project" onkeydown="create_project()" style="margin:3px;width:100%;" ></input>');
			$('#editprojects').append(msg_data.substring(11));
			$('#editprojects').append('<div style="text-align:center"><button id="project_done"  onclick="cancel_update_projects()" >Done</button></div>');
			$('#myModalProjects').css( "display", "block");
		} else if ( msg_data.indexOf ("filter_status") == 0 ) {
			$('#filter_status').empty();
			$('#filter_status').append(msg_data.substring(13));
		} else if ( msg_data.indexOf ("filter_date") == 0 ) {
			$('#filter_date').empty();
			$('#filter_date').append(msg_data.substring(11));
		} else if ( msg_data.indexOf ("filter") == 0 ) {
			$('#filter').empty();
			$('#filter').append(msg_data.substring(6));
		} else if ( msg_data.indexOf ("edittask") == 0 ) {  // TODO Might rename this since this is used both for edit task and edit project since it is not dependent on what I edit.
			$('#edittask').empty();
			$('#edittask').append(msg_data.substring(8));
			$('#myModal').css( "display", "block");
		} else {
			$('#chatLog').append('<p>' + msg_data + '</p>' );
		}
	}//End data()



function allowDrop(ev) {
    ev.preventDefault();
}

function drag(ev) {
    ev.dataTransfer.setData("text", ev.target.id);
}


function drop(ev) {
    ev.preventDefault();
    var data = ev.dataTransfer.getData("text");
	var data_to_send = { task_UID : "" }

	data_to_send.task_UID  = data;
	data_to_send.project_UID  = ev.target.id;

	socket.send('/connecttasktoproject ' + JSON.stringify( data_to_send ));
}

function connect_this_task_to_project(element) {

	var data_to_send = { task_UID : "" }

	var x = document.getElementsByClassName("class_edit_task");

	data_to_send.task_UID  = x[0].id;
	data_to_send.project_UID  = element.id;

	try{
		if (element.checked) {
			socket.send('/connecttasktoproject ' + JSON.stringify( data_to_send ) );
		} else {
			socket.send('/on_remove_connection_between_task_and_project ' + JSON.stringify( data_to_send ) );
		}
	} catch(exception){
		message('<p class="warning">');
		message('task_UID ' + data_to_send.task_UID);
		message('project_UID ' + data_to_send.project_UID);
	}
}



function generateQuickGuid() {
var d = new Date();
    return d.getTime() + Math.random().toString(36).substring(2, 15) +
        Math.random().toString(36).substring(2, 15);
}

</script>
<meta charset="utf-8" />
<style type="text/css">
body {font-family:Arial, Helvetica, sans-serif;}
#chatLog { padding:5px; border:1px solid black; }
#chatLog p {margin:0;}
.event {color:#999;}
.warning { font-weight:bold; color:#CCC; }
</style>
<title>BSharp ToDo</title>
</head>
<body>



  <div id="wrapper">
  	<div class="container-fluid" id="todocontainer">
  		<br>
        <div class="row">
        	<div class="col-sm" >
				<input id="create_task_summary" type="text" placeholder="Add a task" onkeydown="create_task()" style="width:80%;">
        		</input>
              	<div class="btn-group dropdown dropleft float-right" >
	       	        <button  type="button" class="btn btn-default btn-sm"  data-toggle="dropdown">
	          			<span  class="fas fa-bars"></span>
	        		</button>
	                <ul class="dropdown-menu" role="menu">
	    				  <li>Options...</li>
	    				  <li><button id="list_projects_button" class="btn" style="text-align:center;width:100%;height:100%">Projects...</button></li>
	    				  <li><input id="search_task_summary" type="text" placeholder="Search summary" onkeydown="search_task_summary()"</li>

	    			</ul>
	    		</div>
	        </div>
        </div>
	  	<br>
        <div class="row">
        	<div class="col" id="tasklist"></div>
		</div>
        <div class="row" >
            	<div class="col-xs-4"  style="width:33%;text-align:center;"><button id="new_filter_button" class="btn"  style="text-align:center;width:60%;">Filter</button></div>
	        	<div class="col-xs-4"  style="width:33%;text-align:center;"><button id="list_tasks_button" class="btn" style="text-align:center;width:60%;">All</button></div>
	        	<div class="col-xs-4"  style="width:33%;text-align:center;"><button id="listtaskswithoutproject_button" class="btn" style="text-align:center;width:60%;">Inbox</button></div>
        </div>


        <div class="row" style="text-align:center;margin:3px;" >
        	<div class="col-xs-4" style="text-align:center;margin:3px;">
	       		<div class="btn-group" id="filter"  style="margin:3px;">
				</div>
        	</div>
           	<div class="col-xs-4" style="text-align:center;margin:3px;">
        		<div class="btn-group"  id="filter_status" style="margin:3px;">
			 	</div>
			</div>
        	<div class="col-xs-4" style="text-align:center;margin:3px;">
        		<div class="btn-group dropleft"  id="filter_date" style="margin:3px;">
			 	</div>
	       	</div>
        </div>




		<div class="row">
        	<div class="col-sm" id="diconnectButton" style="display:none;"><button id="disconnect">Disconnect</button><br></div><br>
        	<div class="col-sm" id="chatLog"  style="display:none;"></div>
        	<div class="col-sm" id="svg_demo" ></div>
		</div>
	</div>
  </div>
  		<div id="myModal" class="mymodal">
  			<div class="mymodal-content">
        		<div id="edittask">
        		</div>
			</div>
		</div>

  		<div id="myModalProjects" class="mymodalProjects">
  			<div class="mymodalProjects-content">
        		<div id="editprojects">
        		</div>
			</div>
		</div>




 <!--Start Show Session Expire Warning Popup here -->
    <div class="modal fade" id="session-expire-warning-modal" aria-hidden="true" data-keyboard="false" data-backdrop="static" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
        <div class="modal-dialog" role="document">
            <div class="modal-content">
                <div class="modal-header">
                    <h4 class="modal-title">Session Expire Warning</h4>
                </div>
                <div class="modal-body">
                    Your session will expire in <span id="seconds-timer"></span> seconds. Do you want to extend the session?
                </div>
                <div class="modal-footer">
                    <button id="btnOk" type="button" class="btn btn-default" style="padding: 6px 12px; margin-bottom: 0; font-size: 14px; font-weight: normal; border: 1px solid transparent; border-radius: 4px;  background-color: #428bca; color: #FFF;">Ok</button>
                    <button id="btnSessionExpiredCancelled" type="button" class="btn btn-default" data-dismiss="modal" style="padding: 6px 12px; margin-bottom: 0; font-size: 14px; font-weight: normal; border: 1px solid transparent; border-radius: 4px; background-color: #428bca; color: #FFF;">Cancel</button>
                    <button id="btnLogoutNow" type="button" class="btn btn-default" style="padding: 6px 12px; margin-bottom: 0; font-size: 14px; font-weight: normal; border: 1px solid transparent; border-radius: 4px;  background-color: #428bca; color: #FFF;">Logout now</button>
                </div>
            </div>
        </div>
    </div>
    <!--End Show Session Expire Warning Popup here -->
    <!--Start Show Session Expire Popup here -->
    <div class="modal fade" id="session-expired-modal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
        <div class="modal-dialog" role="document">
            <div class="modal-content">
                <div class="modal-header">
                    <h4 class="modal-title">Session Expired</h4>
                </div>
                <div class="modal-body">
                    Your session is expired.
                </div>
                <div class="modal-footer">
                    <button id="btnExpiredOk" onclick="sessionExpiredRedirect()" type="button" class="btn btn-primary" data-dismiss="modal" style="padding: 6px 12px; margin-bottom: 0; font-size: 14px; font-weight: normal; border: 1px solid transparent; border-radius: 4px; background-color: #428bca; color: #FFF;">Ok</button>
                </div>
            </div>
        </div>
    </div>

	<script> // Code to handle session timeout. I got it from this page https://www.codeproject.com/Tips/1175658/Session-Expiration-Popup
			 // Anoher simpler alternative that might be better to look at to understand the code below.

var sessServerAliveTime = 10 * 600000 * 2; // Changed from 10 * 60 * 2
var sessionTimeout = 55 * 60000; // 55 minute timeout. DONE Set correct timeout that match the length of the github login session (60 minutes). I want this to be less than the github timeout so that I initially does not get any problems.
var sessLastActivity;
var idleTimer, remainingTimer;
var isTimeout = false;

var sess_intervalID, idleIntervalID;
var sess_lastActivity;
var timer;
var isIdleTimerOn = false;
localStorage.setItem('sessionSlide', 'isStarted');

function sessPingServer() { // TODO Must be tested further. Implement ping of server to extend the session. The url does not exist so it returns some code but since we only ignore it I do not see any problems with it.
    if (!isTimeout) {        // Does seem to ping the server, if I uncomment it, but I do not understand why I need to have it. Oroginally the oinging was very frequent.
        //$.ajax({
        //    url: '/SessionTimeout',
        //    dataType: "json",
        //    async: false,
        //    type: "POST"
        //});

        return true;
    }
}

function sessServerAlive() {
    sess_intervalID = setInterval('sessPingServer()', sessServerAliveTime);
}

 // TODO I assume that this is to hanlde that the user is active. But since it does not connect to the server I am not sure that it updates the github timeout. But the call to the sessServerAlive might have been the intention to do that
function initSessionMonitor() {
    $(document).bind('keypress.session', function (ed, e) {
        sessKeyPressed(ed, e);
    });
    $(document).bind('mousedown keydown', function (ed, e) {

        sessKeyPressed(ed, e);
    });
    sessServerAlive();
    startIdleTime();
}


// TODO Same comment as above
$(window).scroll(function (e) {
    localStorage.setItem('sessionSlide', 'isStarted');
    startIdleTime();
});

function sessKeyPressed(ed, e) {
    var target = ed ? ed.target : window.event.srcElement;
    var sessionTarget = $(target).parents("#session-expire-warning-modal").length;

    if (sessionTarget != null && sessionTarget != undefined) {
        if (ed.target.id != "btnSessionExpiredCancelled" && ed.target.id != "btnSessionModal" && ed.currentTarget.activeElement.id != "session-expire-warning-modal" && ed.target.id != "btnExpiredOk"
             && ed.currentTarget.activeElement.className != "modal fade modal-overflow in" && ed.currentTarget.activeElement.className != 'modal-header'
    && sessionTarget != 1 && ed.target.id != "session-expire-warning-modal") {
            localStorage.setItem('sessionSlide', 'isStarted');
            startIdleTime();
        }
    }
}

function startIdleTime() {
    stopIdleTime();
    localStorage.setItem("sessIdleTimeCounter", $.now());
    idleIntervalID = setInterval('checkIdleTimeout()', 1000);
    isIdleTimerOn = false;
}

var sessionExpired = document.getElementById("session-expired-modal");

function sessionExpiredClicked(evt) {
    window.location = "Logout.html";

}

sessionExpired.addEventListener("click", sessionExpiredClicked, false);

function stopIdleTime() {
    clearInterval(idleIntervalID);
    clearInterval(remainingTimer);
}

function checkIdleTimeout() {
     // $('#sessionValue').val() * 60000;
    var idleTime = (parseInt(localStorage.getItem('sessIdleTimeCounter')) + (sessionTimeout));
    if ($.now() > idleTime + 60000) {
        $("#session-expire-warning-modal").modal('hide');
        $("#session-expired-modal").modal('show');
        clearInterval(sess_intervalID);
        clearInterval(idleIntervalID);

        $('.modal-backdrop').css("z-index", parseInt($('.modal-backdrop').css('z-index')) + 100);
        $("#session-expired-modal").css('z-index', 2000);
        $('#btnExpiredOk').css('background-color', '#428bca');
        $('#btnExpiredOk').css('color', '#fff');

        isTimeout = true;

        sessLogOut();

    }
    else if ($.now() > idleTime) {
        ////var isDialogOpen = $("#session-expire-warning-modal").is(":visible");
        if (!isIdleTimerOn) {
            ////alert('Reached idle');
            localStorage.setItem('sessionSlide', false);
            countdownDisplay();

            $('.modal-backdrop').css("z-index", parseInt($('.modal-backdrop').css('z-index')) + 500);
            $('#session-expire-warning-modal').css('z-index', 1500);
            $('#btnOk').css('background-color', '#428bca');
            $('#btnOk').css('color', '#fff');
            $('#btnSessionExpiredCancelled').css('background-color', '#428bca');
            $('#btnSessionExpiredCancelled').css('color', '#fff');
            $('#btnLogoutNow').css('background-color', '#428bca');
            $('#btnLogoutNow').css('color', '#fff');

            $("#seconds-timer").empty();
            $("#session-expire-warning-modal").modal('show');


            isIdleTimerOn = true;
        }
    }
}

$("#btnSessionExpiredCancelled").click(function () {
    $('.modal-backdrop').css("z-index", parseInt($('.modal-backdrop').css('z-index')) - 500);
});

$("#btnOk").click(function () {
    $("#session-expire-warning-modal").modal('hide');
    $('.modal-backdrop').css("z-index", parseInt($('.modal-backdrop').css('z-index')) - 500);
    startIdleTime();
    clearInterval(remainingTimer);
    localStorage.setItem('sessionSlide', 'isStarted');

    // TODO/DONE Add a call to the server to refresh the timeout of the github login. Is it necessary to do a winsock call?
    // Is this correct below?

     $.ajax({
            url: '/SessionTimeout',
            dataType: "json",
            async: true,
            type: "POST"
        });



});

$("#btnLogoutNow").click(function () {
    localStorage.setItem('sessionSlide', 'loggedOut');
    window.location = "Logout.html";
    sessLogOut();
    $("#session-expired-modal").modal('hide');

});
$('#session-expired-modal').on('shown.bs.modal', function () {
    $("#session-expire-warning-modal").modal('hide');
    $(this).before($('.modal-backdrop'));
    $(this).css("z-index", parseInt($('.modal-backdrop').css('z-index')) + 1);
});


// TODO I am not sure what this do
$("#session-expired-modal").on("hidden.bs.modal", function () {
    window.location = "Logout.html";
});


// TODO I am not sure what this do
$('#session-expire-warning-modal').on('shown.bs.modal', function () {
    $("#session-expire-warning-modal").modal('show');
    $(this).before($('.modal-backdrop'));
    $(this).css("z-index", parseInt($('.modal-backdrop').css('z-index')) + 1);
});


function countdownDisplay() {

    var dialogDisplaySeconds = 60;

    remainingTimer = setInterval(function () {
        if (localStorage.getItem('sessionSlide') == "isStarted") {
            $("#session-expire-warning-modal").modal('hide');
            startIdleTime();
            clearInterval(remainingTimer);
        }
        else if (localStorage.getItem('sessionSlide') == "loggedOut") {
            $("#session-expire-warning-modal").modal('hide');
            $("#session-expired-modal").modal('show');
        }
        else {

            $('#seconds-timer').html(dialogDisplaySeconds);
            dialogDisplaySeconds -= 1;
        }
    }
    , 1000);
};

function sessLogOut() { //TODO  AJAX call might not be needed in  my case.
   // $.ajax({
   //     url: 'Logout.html',
   //     dataType: "json",
  //      async: false,
  //      type: "POST"
 //   });

	window.location = "Logout.html";

}





	</script>
	 <!-- This will init session -->
	<script>
	 initSessionMonitor();
	</script>




</body>
</html>
			]"
			Result.replace_substring_all ("##HOSTNAME##", a_host)
			Result.replace_substring_all ("##PORTNUMBER##", a_port.out)
			if request.is_https then
				Result.replace_substring_all ("##HTTPSCHEME##", "https")
				Result.replace_substring_all ("##WSSCHEME##", "wss")
			else
				Result.replace_substring_all ("##HTTPSCHEME##", "http")
				Result.replace_substring_all ("##WSSCHEME##", "ws")
			end
		end


	websocket_admin_html (a_host: STRING; a_port: INTEGER): STRING
		do

			Result := "[
<!DOCTYPE html>
<html  lang="en">

<head>
<meta charset="utf-8"> 
<!-- jQuery library -->
<script src="##HTTPSCHEME##://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<script type="text/javascript">

	var socket;
	
$(document).ready(function() {



	function connect(){

			var host = "##WSSCHEME##://##HOSTNAME##:##PORTNUMBER##/app";

			try{

				socket = new WebSocket(host);
				message('<p class="event">Socket Status: '+socket.readyState);
				socket.onopen = function(){
						message('<p class="event">Socket Status: '+socket.readyState+' (open)');
					}
				socket.onmessage = function(msg){
						data(msg.data);
					}
				socket.onclose = function(){
						message('<p class="event">Socket Status: '+socket.readyState+' (Closed)');
					}
			} catch(exception){
				message('<p>Error'+exception);
			}
	}



	$('#disconnect').click(function(){
		socket.close();
	});



	if (!("WebSocket" in window)){
		$('#chatLog, input, button, #examples').fadeOut("fast");
		$('<p>You need a browser that supports WebSockets. How about <a href="http://www.google.com/chrome">Google Chrome</a>?</p>').appendTo('#todocontainer');
	}else{
		//The user has WebSockets
		connect();
	}



});


	function create_user(element) {
	if (event.keyCode === 13) {
			var data_to_send = { user : "" }

			try{
				data_to_send.user  = $('#user').val();
				socket.send('/adduser ' + JSON.stringify( data_to_send ) );

			} catch(exception){
				message('<p class="warning">');
			}
		}
	}

	function message(msg){
		$('#chatLog').append(msg+'</p>' );
	}//End message()

	function data(msg_data){
		if ( msg_data.indexOf ("taskcreated") == 0 ) {
			$('#chatLog').append('<p>' + msg_data.substring(11) + '</p>' );
		} else {
			$('#chatLog').append('<p>' + msg_data + '</p>' );
		}
	}//End data()




</script>
<meta charset="utf-8" />
<style type="text/css">
body {font-family:Arial, Helvetica, sans-serif;}
#chatLog { padding:5px; border:1px solid black; }
#chatLog p {margin:0;}
.event {color:#999;}
.warning { font-weight:bold; color:#CCC; }
</style>
<title>BSharp AB ToDo Admin Page</title>
</head>
<body>



  <div>
    	<h1>BSharp AB ToDo Admin Page</h1>
        	<div><input id="user" type="text" placeholder="Add a user" onkeydown="create_user()"></input><br></div>
       
 
	</div>
 
 	<div  id="chatLog"></div>

       	<div ><button id="disconnect">Disconnect</button><br></div>

 </body>
</html>
			]"
			Result.replace_substring_all ("##HOSTNAME##", a_host)
			Result.replace_substring_all ("##PORTNUMBER##", a_port.out)
			if request.is_https then
				Result.replace_substring_all ("##HTTPSCHEME##", "https")
				Result.replace_substring_all ("##WSSCHEME##", "wss")
			else
				Result.replace_substring_all ("##HTTPSCHEME##", "http")
				Result.replace_substring_all ("##WSSCHEME##", "ws")
			end
		end

end
