note
	description: "[
		Simple API to call Google Custome Search Engine
		Example call:
		GET https://www.googleapis.com/customsearch/v1?key=INSERT_YOUR_API_KEY&cx=017576662512468239146:omuauf_lfve&q=lectures
	]"
	date: "$Date: 2015-10-09 08:11:07 -0300 (vi., 09 oct. 2015) $"
	revision: "$Revision: 97973 $"
	EIS: "name=Google Custom Search Engine", "src=https://developers.google.com/custom-search/json-api/v1/using_rest", "protocol=uri"

class
	GCSE_API

create
	make

feature {NONE} -- Initialization

	make (a_query_parameters: GCSE_QUERY_PARAMETERS)
			-- Create an object GCSE with query_parameters `a_query_parameters'
		do
			query_parameter := a_query_parameters
		ensure
			query_parameters_set: query_parameter = a_query_parameters
		end

feature -- Access

	base_uri: STRING_8 = "https://www.googleapis.com/customsearch/v1"
			-- Google custom search base URI.

	query_parameter: GCSE_QUERY_PARAMETERS
			-- Google custom search parameters.

	last_result: detachable GCSE_RESPONSE
			-- Search results.

feature -- Status Reports

	errors: detachable LIST [READABLE_STRING_8]
			-- optional list of error messages.

feature -- API

	search
			-- Search
		local
			l_parser: JSON_PARSER
			l_gcse_response: detachable GCSE_RESPONSE
		do
				-- Data format for the response.
				-- At the moment we are using the default value: json
				-- but it's possible to define atom response using the alt parameter.
			last_result := Void
			if attached get as l_response then
				create l_gcse_response
				l_gcse_response.set_status (l_response.status)
				l_gcse_response.set_status_nessage (l_response.status_message)

				if attached l_response.body as l_body then
					create l_parser.make_with_string (l_body)
					l_parser.parse_content
					if l_response.status = 200 and then l_parser.is_parsed and then attached {JSON_OBJECT} l_parser.parsed_json_object as jv then
							-- Queries
						if attached {JSON_OBJECT} jv.item (queries_key) as jqueries then
								-- Next Page
							if attached {GCSE_PAGE} query_page (next_page_key, jqueries) as l_page then
								l_gcse_response.set_next_page (l_page)
							end
								-- Current Page
							if attached {GCSE_PAGE} query_page (request_key, jqueries) as l_page then
								l_gcse_response.set_current_page (l_page)
							end
								-- Previous Page
							if attached {GCSE_PAGE} query_page (previous_page_key, jqueries) as l_page then
								l_gcse_response.set_previous_page (l_page)
							end
						end
						if attached {JSON_ARRAY} jv.item (items_key) as jitems then
							across jitems as ic loop
								if attached{JSON_OBJECT} ic.item as j_item  then
									l_gcse_response.add_item (item (j_item))
								end
							end
						end
					else
						put_error (l_body)
					end
				else
					put_error (l_response.status.out)
				end
			else
				put_error ("unknown")
			end
			last_result := l_gcse_response
		end

feature {NONE} -- REST API

	get: detachable RESPONSE
			-- Reading Data.
		local
			l_request: REQUEST
		do
			create l_request.make ("GET", new_uri)
			Result := l_request.execute
		end

feature {NONE} -- Implementation

	new_uri: STRING_8
			-- new uri (BaseUri?key=secret_value&cx=a_cx_id&q=a_query
			-- ?key=INSERT_YOUR_API_KEY&cx=017576662512468239146:omuauf_lfve&q=lectures
			-- full template BaseUri?q={searchTerms}&num={count?}&start={startIndex?}&lr={language?}&
			-- safe={safe?}&cx={cx?}&cref={cref?}&sort={sort?}&filter={filter?}&gl={gl?}&cr={cr?}&
			-- googlehost={googleHost?}&c2coff={disableCnTwTranslation?}&hq={hq?}&hl={hl?}&siteSearch={siteSearch?}&
			-- siteSearchFilter={siteSearchFilter?}&exactTerms={exactTerms?}&excludeTerms={excludeTerms?}&linkSite={linkSite?}&
			-- orTerms={orTerms?}&relatedSite={relatedSite?}&dateRestrict={dateRestrict?}&lowRange={lowRange?}&highRange={highRange?}&
			-- searchType={searchType}&fileType={fileType?}&rights={rights?}&imgSize={imgSize?}&imgType={imgType?}&
			-- imgColorType={imgColorType?}&imgDominantColor={imgDominantColor?}&alt=json"

		do
			create Result.make_from_string (base_uri)
			Result.append ("?key=")
			Result.append (query_parameter.secret)
			Result.append ("&cx=")
			Result.append (query_parameter.cx)
			Result.append ("&q=")
			Result.append (query_parameter.query)
				-- num
			if attached query_parameter.num as l_num then
				Result.append ("&num=")
				Result.append (l_num)
			end
			if attached query_parameter.start as l_start then
				Result.append ("&start=")
				Result.append (l_start)
			end
		end

	put_error (a_message: READABLE_STRING_GENERAL)
			-- put error message `a_message'.
		local
			l_errors: like errors
			utf: UTF_CONVERTER
		do
			l_errors := errors
			if l_errors = Void then
				create {ARRAYED_LIST [STRING]} l_errors.make (1)
				errors := l_errors
			end
			l_errors.force (utf.utf_32_string_to_utf_8_string_8 (a_message))
		end

	item (a_item: JSON_OBJECT): GCSE_PAGE_ITEM
			-- Google Result Metadata Item.
		do
			create Result
			if attached {JSON_STRING} a_item.item ("kind") as l_kind then
				Result.set_kind (l_kind.item)
			end
			if attached {JSON_STRING} a_item.item ("title") as l_title then
				Result.set_title (l_title.item)
			end
			if attached {JSON_STRING} a_item.item ("htmlTitle") as l_htmltitle then
				Result.set_html_title (l_htmltitle.unescaped_string_32)
			end
			if attached {JSON_STRING} a_item.item ("link") as l_link then
				Result.set_link (l_link.item)
			end
			if attached {JSON_STRING} a_item.item ("displayLink") as l_display_link then
				Result.set_display_link (l_display_link.item)
			end
			if attached {JSON_STRING} a_item.item ("snippet") as l_snippet then
				Result.set_snippet (l_snippet.unescaped_string_8)
			end
			if attached {JSON_STRING} a_item.item ("htmlSnippet") as l_html_snippet then
				Result.set_html_snippet (l_html_snippet.unescaped_string_32)
			end
			if attached {JSON_STRING} a_item.item ("formattedUrl") as l_formatted_url then
				Result.set_formatted_url (l_formatted_url.item)
			end
		end

	query_page (a_page_key: JSON_STRING; a_queries: JSON_OBJECT): detachable GCSE_PAGE
			-- Google result medata query. Return a query page based for a query with page key `a_page_key', if any.
		do
			if
				attached {JSON_ARRAY} a_queries.item (a_page_key) as jquerypage and then
				jquerypage.count > 0 and then
				attached {JSON_OBJECT} jquerypage.i_th (1) as jpage
			then
				create Result
				if attached {JSON_STRING} jpage.item ("title") as l_title then
					Result.set_title (l_title.item)
				end
				if attached {JSON_STRING} jpage.item ("totalResults") as l_results then
					Result.set_total_results (l_results.item.to_integer)
				end
				if attached {JSON_STRING} jpage.item ("searchTerms") as l_search_terms then
					Result.set_search_terms (l_search_terms.item)
				end
					-- TODO check if we should use INTEGER_64
				if attached {JSON_NUMBER} jpage.item ("count") as l_count then
					Result.set_count (l_count.integer_64_item.as_integer_32)
				end
				if attached {JSON_NUMBER} jpage.item ("startIndex") as l_index then
					Result.set_start_index (l_index.integer_64_item.as_integer_32)
				end
			end
		end

feature {NONE} -- JSON Keys

	queries_key: STRING = "queries"

	next_page_key: STRING = "nextPage"

	request_key: STRING = "request"

	previous_page_key: STRING = "previousPage"

	items_key: STRING = "items"

note
	copyright: "2011-2015 Javier Velilla, Jocelyn Fiat, Eiffel Software and others"
	license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)"
	source: "[
			Eiffel Software
			5949 Hollister Ave., Goleta, CA 93117 USA
			Telephone 805-685-1006, Fax 805-685-6869
			Website http://www.eiffel.com
			Customer support http://support.eiffel.com
		]"

end
