--[[

NoteCase Pro script

   See http://www.notecasepro.com/
   
   Notecase Pro sample script (requires Notecase Pro >= 3.5.0)

SCRIPT NAME: 59_GlobalSearch.lua

   Version 1.0 

PURPOSE: Implements global search system (i.e. not related to current document only).
The script throws a text input dialog for entry of a text to search for 
(case-sensitive) in all open documents. After the search, the script
displays a menu of note titles for notes in which the string was found. 
Selecting the note title in the menu and hitting the OK button or 
double-clicking the note title will take you to that note.

Each note title in the menu is preceded by a number that 
corresponds to a document tab index number for the document 
containing the "hit." For purposes of this script, document tab 
index numbers start on the left with tab 1.)

RIGHTS: This script's author, Miroslav Rajcic, hereby waives 
all copyright and related or neighboring rights to this script, 
pursuant to the Creative Commons CC0 Universal relinquishment 
of rights found at http://creativecommons.org/publicdomain/zero/1.0/

--]]

-- make sure app version supports necessary scriptable program commands
nMaj, nMin, nRev = Nc_Config_GetAppVersion()
if (nMaj < 3 or (nMaj == 3 and nMin < 5)) then
	Nc_GUI_MessageBox("ERROR: Script requires NcPro version >= 3.5.0")
	return
end 

function goto_search(tData, nIdx, nSearchLen)
	local nDocID = tData[nIdx]["doc"]
	local strNodeID = tData[nIdx]["note"]

	-- select note
	Nc_Doc_MakeCur(nDocID)
	Nc_Note_ID_SetCur(strNodeID)
	
	-- go to offset (convert to 0-based offset)
	local nOffset = tData[nIdx]["offset"] - 1
	local nIsText = (tData[nIdx]["target"] == "text")
	if nIsText then
	 Nc_GUI_Focus_Set(1)
	 Nc_Note_SelectionRange_Set(nDocID, strNodeID, nOffset, nOffset + nSearchLen)
	end
end

function prepare_menu(tData)
	-- prepare table version to fill the dialog
	local t = {}
	local nSize = #tData
	for i=1, nSize do
		t[#t + 1] = tData[i]["title"]
	end
	return t
end

function search_text(strSearch)
	-- make search case insensitive
	strSearch = utf8ex.lower(strSearch)
			
	-- search all open documents
	t = {}
	local nDocCount = Nc_App_GetDocCount()

	local nCurTotalNote = 0
	local nTotalNotes = 0
	for i=0,nDocCount-1 do
		local nDocID = Nc_Doc_ID_GetByIdx(i)
		nTotalNotes = nTotalNotes + Nc_Doc_NoteCount(nDocID);
	end
	Nc_GUI_ProgressDlg_Start("Searching", nTotalNotes)

	for i=0,nDocCount-1 do
		-- search single document
		local nDocID = Nc_Doc_ID_GetByIdx(i)
		local nNoteCount = Nc_Doc_NoteCount(nDocID)
		for j=0,nNoteCount-1 do
			-- search single note
			nCurTotalNote = nCurTotalNote + 1
			Nc_GUI_ProgressDlg_SetPos(nCurTotalNote)
			
			-- get document file name from path (if exists)
			local strPath = Nc_Doc_GetPath(nDocID)
			local strFile = ""
			if string.len(strPath) > 0 then
				local index = string.find(strPath, "/[^/]*$")
				if index == nil then
					index = string.find(strPath, "\\[^\\]*$")
				end	
				if index ~= nil then
					strFile = string.sub(strPath, index+1)
				end	
			end
			-- make document title equal to file name if path exists, doc number if not
			local strDocTitle = (i + 1)
			if string.len(strFile) > 0 then
				strDocTitle = strFile
			end
			
			local strNoteID = Nc_Note_ID_GetByIdx(nDocID, j)
			local strTitle = Nc_Note_Title_Get(nDocID, strNoteID)
			local strText = Nc_Note_Content_Get(nDocID, strNoteID)
	
			-- make search case insensitive
			strTitleCase = utf8ex.lower(strTitle)
			strTextCase = utf8ex.lower(strText)
	
			local nOffsetTitle = utf8ex.find(strTitleCase, strSearch);
			local nOffsetText = utf8ex.find(strTextCase, strSearch);
			if nil ~= nOffsetTitle or nil ~= nOffsetText then
				 tRow = {}
				 tRow["doc"] = nDocID
				 tRow["note"] = strNoteID
				 tRow["title"] = "[" .. strDocTitle .. "]: " .. strTitle
				 if nil ~= nOffsetText then
					tRow["offset"] = nOffsetText
					tRow["target"] = "text"
				 else
				  tRow["offset"] = nOffsetTitle
				  tRow["target"] = "title"
				 end
				 t[#t + 1] = tRow
			end
		end
	end
	Nc_GUI_ProgressDlg_Close()
	return t
end

-- ask for search text
local strSearch = Nc_GUI_InputDlg("Search text", "", "", 0, 1)
if strSearch == "" then
	return
end

-- perform search
tResults = search_text(strSearch)

-- loop until results closed
local nSelKey = 1
while 1 do
	-- show search results
	nSelKey = Nc_GUI_SelectionDlgTbl("Global Search", prepare_menu(tResults), #tResults .. " matches found for '" .. strSearch .. "'", nSelKey)
	if tResults == nil or nSelKey <= 0 then
		return
	end
	-- handle selection result
	goto_search(tResults, nSelKey, utf8ex.len(strSearch))
end