(* ::Package:: *)

ToCamelCase = RemoveDiacritics /* ResourceFunction[ResourceObject[Association["Name" -> "ToCamelCase", "UUID" -> "3228539e-4039-49b0-aabb-b70a922366ee", "ResourceType" -> "Function", "Description" -> "Takes a string and puts it in (lower) camel case.", "ResourceLocations" -> {CloudObject["https://www.wolframcloud.com/objects/user-6a5e82a9-068b-4620-a269-0974427cc934/Resources/322/3228539e-4039-49b0-aabb-b70a922366ee"]}, "Version" -> None, "Keywords" -> {"camel case", "text", "string"}, "ContributorInformation" -> Association["ContributedBy" -> "Andrew Steinacher"], "Documentation" -> Association["Usage" -> {Association["Usage" -> BoxData[RowBox[{StyleBox[RowBox[{StyleBox["ResourceFunction", "ResourceFunctionSymbol"], "[", StyleBox["\"ToCamelCase\"", "ResourceFunctionName"], "]"}], "ResourceFunctionHandle"], "[", StyleBox["string", FontSlant -> "Italic"], "]"}]], "Description" -> "converts string to (lower) camel case"]}, "Notes" -> {Cell["." "Camel case, also known as " " is a string without spaces where each word is capitalized, such as " " or "^2 camel capitals caps JaneDoe johnSmith medial, "Notes", CellEventActions -> {Inherited, {"KeyDown", "\t"} :> Replace[SelectionMove[SelectedNotebook[], After, Cell]; NotebookFind[SelectedNotebook[], "TabNext", Next, CellTags, AutoScroll -> True, WrapAround -> True], Blank[NotebookSelection] :> SelectionMove[SelectedNotebook[], All, CellContents, AutoScroll -> True]], PassEventsDown -> False, PassEventsUp -> False}, CellChangeTimes -> {{3.759241008455344*^9, 3.75924103809027*^9}, {3.759241121075864*^9, 3.7592411508818235`*^9}, {3.7592412102047434`*^9, 3.7592412116758904`*^9}, {3.7592416381785364`*^9, 3.7592416651002283`*^9}, {3.7592418677124877`*^9, 3.759241870829799*^9}, {3.7592420664307704`*^9, 3.7592420664317703`*^9}}, CellTags -> "TabNext", CellID -> 107622986], Cell["Camel case is a naming convention frequently used for variable names in computer programming.", "Notes", CellEventActions -> {Inherited, {"KeyDown", "\t"} :> Replace[SelectionMove[SelectedNotebook[], After, Cell]; NotebookFind[SelectedNotebook[], "TabNext", Next, CellTags, AutoScroll -> True, WrapAround -> True], Blank[NotebookSelection] :> SelectionMove[SelectedNotebook[], All, CellContents, AutoScroll -> True]], PassEventsDown -> False, PassEventsUp -> False}, CellChangeTimes -> {{3.759241008455344*^9, 3.75924103809027*^9}, {3.759241121075864*^9, 3.7592411508818235`*^9}, {3.7592412102047434`*^9, 3.7592412116758904`*^9}, {3.7592416381785364`*^9, 3.7592416651002283`*^9}, {3.7592418677124877`*^9, 3.759241870829799*^9}, {3.7592420668397703`*^9, 3.7592420889577703`*^9}}, CellID -> 22632747], Cell["." "). This is sometimes known as " "ToCamelCase converts strings to lower camel case (e.g. " case Dromedary johnSmith, "Notes", CellEventActions -> {Inherited, {"KeyDown", "\t"} :> Replace[SelectionMove[SelectedNotebook[], After, Cell]; NotebookFind[SelectedNotebook[], "TabNext", Next, CellTags, AutoScroll -> True, WrapAround -> True], Blank[NotebookSelection] :> SelectionMove[SelectedNotebook[], All, CellContents, AutoScroll -> True]], PassEventsDown -> False, PassEventsUp -> False}, CellChangeTimes -> {{3.759241008455344*^9, 3.75924103809027*^9}, {3.759241121075864*^9, 3.7592411508818235`*^9}, {3.7592412102047434`*^9, 3.7592412116758904`*^9}, {3.7592416381785364`*^9, 3.759241881849901*^9}, {3.75924202454677*^9, 3.75924203380377*^9}}, CellID -> 16434108], Cell["." "To create a string in upper camel case (e.g. " ") use Capitalize after ToCamelCase. This is sometimes known as " case JaneDoe Pascal, "Notes", CellChangeTimes -> {{3.7592418034350605`*^9, 3.759241810076724*^9}, {3.759241890019718*^9, 3.7592420439887705`*^9}}, CellID -> 504426250], Cell["The capitalized letters in a camel case string resemble the humps on a camel.", "Notes", CellEventActions -> {Inherited, {"KeyDown", "\t"} :> Replace[SelectionMove[SelectedNotebook[], After, Cell]; NotebookFind[SelectedNotebook[], "TabNext", Next, CellTags, AutoScroll -> True, WrapAround -> True], Blank[NotebookSelection] :> SelectionMove[SelectedNotebook[], All, CellContents, AutoScroll -> True]], PassEventsDown -> False, PassEventsUp -> False}, CellChangeTimes -> {{3.759241008455344*^9, 3.75924103809027*^9}, {3.759241121075864*^9, 3.7592411508818235`*^9}, {3.7592412102047434`*^9, 3.759241277801502*^9}, {3.7592413107327952`*^9, 3.7592413121119328`*^9}, {3.759241648948613*^9, 3.759241648955614*^9}}, CellID -> 381198450]}], "ExampleNotebook" -> NotebookObject[FrontEndObject[LinkObject["r7uga_shm", 3, 1]], 76], "ExampleNotebookData" -> Automatic, "ExternalLinks" -> {Hyperlink["https://en.wikipedia.org/wiki/Camel_case"]}, "FunctionLocation" -> CloudObject["https://www.wolframcloud.com/objects/user-6a5e82a9-068b-4620-a269-0974427cc934/Resources/322/3228539e-4039-49b0-aabb-b70a922366ee/download/DefinitionData"], "ShortName" -> "ToCamelCase", "SourceMetadata" -> Association["Citation" -> {"https://en.wikipedia.org/wiki/Camel_case"}], "SymbolName" -> "FunctionRepository`$3228539e403949b0aabbb70a922366ee`ToCamelCase", "VerificationTests" -> HoldComplete[VerificationTest[GeneralUtilities`ToCamelCase["This is a test"], "thisIsATest"], VerificationTest[GeneralUtilities`ToCamelCase["This is a test."], "thisIsATest."]]]]] /* Capitalize;

processData[data_List] := Module[
	{processedData},
	processedData = Last @ Reap[createRestaurantEntity[data], _, Rule];
	Association /@ Association[processedData]
];

createRestaurantEntity[l_List] := createRestaurantEntity /@ l;
createRestaurantEntity[a_Association] := Module[
	{canonicalName},
	canonicalName = ToCamelCase[a["restaurantname"]];
	Sow[
		Rule[
			canonicalName,
			<|
				"Name" -> #restaurantname,
				"RestaurantGroup" -> createEntity["RestaurantGroup"][#restaurantgroup],
				"PhoneNumber" -> #phonenumber,
				"URL" -> URL[#webaddress],
				"Cuisines" -> createEntity["Cuisine"][splitCuisineString[#cuisinename]],
				"OpeningDate" -> #openingdate,
				"ClosingDate" -> Replace[#closingdate, Except[_DateObject] -> Missing["CurrentlyOperating"]],
				"DateLastUpdated" -> #Timestamp,
				"StreetAddress" -> Replace[#streetaddress, Except[_String] -> Missing["NotAvailable"]],
				"Location" -> Replace[#streetaddress, Except[_GeoPosition] -> Missing["NotAvailable"]],
				"Cookbooks" -> createEntity["Cookbook"][canonicalName, handleList[#cookbookinformation]],
				"ImportantPeopleByRole" -> createEntity["ImportantPerson"][handleList[#importantpeople]],
				"AwardsByYear" -> createEntity["RestaurantAward"][filterMissingValues[Replace[#awardswon, Except[_List] -> {}]]]
			|>&[a] // Map[Replace[Missing[Except["CurrentlyOperating"], ___] -> Missing["NotAvailable"]]]
		],
		"AwardWinningRestaurant"
	];
];

filterMissingValues = Select[First/*MatchQ[_Missing]/*Not];
handleList[x_] := filterMissingValues[Replace[x, Except[_List] -> {}]];

createEntity[type_String][l_List] := createEntity[type] /@ l;
createEntity[type_String][s_String] := Module[
	{canonicalName = ToCamelCase[s]},
	Sow[Rule[canonicalName, iCreateEntityData[type][canonicalName, s]], type];
	Entity[type, canonicalName]
];
createEntity["Cookbook"][restaurant_String, l_List] := createEntity["Cookbook"][restaurant, #]& /@ l;
createEntity["Cookbook"][restaurant_String, a_Association] := Module[
	{canonicalName = ToCamelCase@Lookup[DeleteMissing[a], "cookbooktitle", restaurant <> "::" <> myRandomString[]]},
	Sow[
		Rule[
			canonicalName,
			<|
				"Name" -> #cookbooktitle,
				"Restaurants" -> {Entity["AwardWinningRestaurant", restaurant]},
				"Publisher" -> #cookbookpublisher,
				"ISBNs" -> DeleteMissing[{#cookbookisbn10, #cookbookisbn13}]
			|>&[a]
		],
		"Cookbook"
	];
	Entity["Cookbook", canonicalName]
];

createEntity[type : "ImportantPerson" | "RestaurantAward"][l : {__Association}] := Merge[
	createEntity[type] /@ l, Union];
createEntity["ImportantPerson"][a_Association] := Module[
	{canonicalName = ToCamelCase[a["name"]]},
	Sow[Rule[canonicalName, <|"Name" -> #name, "Titles" -> {#title}|>&[a]], "ImportantPerson"];
	a["title"] -> Entity["ImportantPerson", canonicalName]
];

createEntity["RestaurantAward"][a_Association] := Module[
	{canonicalName = ToCamelCase[a["awardname"]]},
	Sow[Rule[canonicalName, <|"Name" -> #awardname|>&[a]], "RestaurantAward"];
	a["awarddate"] -> Entity["RestaurantAward", canonicalName]
];

createEntity[type_String][___] := Missing["NotAvailable"];

iCreateEntityData[type_String][canonicalName_String, s_String] := <|"Name" -> s|>;
iCreateEntityData[type_String][___] := Missing["NotAvailable"];

splitCuisineString[s_String] := With[
	{split = StringSplit[s, ", " | " and " | " & " | "/"]},
	(StringTrim/*StringReplace[StartOfString ~~ "and " -> ""]/*StringTrim) /@ split
];
splitCuisineString[___] := Missing["NotAvailable"];

(* Short random string to avoid collisions if multiple "empty" cookbooks *)
myRandomString[] := ToUpperCase[StringJoin[IntegerString[RandomInteger[16, 4], 16]]];

