# SharedPnpFunctions.ps1

function SetPnPHomePage($folderRelativeUrl)
{
	$result = Set-PnPHomePage -RootFolderRelativeUrl $folderRelativeUrl
}

function AddPnPFile($path, $folder, $checkedInUrl)
{
	# Skip file uploads when Custom Script is disabled
	if ($global:SkipCustomScriptOperations -eq $true)
	{
		Info "Skipping file upload to $folder (modern mode — Custom Script operations disabled)"
		return
	}

	if ($SPversion -ne "foundation")
	{
		$result = Add-PnPFile -Path $path -Folder $folder -Checkout -Publish
	}
	else 
	{
		$result = Add-PnPFile -Path $path -Folder $folder
	}

	if ($checkedInUrl -ne $null) 
	{
		$result = Set-PnPFileCheckedIn -Url $checkedInUrl
	}
}

# Fields

function GetPnPField($fieldName, $listTitle)
{
	try
	{
		if ($listTitle -ne $null)
		{
			$field = Get-PnPField -List $listTitle -Identity $fieldName
		}
		else 
		{
			try
			{
				$field = Get-PnPField -Identity $fieldName
			}
			catch 
			{
				$field = Get-PnPField -Identity $fieldName -InSiteHierarchy
			}
		}

		return $field
	}
	catch 
	{
		return $null
	}
}

function GetPnPFieldWithListTitle($fieldName, $listTitle)
{
	$field = GetPnpField $fieldName $listTitle
	return @($field, $listTitle)
}

function AddPnPFieldFromXml($xml, $lookupListTitle, $checkFieldName, $listTitle, [switch]$ignoreDuplicateException) 
{
	if ($lookupListTitle -ne $null) 
	{
		$list = GetPnPList $lookupListTitle
		if ($list -ne $null)
		{
			$xml = $xml.Replace('$listId', $list.Id) 
		}
	}

	$checkField = $null
	if ($checkFieldName -ne $null) 
	{
		$checkField = GetPnPField $checkFieldName $listTitle
	}

	if ($checkField -ne $null) 
	{
		return
	}
	
	while ($true)
	{
		try
		{
			if ($listTitle -ne $null) 
			{
				$result = Add-PnPFieldFromXml -List $listTitle -FieldXml $xml
			}
			else 
			{
				$result = Add-PnPFieldFromXml -FieldXml $xml
			}

			return
		}
		catch 
		{
			$serverErrorCode = $_.Exception.ServerErrorCode
			if ($ignoreDuplicateException -and $serverErrorCode -eq -2146232832)
			{
				return
			}

			# The local device name is already in use. (Exception from HRESULT: 0x80070055)
			if ($serverErrorCode -eq -2147024811)
			{
				$pos = $xml.IndexOf("ID") + 5
				$oldGuid = $xml.Substring($pos, 36)
				$newGuid = New-Guid
				$xml = $xml.Replace($oldGuid, $newGuid) 
				continue
			}

			throw
		}
	}
}

function RemovePnPField($fieldName, $listTitle, [switch]$ignoreException)
{
	$checkField = GetPnPField $fieldName $listTitle
	if ($checkField -eq $null) 
	{
		return
	}

	try 
	{
		if ($listTitle -ne $null) 
		{
			$result = Remove-PnPField -List $listTitle -Identity $fieldName -Force	
		}
		else 
		{
			$result = Remove-PnPField -Identity $fieldName -Force
		}
	}
	catch 
	{
		if ($ignoreException -eq $false)
		{
			throw
		}
	}
}

function HideField($fieldName, $listTitle)
{
	$field = GetPnPField $fieldName $listTitle
	$field.Hidden = $true
	$field.Required = $false
	$field.Update()
	Invoke-PnPQuery
}

# Content types

function GetPnPContentType($ctName, $listTitle)
{
	if ($listTitle -ne $null) 
	{
		$ct = Get-PnPContentType -Identity $ctName -List $listTitle -ErrorAction Ignore
	}
	else 
	{
		$ct = Get-PnPContentType -Identity $ctName -ErrorAction Ignore
		if ($ct -eq $null) 
		{
			$ct = Get-PnPContentType -Identity $ctName -InSiteHierarchy -ErrorAction Ignore
		}
	}

	return $ct
}

function AddPnPContentType($ctName, $ctId, $ctDescription)
{
	if ($ctDescription -eq $null) 
	{
		$ctDescription = ""
	}

	$ct = GetPnPContentType $ctName
	if ($ct -eq $null) 
	{
		try
		{
			$result = Add-PnPContentType -Name $ctName -ContentTypeId $ctId -Description $ctDescription -Group "AnywhereNow" 
		}
		catch
		{
			$serverErrorCode = $_.Exception.ServerErrorCode
			Error "$serverErrorCode - $ctId - $ctName"
			throw
		}
	}
}

function RemovePnPContentType($ctName)
{
	Remove-PnPContentType -Identity $ctName -Force
}

function AddPnPFieldsToContentType($ctName, $fieldNames, $orderFields)
{
	foreach ($fieldName in $fieldNames) 
	{
		$required = $false
		if ($fieldName -like "!*") 
		{ 
			$fieldName = $fieldName.Replace("!", "") 
			$required = $true
		}
		
		$field = GetPnPField $fieldName
		if ($field -eq $null)
		{
			# Field doesn't exist, skip it
			continue
		}
		
		if ($required)
		{
			$result = Add-PnPFieldToContentType -Field $field -ContentType $ctName -Required
		}
		else 
		{
			$result = Add-PnPFieldToContentType -Field $field -ContentType $ctName
		}
	}

	if ($orderFields -ne $null) 
	{
		$ct = GetPnPContentType $ctName
		if ($ct -ne $null)
		{
			$fieldLinks = Get-PnPProperty -ClientObject $ct -property "FieldLinks"
			$fieldLinks.Reorder($orderFields)
			$ct.Update($true)
			Invoke-PnPQuery
		}
	}
}

function RemoveFieldsFromContentType($ctName, $removeFields, $listTitle)
{
	$ct = GetPnPContentType $ctName $listTitle
	if ($ct -eq $null)
	{
		return
	}
	$fieldLinks = Get-PnPProperty -ClientObject $ct -property "FieldLinks"
	foreach ($removeField in $removeFields) 
	{
		$fieldLink = $fieldLinks | Where { $_.Name -eq $removeField } 
		if ($fieldLink -ne $null) 
		{
			$fieldLink.DeleteObject()
		}
	}	
		
	$ct.Update($false)
	Invoke-PnPQuery
}


function AddPnPContentTypesToList($listTitle, $contentTypes, [switch]$dontSetDefault)
{
	$defaultCtSet = $false
	foreach ($contentType in $contentTypes) 
	{
		if (!$defaultCtSet -and !$dontSetDefault) 
		{
			$result = Add-PnPContentTypeToList -List $listTitle -ContentType $contentType -DefaultContentType
			$defaultCtSet = $true
		}
		else 
		{
			$result = Add-PnPContentTypeToList -List $listTitle -ContentType $contentType
		}
	}

	Remove-PnPContentTypeFromList -List $listTitle -ContentType "Item"
}

function SetContentTypeFieldRequired($listTitle, $ctName, $fieldName, $required)
{
	$ct = GetPnPContentType $ctName $listTitle
	if ($ct -eq $null)
	{
		return
	}
	$fieldLinks = Get-PnPProperty -ClientObject $ct -property "FieldLinks"
	$fieldLink = $fieldLinks | Where { $_.Name -eq $fieldName } 
	$fieldLink.Required = $required
	$ct.Update($false)
	Invoke-PnPQuery
}

function SetContentTypeFieldDisplayName($listTitle, $ctName, $fieldName, $displayName)
{
	$ct = GetPnPContentType $ctName $listTitle
	if ($ct -eq $null)
	{
		return
	}
	$fieldLinks = Get-PnPProperty -ClientObject $ct -property "FieldLinks"
	$fieldLink = $fieldLinks | Where { $_.Name -eq $fieldName } 
	$fieldLink.DisplayName = $displayName
	$ct.Update($false)
	Invoke-PnPQuery
}

function SetContentTypeDescription($ctName, $ctDescription, $listTitle) 
{
	$ct = GetPnPContentType $ctName $listTitle
	$ct.Description = $ctDescription
	$ct.Update($false)
	Invoke-PnPQuery
}

# Views

function AddPnPView($listTitle, $viewUrl, $viewTitle, $rowLimit, $query, $fields, [switch]$default, [switch]$removeIfExists) 
{
	if ($removeIfExists) 
	{
		RemovePnPView $listTitle $viewTitle
	}
	
	if ($default) 
	{
		$result = Add-PnPView -List $listTitle -Title $viewUrl -RowLimit $rowLimit -Query $query -Fields $fields -Paged -SetAsDefault
	}
	else 
	{
		$result = Add-PnPView -List $listTitle -Title $viewUrl -RowLimit $rowLimit -Query $query -Fields $fields -Paged
	}

	if ($viewUrl -ne $viewTitle) 
	{
		$result = Set-PnPView -List $listTitle -Identity $viewUrl -Values @{Title = $viewTitle}
	}
}

function RemovePnPView($listTitle, $viewTitle) 
{
	$result = Remove-PnPView -List $listTitle -Identity $viewTitle -Force
}

# Forms

function AddForms($relativeURL, $listTitle, $extraViews, [switch]$removeIfExists) 
{
	# Skip webpart operations when Custom Script is disabled
	if ($global:SkipCustomScriptOperations -eq $true)
	{
		# Silently skip - lists work fine without custom form webparts
		return
	}

	$newForm = $relativeURL + "/Lists/$listTitle/NewForm.aspx"
	$editForm = $relativeURL + "/Lists/$listTitle/EditForm.aspx"
	$dispForm = $relativeURL + "/Lists/$listTitle/DispForm.aspx"
	$listviewForm = $relativeURL + "/Lists/$listTitle/AllItems.aspx"
	if ($removeIfExists) 
	{
		Remove-PnPWebPart -ServerRelativePageUrl $newForm -Title "JS"
		Remove-PnPWebPart -ServerRelativePageUrl $editForm -Title "JS"
		Remove-PnPWebPart -ServerRelativePageUrl $dispForm -Title "JS"
		Remove-PnPWebPart -ServerRelativePageUrl $listviewForm -Title "JS"
		Remove-PnPWebPart -ServerRelativePageUrl $listviewForm -Title "MakeRibbonVisible"
	}

	$result = Add-PnPWebPartToWebPartPage -ServerRelativePageUrl $newForm -Path "$RootPath\AnywhereNow\ListForms\$listTitle\add.webpart" -ZoneId "Main" -ZoneIndex 1
	$result = Add-PnPWebPartToWebPartPage -ServerRelativePageUrl $editForm -Path "$RootPath\AnywhereNow\ListForms\$listTitle\edit.webpart" -ZoneId "Main" -ZoneIndex 1
	$result = Add-PnPWebPartToWebPartPage -ServerRelativePageUrl $dispForm -Path "$RootPath\AnywhereNow\ListForms\$listTitle\disp.webpart" -ZoneId "Main" -ZoneIndex 1
	$result = Add-PnPWebPartToWebPartPage -ServerRelativePageUrl $listviewForm -Path "$RootPath\AnywhereNow\ListForms\$listTitle\listview.webpart" -ZoneId "Main" -ZoneIndex 1
	$result = Add-PnPWebPartToWebPartPage -ServerRelativePageUrl $listviewForm -Path "$RootPath\AnywhereNow\ListForms\MakeRibbonVisible.webpart" -ZoneId "Main" -ZoneIndex 1
	
	foreach ($view in $extraViews) 
	{
		$extraForm = $relativeURL + "/Lists/$listTitle/$view.aspx"
		if ($removeIfExists) 
		{
			Remove-PnPWebPart -ServerRelativePageUrl $extraForm -Title "JS"
			Remove-PnPWebPart -ServerRelativePageUrl $extraForm -Title "MakeRibbonVisible"
		}

		$result = Add-PnPWebPartToWebPartPage -ServerRelativePageUrl $extraForm -Path "$RootPath\AnywhereNow\ListForms\$listTitle\listview.webpart" -ZoneId "Main" -ZoneIndex 1
		$result = Add-PnPWebPartToWebPartPage -ServerRelativePageUrl $extraForm -Path "$RootPath\AnywhereNow\ListForms\MakeRibbonVisible.webpart" -ZoneId "Main" -ZoneIndex 1
	}
}

# Lists

function GetPnPList($listTitle, [switch]$includes)
{
	try
	{
		if ($includes) 
		{
			return Get-PnPList -Identity $listTitle -Includes ContentTypes, RootFolder.UniqueContentTypeOrder
		}
		else 
		{
			return Get-PnPList -Identity $listTitle
		}	
	}
	catch 
	{
		return $null
	}
}

function AddPnPList($listTitle, $listUrl, [switch]$documentLibrary, [switch]$survey, [switch]$removeDefaultView, [switch]$hidden, [switch]$enableContentTypes, [switch]$enableAttachments, [switch]$removeIfExists)
{
	$checkList = GetPnPList $listTitle
    if ($checkList -ne $null) 
	{
		if ($removeIfExists -eq $false)
		{
			return $false
		}
		
		RemovePnPList $listTitle
	}

	if ($listUrl -eq $null) 
	{
		$listUrl = $listTitle
	}

	if ($documentLibrary)
	{
		New-PnPList -Title $listUrl -Template DocumentLibrary -EnableVersioning
	}
	elseif ($survey)
	{
		New-PnPList -Title $listUrl -Template "Survey"  
	}
	else
	{
		New-PnPList -Title $listUrl -Template GenericList -EnableVersioning
		Set-PnPList -Identity $listUrl -EnableAttachments $false
	}

	if ($listUrl -ne $listTitle) 
	{
		Set-PnPList -Identity $listUrl -Title $listTitle
	}

	if ($removeDefaultView) 
	{
		$view = Get-PnPView -List $listTitle
		Remove-PnPView -List $listTitle -Identity $view.Id -Force
	}

	if ($hidden) 
	{
		Set-PnPList -Identity $listTitle -Hidden $true
	}

	if ($enableContentTypes)
	{
		Set-PnPList -Identity $listTitle -EnableContentTypes $true
	}

	if ($enableAttachments) 
	{
		Set-PnPList -Identity $listTitle -EnableAttachments $true
	}

	return $true
}

function RemovePnPList($listTitle)
{
	Remove-PnPList -Identity $listTitle -Force
}

# Items

function AddPnPListItem($listTitle, $values, $ctName)
{
	$retryCount = 0
	while ($retryCount -lt 3)
	{
		try
		{
			if ($ctName -ne $null)
			{
				$result = Add-PnPListItem -List $listTitle -ContentType $ctName -Values $values
			}
			else 
			{
				$result = Add-PnPListItem -List $listTitle -Values $values
			}

			break
		}
		catch 
		{
			$retryCount++
			if ($retryCount -lt 3)
			{
				Start-Sleep -s $retryCount
			}
			else 
			{
				Error "Could not add item to '$listTitle' list after 2 retry attempt(s)..." 
				throw $($_.Exception)
			}
		}
	}
}

function SetPnpListItem($listTitle, $identity, $values)
{
	$retryCount = 0
	while ($retryCount -lt 3)
	{
		try
		{
			$result = Set-PnPListItem -List $listTitle -Identity $identity -Values $values
			break
		}
		catch 
		{
			$retryCount++
			if ($retryCount -lt 3)
			{
				Start-Sleep -s $retryCount
			}
			else 
			{
				Error "Could not edit item in '$listTitle' list after 2 retry attempt(s)..." 
				throw $($_.Exception)
			}
		}
	}
}

function GetPnPListItem
{
	param($list, $query, $id, $fields)
	
	$checkList = GetPnPList $list
	if ($checklist -eq $null)
	{
		return $null
	}

	if ($query -ne $null)
	{
		return Get-PnPListItem -List $listTitle -Query $query
	}
	elseif ($id -ne $null)
	{
		return Get-PnPListItem -List $listTitle -Id $id
	}
	elseif ($fields -ne $null)
	{
		return Get-PnPListItem -List $listTitle -Fields $field
	}
	else
	{
		return Get-PnPListItem -List $listTitle
	}
}